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