1: /*
   2:  * Copyright (c) 1986 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  *
   6:  *	@(#)kern_fork.c	1.6 (2.11BSD) 1999/8/11
   7:  */
   8: 
   9: #include "param.h"
  10: #include "../machine/reg.h"
  11: #include "../machine/seg.h"
  12: 
  13: #include "systm.h"
  14: #include "map.h"
  15: #include "user.h"
  16: #include "proc.h"
  17: #include "inode.h"
  18: #include "acct.h"
  19: #include "file.h"
  20: #include "vm.h"
  21: #include "text.h"
  22: #include "kernel.h"
  23: #ifdef QUOTA
  24: #include "quota.h"
  25: #endif
  26: 
  27: /*
  28:  * fork --
  29:  *	fork system call
  30:  */
  31: fork()
  32: {
  33:     fork1(0);
  34: }
  35: 
  36: /*
  37:  * vfork --
  38:  *	vfork system call, fast version of fork
  39:  */
  40: vfork()
  41: {
  42:     fork1(1);
  43: }
  44: 
  45: fork1(isvfork)
  46: {
  47:     register int a;
  48:     register struct proc *p1, *p2;
  49: 
  50:     a = 0;
  51:     if (u.u_uid != 0) {
  52:         for (p1 = allproc; p1; p1 = p1->p_nxt)
  53:             if (p1->p_uid == u.u_uid)
  54:                 a++;
  55:         for (p1 = zombproc; p1; p1 = p1->p_nxt)
  56:             if (p1->p_uid == u.u_uid)
  57:                 a++;
  58:     }
  59:     /*
  60: 	 * Disallow if
  61: 	 *  No processes at all;
  62: 	 *  not su and too many procs owned; or
  63: 	 *  not su and would take last slot.
  64: 	 */
  65:     p2 = freeproc;
  66:     if (p2==NULL)
  67:         tablefull("proc");
  68:     if (p2==NULL || (u.u_uid!=0 && (p2->p_nxt == NULL || a>MAXUPRC))) {
  69:         u.u_error = EAGAIN;
  70:         goto out;
  71:     }
  72:     p1 = u.u_procp;
  73:     if (newproc(isvfork)) {
  74:         u.u_r.r_val1 = p1->p_pid;
  75: #ifndef pdp11
  76:         u.u_r.r_val2 = 1;  /* child */
  77: #endif
  78:         u.u_start = time.tv_sec;
  79:         /* set forked but preserve suid/gid state */
  80:         u.u_acflag = AFORK | (u.u_acflag & ASUGID);
  81:         bzero(&u.u_ru, sizeof(u.u_ru));
  82:         bzero(&u.u_cru, sizeof(u.u_cru));
  83:         return;
  84:     }
  85:     u.u_r.r_val1 = p2->p_pid;
  86: 
  87: out:
  88: #ifdef pdp11            /* see libc/pdp/sys/fork.s */
  89:     u.u_ar0[R7] += NBPW;
  90: #else
  91:     u.u_r.r_val2 = 0;
  92: #endif
  93: }
  94: 
  95: /*
  96:  * newproc --
  97:  *	Create a new process -- the internal version of system call fork.
  98:  *	It returns 1 in the new process, 0 in the old.
  99:  */
 100: newproc(isvfork)
 101:     int isvfork;
 102: {
 103:     register struct proc *rpp, *rip;
 104:     register int n;
 105:     static int pidchecked = 0;
 106:     struct file *fp;
 107:     int a1, s;
 108:     memaddr a[3];
 109: 
 110:     /*
 111: 	 * First, just locate a slot for a process
 112: 	 * and copy the useful info from this process into it.
 113: 	 * The panic "cannot happen" because fork has already
 114: 	 * checked for the existence of a slot.
 115: 	 */
 116:     mpid++;
 117: retry:
 118:     if (mpid >= 30000) {
 119:         mpid = 100;
 120:         pidchecked = 0;
 121:     }
 122:     if (mpid >= pidchecked) {
 123:         int doingzomb = 0;
 124: 
 125:         pidchecked = 30000;
 126:         /*
 127: 		 * Scan the proc table to check whether this pid
 128: 		 * is in use.  Remember the lowest pid that's greater
 129: 		 * than mpid, so we can avoid checking for a while.
 130: 		 */
 131:         rpp = allproc;
 132: again:
 133:         for (; rpp != NULL; rpp = rpp->p_nxt) {
 134:             if (rpp->p_pid == mpid || rpp->p_pgrp == mpid) {
 135:                 mpid++;
 136:                 if (mpid >= pidchecked)
 137:                     goto retry;
 138:             }
 139:             if (rpp->p_pid > mpid && pidchecked > rpp->p_pid)
 140:                 pidchecked = rpp->p_pid;
 141:             if (rpp->p_pgrp > mpid && pidchecked > rpp->p_pgrp)
 142:                 pidchecked = rpp->p_pgrp;
 143:         }
 144:         if (!doingzomb) {
 145:             doingzomb = 1;
 146:             rpp = zombproc;
 147:             goto again;
 148:         }
 149:     }
 150:     if ((rpp = freeproc) == NULL)
 151:         panic("no procs");
 152: 
 153:     freeproc = rpp->p_nxt;          /* off freeproc */
 154: 
 155:     /*
 156: 	 * Make a proc table entry for the new process.
 157: 	 */
 158:     rip = u.u_procp;
 159: #ifdef QUOTA
 160:     QUOTAMAP();
 161:     u.u_quota->q_cnt++;
 162:     QUOTAUNMAP();
 163: #endif
 164:     rpp->p_stat = SIDL;
 165:     rpp->p_realtimer.it_value = 0;
 166:     rpp->p_flag = SLOAD;
 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 = rip->p_textp;
 171:     rpp->p_pid = mpid;
 172:     rpp->p_ppid = rip->p_pid;
 173:     rpp->p_pptr = rip;
 174:     rpp->p_time = 0;
 175:     rpp->p_cpu = 0;
 176:     rpp->p_sigmask = rip->p_sigmask;
 177:     rpp->p_sigcatch = rip->p_sigcatch;
 178:     rpp->p_sigignore = rip->p_sigignore;
 179:     /* take along any pending signals like stops? */
 180: #ifdef UCB_METER
 181:     if (isvfork) {
 182:         forkstat.cntvfork++;
 183:         forkstat.sizvfork += rip->p_dsize + rip->p_ssize;
 184:     } else {
 185:         forkstat.cntfork++;
 186:         forkstat.sizfork += rip->p_dsize + rip->p_ssize;
 187:     }
 188: #endif
 189:     rpp->p_wchan = 0;
 190:     rpp->p_slptime = 0;
 191:     {
 192:     struct proc **hash = &pidhash[PIDHASH(rpp->p_pid)];
 193: 
 194:     rpp->p_hash = *hash;
 195:     *hash = rpp;
 196:     }
 197:     /*
 198: 	 * some shuffling here -- in most UNIX kernels, the allproc assign
 199: 	 * is done after grabbing the struct off of the freeproc list.  We
 200: 	 * wait so that if the clock interrupts us and vmtotal walks allproc
 201: 	 * the text pointer isn't garbage.
 202: 	 */
 203:     rpp->p_nxt = allproc;           /* onto allproc */
 204:     rpp->p_nxt->p_prev = &rpp->p_nxt;   /*   (allproc is never NULL) */
 205:     rpp->p_prev = &allproc;
 206:     allproc = rpp;
 207: 
 208:     /*
 209: 	 * Increase reference counts on shared objects.
 210: 	 */
 211:     for (n = 0; n <= u.u_lastfile; n++) {
 212:         fp = u.u_ofile[n];
 213:         if (fp == NULL)
 214:             continue;
 215:         fp->f_count++;
 216:     }
 217:     if ((rip->p_textp != NULL) && !isvfork) {
 218:         rip->p_textp->x_count++;
 219:         rip->p_textp->x_ccount++;
 220:     }
 221:     u.u_cdir->i_count++;
 222:     if (u.u_rdir)
 223:         u.u_rdir->i_count++;
 224: 
 225:     /*
 226: 	 * When the longjmp is executed for the new process,
 227: 	 * here's where it will resume.
 228: 	 */
 229:     if (setjmp(&u.u_ssave)) {
 230:         sureg();
 231:         return(1);
 232:     }
 233: 
 234:     rpp->p_dsize = rip->p_dsize;
 235:     rpp->p_ssize = rip->p_ssize;
 236:     rpp->p_daddr = rip->p_daddr;
 237:     rpp->p_saddr = rip->p_saddr;
 238:     a1 = rip->p_addr;
 239:     if (isvfork)
 240:         a[2] = malloc(coremap,USIZE);
 241:     else
 242:         a[2] = malloc3(coremap, rip->p_dsize, rip->p_ssize, USIZE, a);
 243: 
 244:     /*
 245: 	 * Partially simulate the environment of the new process so that
 246: 	 * when it is actually created (by copying) it will look right.
 247: 	 */
 248:     u.u_procp = rpp;
 249: 
 250:     /*
 251: 	 * If there is not enough core for the new process, swap out the
 252: 	 * current process to generate the copy.
 253: 	 */
 254:     if (a[2] == NULL) {
 255:         rip->p_stat = SIDL;
 256:         rpp->p_addr = a1;
 257:         rpp->p_stat = SRUN;
 258:         swapout(rpp, X_DONTFREE, X_OLDSIZE, X_OLDSIZE);
 259:         rip->p_stat = SRUN;
 260:         u.u_procp = rip;
 261:     }
 262:     else {
 263:         /*
 264: 		 * There is core, so just copy.
 265: 		 */
 266:         rpp->p_addr = a[2];
 267:         copy(a1, rpp->p_addr, USIZE);
 268:         u.u_procp = rip;
 269:         if (isvfork == 0) {
 270:             rpp->p_daddr = a[0];
 271:             copy(rip->p_daddr, rpp->p_daddr, rpp->p_dsize);
 272:             rpp->p_saddr = a[1];
 273:             copy(rip->p_saddr, rpp->p_saddr, rpp->p_ssize);
 274:         }
 275:         s = splhigh();
 276:         rpp->p_stat = SRUN;
 277:         setrq(rpp);
 278:         splx(s);
 279:     }
 280:     rpp->p_flag |= SSWAP;
 281:     if (isvfork) {
 282:         /*
 283: 		 *  Set the parent's sizes to 0, since the child now
 284: 		 *  has the data and stack.
 285: 		 *  (If we had to swap, just free parent resources.)
 286: 		 *  Then wait for the child to finish with it.
 287: 		 */
 288:         if (a[2] == NULL) {
 289:             mfree(coremap,rip->p_dsize,rip->p_daddr);
 290:             mfree(coremap,rip->p_ssize,rip->p_saddr);
 291:         }
 292:         rip->p_dsize = 0;
 293:         rip->p_ssize = 0;
 294:         rip->p_textp = NULL;
 295:         rpp->p_flag |= SVFORK;
 296:         rip->p_flag |= SVFPRNT;
 297:         while (rpp->p_flag & SVFORK)
 298:             sleep((caddr_t)rpp,PSWP+1);
 299:         if ((rpp->p_flag & SLOAD) == 0)
 300:             panic("newproc vfork");
 301:         u.u_dsize = rip->p_dsize = rpp->p_dsize;
 302:         rip->p_daddr = rpp->p_daddr;
 303:         rpp->p_dsize = 0;
 304:         u.u_ssize = rip->p_ssize = rpp->p_ssize;
 305:         rip->p_saddr = rpp->p_saddr;
 306:         rpp->p_ssize = 0;
 307:         rip->p_textp = rpp->p_textp;
 308:         rpp->p_textp = NULL;
 309:         rpp->p_flag |= SVFDONE;
 310:         wakeup((caddr_t)rip);
 311:         /* must do estabur if dsize/ssize are different */
 312:         estabur(u.u_tsize,u.u_dsize,u.u_ssize,u.u_sep,RO);
 313:         rip->p_flag &= ~SVFPRNT;
 314:     }
 315:     return(0);
 316: }

Defined functions

fork defined in line 31; used 2 times
fork1 defined in line 45; used 2 times
newproc defined in line 100; used 2 times
vfork defined in line 40; used 2 times
Last modified: 1999-08-12
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 176
Valid CSS Valid XHTML 1.0 Strict