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*45727Smckusick * @(#)kern_fork.c 7.22 (Berkeley) 12/05/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 "file.h" 1917090Sbloom #include "acct.h" 2040812Smarc #include "ktrace.h" 2112791Ssam 2237523Smckusick #include "machine/reg.h" 2337523Smckusick #include "machine/psl.h" 2437523Smckusick 2512791Ssam /* 2612791Ssam * fork system call. 2712791Ssam */ 2842921Smckusick /* ARGSUSED */ 2942921Smckusick fork(p, uap, retval) 3042921Smckusick struct proc *p; 3142921Smckusick struct args *uap; 3242921Smckusick int retval[]; 3312791Ssam { 3442921Smckusick int error; 3512791Ssam 3644404Skarels return (fork1(p, 0, retval)); 3712791Ssam } 3812791Ssam 3942921Smckusick /* ARGSUSED */ 4042921Smckusick vfork(p, uap, retval) 4142921Smckusick struct proc *p; 4242921Smckusick struct args *uap; 4342921Smckusick int retval[]; 4412791Ssam { 4512791Ssam 4644404Skarels return (fork1(p, 1, retval)); 4712791Ssam } 4812791Ssam 4942921Smckusick fork1(p1, isvfork, retval) 5042921Smckusick register struct proc *p1; 5142921Smckusick int isvfork, retval[]; 5212791Ssam { 5342921Smckusick register struct proc *p2; 5442921Smckusick register int a; 5512791Ssam 5612791Ssam a = 0; 5742921Smckusick if (p1->p_uid != 0) { 5842921Smckusick for (p2 = allproc; p2; p2 = p2->p_nxt) 5942921Smckusick if (p2->p_uid == p1->p_uid) 6012791Ssam a++; 6142921Smckusick for (p2 = zombproc; p2; p2 = p2->p_nxt) 6242921Smckusick if (p2->p_uid == p1->p_uid) 6316528Skarels a++; 6412791Ssam } 6512791Ssam /* 6612791Ssam * Disallow if 6712791Ssam * No processes at all; 6812791Ssam * not su and too many procs owned; or 6912791Ssam * not su and would take last slot. 7012791Ssam */ 7116528Skarels p2 = freeproc; 7212791Ssam if (p2==NULL) 7312791Ssam tablefull("proc"); 7442921Smckusick if (p2 == NULL || 7542921Smckusick (p1->p_uid != 0 && (p2->p_nxt == NULL || a > MAXUPRC))) { 7642921Smckusick retval[1] = 0; 7742921Smckusick return (EAGAIN); 7812791Ssam } 7912791Ssam if (newproc(isvfork)) { 8042921Smckusick retval[0] = p1->p_pid; 8142921Smckusick retval[1] = 1; /* child */ 8212791Ssam u.u_acflag = AFORK; 8342921Smckusick return (0); 8412791Ssam } 8542921Smckusick retval[0] = p2->p_pid; 8642921Smckusick retval[1] = 0; 8742921Smckusick return (0); 8812791Ssam } 8912791Ssam 9012791Ssam /* 9112791Ssam * Create a new process-- the internal version of 9212791Ssam * sys fork. 9312791Ssam * It returns 1 in the new process, 0 in the old. 9412791Ssam */ 9512791Ssam newproc(isvfork) 9612791Ssam int isvfork; 9712791Ssam { 9812791Ssam register struct proc *rpp, *rip; 9912791Ssam register int n; 10012791Ssam register struct file *fp; 10116528Skarels static int pidchecked = 0; 10212791Ssam 10312791Ssam /* 10412791Ssam * First, just locate a slot for a process 10512791Ssam * and copy the useful info from this process into it. 10612791Ssam * The panic "cannot happen" because fork has already 10712791Ssam * checked for the existence of a slot. 10812791Ssam */ 10916528Skarels mpid++; 11012791Ssam retry: 11145005Skarels if (mpid >= PID_MAX) { 11216528Skarels mpid = 100; 11316528Skarels pidchecked = 0; 11412791Ssam } 11516528Skarels if (mpid >= pidchecked) { 11616528Skarels int doingzomb = 0; 11716578Ssam 11845005Skarels pidchecked = PID_MAX; 11916528Skarels /* 12016528Skarels * Scan the proc table to check whether this pid 12116528Skarels * is in use. Remember the lowest pid that's greater 12216528Skarels * than mpid, so we can avoid checking for a while. 12316528Skarels */ 12416528Skarels rpp = allproc; 12516528Skarels again: 12616528Skarels for (; rpp != NULL; rpp = rpp->p_nxt) { 12735810Smarc if (rpp->p_pid == mpid || rpp->p_pgrp->pg_id == mpid) { 12816528Skarels mpid++; 12916528Skarels if (mpid >= pidchecked) 13016528Skarels goto retry; 13116528Skarels } 13216578Ssam if (rpp->p_pid > mpid && pidchecked > rpp->p_pid) 13316528Skarels pidchecked = rpp->p_pid; 13435810Smarc if (rpp->p_pgrp->pg_id > mpid && 13535810Smarc pidchecked > rpp->p_pgrp->pg_id) 13635810Smarc pidchecked = rpp->p_pgrp->pg_id; 13716528Skarels } 13816528Skarels if (!doingzomb) { 13916528Skarels doingzomb = 1; 14016528Skarels rpp = zombproc; 14116528Skarels goto again; 14216528Skarels } 14312791Ssam } 14416528Skarels if ((rpp = freeproc) == NULL) 14512791Ssam panic("no procs"); 14612791Ssam 14716528Skarels freeproc = rpp->p_nxt; /* off freeproc */ 14816528Skarels rpp->p_nxt = allproc; /* onto allproc */ 14916528Skarels rpp->p_nxt->p_prev = &rpp->p_nxt; /* (allproc is never NULL) */ 15016528Skarels rpp->p_prev = &allproc; 15116528Skarels allproc = rpp; 15216528Skarels 15312791Ssam /* 15412791Ssam * Make a proc table entry for the new process. 15512791Ssam */ 15612791Ssam rip = u.u_procp; 15729946Skarels #if defined(tahoe) 15829946Skarels rpp->p_ckey = rip->p_ckey; 15929946Skarels rpp->p_dkey = 0; 16029946Skarels #endif 16112791Ssam rpp->p_stat = SIDL; 16212791Ssam timerclear(&rpp->p_realtimer.it_value); 16342206Smarc rpp->p_flag = SLOAD | (rip->p_flag & (SPAGV|SHPUX)); 16442206Smarc if (rip->p_session->s_ttyvp != NULL && rip->p_flag & SCTTY) 16542206Smarc rpp->p_flag |= SCTTY; 166*45727Smckusick if (isvfork) 16712791Ssam rpp->p_flag |= SVFORK; 168*45727Smckusick rpp->p_ndx = rpp - proc; 16940812Smarc bcopy(rip->p_comm, rpp->p_comm, MAXCOMLEN+1); 17040812Smarc bcopy(rip->p_logname, rpp->p_logname, MAXLOGNAME); 17112791Ssam rpp->p_uid = rip->p_uid; 17238929Skarels rpp->p_ruid = rip->p_ruid; 17338929Skarels rpp->p_rgid = rip->p_rgid; 17412791Ssam rpp->p_pgrp = rip->p_pgrp; 17535810Smarc rpp->p_pgrpnxt = rip->p_pgrpnxt; 17635810Smarc rip->p_pgrpnxt = rpp; 17712791Ssam rpp->p_nice = rip->p_nice; 17812791Ssam rpp->p_pid = mpid; 17912791Ssam rpp->p_ppid = rip->p_pid; 18012791Ssam rpp->p_pptr = rip; 18112791Ssam rpp->p_osptr = rip->p_cptr; 18212791Ssam if (rip->p_cptr) 18312791Ssam rip->p_cptr->p_ysptr = rpp; 18412791Ssam rpp->p_ysptr = NULL; 18512791Ssam rpp->p_cptr = NULL; 18612791Ssam rip->p_cptr = rpp; 18712791Ssam rpp->p_time = 0; 18841180Smarc bzero((caddr_t)&rpp->p_utime, sizeof (struct timeval)); 18941180Smarc bzero((caddr_t)&rpp->p_stime, sizeof (struct timeval)); 19012791Ssam rpp->p_cpu = 0; 19112882Ssam rpp->p_sigmask = rip->p_sigmask; 19212882Ssam rpp->p_sigcatch = rip->p_sigcatch; 19312882Ssam rpp->p_sigignore = rip->p_sigignore; 19437592Smarc #ifdef KTRACE 19540812Smarc if (rip->p_traceflag&KTRFAC_INHERIT) { 19640812Smarc rpp->p_traceflag = rip->p_traceflag; 19738422Smarc if ((rpp->p_tracep = rip->p_tracep) != NULL) 19838422Smarc VREF(rpp->p_tracep); 19937592Smarc } else { 20037592Smarc rpp->p_tracep = NULL; 20137592Smarc rpp->p_traceflag = 0; 20237592Smarc } 20337592Smarc #endif 20412791Ssam rpp->p_rssize = 0; 20512791Ssam rpp->p_maxrss = rip->p_maxrss; 20612791Ssam rpp->p_wchan = 0; 20712791Ssam rpp->p_slptime = 0; 20812791Ssam rpp->p_pctcpu = 0; 20912791Ssam rpp->p_cpticks = 0; 21040812Smarc { 21140812Smarc struct proc **hash = &pidhash[PIDHASH(rpp->p_pid)]; 21240812Smarc 21340812Smarc rpp->p_hash = *hash; 21440812Smarc *hash = rpp; 21540812Smarc } 21612791Ssam 21712791Ssam /* 21812791Ssam * Increase reference counts on shared objects. 21912791Ssam */ 22021102Skarels for (n = 0; n <= u.u_lastfile; n++) { 22112791Ssam fp = u.u_ofile[n]; 22212791Ssam if (fp == NULL) 22312791Ssam continue; 22412791Ssam fp->f_count++; 22512791Ssam } 226*45727Smckusick #ifdef SYSVSHM 227*45727Smckusick if (rip->p_shm) 228*45727Smckusick shmfork(rip, rpp, isvfork); 229*45727Smckusick #endif 23038347Smckusick VREF(u.u_cdir); 23112791Ssam if (u.u_rdir) 23238347Smckusick VREF(u.u_rdir); 23337728Smckusick crhold(u.u_cred); 23412791Ssam 23512791Ssam /* 23612791Ssam * This begins the section where we must prevent the parent 23712791Ssam * from being swapped. 23812791Ssam */ 23912791Ssam rip->p_flag |= SKEEP; 24041180Smarc if (procdup(rpp, isvfork)) { 24141180Smarc (void) splclock(); 24241180Smarc u.u_start = time; 24341180Smarc (void) spl0(); 24412791Ssam return (1); 24541180Smarc } 24612791Ssam 24712791Ssam /* 24812791Ssam * Make child runnable and add to run queue. 24912791Ssam */ 25026277Skarels (void) splclock(); 25112791Ssam rpp->p_stat = SRUN; 25212791Ssam setrq(rpp); 25312791Ssam (void) spl0(); 25412791Ssam 25512791Ssam /* 25612791Ssam * Cause child to take a non-local goto as soon as it runs. 25712791Ssam * On older systems this was done with SSWAP bit in proc 25812791Ssam * table; on VAX we use u.u_pcb.pcb_sswap so don't need 25912791Ssam * to do rpp->p_flag |= SSWAP. Actually do nothing here. 26012791Ssam */ 26112791Ssam /* rpp->p_flag |= SSWAP; */ 26212791Ssam 26312791Ssam /* 26412791Ssam * Now can be swapped. 26512791Ssam */ 26612791Ssam rip->p_flag &= ~SKEEP; 26712791Ssam 26812791Ssam /* 269*45727Smckusick * XXX preserve synchronization semantics of vfork 27012791Ssam */ 27112791Ssam if (isvfork) { 27212791Ssam u.u_procp->p_flag |= SNOVM; 27312791Ssam while (rpp->p_flag & SVFORK) 27412791Ssam sleep((caddr_t)rpp, PZERO - 1); 27512791Ssam if ((rpp->p_flag & SLOAD) == 0) 27612791Ssam panic("newproc vfork"); 27712791Ssam u.u_procp->p_flag &= ~SNOVM; 27812791Ssam rpp->p_flag |= SVFDONE; 27912791Ssam wakeup((caddr_t)rpp); 28012791Ssam } 28112791Ssam 28212791Ssam /* 28312791Ssam * 0 return means parent. 28412791Ssam */ 28512791Ssam return (0); 28612791Ssam } 287