# 2.11BSD#431 - /usr/src/sys/sys/kern_fork.c

##### Functions

    fork              X
    fork1             X
    newproc           X
    vfork             X

       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

- in /usr/src/sys/sys/init_sysent.c line 20, 112

fork1 defined in line 45; used 2 times

- in line 33, 42

newproc defined in line 100; used 2 times

- in line 73
- in /usr/src/sys/sys/init_main.c line 242

vfork defined in line 40; used 2 times

- in /usr/src/sys/sys/init_sysent.c line 90, 176

Last modified: 1999-08-12 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1003 |