xref: /csrg-svn/sys/kern/kern_fork.c (revision 45914)
123370Smckusick /*
237728Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
337728Smckusick  * All rights reserved.
423370Smckusick  *
544434Sbostic  * %sccs.include.redist.c%
637728Smckusick  *
7*45914Smckusick  *	@(#)kern_fork.c	7.23 (Berkeley) 01/10/91
823370Smckusick  */
912791Ssam 
1017090Sbloom #include "param.h"
1117090Sbloom #include "systm.h"
1217090Sbloom #include "map.h"
1344404Skarels #include "user.h"
14*45914Smckusick #include "filedesc.h"
1517090Sbloom #include "kernel.h"
1617090Sbloom #include "proc.h"
1737728Smckusick #include "vnode.h"
1817090Sbloom #include "seg.h"
1917090Sbloom #include "file.h"
2017090Sbloom #include "acct.h"
2140812Smarc #include "ktrace.h"
2212791Ssam 
2337523Smckusick #include "machine/reg.h"
2437523Smckusick #include "machine/psl.h"
2537523Smckusick 
2612791Ssam /*
2712791Ssam  * fork system call.
2812791Ssam  */
2942921Smckusick /* ARGSUSED */
3042921Smckusick fork(p, uap, retval)
3142921Smckusick 	struct proc *p;
3242921Smckusick 	struct args *uap;
3342921Smckusick 	int retval[];
3412791Ssam {
3542921Smckusick 	int error;
3612791Ssam 
3744404Skarels 	return (fork1(p, 0, retval));
3812791Ssam }
3912791Ssam 
4042921Smckusick /* ARGSUSED */
4142921Smckusick vfork(p, uap, retval)
4242921Smckusick 	struct proc *p;
4342921Smckusick 	struct args *uap;
4442921Smckusick 	int retval[];
4512791Ssam {
4612791Ssam 
4744404Skarels 	return (fork1(p, 1, retval));
4812791Ssam }
4912791Ssam 
5042921Smckusick fork1(p1, isvfork, retval)
5142921Smckusick 	register struct proc *p1;
5242921Smckusick 	int isvfork, retval[];
5312791Ssam {
5442921Smckusick 	register struct proc *p2;
5542921Smckusick 	register int a;
5612791Ssam 
5712791Ssam 	a = 0;
5842921Smckusick 	if (p1->p_uid != 0) {
5942921Smckusick 		for (p2 = allproc; p2; p2 = p2->p_nxt)
6042921Smckusick 			if (p2->p_uid == p1->p_uid)
6112791Ssam 				a++;
6242921Smckusick 		for (p2 = zombproc; p2; p2 = p2->p_nxt)
6342921Smckusick 			if (p2->p_uid == p1->p_uid)
6416528Skarels 				a++;
6512791Ssam 	}
6612791Ssam 	/*
6712791Ssam 	 * Disallow if
6812791Ssam 	 *  No processes at all;
6912791Ssam 	 *  not su and too many procs owned; or
7012791Ssam 	 *  not su and would take last slot.
7112791Ssam 	 */
7216528Skarels 	p2 = freeproc;
7312791Ssam 	if (p2==NULL)
7412791Ssam 		tablefull("proc");
7542921Smckusick 	if (p2 == NULL ||
7642921Smckusick 	    (p1->p_uid != 0 && (p2->p_nxt == NULL || a > MAXUPRC))) {
7742921Smckusick 		retval[1] = 0;
7842921Smckusick 		return (EAGAIN);
7912791Ssam 	}
8012791Ssam 	if (newproc(isvfork)) {
8142921Smckusick 		retval[0] = p1->p_pid;
8242921Smckusick 		retval[1] = 1;  /* child */
8312791Ssam 		u.u_acflag = AFORK;
8442921Smckusick 		return (0);
8512791Ssam 	}
8642921Smckusick 	retval[0] = p2->p_pid;
8742921Smckusick 	retval[1] = 0;
8842921Smckusick 	return (0);
8912791Ssam }
9012791Ssam 
9112791Ssam /*
9212791Ssam  * Create a new process-- the internal version of
9312791Ssam  * sys fork.
9412791Ssam  * It returns 1 in the new process, 0 in the old.
9512791Ssam  */
9612791Ssam newproc(isvfork)
9712791Ssam 	int isvfork;
9812791Ssam {
9912791Ssam 	register struct proc *rpp, *rip;
10012791Ssam 	register struct file *fp;
10116528Skarels 	static int pidchecked = 0;
10212791Ssam 
10312791Ssam 	/*
10412791Ssam 	 * First, just locate a slot for a process
10512791Ssam 	 * and copy the useful info from this process into it.
10612791Ssam 	 * The panic "cannot happen" because fork has already
10712791Ssam 	 * checked for the existence of a slot.
10812791Ssam 	 */
10916528Skarels 	mpid++;
11012791Ssam retry:
11145005Skarels 	if (mpid >= PID_MAX) {
11216528Skarels 		mpid = 100;
11316528Skarels 		pidchecked = 0;
11412791Ssam 	}
11516528Skarels 	if (mpid >= pidchecked) {
11616528Skarels 		int doingzomb = 0;
11716578Ssam 
11845005Skarels 		pidchecked = PID_MAX;
11916528Skarels 		/*
12016528Skarels 		 * Scan the proc table to check whether this pid
12116528Skarels 		 * is in use.  Remember the lowest pid that's greater
12216528Skarels 		 * than mpid, so we can avoid checking for a while.
12316528Skarels 		 */
12416528Skarels 		rpp = allproc;
12516528Skarels again:
12616528Skarels 		for (; rpp != NULL; rpp = rpp->p_nxt) {
12735810Smarc 			if (rpp->p_pid == mpid || rpp->p_pgrp->pg_id == mpid) {
12816528Skarels 				mpid++;
12916528Skarels 				if (mpid >= pidchecked)
13016528Skarels 					goto retry;
13116528Skarels 			}
13216578Ssam 			if (rpp->p_pid > mpid && pidchecked > rpp->p_pid)
13316528Skarels 				pidchecked = rpp->p_pid;
13435810Smarc 			if (rpp->p_pgrp->pg_id > mpid &&
13535810Smarc 			    pidchecked > rpp->p_pgrp->pg_id)
13635810Smarc 				pidchecked = rpp->p_pgrp->pg_id;
13716528Skarels 		}
13816528Skarels 		if (!doingzomb) {
13916528Skarels 			doingzomb = 1;
14016528Skarels 			rpp = zombproc;
14116528Skarels 			goto again;
14216528Skarels 		}
14312791Ssam 	}
14416528Skarels 	if ((rpp = freeproc) == NULL)
14512791Ssam 		panic("no procs");
14612791Ssam 
14716528Skarels 	freeproc = rpp->p_nxt;			/* off freeproc */
14816528Skarels 	rpp->p_nxt = allproc;			/* onto allproc */
14916528Skarels 	rpp->p_nxt->p_prev = &rpp->p_nxt;	/*   (allproc is never NULL) */
15016528Skarels 	rpp->p_prev = &allproc;
15116528Skarels 	allproc = rpp;
15216528Skarels 
15312791Ssam 	/*
15412791Ssam 	 * Make a proc table entry for the new process.
15512791Ssam 	 */
15612791Ssam 	rip = u.u_procp;
15729946Skarels #if defined(tahoe)
15829946Skarels 	rpp->p_ckey = rip->p_ckey;
15929946Skarels 	rpp->p_dkey = 0;
16029946Skarels #endif
16112791Ssam 	rpp->p_stat = SIDL;
16212791Ssam 	timerclear(&rpp->p_realtimer.it_value);
16342206Smarc 	rpp->p_flag = SLOAD | (rip->p_flag & (SPAGV|SHPUX));
16442206Smarc 	if (rip->p_session->s_ttyvp != NULL && rip->p_flag & SCTTY)
16542206Smarc 		rpp->p_flag |= SCTTY;
16645727Smckusick 	if (isvfork)
16712791Ssam 		rpp->p_flag |= SVFORK;
16845727Smckusick 	rpp->p_ndx = rpp - proc;
16940812Smarc 	bcopy(rip->p_comm, rpp->p_comm, MAXCOMLEN+1);
17040812Smarc 	bcopy(rip->p_logname, rpp->p_logname, MAXLOGNAME);
17112791Ssam 	rpp->p_uid = rip->p_uid;
17238929Skarels 	rpp->p_ruid = rip->p_ruid;
17338929Skarels 	rpp->p_rgid = rip->p_rgid;
17412791Ssam 	rpp->p_pgrp = rip->p_pgrp;
17535810Smarc 	rpp->p_pgrpnxt = rip->p_pgrpnxt;
17635810Smarc 	rip->p_pgrpnxt = rpp;
17712791Ssam 	rpp->p_nice = rip->p_nice;
17812791Ssam 	rpp->p_pid = mpid;
17912791Ssam 	rpp->p_ppid = rip->p_pid;
18012791Ssam 	rpp->p_pptr = rip;
18112791Ssam 	rpp->p_osptr = rip->p_cptr;
18212791Ssam 	if (rip->p_cptr)
18312791Ssam 		rip->p_cptr->p_ysptr = rpp;
18412791Ssam 	rpp->p_ysptr = NULL;
18512791Ssam 	rpp->p_cptr = NULL;
18612791Ssam 	rip->p_cptr = rpp;
18712791Ssam 	rpp->p_time = 0;
18841180Smarc 	bzero((caddr_t)&rpp->p_utime, sizeof (struct timeval));
18941180Smarc 	bzero((caddr_t)&rpp->p_stime, sizeof (struct timeval));
19012791Ssam 	rpp->p_cpu = 0;
19112882Ssam 	rpp->p_sigmask = rip->p_sigmask;
19212882Ssam 	rpp->p_sigcatch = rip->p_sigcatch;
19312882Ssam 	rpp->p_sigignore = rip->p_sigignore;
19437592Smarc #ifdef KTRACE
19540812Smarc 	if (rip->p_traceflag&KTRFAC_INHERIT) {
19640812Smarc 		rpp->p_traceflag = rip->p_traceflag;
19738422Smarc 		if ((rpp->p_tracep = rip->p_tracep) != NULL)
19838422Smarc 			VREF(rpp->p_tracep);
19937592Smarc 	} else {
20037592Smarc 		rpp->p_tracep = NULL;
20137592Smarc 		rpp->p_traceflag = 0;
20237592Smarc 	}
20337592Smarc #endif
20412791Ssam 	rpp->p_rssize = 0;
20512791Ssam 	rpp->p_maxrss = rip->p_maxrss;
20612791Ssam 	rpp->p_wchan = 0;
20712791Ssam 	rpp->p_slptime = 0;
20812791Ssam 	rpp->p_pctcpu = 0;
20912791Ssam 	rpp->p_cpticks = 0;
21040812Smarc 	{
21140812Smarc 	struct proc **hash = &pidhash[PIDHASH(rpp->p_pid)];
21240812Smarc 
21340812Smarc 	rpp->p_hash = *hash;
21440812Smarc 	*hash = rpp;
21540812Smarc 	}
21612791Ssam 
21712791Ssam 	/*
21812791Ssam 	 * Increase reference counts on shared objects.
21912791Ssam 	 */
220*45914Smckusick 	rpp->p_fd = fddup(rip->p_fd, 0);
22145727Smckusick #ifdef SYSVSHM
22245727Smckusick 	if (rip->p_shm)
22345727Smckusick 		shmfork(rip, rpp, isvfork);
22445727Smckusick #endif
22537728Smckusick 	crhold(u.u_cred);
22612791Ssam 
22712791Ssam 	/*
22812791Ssam 	 * This begins the section where we must prevent the parent
22912791Ssam 	 * from being swapped.
23012791Ssam 	 */
23112791Ssam 	rip->p_flag |= SKEEP;
23241180Smarc 	if (procdup(rpp, isvfork)) {
23341180Smarc 		(void) splclock();
23441180Smarc 		u.u_start = time;
23541180Smarc 		(void) spl0();
23612791Ssam 		return (1);
23741180Smarc 	}
23812791Ssam 
23912791Ssam 	/*
24012791Ssam 	 * Make child runnable and add to run queue.
24112791Ssam 	 */
24226277Skarels 	(void) splclock();
24312791Ssam 	rpp->p_stat = SRUN;
24412791Ssam 	setrq(rpp);
24512791Ssam 	(void) spl0();
24612791Ssam 
24712791Ssam 	/*
24812791Ssam 	 * Cause child to take a non-local goto as soon as it runs.
24912791Ssam 	 * On older systems this was done with SSWAP bit in proc
25012791Ssam 	 * table; on VAX we use u.u_pcb.pcb_sswap so don't need
25112791Ssam 	 * to do rpp->p_flag |= SSWAP.  Actually do nothing here.
25212791Ssam 	 */
25312791Ssam 	/* rpp->p_flag |= SSWAP; */
25412791Ssam 
25512791Ssam 	/*
25612791Ssam 	 * Now can be swapped.
25712791Ssam 	 */
25812791Ssam 	rip->p_flag &= ~SKEEP;
25912791Ssam 
26012791Ssam 	/*
26145727Smckusick 	 * XXX preserve synchronization semantics of vfork
26212791Ssam 	 */
26312791Ssam 	if (isvfork) {
26412791Ssam 		u.u_procp->p_flag |= SNOVM;
26512791Ssam 		while (rpp->p_flag & SVFORK)
26612791Ssam 			sleep((caddr_t)rpp, PZERO - 1);
26712791Ssam 		if ((rpp->p_flag & SLOAD) == 0)
26812791Ssam 			panic("newproc vfork");
26912791Ssam 		u.u_procp->p_flag &= ~SNOVM;
27012791Ssam 		rpp->p_flag |= SVFDONE;
27112791Ssam 		wakeup((caddr_t)rpp);
27212791Ssam 	}
27312791Ssam 
27412791Ssam 	/*
27512791Ssam 	 * 0 return means parent.
27612791Ssam 	 */
27712791Ssam 	return (0);
27812791Ssam }
279