123370Smckusick /* 237728Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 337728Smckusick * All rights reserved. 423370Smckusick * 544434Sbostic * %sccs.include.redist.c% 637728Smckusick * 7*45005Skarels * @(#)kern_fork.c 7.20 (Berkeley) 07/27/90 823370Smckusick */ 912791Ssam 1017090Sbloom #include "param.h" 1117090Sbloom #include "systm.h" 1217090Sbloom #include "map.h" 1344404Skarels #include "user.h" 1417090Sbloom #include "kernel.h" 1517090Sbloom #include "proc.h" 1637728Smckusick #include "vnode.h" 1717090Sbloom #include "seg.h" 1817090Sbloom #include "vm.h" 1917090Sbloom #include "text.h" 2017090Sbloom #include "file.h" 2117090Sbloom #include "acct.h" 2240812Smarc #include "ktrace.h" 2337728Smckusick #include "../ufs/quota.h" 2412791Ssam 2537523Smckusick #include "machine/reg.h" 2637523Smckusick #include "machine/pte.h" 2737523Smckusick #include "machine/psl.h" 2837523Smckusick 2912791Ssam /* 3012791Ssam * fork system call. 3112791Ssam */ 3242921Smckusick /* ARGSUSED */ 3342921Smckusick fork(p, uap, retval) 3442921Smckusick struct proc *p; 3542921Smckusick struct args *uap; 3642921Smckusick int retval[]; 3712791Ssam { 3842921Smckusick int error; 3912791Ssam 4012791Ssam u.u_cdmap = zdmap; 4112791Ssam u.u_csmap = zdmap; 4242921Smckusick if (error = swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap)) { 4342921Smckusick retval[1] = 0; 4444404Skarels return (error); 4512791Ssam } 4644404Skarels return (fork1(p, 0, retval)); 4712791Ssam } 4812791Ssam 4942921Smckusick /* ARGSUSED */ 5042921Smckusick vfork(p, uap, retval) 5142921Smckusick struct proc *p; 5242921Smckusick struct args *uap; 5342921Smckusick int retval[]; 5412791Ssam { 5512791Ssam 5644404Skarels return (fork1(p, 1, retval)); 5712791Ssam } 5812791Ssam 5942921Smckusick fork1(p1, isvfork, retval) 6042921Smckusick register struct proc *p1; 6142921Smckusick int isvfork, retval[]; 6212791Ssam { 6342921Smckusick register struct proc *p2; 6442921Smckusick register int a; 6512791Ssam 6612791Ssam a = 0; 6742921Smckusick if (p1->p_uid != 0) { 6842921Smckusick for (p2 = allproc; p2; p2 = p2->p_nxt) 6942921Smckusick if (p2->p_uid == p1->p_uid) 7012791Ssam a++; 7142921Smckusick for (p2 = zombproc; p2; p2 = p2->p_nxt) 7242921Smckusick if (p2->p_uid == p1->p_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"); 8442921Smckusick if (p2 == NULL || 8542921Smckusick (p1->p_uid != 0 && (p2->p_nxt == NULL || a > MAXUPRC))) { 8612791Ssam if (!isvfork) { 8742087Sbostic (void) vsexpand((segsz_t)0, &u.u_cdmap, 1); 8842087Sbostic (void) vsexpand((segsz_t)0, &u.u_csmap, 1); 8912791Ssam } 9042921Smckusick retval[1] = 0; 9142921Smckusick return (EAGAIN); 9212791Ssam } 9312791Ssam if (newproc(isvfork)) { 9442921Smckusick retval[0] = p1->p_pid; 9542921Smckusick retval[1] = 1; /* child */ 9612791Ssam u.u_acflag = AFORK; 9742921Smckusick return (0); 9812791Ssam } 9942921Smckusick retval[0] = p2->p_pid; 10042921Smckusick retval[1] = 0; 10142921Smckusick return (0); 10212791Ssam } 10312791Ssam 10412791Ssam /* 10512791Ssam * Create a new process-- the internal version of 10612791Ssam * sys fork. 10712791Ssam * It returns 1 in the new process, 0 in the old. 10812791Ssam */ 10912791Ssam newproc(isvfork) 11012791Ssam int isvfork; 11112791Ssam { 11212791Ssam register struct proc *rpp, *rip; 11312791Ssam register int n; 11412791Ssam register struct file *fp; 11516528Skarels static int pidchecked = 0; 11612791Ssam 11712791Ssam /* 11812791Ssam * First, just locate a slot for a process 11912791Ssam * and copy the useful info from this process into it. 12012791Ssam * The panic "cannot happen" because fork has already 12112791Ssam * checked for the existence of a slot. 12212791Ssam */ 12316528Skarels mpid++; 12412791Ssam retry: 125*45005Skarels if (mpid >= PID_MAX) { 12616528Skarels mpid = 100; 12716528Skarels pidchecked = 0; 12812791Ssam } 12916528Skarels if (mpid >= pidchecked) { 13016528Skarels int doingzomb = 0; 13116578Ssam 132*45005Skarels pidchecked = PID_MAX; 13316528Skarels /* 13416528Skarels * Scan the proc table to check whether this pid 13516528Skarels * is in use. Remember the lowest pid that's greater 13616528Skarels * than mpid, so we can avoid checking for a while. 13716528Skarels */ 13816528Skarels rpp = allproc; 13916528Skarels again: 14016528Skarels for (; rpp != NULL; rpp = rpp->p_nxt) { 14135810Smarc if (rpp->p_pid == mpid || rpp->p_pgrp->pg_id == mpid) { 14216528Skarels mpid++; 14316528Skarels if (mpid >= pidchecked) 14416528Skarels goto retry; 14516528Skarels } 14616578Ssam if (rpp->p_pid > mpid && pidchecked > rpp->p_pid) 14716528Skarels pidchecked = rpp->p_pid; 14835810Smarc if (rpp->p_pgrp->pg_id > mpid && 14935810Smarc pidchecked > rpp->p_pgrp->pg_id) 15035810Smarc pidchecked = rpp->p_pgrp->pg_id; 15116528Skarels } 15216528Skarels if (!doingzomb) { 15316528Skarels doingzomb = 1; 15416528Skarels rpp = zombproc; 15516528Skarels goto again; 15616528Skarels } 15712791Ssam } 15816528Skarels if ((rpp = freeproc) == NULL) 15912791Ssam panic("no procs"); 16012791Ssam 16116528Skarels freeproc = rpp->p_nxt; /* off freeproc */ 16216528Skarels rpp->p_nxt = allproc; /* onto allproc */ 16316528Skarels rpp->p_nxt->p_prev = &rpp->p_nxt; /* (allproc is never NULL) */ 16416528Skarels rpp->p_prev = &allproc; 16516528Skarels allproc = rpp; 16616528Skarels 16712791Ssam /* 16812791Ssam * Make a proc table entry for the new process. 16912791Ssam */ 17012791Ssam rip = u.u_procp; 17129946Skarels #if defined(tahoe) 17229946Skarels rpp->p_ckey = rip->p_ckey; 17329946Skarels rpp->p_dkey = 0; 17429946Skarels #endif 17512791Ssam rpp->p_stat = SIDL; 17612791Ssam timerclear(&rpp->p_realtimer.it_value); 17742206Smarc rpp->p_flag = SLOAD | (rip->p_flag & (SPAGV|SHPUX)); 17842206Smarc if (rip->p_session->s_ttyvp != NULL && rip->p_flag & SCTTY) 17942206Smarc rpp->p_flag |= SCTTY; 18012791Ssam if (isvfork) { 18112791Ssam rpp->p_flag |= SVFORK; 18212791Ssam rpp->p_ndx = rip->p_ndx; 18312791Ssam } else 18412791Ssam rpp->p_ndx = rpp - proc; 18540812Smarc bcopy(rip->p_comm, rpp->p_comm, MAXCOMLEN+1); 18640812Smarc bcopy(rip->p_logname, rpp->p_logname, MAXLOGNAME); 18712791Ssam rpp->p_uid = rip->p_uid; 18838929Skarels rpp->p_ruid = rip->p_ruid; 18938929Skarels rpp->p_rgid = rip->p_rgid; 19012791Ssam rpp->p_pgrp = rip->p_pgrp; 19135810Smarc rpp->p_pgrpnxt = rip->p_pgrpnxt; 19235810Smarc rip->p_pgrpnxt = rpp; 19312791Ssam rpp->p_nice = rip->p_nice; 19412791Ssam rpp->p_textp = isvfork ? 0 : rip->p_textp; 19512791Ssam rpp->p_pid = mpid; 19612791Ssam rpp->p_ppid = rip->p_pid; 19712791Ssam rpp->p_pptr = rip; 19812791Ssam rpp->p_osptr = rip->p_cptr; 19912791Ssam if (rip->p_cptr) 20012791Ssam rip->p_cptr->p_ysptr = rpp; 20112791Ssam rpp->p_ysptr = NULL; 20212791Ssam rpp->p_cptr = NULL; 20312791Ssam rip->p_cptr = rpp; 20412791Ssam rpp->p_time = 0; 20541180Smarc bzero((caddr_t)&rpp->p_utime, sizeof (struct timeval)); 20641180Smarc bzero((caddr_t)&rpp->p_stime, sizeof (struct timeval)); 20712791Ssam rpp->p_cpu = 0; 20812882Ssam rpp->p_sigmask = rip->p_sigmask; 20912882Ssam rpp->p_sigcatch = rip->p_sigcatch; 21012882Ssam rpp->p_sigignore = rip->p_sigignore; 21112882Ssam /* take along any pending signals like stops? */ 21212791Ssam if (isvfork) { 21341571Smckusick rpp->p_tsize = rpp->p_dsize = rpp->p_mmsize = rpp->p_ssize = 0; 21441571Smckusick rpp->p_szpt = clrnd(ctopt(HIGHPAGES)); 21512791Ssam forkstat.cntvfork++; 21612791Ssam forkstat.sizvfork += rip->p_dsize + rip->p_ssize; 21712791Ssam } else { 21812791Ssam rpp->p_tsize = rip->p_tsize; 21912791Ssam rpp->p_dsize = rip->p_dsize; 22041571Smckusick rpp->p_mmsize = rip->p_mmsize; 22112791Ssam rpp->p_ssize = rip->p_ssize; 22212791Ssam rpp->p_szpt = rip->p_szpt; 22312791Ssam forkstat.cntfork++; 22412791Ssam forkstat.sizfork += rip->p_dsize + rip->p_ssize; 22512791Ssam } 22637592Smarc #ifdef KTRACE 22740812Smarc if (rip->p_traceflag&KTRFAC_INHERIT) { 22840812Smarc rpp->p_traceflag = rip->p_traceflag; 22938422Smarc if ((rpp->p_tracep = rip->p_tracep) != NULL) 23038422Smarc VREF(rpp->p_tracep); 23137592Smarc } else { 23237592Smarc rpp->p_tracep = NULL; 23337592Smarc rpp->p_traceflag = 0; 23437592Smarc } 23537592Smarc #endif 23612791Ssam rpp->p_rssize = 0; 23712791Ssam rpp->p_maxrss = rip->p_maxrss; 23812791Ssam rpp->p_wchan = 0; 23912791Ssam rpp->p_slptime = 0; 24012791Ssam rpp->p_pctcpu = 0; 24112791Ssam rpp->p_cpticks = 0; 24240812Smarc { 24340812Smarc struct proc **hash = &pidhash[PIDHASH(rpp->p_pid)]; 24440812Smarc 24540812Smarc rpp->p_hash = *hash; 24640812Smarc *hash = rpp; 24740812Smarc } 24812791Ssam multprog++; 24912791Ssam 25012791Ssam /* 25112791Ssam * Increase reference counts on shared objects. 25212791Ssam */ 25321102Skarels for (n = 0; n <= u.u_lastfile; n++) { 25412791Ssam fp = u.u_ofile[n]; 25512791Ssam if (fp == NULL) 25612791Ssam continue; 25712791Ssam fp->f_count++; 25812791Ssam } 25938347Smckusick VREF(u.u_cdir); 26012791Ssam if (u.u_rdir) 26138347Smckusick VREF(u.u_rdir); 26237728Smckusick crhold(u.u_cred); 26312791Ssam 26412791Ssam /* 26512791Ssam * This begins the section where we must prevent the parent 26612791Ssam * from being swapped. 26712791Ssam */ 26812791Ssam rip->p_flag |= SKEEP; 26941180Smarc if (procdup(rpp, isvfork)) { 27041180Smarc (void) splclock(); 27141180Smarc u.u_start = time; 27241180Smarc (void) spl0(); 27312791Ssam return (1); 27441180Smarc } 27512791Ssam 27612791Ssam /* 27712791Ssam * Make child runnable and add to run queue. 27812791Ssam */ 27926277Skarels (void) splclock(); 28012791Ssam rpp->p_stat = SRUN; 28112791Ssam setrq(rpp); 28212791Ssam (void) spl0(); 28312791Ssam 28412791Ssam /* 28512791Ssam * Cause child to take a non-local goto as soon as it runs. 28612791Ssam * On older systems this was done with SSWAP bit in proc 28712791Ssam * table; on VAX we use u.u_pcb.pcb_sswap so don't need 28812791Ssam * to do rpp->p_flag |= SSWAP. Actually do nothing here. 28912791Ssam */ 29012791Ssam /* rpp->p_flag |= SSWAP; */ 29112791Ssam 29212791Ssam /* 29312791Ssam * Now can be swapped. 29412791Ssam */ 29512791Ssam rip->p_flag &= ~SKEEP; 29612791Ssam 29712791Ssam /* 29812791Ssam * If vfork make chain from parent process to child 29912791Ssam * (where virtal memory is temporarily). Wait for 30012791Ssam * child to finish, steal virtual memory back, 30112791Ssam * and wakeup child to let it die. 30212791Ssam */ 30312791Ssam if (isvfork) { 30412791Ssam u.u_procp->p_xlink = rpp; 30512791Ssam u.u_procp->p_flag |= SNOVM; 30612791Ssam while (rpp->p_flag & SVFORK) 30712791Ssam sleep((caddr_t)rpp, PZERO - 1); 30812791Ssam if ((rpp->p_flag & SLOAD) == 0) 30912791Ssam panic("newproc vfork"); 31012791Ssam uaccess(rpp, Vfmap, &vfutl); 31112791Ssam u.u_procp->p_xlink = 0; 31212791Ssam vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap); 31312791Ssam u.u_procp->p_flag &= ~SNOVM; 31412791Ssam rpp->p_ndx = rpp - proc; 31512791Ssam rpp->p_flag |= SVFDONE; 31612791Ssam wakeup((caddr_t)rpp); 31712791Ssam } 31812791Ssam 31912791Ssam /* 32012791Ssam * 0 return means parent. 32112791Ssam */ 32212791Ssam return (0); 32312791Ssam } 324