1*16528Skarels /* kern_fork.c 6.2 84/05/22 */ 212791Ssam 312791Ssam #include "../machine/reg.h" 412791Ssam #include "../machine/pte.h" 512791Ssam #include "../machine/psl.h" 612791Ssam 712791Ssam #include "../h/param.h" 812791Ssam #include "../h/systm.h" 912791Ssam #include "../h/map.h" 1012791Ssam #include "../h/dir.h" 1112791Ssam #include "../h/user.h" 1212791Ssam #include "../h/kernel.h" 1312791Ssam #include "../h/proc.h" 1412791Ssam #include "../h/inode.h" 1512791Ssam #include "../h/seg.h" 1612791Ssam #include "../h/vm.h" 1712791Ssam #include "../h/text.h" 1812791Ssam #include "../h/file.h" 1912791Ssam #include "../h/acct.h" 2012791Ssam #include "../h/quota.h" 2112791Ssam 2212791Ssam /* 2312791Ssam * fork system call. 2412791Ssam */ 2512791Ssam fork() 2612791Ssam { 2712791Ssam 2812791Ssam u.u_cdmap = zdmap; 2912791Ssam u.u_csmap = zdmap; 3012791Ssam if (swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap) == 0) { 3112791Ssam u.u_r.r_val2 = 0; 3212791Ssam return; 3312791Ssam } 3412791Ssam fork1(0); 3512791Ssam } 3612791Ssam 3712791Ssam vfork() 3812791Ssam { 3912791Ssam 4012791Ssam fork1(1); 4112791Ssam } 4212791Ssam 4312791Ssam fork1(isvfork) 4412791Ssam int isvfork; 4512791Ssam { 4612791Ssam register struct proc *p1, *p2; 4712791Ssam register a; 4812791Ssam 4912791Ssam a = 0; 50*16528Skarels if (u.u_uid != 0) { 51*16528Skarels for (p1 = allproc; p1; p1 = p1->p_nxt) 52*16528Skarels if (p1->p_uid == u.u_uid) 5312791Ssam a++; 54*16528Skarels for (p1 = zombproc; p1; p1 = p1->p_nxt) 55*16528Skarels if (p1->p_uid == u.u_uid) 56*16528Skarels a++; 5712791Ssam } 5812791Ssam /* 5912791Ssam * Disallow if 6012791Ssam * No processes at all; 6112791Ssam * not su and too many procs owned; or 6212791Ssam * not su and would take last slot. 6312791Ssam */ 64*16528Skarels p2 = freeproc; 6512791Ssam if (p2==NULL) 6612791Ssam tablefull("proc"); 67*16528Skarels if (p2==NULL || (u.u_uid!=0 && (p2->p_nxt == NULL || a>MAXUPRC))) { 6812791Ssam u.u_error = EAGAIN; 6912791Ssam if (!isvfork) { 7012791Ssam (void) vsexpand(0, &u.u_cdmap, 1); 7112791Ssam (void) vsexpand(0, &u.u_csmap, 1); 7212791Ssam } 7312791Ssam goto out; 7412791Ssam } 7512791Ssam p1 = u.u_procp; 7612791Ssam if (newproc(isvfork)) { 7712791Ssam u.u_r.r_val1 = p1->p_pid; 7812791Ssam u.u_r.r_val2 = 1; /* child */ 7912791Ssam u.u_start = time.tv_sec; 8012791Ssam u.u_acflag = AFORK; 8112791Ssam return; 8212791Ssam } 8312791Ssam u.u_r.r_val1 = p2->p_pid; 8412791Ssam 8512791Ssam out: 8612791Ssam u.u_r.r_val2 = 0; 8712791Ssam } 8812791Ssam 8912791Ssam /* 9012791Ssam * Create a new process-- the internal version of 9112791Ssam * sys fork. 9212791Ssam * It returns 1 in the new process, 0 in the old. 9312791Ssam */ 9412791Ssam newproc(isvfork) 9512791Ssam int isvfork; 9612791Ssam { 9712791Ssam register struct proc *rpp, *rip; 9812791Ssam register int n; 9912791Ssam register struct file *fp; 100*16528Skarels static int pidchecked = 0; 10112791Ssam 10212791Ssam /* 10312791Ssam * First, just locate a slot for a process 10412791Ssam * and copy the useful info from this process into it. 10512791Ssam * The panic "cannot happen" because fork has already 10612791Ssam * checked for the existence of a slot. 10712791Ssam */ 108*16528Skarels mpid++; 10912791Ssam retry: 11012791Ssam if (mpid >= 30000) { 111*16528Skarels mpid = 100; 112*16528Skarels pidchecked = 0; 11312791Ssam } 114*16528Skarels if (mpid >= pidchecked) { 115*16528Skarels int doingzomb = 0; 116*16528Skarels pidchecked = 30000; 117*16528Skarels /* 118*16528Skarels * Scan the proc table to check whether this pid 119*16528Skarels * is in use. Remember the lowest pid that's greater 120*16528Skarels * than mpid, so we can avoid checking for a while. 121*16528Skarels */ 122*16528Skarels rpp = allproc; 123*16528Skarels again: 124*16528Skarels for (; rpp != NULL; rpp = rpp->p_nxt) { 125*16528Skarels if (rpp->p_pid==mpid || rpp->p_pgrp==mpid) { 126*16528Skarels mpid++; 127*16528Skarels if (mpid >= pidchecked) 128*16528Skarels goto retry; 129*16528Skarels } 130*16528Skarels if ((rpp->p_pid > mpid) && (pidchecked > rpp->p_pid)) 131*16528Skarels pidchecked = rpp->p_pid; 132*16528Skarels if ((rpp->p_pgrp > mpid) && (pidchecked > rpp->p_pgrp)) 133*16528Skarels pidchecked = rpp->p_pgrp; 134*16528Skarels } 135*16528Skarels if (!doingzomb) { 136*16528Skarels doingzomb = 1; 137*16528Skarels rpp = zombproc; 138*16528Skarels goto again; 139*16528Skarels } 14012791Ssam } 141*16528Skarels if ((rpp = freeproc) == NULL) 14212791Ssam panic("no procs"); 14312791Ssam 144*16528Skarels freeproc = rpp->p_nxt; /* off freeproc */ 145*16528Skarels rpp->p_nxt = allproc; /* onto allproc */ 146*16528Skarels rpp->p_nxt->p_prev = &rpp->p_nxt; /* (allproc is never NULL) */ 147*16528Skarels rpp->p_prev = &allproc; 148*16528Skarels allproc = rpp; 149*16528Skarels 15012791Ssam /* 15112791Ssam * Make a proc table entry for the new process. 15212791Ssam */ 15312791Ssam rip = u.u_procp; 15412791Ssam #ifdef QUOTA 15512791Ssam rpp->p_quota = rip->p_quota; 15612791Ssam rpp->p_quota->q_cnt++; 15712791Ssam #endif 15812791Ssam rpp->p_stat = SIDL; 15912791Ssam timerclear(&rpp->p_realtimer.it_value); 16012882Ssam rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SOUSIG)); 16112791Ssam if (isvfork) { 16212791Ssam rpp->p_flag |= SVFORK; 16312791Ssam rpp->p_ndx = rip->p_ndx; 16412791Ssam } else 16512791Ssam rpp->p_ndx = rpp - proc; 16612791Ssam rpp->p_uid = rip->p_uid; 16712791Ssam rpp->p_pgrp = rip->p_pgrp; 16812791Ssam rpp->p_nice = rip->p_nice; 16912791Ssam rpp->p_textp = isvfork ? 0 : rip->p_textp; 17012791Ssam rpp->p_pid = mpid; 17112791Ssam rpp->p_ppid = rip->p_pid; 17212791Ssam rpp->p_pptr = rip; 17312791Ssam rpp->p_osptr = rip->p_cptr; 17412791Ssam if (rip->p_cptr) 17512791Ssam rip->p_cptr->p_ysptr = rpp; 17612791Ssam rpp->p_ysptr = NULL; 17712791Ssam rpp->p_cptr = NULL; 17812791Ssam rip->p_cptr = rpp; 17912791Ssam rpp->p_time = 0; 18012791Ssam rpp->p_cpu = 0; 18112882Ssam rpp->p_sigmask = rip->p_sigmask; 18212882Ssam rpp->p_sigcatch = rip->p_sigcatch; 18312882Ssam rpp->p_sigignore = rip->p_sigignore; 18412882Ssam /* take along any pending signals like stops? */ 18512791Ssam if (isvfork) { 18612791Ssam rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0; 18712791Ssam rpp->p_szpt = clrnd(ctopt(UPAGES)); 18812791Ssam forkstat.cntvfork++; 18912791Ssam forkstat.sizvfork += rip->p_dsize + rip->p_ssize; 19012791Ssam } else { 19112791Ssam rpp->p_tsize = rip->p_tsize; 19212791Ssam rpp->p_dsize = rip->p_dsize; 19312791Ssam rpp->p_ssize = rip->p_ssize; 19412791Ssam rpp->p_szpt = rip->p_szpt; 19512791Ssam forkstat.cntfork++; 19612791Ssam forkstat.sizfork += rip->p_dsize + rip->p_ssize; 19712791Ssam } 19812791Ssam rpp->p_rssize = 0; 19912791Ssam rpp->p_maxrss = rip->p_maxrss; 20012791Ssam rpp->p_wchan = 0; 20112791Ssam rpp->p_slptime = 0; 20212791Ssam rpp->p_pctcpu = 0; 20312791Ssam rpp->p_cpticks = 0; 20412791Ssam n = PIDHASH(rpp->p_pid); 205*16528Skarels rpp->p_idhash = pidhash[n]; 20612791Ssam pidhash[n] = rpp - proc; 20712791Ssam multprog++; 20812791Ssam 20912791Ssam /* 21012791Ssam * Increase reference counts on shared objects. 21112791Ssam */ 21212791Ssam for (n = 0; n < NOFILE; n++) { 21312791Ssam fp = u.u_ofile[n]; 21412791Ssam if (fp == NULL) 21512791Ssam continue; 21612791Ssam fp->f_count++; 21712791Ssam } 21812791Ssam u.u_cdir->i_count++; 21912791Ssam if (u.u_rdir) 22012791Ssam u.u_rdir->i_count++; 22112791Ssam 22212791Ssam /* 22312791Ssam * This begins the section where we must prevent the parent 22412791Ssam * from being swapped. 22512791Ssam */ 22612791Ssam rip->p_flag |= SKEEP; 22712791Ssam if (procdup(rpp, isvfork)) 22812791Ssam return (1); 22912791Ssam 23012791Ssam /* 23112791Ssam * Make child runnable and add to run queue. 23212791Ssam */ 23312791Ssam (void) spl6(); 23412791Ssam rpp->p_stat = SRUN; 23512791Ssam setrq(rpp); 23612791Ssam (void) spl0(); 23712791Ssam 23812791Ssam /* 23912791Ssam * Cause child to take a non-local goto as soon as it runs. 24012791Ssam * On older systems this was done with SSWAP bit in proc 24112791Ssam * table; on VAX we use u.u_pcb.pcb_sswap so don't need 24212791Ssam * to do rpp->p_flag |= SSWAP. Actually do nothing here. 24312791Ssam */ 24412791Ssam /* rpp->p_flag |= SSWAP; */ 24512791Ssam 24612791Ssam /* 24712791Ssam * Now can be swapped. 24812791Ssam */ 24912791Ssam rip->p_flag &= ~SKEEP; 25012791Ssam 25112791Ssam /* 25212791Ssam * If vfork make chain from parent process to child 25312791Ssam * (where virtal memory is temporarily). Wait for 25412791Ssam * child to finish, steal virtual memory back, 25512791Ssam * and wakeup child to let it die. 25612791Ssam */ 25712791Ssam if (isvfork) { 25812791Ssam u.u_procp->p_xlink = rpp; 25912791Ssam u.u_procp->p_flag |= SNOVM; 26012791Ssam while (rpp->p_flag & SVFORK) 26112791Ssam sleep((caddr_t)rpp, PZERO - 1); 26212791Ssam if ((rpp->p_flag & SLOAD) == 0) 26312791Ssam panic("newproc vfork"); 26412791Ssam uaccess(rpp, Vfmap, &vfutl); 26512791Ssam u.u_procp->p_xlink = 0; 26612791Ssam vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap); 26712791Ssam u.u_procp->p_flag &= ~SNOVM; 26812791Ssam rpp->p_ndx = rpp - proc; 26912791Ssam rpp->p_flag |= SVFDONE; 27012791Ssam wakeup((caddr_t)rpp); 27112791Ssam } 27212791Ssam 27312791Ssam /* 27412791Ssam * 0 return means parent. 27512791Ssam */ 27612791Ssam return (0); 27712791Ssam } 278