123370Smckusick /* 237728Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 337728Smckusick * All rights reserved. 423370Smckusick * 537728Smckusick * Redistribution and use in source and binary forms are permitted 637728Smckusick * provided that the above copyright notice and this paragraph are 737728Smckusick * duplicated in all such forms and that any documentation, 837728Smckusick * advertising materials, and other materials related to such 937728Smckusick * distribution and use acknowledge that the software was developed 1037728Smckusick * by the University of California, Berkeley. The name of the 1137728Smckusick * University may not be used to endorse or promote products derived 1237728Smckusick * from this software without specific prior written permission. 1337728Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1437728Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1537728Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1637728Smckusick * 17*42087Sbostic * @(#)kern_fork.c 7.15 (Berkeley) 05/15/90 1823370Smckusick */ 1912791Ssam 2017090Sbloom #include "param.h" 2117090Sbloom #include "systm.h" 2217090Sbloom #include "map.h" 2317090Sbloom #include "user.h" 2417090Sbloom #include "kernel.h" 2517090Sbloom #include "proc.h" 2637728Smckusick #include "vnode.h" 2717090Sbloom #include "seg.h" 2817090Sbloom #include "vm.h" 2917090Sbloom #include "text.h" 3017090Sbloom #include "file.h" 3117090Sbloom #include "acct.h" 3240812Smarc #include "ktrace.h" 3337728Smckusick #include "../ufs/quota.h" 3412791Ssam 3537523Smckusick #include "machine/reg.h" 3637523Smckusick #include "machine/pte.h" 3737523Smckusick #include "machine/psl.h" 3837523Smckusick 3912791Ssam /* 4012791Ssam * fork system call. 4112791Ssam */ 4212791Ssam fork() 4312791Ssam { 4412791Ssam 4512791Ssam u.u_cdmap = zdmap; 4612791Ssam u.u_csmap = zdmap; 4712791Ssam if (swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap) == 0) { 4812791Ssam u.u_r.r_val2 = 0; 4912791Ssam return; 5012791Ssam } 5112791Ssam fork1(0); 5212791Ssam } 5312791Ssam 5412791Ssam vfork() 5512791Ssam { 5612791Ssam 5712791Ssam fork1(1); 5812791Ssam } 5912791Ssam 6012791Ssam fork1(isvfork) 6112791Ssam int isvfork; 6212791Ssam { 6312791Ssam register struct proc *p1, *p2; 6412791Ssam register a; 6512791Ssam 6612791Ssam a = 0; 6716528Skarels if (u.u_uid != 0) { 6816528Skarels for (p1 = allproc; p1; p1 = p1->p_nxt) 6916528Skarels if (p1->p_uid == u.u_uid) 7012791Ssam a++; 7116528Skarels for (p1 = zombproc; p1; p1 = p1->p_nxt) 7216528Skarels if (p1->p_uid == u.u_uid) 7316528Skarels a++; 7412791Ssam } 7512791Ssam /* 7612791Ssam * Disallow if 7712791Ssam * No processes at all; 7812791Ssam * not su and too many procs owned; or 7912791Ssam * not su and would take last slot. 8012791Ssam */ 8116528Skarels p2 = freeproc; 8212791Ssam if (p2==NULL) 8312791Ssam tablefull("proc"); 8416528Skarels if (p2==NULL || (u.u_uid!=0 && (p2->p_nxt == NULL || a>MAXUPRC))) { 8512791Ssam u.u_error = EAGAIN; 8612791Ssam if (!isvfork) { 87*42087Sbostic (void) vsexpand((segsz_t)0, &u.u_cdmap, 1); 88*42087Sbostic (void) vsexpand((segsz_t)0, &u.u_csmap, 1); 8912791Ssam } 9012791Ssam goto out; 9112791Ssam } 9212791Ssam p1 = u.u_procp; 9312791Ssam if (newproc(isvfork)) { 9412791Ssam u.u_r.r_val1 = p1->p_pid; 9512791Ssam u.u_r.r_val2 = 1; /* child */ 9612791Ssam u.u_acflag = AFORK; 9712791Ssam return; 9812791Ssam } 9912791Ssam u.u_r.r_val1 = p2->p_pid; 10012791Ssam 10112791Ssam out: 10212791Ssam u.u_r.r_val2 = 0; 10312791Ssam } 10412791Ssam 10512791Ssam /* 10612791Ssam * Create a new process-- the internal version of 10712791Ssam * sys fork. 10812791Ssam * It returns 1 in the new process, 0 in the old. 10912791Ssam */ 11012791Ssam newproc(isvfork) 11112791Ssam int isvfork; 11212791Ssam { 11312791Ssam register struct proc *rpp, *rip; 11412791Ssam register int n; 11512791Ssam register struct file *fp; 11616528Skarels static int pidchecked = 0; 11712791Ssam 11812791Ssam /* 11912791Ssam * First, just locate a slot for a process 12012791Ssam * and copy the useful info from this process into it. 12112791Ssam * The panic "cannot happen" because fork has already 12212791Ssam * checked for the existence of a slot. 12312791Ssam */ 12416528Skarels mpid++; 12512791Ssam retry: 12612791Ssam if (mpid >= 30000) { 12716528Skarels mpid = 100; 12816528Skarels pidchecked = 0; 12912791Ssam } 13016528Skarels if (mpid >= pidchecked) { 13116528Skarels int doingzomb = 0; 13216578Ssam 13316528Skarels pidchecked = 30000; 13416528Skarels /* 13516528Skarels * Scan the proc table to check whether this pid 13616528Skarels * is in use. Remember the lowest pid that's greater 13716528Skarels * than mpid, so we can avoid checking for a while. 13816528Skarels */ 13916528Skarels rpp = allproc; 14016528Skarels again: 14116528Skarels for (; rpp != NULL; rpp = rpp->p_nxt) { 14235810Smarc if (rpp->p_pid == mpid || rpp->p_pgrp->pg_id == mpid) { 14316528Skarels mpid++; 14416528Skarels if (mpid >= pidchecked) 14516528Skarels goto retry; 14616528Skarels } 14716578Ssam if (rpp->p_pid > mpid && pidchecked > rpp->p_pid) 14816528Skarels pidchecked = rpp->p_pid; 14935810Smarc if (rpp->p_pgrp->pg_id > mpid && 15035810Smarc pidchecked > rpp->p_pgrp->pg_id) 15135810Smarc pidchecked = rpp->p_pgrp->pg_id; 15216528Skarels } 15316528Skarels if (!doingzomb) { 15416528Skarels doingzomb = 1; 15516528Skarels rpp = zombproc; 15616528Skarels goto again; 15716528Skarels } 15812791Ssam } 15916528Skarels if ((rpp = freeproc) == NULL) 16012791Ssam panic("no procs"); 16112791Ssam 16216528Skarels freeproc = rpp->p_nxt; /* off freeproc */ 16316528Skarels rpp->p_nxt = allproc; /* onto allproc */ 16416528Skarels rpp->p_nxt->p_prev = &rpp->p_nxt; /* (allproc is never NULL) */ 16516528Skarels rpp->p_prev = &allproc; 16616528Skarels allproc = rpp; 16716528Skarels 16812791Ssam /* 16912791Ssam * Make a proc table entry for the new process. 17012791Ssam */ 17112791Ssam rip = u.u_procp; 17229946Skarels #if defined(tahoe) 17329946Skarels rpp->p_ckey = rip->p_ckey; 17429946Skarels rpp->p_dkey = 0; 17529946Skarels #endif 17612791Ssam rpp->p_stat = SIDL; 17712791Ssam timerclear(&rpp->p_realtimer.it_value); 17841571Smckusick rpp->p_flag = SLOAD | (rip->p_flag & (SPAGV|SCTTY|SHPUX)); 17912791Ssam if (isvfork) { 18012791Ssam rpp->p_flag |= SVFORK; 18112791Ssam rpp->p_ndx = rip->p_ndx; 18212791Ssam } else 18312791Ssam rpp->p_ndx = rpp - proc; 18440812Smarc bcopy(rip->p_comm, rpp->p_comm, MAXCOMLEN+1); 18540812Smarc bcopy(rip->p_logname, rpp->p_logname, MAXLOGNAME); 18612791Ssam rpp->p_uid = rip->p_uid; 18738929Skarels rpp->p_ruid = rip->p_ruid; 18838929Skarels rpp->p_rgid = rip->p_rgid; 18912791Ssam rpp->p_pgrp = rip->p_pgrp; 19035810Smarc rpp->p_pgrpnxt = rip->p_pgrpnxt; 19135810Smarc rip->p_pgrpnxt = rpp; 19212791Ssam rpp->p_nice = rip->p_nice; 19312791Ssam rpp->p_textp = isvfork ? 0 : rip->p_textp; 19412791Ssam rpp->p_pid = mpid; 19512791Ssam rpp->p_ppid = rip->p_pid; 19612791Ssam rpp->p_pptr = rip; 19712791Ssam rpp->p_osptr = rip->p_cptr; 19812791Ssam if (rip->p_cptr) 19912791Ssam rip->p_cptr->p_ysptr = rpp; 20012791Ssam rpp->p_ysptr = NULL; 20112791Ssam rpp->p_cptr = NULL; 20212791Ssam rip->p_cptr = rpp; 20312791Ssam rpp->p_time = 0; 20441180Smarc bzero((caddr_t)&rpp->p_utime, sizeof (struct timeval)); 20541180Smarc bzero((caddr_t)&rpp->p_stime, sizeof (struct timeval)); 20612791Ssam rpp->p_cpu = 0; 20712882Ssam rpp->p_sigmask = rip->p_sigmask; 20812882Ssam rpp->p_sigcatch = rip->p_sigcatch; 20912882Ssam rpp->p_sigignore = rip->p_sigignore; 21012882Ssam /* take along any pending signals like stops? */ 21112791Ssam if (isvfork) { 21241571Smckusick rpp->p_tsize = rpp->p_dsize = rpp->p_mmsize = rpp->p_ssize = 0; 21341571Smckusick rpp->p_szpt = clrnd(ctopt(HIGHPAGES)); 21412791Ssam forkstat.cntvfork++; 21512791Ssam forkstat.sizvfork += rip->p_dsize + rip->p_ssize; 21612791Ssam } else { 21712791Ssam rpp->p_tsize = rip->p_tsize; 21812791Ssam rpp->p_dsize = rip->p_dsize; 21941571Smckusick rpp->p_mmsize = rip->p_mmsize; 22012791Ssam rpp->p_ssize = rip->p_ssize; 22112791Ssam rpp->p_szpt = rip->p_szpt; 22212791Ssam forkstat.cntfork++; 22312791Ssam forkstat.sizfork += rip->p_dsize + rip->p_ssize; 22412791Ssam } 22537592Smarc #ifdef KTRACE 22640812Smarc if (rip->p_traceflag&KTRFAC_INHERIT) { 22740812Smarc rpp->p_traceflag = rip->p_traceflag; 22838422Smarc if ((rpp->p_tracep = rip->p_tracep) != NULL) 22938422Smarc VREF(rpp->p_tracep); 23037592Smarc } else { 23137592Smarc rpp->p_tracep = NULL; 23237592Smarc rpp->p_traceflag = 0; 23337592Smarc } 23437592Smarc #endif 23512791Ssam rpp->p_rssize = 0; 23612791Ssam rpp->p_maxrss = rip->p_maxrss; 23712791Ssam rpp->p_wchan = 0; 23812791Ssam rpp->p_slptime = 0; 23912791Ssam rpp->p_pctcpu = 0; 24012791Ssam rpp->p_cpticks = 0; 24140812Smarc { 24240812Smarc struct proc **hash = &pidhash[PIDHASH(rpp->p_pid)]; 24340812Smarc 24440812Smarc rpp->p_hash = *hash; 24540812Smarc *hash = rpp; 24640812Smarc } 24712791Ssam multprog++; 24812791Ssam 24912791Ssam /* 25012791Ssam * Increase reference counts on shared objects. 25112791Ssam */ 25221102Skarels for (n = 0; n <= u.u_lastfile; n++) { 25312791Ssam fp = u.u_ofile[n]; 25412791Ssam if (fp == NULL) 25512791Ssam continue; 25612791Ssam fp->f_count++; 25712791Ssam } 25838347Smckusick VREF(u.u_cdir); 25912791Ssam if (u.u_rdir) 26038347Smckusick VREF(u.u_rdir); 26137728Smckusick crhold(u.u_cred); 26212791Ssam 26312791Ssam /* 26412791Ssam * This begins the section where we must prevent the parent 26512791Ssam * from being swapped. 26612791Ssam */ 26712791Ssam rip->p_flag |= SKEEP; 26841180Smarc if (procdup(rpp, isvfork)) { 26941180Smarc (void) splclock(); 27041180Smarc u.u_start = time; 27141180Smarc (void) spl0(); 27212791Ssam return (1); 27341180Smarc } 27412791Ssam 27512791Ssam /* 27612791Ssam * Make child runnable and add to run queue. 27712791Ssam */ 27826277Skarels (void) splclock(); 27912791Ssam rpp->p_stat = SRUN; 28012791Ssam setrq(rpp); 28112791Ssam (void) spl0(); 28212791Ssam 28312791Ssam /* 28412791Ssam * Cause child to take a non-local goto as soon as it runs. 28512791Ssam * On older systems this was done with SSWAP bit in proc 28612791Ssam * table; on VAX we use u.u_pcb.pcb_sswap so don't need 28712791Ssam * to do rpp->p_flag |= SSWAP. Actually do nothing here. 28812791Ssam */ 28912791Ssam /* rpp->p_flag |= SSWAP; */ 29012791Ssam 29112791Ssam /* 29212791Ssam * Now can be swapped. 29312791Ssam */ 29412791Ssam rip->p_flag &= ~SKEEP; 29512791Ssam 29612791Ssam /* 29712791Ssam * If vfork make chain from parent process to child 29812791Ssam * (where virtal memory is temporarily). Wait for 29912791Ssam * child to finish, steal virtual memory back, 30012791Ssam * and wakeup child to let it die. 30112791Ssam */ 30212791Ssam if (isvfork) { 30312791Ssam u.u_procp->p_xlink = rpp; 30412791Ssam u.u_procp->p_flag |= SNOVM; 30512791Ssam while (rpp->p_flag & SVFORK) 30612791Ssam sleep((caddr_t)rpp, PZERO - 1); 30712791Ssam if ((rpp->p_flag & SLOAD) == 0) 30812791Ssam panic("newproc vfork"); 30912791Ssam uaccess(rpp, Vfmap, &vfutl); 31012791Ssam u.u_procp->p_xlink = 0; 31112791Ssam vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap); 31212791Ssam u.u_procp->p_flag &= ~SNOVM; 31312791Ssam rpp->p_ndx = rpp - proc; 31412791Ssam rpp->p_flag |= SVFDONE; 31512791Ssam wakeup((caddr_t)rpp); 31612791Ssam } 31712791Ssam 31812791Ssam /* 31912791Ssam * 0 return means parent. 32012791Ssam */ 32112791Ssam return (0); 32212791Ssam } 323