1 /* 2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)kern_fork.c 7.16 (Berkeley) 05/17/90 18 */ 19 20 #include "param.h" 21 #include "systm.h" 22 #include "map.h" 23 #include "user.h" 24 #include "kernel.h" 25 #include "proc.h" 26 #include "vnode.h" 27 #include "seg.h" 28 #include "vm.h" 29 #include "text.h" 30 #include "file.h" 31 #include "acct.h" 32 #include "ktrace.h" 33 #include "../ufs/quota.h" 34 35 #include "machine/reg.h" 36 #include "machine/pte.h" 37 #include "machine/psl.h" 38 39 /* 40 * fork system call. 41 */ 42 fork() 43 { 44 45 u.u_cdmap = zdmap; 46 u.u_csmap = zdmap; 47 if (swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap) == 0) { 48 u.u_r.r_val2 = 0; 49 return; 50 } 51 fork1(0); 52 } 53 54 vfork() 55 { 56 57 fork1(1); 58 } 59 60 fork1(isvfork) 61 int isvfork; 62 { 63 register struct proc *p1, *p2; 64 register a; 65 66 a = 0; 67 if (u.u_uid != 0) { 68 for (p1 = allproc; p1; p1 = p1->p_nxt) 69 if (p1->p_uid == u.u_uid) 70 a++; 71 for (p1 = zombproc; p1; p1 = p1->p_nxt) 72 if (p1->p_uid == u.u_uid) 73 a++; 74 } 75 /* 76 * Disallow if 77 * No processes at all; 78 * not su and too many procs owned; or 79 * not su and would take last slot. 80 */ 81 p2 = freeproc; 82 if (p2==NULL) 83 tablefull("proc"); 84 if (p2==NULL || (u.u_uid!=0 && (p2->p_nxt == NULL || a>MAXUPRC))) { 85 u.u_error = EAGAIN; 86 if (!isvfork) { 87 (void) vsexpand((segsz_t)0, &u.u_cdmap, 1); 88 (void) vsexpand((segsz_t)0, &u.u_csmap, 1); 89 } 90 goto out; 91 } 92 p1 = u.u_procp; 93 if (newproc(isvfork)) { 94 u.u_r.r_val1 = p1->p_pid; 95 u.u_r.r_val2 = 1; /* child */ 96 u.u_acflag = AFORK; 97 return; 98 } 99 u.u_r.r_val1 = p2->p_pid; 100 101 out: 102 u.u_r.r_val2 = 0; 103 } 104 105 /* 106 * Create a new process-- the internal version of 107 * sys fork. 108 * It returns 1 in the new process, 0 in the old. 109 */ 110 newproc(isvfork) 111 int isvfork; 112 { 113 register struct proc *rpp, *rip; 114 register int n; 115 register struct file *fp; 116 static int pidchecked = 0; 117 118 /* 119 * First, just locate a slot for a process 120 * and copy the useful info from this process into it. 121 * The panic "cannot happen" because fork has already 122 * checked for the existence of a slot. 123 */ 124 mpid++; 125 retry: 126 if (mpid >= 30000) { 127 mpid = 100; 128 pidchecked = 0; 129 } 130 if (mpid >= pidchecked) { 131 int doingzomb = 0; 132 133 pidchecked = 30000; 134 /* 135 * Scan the proc table to check whether this pid 136 * is in use. Remember the lowest pid that's greater 137 * than mpid, so we can avoid checking for a while. 138 */ 139 rpp = allproc; 140 again: 141 for (; rpp != NULL; rpp = rpp->p_nxt) { 142 if (rpp->p_pid == mpid || rpp->p_pgrp->pg_id == mpid) { 143 mpid++; 144 if (mpid >= pidchecked) 145 goto retry; 146 } 147 if (rpp->p_pid > mpid && pidchecked > rpp->p_pid) 148 pidchecked = rpp->p_pid; 149 if (rpp->p_pgrp->pg_id > mpid && 150 pidchecked > rpp->p_pgrp->pg_id) 151 pidchecked = rpp->p_pgrp->pg_id; 152 } 153 if (!doingzomb) { 154 doingzomb = 1; 155 rpp = zombproc; 156 goto again; 157 } 158 } 159 if ((rpp = freeproc) == NULL) 160 panic("no procs"); 161 162 freeproc = rpp->p_nxt; /* off freeproc */ 163 rpp->p_nxt = allproc; /* onto allproc */ 164 rpp->p_nxt->p_prev = &rpp->p_nxt; /* (allproc is never NULL) */ 165 rpp->p_prev = &allproc; 166 allproc = rpp; 167 168 /* 169 * Make a proc table entry for the new process. 170 */ 171 rip = u.u_procp; 172 #if defined(tahoe) 173 rpp->p_ckey = rip->p_ckey; 174 rpp->p_dkey = 0; 175 #endif 176 rpp->p_stat = SIDL; 177 timerclear(&rpp->p_realtimer.it_value); 178 rpp->p_flag = SLOAD | (rip->p_flag & (SPAGV|SHPUX)); 179 if (rip->p_session->s_ttyvp != NULL && rip->p_flag & SCTTY) 180 rpp->p_flag |= SCTTY; 181 if (isvfork) { 182 rpp->p_flag |= SVFORK; 183 rpp->p_ndx = rip->p_ndx; 184 } else 185 rpp->p_ndx = rpp - proc; 186 bcopy(rip->p_comm, rpp->p_comm, MAXCOMLEN+1); 187 bcopy(rip->p_logname, rpp->p_logname, MAXLOGNAME); 188 rpp->p_uid = rip->p_uid; 189 rpp->p_ruid = rip->p_ruid; 190 rpp->p_rgid = rip->p_rgid; 191 rpp->p_pgrp = rip->p_pgrp; 192 rpp->p_pgrpnxt = rip->p_pgrpnxt; 193 rip->p_pgrpnxt = rpp; 194 rpp->p_nice = rip->p_nice; 195 rpp->p_textp = isvfork ? 0 : rip->p_textp; 196 rpp->p_pid = mpid; 197 rpp->p_ppid = rip->p_pid; 198 rpp->p_pptr = rip; 199 rpp->p_osptr = rip->p_cptr; 200 if (rip->p_cptr) 201 rip->p_cptr->p_ysptr = rpp; 202 rpp->p_ysptr = NULL; 203 rpp->p_cptr = NULL; 204 rip->p_cptr = rpp; 205 rpp->p_time = 0; 206 bzero((caddr_t)&rpp->p_utime, sizeof (struct timeval)); 207 bzero((caddr_t)&rpp->p_stime, sizeof (struct timeval)); 208 rpp->p_cpu = 0; 209 rpp->p_sigmask = rip->p_sigmask; 210 rpp->p_sigcatch = rip->p_sigcatch; 211 rpp->p_sigignore = rip->p_sigignore; 212 /* take along any pending signals like stops? */ 213 if (isvfork) { 214 rpp->p_tsize = rpp->p_dsize = rpp->p_mmsize = rpp->p_ssize = 0; 215 rpp->p_szpt = clrnd(ctopt(HIGHPAGES)); 216 forkstat.cntvfork++; 217 forkstat.sizvfork += rip->p_dsize + rip->p_ssize; 218 } else { 219 rpp->p_tsize = rip->p_tsize; 220 rpp->p_dsize = rip->p_dsize; 221 rpp->p_mmsize = rip->p_mmsize; 222 rpp->p_ssize = rip->p_ssize; 223 rpp->p_szpt = rip->p_szpt; 224 forkstat.cntfork++; 225 forkstat.sizfork += rip->p_dsize + rip->p_ssize; 226 } 227 #ifdef KTRACE 228 if (rip->p_traceflag&KTRFAC_INHERIT) { 229 rpp->p_traceflag = rip->p_traceflag; 230 if ((rpp->p_tracep = rip->p_tracep) != NULL) 231 VREF(rpp->p_tracep); 232 } else { 233 rpp->p_tracep = NULL; 234 rpp->p_traceflag = 0; 235 } 236 #endif 237 rpp->p_rssize = 0; 238 rpp->p_maxrss = rip->p_maxrss; 239 rpp->p_wchan = 0; 240 rpp->p_slptime = 0; 241 rpp->p_pctcpu = 0; 242 rpp->p_cpticks = 0; 243 { 244 struct proc **hash = &pidhash[PIDHASH(rpp->p_pid)]; 245 246 rpp->p_hash = *hash; 247 *hash = rpp; 248 } 249 multprog++; 250 251 /* 252 * Increase reference counts on shared objects. 253 */ 254 for (n = 0; n <= u.u_lastfile; n++) { 255 fp = u.u_ofile[n]; 256 if (fp == NULL) 257 continue; 258 fp->f_count++; 259 } 260 VREF(u.u_cdir); 261 if (u.u_rdir) 262 VREF(u.u_rdir); 263 crhold(u.u_cred); 264 265 /* 266 * This begins the section where we must prevent the parent 267 * from being swapped. 268 */ 269 rip->p_flag |= SKEEP; 270 if (procdup(rpp, isvfork)) { 271 (void) splclock(); 272 u.u_start = time; 273 (void) spl0(); 274 return (1); 275 } 276 277 /* 278 * Make child runnable and add to run queue. 279 */ 280 (void) splclock(); 281 rpp->p_stat = SRUN; 282 setrq(rpp); 283 (void) spl0(); 284 285 /* 286 * Cause child to take a non-local goto as soon as it runs. 287 * On older systems this was done with SSWAP bit in proc 288 * table; on VAX we use u.u_pcb.pcb_sswap so don't need 289 * to do rpp->p_flag |= SSWAP. Actually do nothing here. 290 */ 291 /* rpp->p_flag |= SSWAP; */ 292 293 /* 294 * Now can be swapped. 295 */ 296 rip->p_flag &= ~SKEEP; 297 298 /* 299 * If vfork make chain from parent process to child 300 * (where virtal memory is temporarily). Wait for 301 * child to finish, steal virtual memory back, 302 * and wakeup child to let it die. 303 */ 304 if (isvfork) { 305 u.u_procp->p_xlink = rpp; 306 u.u_procp->p_flag |= SNOVM; 307 while (rpp->p_flag & SVFORK) 308 sleep((caddr_t)rpp, PZERO - 1); 309 if ((rpp->p_flag & SLOAD) == 0) 310 panic("newproc vfork"); 311 uaccess(rpp, Vfmap, &vfutl); 312 u.u_procp->p_xlink = 0; 313 vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap); 314 u.u_procp->p_flag &= ~SNOVM; 315 rpp->p_ndx = rpp - proc; 316 rpp->p_flag |= SVFDONE; 317 wakeup((caddr_t)rpp); 318 } 319 320 /* 321 * 0 return means parent. 322 */ 323 return (0); 324 } 325