1*12791Ssam /* kern_fork.c 4.1 83/05/27 */ 2*12791Ssam 3*12791Ssam #include "../machine/reg.h" 4*12791Ssam #include "../machine/pte.h" 5*12791Ssam #include "../machine/psl.h" 6*12791Ssam 7*12791Ssam #include "../h/param.h" 8*12791Ssam #include "../h/systm.h" 9*12791Ssam #include "../h/map.h" 10*12791Ssam #include "../h/dir.h" 11*12791Ssam #include "../h/user.h" 12*12791Ssam #include "../h/kernel.h" 13*12791Ssam #include "../h/proc.h" 14*12791Ssam #include "../h/inode.h" 15*12791Ssam #include "../h/seg.h" 16*12791Ssam #include "../h/vm.h" 17*12791Ssam #include "../h/text.h" 18*12791Ssam #include "../h/file.h" 19*12791Ssam #include "../h/acct.h" 20*12791Ssam #include "../h/quota.h" 21*12791Ssam 22*12791Ssam /* 23*12791Ssam * fork system call. 24*12791Ssam */ 25*12791Ssam fork() 26*12791Ssam { 27*12791Ssam 28*12791Ssam u.u_cdmap = zdmap; 29*12791Ssam u.u_csmap = zdmap; 30*12791Ssam if (swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap) == 0) { 31*12791Ssam u.u_r.r_val2 = 0; 32*12791Ssam return; 33*12791Ssam } 34*12791Ssam fork1(0); 35*12791Ssam } 36*12791Ssam 37*12791Ssam vfork() 38*12791Ssam { 39*12791Ssam 40*12791Ssam fork1(1); 41*12791Ssam } 42*12791Ssam 43*12791Ssam fork1(isvfork) 44*12791Ssam int isvfork; 45*12791Ssam { 46*12791Ssam register struct proc *p1, *p2; 47*12791Ssam register a; 48*12791Ssam 49*12791Ssam a = 0; 50*12791Ssam p2 = NULL; 51*12791Ssam for (p1 = proc; p1 < procNPROC; p1++) { 52*12791Ssam if (p1->p_stat==NULL && p2==NULL) 53*12791Ssam p2 = p1; 54*12791Ssam else { 55*12791Ssam if (p1->p_uid==u.u_uid && p1->p_stat!=NULL) 56*12791Ssam a++; 57*12791Ssam } 58*12791Ssam } 59*12791Ssam /* 60*12791Ssam * Disallow if 61*12791Ssam * No processes at all; 62*12791Ssam * not su and too many procs owned; or 63*12791Ssam * not su and would take last slot. 64*12791Ssam */ 65*12791Ssam if (p2==NULL) 66*12791Ssam tablefull("proc"); 67*12791Ssam if (p2==NULL || (u.u_uid!=0 && (p2==procNPROC-1 || a>MAXUPRC))) { 68*12791Ssam u.u_error = EAGAIN; 69*12791Ssam if (!isvfork) { 70*12791Ssam (void) vsexpand(0, &u.u_cdmap, 1); 71*12791Ssam (void) vsexpand(0, &u.u_csmap, 1); 72*12791Ssam } 73*12791Ssam goto out; 74*12791Ssam } 75*12791Ssam p1 = u.u_procp; 76*12791Ssam if (newproc(isvfork)) { 77*12791Ssam u.u_r.r_val1 = p1->p_pid; 78*12791Ssam u.u_r.r_val2 = 1; /* child */ 79*12791Ssam u.u_start = time.tv_sec; 80*12791Ssam u.u_acflag = AFORK; 81*12791Ssam return; 82*12791Ssam } 83*12791Ssam u.u_r.r_val1 = p2->p_pid; 84*12791Ssam 85*12791Ssam out: 86*12791Ssam u.u_r.r_val2 = 0; 87*12791Ssam } 88*12791Ssam 89*12791Ssam /* 90*12791Ssam * Create a new process-- the internal version of 91*12791Ssam * sys fork. 92*12791Ssam * It returns 1 in the new process, 0 in the old. 93*12791Ssam */ 94*12791Ssam newproc(isvfork) 95*12791Ssam int isvfork; 96*12791Ssam { 97*12791Ssam register struct proc *p; 98*12791Ssam register struct proc *rpp, *rip; 99*12791Ssam register int n; 100*12791Ssam register struct file *fp; 101*12791Ssam 102*12791Ssam p = NULL; 103*12791Ssam /* 104*12791Ssam * First, just locate a slot for a process 105*12791Ssam * and copy the useful info from this process into it. 106*12791Ssam * The panic "cannot happen" because fork has already 107*12791Ssam * checked for the existence of a slot. 108*12791Ssam */ 109*12791Ssam retry: 110*12791Ssam mpid++; 111*12791Ssam if (mpid >= 30000) { 112*12791Ssam mpid = 0; 113*12791Ssam goto retry; 114*12791Ssam } 115*12791Ssam for (rpp = proc; rpp < procNPROC; rpp++) { 116*12791Ssam if (rpp->p_stat == NULL && p==NULL) 117*12791Ssam p = rpp; 118*12791Ssam if (rpp->p_pid==mpid || rpp->p_pgrp==mpid) 119*12791Ssam goto retry; 120*12791Ssam } 121*12791Ssam if ((rpp = p) == NULL) 122*12791Ssam panic("no procs"); 123*12791Ssam 124*12791Ssam /* 125*12791Ssam * Make a proc table entry for the new process. 126*12791Ssam */ 127*12791Ssam rip = u.u_procp; 128*12791Ssam #ifdef QUOTA 129*12791Ssam rpp->p_quota = rip->p_quota; 130*12791Ssam rpp->p_quota->q_cnt++; 131*12791Ssam #endif 132*12791Ssam rpp->p_stat = SIDL; 133*12791Ssam timerclear(&rpp->p_realtimer.it_value); 134*12791Ssam rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SNUSIG)); 135*12791Ssam if (isvfork) { 136*12791Ssam rpp->p_flag |= SVFORK; 137*12791Ssam rpp->p_ndx = rip->p_ndx; 138*12791Ssam } else 139*12791Ssam rpp->p_ndx = rpp - proc; 140*12791Ssam rpp->p_uid = rip->p_uid; 141*12791Ssam rpp->p_pgrp = rip->p_pgrp; 142*12791Ssam rpp->p_nice = rip->p_nice; 143*12791Ssam rpp->p_textp = isvfork ? 0 : rip->p_textp; 144*12791Ssam rpp->p_pid = mpid; 145*12791Ssam rpp->p_ppid = rip->p_pid; 146*12791Ssam rpp->p_pptr = rip; 147*12791Ssam rpp->p_osptr = rip->p_cptr; 148*12791Ssam if (rip->p_cptr) 149*12791Ssam rip->p_cptr->p_ysptr = rpp; 150*12791Ssam rpp->p_ysptr = NULL; 151*12791Ssam rpp->p_cptr = NULL; 152*12791Ssam rip->p_cptr = rpp; 153*12791Ssam rpp->p_time = 0; 154*12791Ssam rpp->p_cpu = 0; 155*12791Ssam rpp->p_siga0 = rip->p_siga0; 156*12791Ssam rpp->p_siga1 = rip->p_siga1; 157*12791Ssam /* take along any pending signals, like stops? */ 158*12791Ssam if (isvfork) { 159*12791Ssam rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0; 160*12791Ssam rpp->p_szpt = clrnd(ctopt(UPAGES)); 161*12791Ssam forkstat.cntvfork++; 162*12791Ssam forkstat.sizvfork += rip->p_dsize + rip->p_ssize; 163*12791Ssam } else { 164*12791Ssam rpp->p_tsize = rip->p_tsize; 165*12791Ssam rpp->p_dsize = rip->p_dsize; 166*12791Ssam rpp->p_ssize = rip->p_ssize; 167*12791Ssam rpp->p_szpt = rip->p_szpt; 168*12791Ssam forkstat.cntfork++; 169*12791Ssam forkstat.sizfork += rip->p_dsize + rip->p_ssize; 170*12791Ssam } 171*12791Ssam rpp->p_rssize = 0; 172*12791Ssam rpp->p_maxrss = rip->p_maxrss; 173*12791Ssam rpp->p_wchan = 0; 174*12791Ssam rpp->p_slptime = 0; 175*12791Ssam rpp->p_pctcpu = 0; 176*12791Ssam rpp->p_cpticks = 0; 177*12791Ssam n = PIDHASH(rpp->p_pid); 178*12791Ssam p->p_idhash = pidhash[n]; 179*12791Ssam pidhash[n] = rpp - proc; 180*12791Ssam multprog++; 181*12791Ssam 182*12791Ssam /* 183*12791Ssam * Increase reference counts on shared objects. 184*12791Ssam */ 185*12791Ssam for (n = 0; n < NOFILE; n++) { 186*12791Ssam fp = u.u_ofile[n]; 187*12791Ssam if (fp == NULL) 188*12791Ssam continue; 189*12791Ssam fp->f_count++; 190*12791Ssam if (u.u_pofile[n]&UF_SHLOCK) 191*12791Ssam ((struct inode *)fp->f_data)->i_shlockc++; 192*12791Ssam if (u.u_pofile[n]&UF_EXLOCK) 193*12791Ssam ((struct inode *)fp->f_data)->i_exlockc++; 194*12791Ssam } 195*12791Ssam u.u_cdir->i_count++; 196*12791Ssam if (u.u_rdir) 197*12791Ssam u.u_rdir->i_count++; 198*12791Ssam 199*12791Ssam /* 200*12791Ssam * Partially simulate the environment 201*12791Ssam * of the new process so that when it is actually 202*12791Ssam * created (by copying) it will look right. 203*12791Ssam * This begins the section where we must prevent the parent 204*12791Ssam * from being swapped. 205*12791Ssam */ 206*12791Ssam rip->p_flag |= SKEEP; 207*12791Ssam if (procdup(rpp, isvfork)) 208*12791Ssam return (1); 209*12791Ssam 210*12791Ssam /* 211*12791Ssam * Make child runnable and add to run queue. 212*12791Ssam */ 213*12791Ssam (void) spl6(); 214*12791Ssam rpp->p_stat = SRUN; 215*12791Ssam setrq(rpp); 216*12791Ssam (void) spl0(); 217*12791Ssam 218*12791Ssam /* 219*12791Ssam * Cause child to take a non-local goto as soon as it runs. 220*12791Ssam * On older systems this was done with SSWAP bit in proc 221*12791Ssam * table; on VAX we use u.u_pcb.pcb_sswap so don't need 222*12791Ssam * to do rpp->p_flag |= SSWAP. Actually do nothing here. 223*12791Ssam */ 224*12791Ssam /* rpp->p_flag |= SSWAP; */ 225*12791Ssam 226*12791Ssam /* 227*12791Ssam * Now can be swapped. 228*12791Ssam */ 229*12791Ssam rip->p_flag &= ~SKEEP; 230*12791Ssam 231*12791Ssam /* 232*12791Ssam * If vfork make chain from parent process to child 233*12791Ssam * (where virtal memory is temporarily). Wait for 234*12791Ssam * child to finish, steal virtual memory back, 235*12791Ssam * and wakeup child to let it die. 236*12791Ssam */ 237*12791Ssam if (isvfork) { 238*12791Ssam u.u_procp->p_xlink = rpp; 239*12791Ssam u.u_procp->p_flag |= SNOVM; 240*12791Ssam while (rpp->p_flag & SVFORK) 241*12791Ssam sleep((caddr_t)rpp, PZERO - 1); 242*12791Ssam if ((rpp->p_flag & SLOAD) == 0) 243*12791Ssam panic("newproc vfork"); 244*12791Ssam uaccess(rpp, Vfmap, &vfutl); 245*12791Ssam u.u_procp->p_xlink = 0; 246*12791Ssam vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap); 247*12791Ssam u.u_procp->p_flag &= ~SNOVM; 248*12791Ssam rpp->p_ndx = rpp - proc; 249*12791Ssam rpp->p_flag |= SVFDONE; 250*12791Ssam wakeup((caddr_t)rpp); 251*12791Ssam } 252*12791Ssam 253*12791Ssam /* 254*12791Ssam * 0 return means parent. 255*12791Ssam */ 256*12791Ssam return (0); 257*12791Ssam } 258