123370Smckusick /* 2*37728Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3*37728Smckusick * All rights reserved. 423370Smckusick * 5*37728Smckusick * Redistribution and use in source and binary forms are permitted 6*37728Smckusick * provided that the above copyright notice and this paragraph are 7*37728Smckusick * duplicated in all such forms and that any documentation, 8*37728Smckusick * advertising materials, and other materials related to such 9*37728Smckusick * distribution and use acknowledge that the software was developed 10*37728Smckusick * by the University of California, Berkeley. The name of the 11*37728Smckusick * University may not be used to endorse or promote products derived 12*37728Smckusick * from this software without specific prior written permission. 13*37728Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*37728Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*37728Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16*37728Smckusick * 17*37728Smckusick * @(#)kern_fork.c 7.6 (Berkeley) 05/09/89 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" 26*37728Smckusick #include "vnode.h" 2717090Sbloom #include "seg.h" 2817090Sbloom #include "vm.h" 2917090Sbloom #include "text.h" 3017090Sbloom #include "file.h" 3117090Sbloom #include "acct.h" 32*37728Smckusick #include "../ufs/quota.h" 3312791Ssam 3437523Smckusick #include "machine/reg.h" 3537523Smckusick #include "machine/pte.h" 3637523Smckusick #include "machine/psl.h" 3737523Smckusick 3812791Ssam /* 3912791Ssam * fork system call. 4012791Ssam */ 4112791Ssam fork() 4212791Ssam { 4312791Ssam 4412791Ssam u.u_cdmap = zdmap; 4512791Ssam u.u_csmap = zdmap; 4612791Ssam if (swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap) == 0) { 4712791Ssam u.u_r.r_val2 = 0; 4812791Ssam return; 4912791Ssam } 5012791Ssam fork1(0); 5112791Ssam } 5212791Ssam 5312791Ssam vfork() 5412791Ssam { 5512791Ssam 5612791Ssam fork1(1); 5712791Ssam } 5812791Ssam 5912791Ssam fork1(isvfork) 6012791Ssam int isvfork; 6112791Ssam { 6212791Ssam register struct proc *p1, *p2; 6312791Ssam register a; 6412791Ssam 6512791Ssam a = 0; 6616528Skarels if (u.u_uid != 0) { 6716528Skarels for (p1 = allproc; p1; p1 = p1->p_nxt) 6816528Skarels if (p1->p_uid == u.u_uid) 6912791Ssam a++; 7016528Skarels for (p1 = zombproc; p1; p1 = p1->p_nxt) 7116528Skarels if (p1->p_uid == u.u_uid) 7216528Skarels a++; 7312791Ssam } 7412791Ssam /* 7512791Ssam * Disallow if 7612791Ssam * No processes at all; 7712791Ssam * not su and too many procs owned; or 7812791Ssam * not su and would take last slot. 7912791Ssam */ 8016528Skarels p2 = freeproc; 8112791Ssam if (p2==NULL) 8212791Ssam tablefull("proc"); 8316528Skarels if (p2==NULL || (u.u_uid!=0 && (p2->p_nxt == NULL || a>MAXUPRC))) { 8412791Ssam u.u_error = EAGAIN; 8512791Ssam if (!isvfork) { 8626353Skarels (void) vsexpand((size_t)0, &u.u_cdmap, 1); 8726353Skarels (void) vsexpand((size_t)0, &u.u_csmap, 1); 8812791Ssam } 8912791Ssam goto out; 9012791Ssam } 9112791Ssam p1 = u.u_procp; 9212791Ssam if (newproc(isvfork)) { 9312791Ssam u.u_r.r_val1 = p1->p_pid; 9412791Ssam u.u_r.r_val2 = 1; /* child */ 9516716Ssam u.u_start = time; 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; 17212791Ssam #ifdef QUOTA 17312791Ssam rpp->p_quota = rip->p_quota; 17412791Ssam rpp->p_quota->q_cnt++; 17512791Ssam #endif 17629946Skarels #if defined(tahoe) 17729946Skarels rpp->p_ckey = rip->p_ckey; 17829946Skarels rpp->p_dkey = 0; 17929946Skarels #endif 18012791Ssam rpp->p_stat = SIDL; 18112791Ssam timerclear(&rpp->p_realtimer.it_value); 182*37728Smckusick rpp->p_flag = SLOAD | (rip->p_flag & (SPAGV|SOUSIG)); 18312791Ssam if (isvfork) { 18412791Ssam rpp->p_flag |= SVFORK; 18512791Ssam rpp->p_ndx = rip->p_ndx; 18612791Ssam } else 18712791Ssam rpp->p_ndx = rpp - proc; 18812791Ssam rpp->p_uid = rip->p_uid; 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; 20412791Ssam rpp->p_cpu = 0; 20512882Ssam rpp->p_sigmask = rip->p_sigmask; 20612882Ssam rpp->p_sigcatch = rip->p_sigcatch; 20712882Ssam rpp->p_sigignore = rip->p_sigignore; 20812882Ssam /* take along any pending signals like stops? */ 20912791Ssam if (isvfork) { 21012791Ssam rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0; 21112791Ssam rpp->p_szpt = clrnd(ctopt(UPAGES)); 21212791Ssam forkstat.cntvfork++; 21312791Ssam forkstat.sizvfork += rip->p_dsize + rip->p_ssize; 21412791Ssam } else { 21512791Ssam rpp->p_tsize = rip->p_tsize; 21612791Ssam rpp->p_dsize = rip->p_dsize; 21712791Ssam rpp->p_ssize = rip->p_ssize; 21812791Ssam rpp->p_szpt = rip->p_szpt; 21912791Ssam forkstat.cntfork++; 22012791Ssam forkstat.sizfork += rip->p_dsize + rip->p_ssize; 22112791Ssam } 22237592Smarc #ifdef KTRACE 22337592Smarc if (rip->p_flag&SKTR) { 22437592Smarc rpp->p_flag |= SKTR; 22537592Smarc if ((rpp->p_tracep = rip->p_tracep) != NULL) { 22637592Smarc igrab(rpp->p_tracep); 22737592Smarc iunlock(rpp->p_tracep); 22837592Smarc } 22937592Smarc rpp->p_traceflag = rip->p_traceflag; 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; 24112791Ssam n = PIDHASH(rpp->p_pid); 24216528Skarels rpp->p_idhash = pidhash[n]; 24312791Ssam pidhash[n] = rpp - proc; 24412791Ssam multprog++; 24512791Ssam 24612791Ssam /* 24712791Ssam * Increase reference counts on shared objects. 24812791Ssam */ 24921102Skarels for (n = 0; n <= u.u_lastfile; n++) { 25012791Ssam fp = u.u_ofile[n]; 25112791Ssam if (fp == NULL) 25212791Ssam continue; 25312791Ssam fp->f_count++; 25412791Ssam } 255*37728Smckusick u.u_cdir->v_count++; 25612791Ssam if (u.u_rdir) 257*37728Smckusick u.u_rdir->v_count++; 258*37728Smckusick crhold(u.u_cred); 25912791Ssam 26012791Ssam /* 26112791Ssam * This begins the section where we must prevent the parent 26212791Ssam * from being swapped. 26312791Ssam */ 26412791Ssam rip->p_flag |= SKEEP; 26512791Ssam if (procdup(rpp, isvfork)) 26612791Ssam return (1); 26712791Ssam 26812791Ssam /* 26912791Ssam * Make child runnable and add to run queue. 27012791Ssam */ 27126277Skarels (void) splclock(); 27212791Ssam rpp->p_stat = SRUN; 27312791Ssam setrq(rpp); 27412791Ssam (void) spl0(); 27512791Ssam 27612791Ssam /* 27712791Ssam * Cause child to take a non-local goto as soon as it runs. 27812791Ssam * On older systems this was done with SSWAP bit in proc 27912791Ssam * table; on VAX we use u.u_pcb.pcb_sswap so don't need 28012791Ssam * to do rpp->p_flag |= SSWAP. Actually do nothing here. 28112791Ssam */ 28212791Ssam /* rpp->p_flag |= SSWAP; */ 28312791Ssam 28412791Ssam /* 28512791Ssam * Now can be swapped. 28612791Ssam */ 28712791Ssam rip->p_flag &= ~SKEEP; 28812791Ssam 28912791Ssam /* 29012791Ssam * If vfork make chain from parent process to child 29112791Ssam * (where virtal memory is temporarily). Wait for 29212791Ssam * child to finish, steal virtual memory back, 29312791Ssam * and wakeup child to let it die. 29412791Ssam */ 29512791Ssam if (isvfork) { 29612791Ssam u.u_procp->p_xlink = rpp; 29712791Ssam u.u_procp->p_flag |= SNOVM; 29812791Ssam while (rpp->p_flag & SVFORK) 29912791Ssam sleep((caddr_t)rpp, PZERO - 1); 30012791Ssam if ((rpp->p_flag & SLOAD) == 0) 30112791Ssam panic("newproc vfork"); 30212791Ssam uaccess(rpp, Vfmap, &vfutl); 30312791Ssam u.u_procp->p_xlink = 0; 30412791Ssam vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap); 30512791Ssam u.u_procp->p_flag &= ~SNOVM; 30612791Ssam rpp->p_ndx = rpp - proc; 30712791Ssam rpp->p_flag |= SVFDONE; 30812791Ssam wakeup((caddr_t)rpp); 30912791Ssam } 31012791Ssam 31112791Ssam /* 31212791Ssam * 0 return means parent. 31312791Ssam */ 31412791Ssam return (0); 31512791Ssam } 316