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