123370Smckusick /* 229090Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 323370Smckusick * All rights reserved. The Berkeley software License Agreement 423370Smckusick * specifies the terms and conditions for redistribution. 523370Smckusick * 6*37592Smarc * @(#)kern_fork.c 7.5 (Berkeley) 05/01/89 723370Smckusick */ 812791Ssam 917090Sbloom #include "param.h" 1017090Sbloom #include "systm.h" 1117090Sbloom #include "map.h" 1217090Sbloom #include "dir.h" 1317090Sbloom #include "user.h" 1417090Sbloom #include "kernel.h" 1517090Sbloom #include "proc.h" 1617090Sbloom #include "inode.h" 1717090Sbloom #include "seg.h" 1817090Sbloom #include "vm.h" 1917090Sbloom #include "text.h" 2017090Sbloom #include "file.h" 2117090Sbloom #include "acct.h" 2217090Sbloom #include "quota.h" 2312791Ssam 2437523Smckusick #include "machine/reg.h" 2537523Smckusick #include "machine/pte.h" 2637523Smckusick #include "machine/psl.h" 2737523Smckusick 2812791Ssam /* 2912791Ssam * fork system call. 3012791Ssam */ 3112791Ssam fork() 3212791Ssam { 3312791Ssam 3412791Ssam u.u_cdmap = zdmap; 3512791Ssam u.u_csmap = zdmap; 3612791Ssam if (swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap) == 0) { 3712791Ssam u.u_r.r_val2 = 0; 3812791Ssam return; 3912791Ssam } 4012791Ssam fork1(0); 4112791Ssam } 4212791Ssam 4312791Ssam vfork() 4412791Ssam { 4512791Ssam 4612791Ssam fork1(1); 4712791Ssam } 4812791Ssam 4912791Ssam fork1(isvfork) 5012791Ssam int isvfork; 5112791Ssam { 5212791Ssam register struct proc *p1, *p2; 5312791Ssam register a; 5412791Ssam 5512791Ssam a = 0; 5616528Skarels if (u.u_uid != 0) { 5716528Skarels for (p1 = allproc; p1; p1 = p1->p_nxt) 5816528Skarels if (p1->p_uid == u.u_uid) 5912791Ssam a++; 6016528Skarels for (p1 = zombproc; p1; p1 = p1->p_nxt) 6116528Skarels if (p1->p_uid == u.u_uid) 6216528Skarels a++; 6312791Ssam } 6412791Ssam /* 6512791Ssam * Disallow if 6612791Ssam * No processes at all; 6712791Ssam * not su and too many procs owned; or 6812791Ssam * not su and would take last slot. 6912791Ssam */ 7016528Skarels p2 = freeproc; 7112791Ssam if (p2==NULL) 7212791Ssam tablefull("proc"); 7316528Skarels if (p2==NULL || (u.u_uid!=0 && (p2->p_nxt == NULL || a>MAXUPRC))) { 7412791Ssam u.u_error = EAGAIN; 7512791Ssam if (!isvfork) { 7626353Skarels (void) vsexpand((size_t)0, &u.u_cdmap, 1); 7726353Skarels (void) vsexpand((size_t)0, &u.u_csmap, 1); 7812791Ssam } 7912791Ssam goto out; 8012791Ssam } 8112791Ssam p1 = u.u_procp; 8212791Ssam if (newproc(isvfork)) { 8312791Ssam u.u_r.r_val1 = p1->p_pid; 8412791Ssam u.u_r.r_val2 = 1; /* child */ 8516716Ssam u.u_start = time; 8612791Ssam u.u_acflag = AFORK; 8712791Ssam return; 8812791Ssam } 8912791Ssam u.u_r.r_val1 = p2->p_pid; 9012791Ssam 9112791Ssam out: 9212791Ssam u.u_r.r_val2 = 0; 9312791Ssam } 9412791Ssam 9512791Ssam /* 9612791Ssam * Create a new process-- the internal version of 9712791Ssam * sys fork. 9812791Ssam * It returns 1 in the new process, 0 in the old. 9912791Ssam */ 10012791Ssam newproc(isvfork) 10112791Ssam int isvfork; 10212791Ssam { 10312791Ssam register struct proc *rpp, *rip; 10412791Ssam register int n; 10512791Ssam register struct file *fp; 10616528Skarels static int pidchecked = 0; 10712791Ssam 10812791Ssam /* 10912791Ssam * First, just locate a slot for a process 11012791Ssam * and copy the useful info from this process into it. 11112791Ssam * The panic "cannot happen" because fork has already 11212791Ssam * checked for the existence of a slot. 11312791Ssam */ 11416528Skarels mpid++; 11512791Ssam retry: 11612791Ssam if (mpid >= 30000) { 11716528Skarels mpid = 100; 11816528Skarels pidchecked = 0; 11912791Ssam } 12016528Skarels if (mpid >= pidchecked) { 12116528Skarels int doingzomb = 0; 12216578Ssam 12316528Skarels pidchecked = 30000; 12416528Skarels /* 12516528Skarels * Scan the proc table to check whether this pid 12616528Skarels * is in use. Remember the lowest pid that's greater 12716528Skarels * than mpid, so we can avoid checking for a while. 12816528Skarels */ 12916528Skarels rpp = allproc; 13016528Skarels again: 13116528Skarels for (; rpp != NULL; rpp = rpp->p_nxt) { 13235810Smarc if (rpp->p_pid == mpid || rpp->p_pgrp->pg_id == mpid) { 13316528Skarels mpid++; 13416528Skarels if (mpid >= pidchecked) 13516528Skarels goto retry; 13616528Skarels } 13716578Ssam if (rpp->p_pid > mpid && pidchecked > rpp->p_pid) 13816528Skarels pidchecked = rpp->p_pid; 13935810Smarc if (rpp->p_pgrp->pg_id > mpid && 14035810Smarc pidchecked > rpp->p_pgrp->pg_id) 14135810Smarc pidchecked = rpp->p_pgrp->pg_id; 14216528Skarels } 14316528Skarels if (!doingzomb) { 14416528Skarels doingzomb = 1; 14516528Skarels rpp = zombproc; 14616528Skarels goto again; 14716528Skarels } 14812791Ssam } 14916528Skarels if ((rpp = freeproc) == NULL) 15012791Ssam panic("no procs"); 15112791Ssam 15216528Skarels freeproc = rpp->p_nxt; /* off freeproc */ 15316528Skarels rpp->p_nxt = allproc; /* onto allproc */ 15416528Skarels rpp->p_nxt->p_prev = &rpp->p_nxt; /* (allproc is never NULL) */ 15516528Skarels rpp->p_prev = &allproc; 15616528Skarels allproc = rpp; 15716528Skarels 15812791Ssam /* 15912791Ssam * Make a proc table entry for the new process. 16012791Ssam */ 16112791Ssam rip = u.u_procp; 16212791Ssam #ifdef QUOTA 16312791Ssam rpp->p_quota = rip->p_quota; 16412791Ssam rpp->p_quota->q_cnt++; 16512791Ssam #endif 16629946Skarels #if defined(tahoe) 16729946Skarels rpp->p_ckey = rip->p_ckey; 16829946Skarels rpp->p_dkey = 0; 16929946Skarels #endif 17012791Ssam rpp->p_stat = SIDL; 17112791Ssam timerclear(&rpp->p_realtimer.it_value); 17212882Ssam rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SOUSIG)); 17312791Ssam if (isvfork) { 17412791Ssam rpp->p_flag |= SVFORK; 17512791Ssam rpp->p_ndx = rip->p_ndx; 17612791Ssam } else 17712791Ssam rpp->p_ndx = rpp - proc; 17812791Ssam rpp->p_uid = rip->p_uid; 17912791Ssam rpp->p_pgrp = rip->p_pgrp; 18035810Smarc rpp->p_pgrpnxt = rip->p_pgrpnxt; 18135810Smarc rip->p_pgrpnxt = rpp; 18212791Ssam rpp->p_nice = rip->p_nice; 18312791Ssam rpp->p_textp = isvfork ? 0 : rip->p_textp; 18412791Ssam rpp->p_pid = mpid; 18512791Ssam rpp->p_ppid = rip->p_pid; 18612791Ssam rpp->p_pptr = rip; 18712791Ssam rpp->p_osptr = rip->p_cptr; 18812791Ssam if (rip->p_cptr) 18912791Ssam rip->p_cptr->p_ysptr = rpp; 19012791Ssam rpp->p_ysptr = NULL; 19112791Ssam rpp->p_cptr = NULL; 19212791Ssam rip->p_cptr = rpp; 19312791Ssam rpp->p_time = 0; 19412791Ssam rpp->p_cpu = 0; 19512882Ssam rpp->p_sigmask = rip->p_sigmask; 19612882Ssam rpp->p_sigcatch = rip->p_sigcatch; 19712882Ssam rpp->p_sigignore = rip->p_sigignore; 19812882Ssam /* take along any pending signals like stops? */ 19912791Ssam if (isvfork) { 20012791Ssam rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0; 20112791Ssam rpp->p_szpt = clrnd(ctopt(UPAGES)); 20212791Ssam forkstat.cntvfork++; 20312791Ssam forkstat.sizvfork += rip->p_dsize + rip->p_ssize; 20412791Ssam } else { 20512791Ssam rpp->p_tsize = rip->p_tsize; 20612791Ssam rpp->p_dsize = rip->p_dsize; 20712791Ssam rpp->p_ssize = rip->p_ssize; 20812791Ssam rpp->p_szpt = rip->p_szpt; 20912791Ssam forkstat.cntfork++; 21012791Ssam forkstat.sizfork += rip->p_dsize + rip->p_ssize; 21112791Ssam } 212*37592Smarc #ifdef KTRACE 213*37592Smarc if (rip->p_flag&SKTR) { 214*37592Smarc rpp->p_flag |= SKTR; 215*37592Smarc if ((rpp->p_tracep = rip->p_tracep) != NULL) { 216*37592Smarc igrab(rpp->p_tracep); 217*37592Smarc iunlock(rpp->p_tracep); 218*37592Smarc } 219*37592Smarc rpp->p_traceflag = rip->p_traceflag; 220*37592Smarc } else { 221*37592Smarc rpp->p_tracep = NULL; 222*37592Smarc rpp->p_traceflag = 0; 223*37592Smarc } 224*37592Smarc #endif 22512791Ssam rpp->p_rssize = 0; 22612791Ssam rpp->p_maxrss = rip->p_maxrss; 22712791Ssam rpp->p_wchan = 0; 22812791Ssam rpp->p_slptime = 0; 22912791Ssam rpp->p_pctcpu = 0; 23012791Ssam rpp->p_cpticks = 0; 23112791Ssam n = PIDHASH(rpp->p_pid); 23216528Skarels rpp->p_idhash = pidhash[n]; 23312791Ssam pidhash[n] = rpp - proc; 23412791Ssam multprog++; 23512791Ssam 23612791Ssam /* 23712791Ssam * Increase reference counts on shared objects. 23812791Ssam */ 23921102Skarels for (n = 0; n <= u.u_lastfile; n++) { 24012791Ssam fp = u.u_ofile[n]; 24112791Ssam if (fp == NULL) 24212791Ssam continue; 24312791Ssam fp->f_count++; 24412791Ssam } 24512791Ssam u.u_cdir->i_count++; 24612791Ssam if (u.u_rdir) 24712791Ssam u.u_rdir->i_count++; 24812791Ssam 24912791Ssam /* 25012791Ssam * This begins the section where we must prevent the parent 25112791Ssam * from being swapped. 25212791Ssam */ 25312791Ssam rip->p_flag |= SKEEP; 25412791Ssam if (procdup(rpp, isvfork)) 25512791Ssam return (1); 25612791Ssam 25712791Ssam /* 25812791Ssam * Make child runnable and add to run queue. 25912791Ssam */ 26026277Skarels (void) splclock(); 26112791Ssam rpp->p_stat = SRUN; 26212791Ssam setrq(rpp); 26312791Ssam (void) spl0(); 26412791Ssam 26512791Ssam /* 26612791Ssam * Cause child to take a non-local goto as soon as it runs. 26712791Ssam * On older systems this was done with SSWAP bit in proc 26812791Ssam * table; on VAX we use u.u_pcb.pcb_sswap so don't need 26912791Ssam * to do rpp->p_flag |= SSWAP. Actually do nothing here. 27012791Ssam */ 27112791Ssam /* rpp->p_flag |= SSWAP; */ 27212791Ssam 27312791Ssam /* 27412791Ssam * Now can be swapped. 27512791Ssam */ 27612791Ssam rip->p_flag &= ~SKEEP; 27712791Ssam 27812791Ssam /* 27912791Ssam * If vfork make chain from parent process to child 28012791Ssam * (where virtal memory is temporarily). Wait for 28112791Ssam * child to finish, steal virtual memory back, 28212791Ssam * and wakeup child to let it die. 28312791Ssam */ 28412791Ssam if (isvfork) { 28512791Ssam u.u_procp->p_xlink = rpp; 28612791Ssam u.u_procp->p_flag |= SNOVM; 28712791Ssam while (rpp->p_flag & SVFORK) 28812791Ssam sleep((caddr_t)rpp, PZERO - 1); 28912791Ssam if ((rpp->p_flag & SLOAD) == 0) 29012791Ssam panic("newproc vfork"); 29112791Ssam uaccess(rpp, Vfmap, &vfutl); 29212791Ssam u.u_procp->p_xlink = 0; 29312791Ssam vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap); 29412791Ssam u.u_procp->p_flag &= ~SNOVM; 29512791Ssam rpp->p_ndx = rpp - proc; 29612791Ssam rpp->p_flag |= SVFDONE; 29712791Ssam wakeup((caddr_t)rpp); 29812791Ssam } 29912791Ssam 30012791Ssam /* 30112791Ssam * 0 return means parent. 30212791Ssam */ 30312791Ssam return (0); 30412791Ssam } 305