xref: /csrg-svn/sys/kern/kern_fork.c (revision 42921)
123370Smckusick /*
237728Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
337728Smckusick  * All rights reserved.
423370Smckusick  *
537728Smckusick  * Redistribution and use in source and binary forms are permitted
637728Smckusick  * provided that the above copyright notice and this paragraph are
737728Smckusick  * duplicated in all such forms and that any documentation,
837728Smckusick  * advertising materials, and other materials related to such
937728Smckusick  * distribution and use acknowledge that the software was developed
1037728Smckusick  * by the University of California, Berkeley.  The name of the
1137728Smckusick  * University may not be used to endorse or promote products derived
1237728Smckusick  * from this software without specific prior written permission.
1337728Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1437728Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1537728Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1637728Smckusick  *
17*42921Smckusick  *	@(#)kern_fork.c	7.17 (Berkeley) 06/05/90
1823370Smckusick  */
1912791Ssam 
2017090Sbloom #include "param.h"
2117090Sbloom #include "systm.h"
2217090Sbloom #include "map.h"
23*42921Smckusick #include "syscontext.h"
2417090Sbloom #include "kernel.h"
2517090Sbloom #include "proc.h"
2637728Smckusick #include "vnode.h"
2717090Sbloom #include "seg.h"
2817090Sbloom #include "vm.h"
2917090Sbloom #include "text.h"
3017090Sbloom #include "file.h"
3117090Sbloom #include "acct.h"
3240812Smarc #include "ktrace.h"
3337728Smckusick #include "../ufs/quota.h"
3412791Ssam 
3537523Smckusick #include "machine/reg.h"
3637523Smckusick #include "machine/pte.h"
3737523Smckusick #include "machine/psl.h"
3837523Smckusick 
3912791Ssam /*
4012791Ssam  * fork system call.
4112791Ssam  */
42*42921Smckusick /* ARGSUSED */
43*42921Smckusick fork(p, uap, retval)
44*42921Smckusick 	struct proc *p;
45*42921Smckusick 	struct args *uap;
46*42921Smckusick 	int retval[];
4712791Ssam {
48*42921Smckusick 	int error;
4912791Ssam 
5012791Ssam 	u.u_cdmap = zdmap;
5112791Ssam 	u.u_csmap = zdmap;
52*42921Smckusick 	if (error = swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap)) {
53*42921Smckusick 		retval[1] = 0;
54*42921Smckusick 		RETURN (error);
5512791Ssam 	}
56*42921Smckusick 	RETURN (fork1(p, 0, retval));
5712791Ssam }
5812791Ssam 
59*42921Smckusick /* ARGSUSED */
60*42921Smckusick vfork(p, uap, retval)
61*42921Smckusick 	struct proc *p;
62*42921Smckusick 	struct args *uap;
63*42921Smckusick 	int retval[];
6412791Ssam {
6512791Ssam 
66*42921Smckusick 	RETURN (fork1(p, 1, retval));
6712791Ssam }
6812791Ssam 
69*42921Smckusick fork1(p1, isvfork, retval)
70*42921Smckusick 	register struct proc *p1;
71*42921Smckusick 	int isvfork, retval[];
7212791Ssam {
73*42921Smckusick 	register struct proc *p2;
74*42921Smckusick 	register int a;
7512791Ssam 
7612791Ssam 	a = 0;
77*42921Smckusick 	if (p1->p_uid != 0) {
78*42921Smckusick 		for (p2 = allproc; p2; p2 = p2->p_nxt)
79*42921Smckusick 			if (p2->p_uid == p1->p_uid)
8012791Ssam 				a++;
81*42921Smckusick 		for (p2 = zombproc; p2; p2 = p2->p_nxt)
82*42921Smckusick 			if (p2->p_uid == p1->p_uid)
8316528Skarels 				a++;
8412791Ssam 	}
8512791Ssam 	/*
8612791Ssam 	 * Disallow if
8712791Ssam 	 *  No processes at all;
8812791Ssam 	 *  not su and too many procs owned; or
8912791Ssam 	 *  not su and would take last slot.
9012791Ssam 	 */
9116528Skarels 	p2 = freeproc;
9212791Ssam 	if (p2==NULL)
9312791Ssam 		tablefull("proc");
94*42921Smckusick 	if (p2 == NULL ||
95*42921Smckusick 	    (p1->p_uid != 0 && (p2->p_nxt == NULL || a > MAXUPRC))) {
9612791Ssam 		if (!isvfork) {
9742087Sbostic 			(void) vsexpand((segsz_t)0, &u.u_cdmap, 1);
9842087Sbostic 			(void) vsexpand((segsz_t)0, &u.u_csmap, 1);
9912791Ssam 		}
100*42921Smckusick 		retval[1] = 0;
101*42921Smckusick 		return (EAGAIN);
10212791Ssam 	}
10312791Ssam 	if (newproc(isvfork)) {
104*42921Smckusick 		retval[0] = p1->p_pid;
105*42921Smckusick 		retval[1] = 1;  /* child */
10612791Ssam 		u.u_acflag = AFORK;
107*42921Smckusick 		return (0);
10812791Ssam 	}
109*42921Smckusick 	retval[0] = p2->p_pid;
110*42921Smckusick 	retval[1] = 0;
111*42921Smckusick 	return (0);
11212791Ssam }
11312791Ssam 
11412791Ssam /*
11512791Ssam  * Create a new process-- the internal version of
11612791Ssam  * sys fork.
11712791Ssam  * It returns 1 in the new process, 0 in the old.
11812791Ssam  */
11912791Ssam newproc(isvfork)
12012791Ssam 	int isvfork;
12112791Ssam {
12212791Ssam 	register struct proc *rpp, *rip;
12312791Ssam 	register int n;
12412791Ssam 	register struct file *fp;
12516528Skarels 	static int pidchecked = 0;
12612791Ssam 
12712791Ssam 	/*
12812791Ssam 	 * First, just locate a slot for a process
12912791Ssam 	 * and copy the useful info from this process into it.
13012791Ssam 	 * The panic "cannot happen" because fork has already
13112791Ssam 	 * checked for the existence of a slot.
13212791Ssam 	 */
13316528Skarels 	mpid++;
13412791Ssam retry:
13512791Ssam 	if (mpid >= 30000) {
13616528Skarels 		mpid = 100;
13716528Skarels 		pidchecked = 0;
13812791Ssam 	}
13916528Skarels 	if (mpid >= pidchecked) {
14016528Skarels 		int doingzomb = 0;
14116578Ssam 
14216528Skarels 		pidchecked = 30000;
14316528Skarels 		/*
14416528Skarels 		 * Scan the proc table to check whether this pid
14516528Skarels 		 * is in use.  Remember the lowest pid that's greater
14616528Skarels 		 * than mpid, so we can avoid checking for a while.
14716528Skarels 		 */
14816528Skarels 		rpp = allproc;
14916528Skarels again:
15016528Skarels 		for (; rpp != NULL; rpp = rpp->p_nxt) {
15135810Smarc 			if (rpp->p_pid == mpid || rpp->p_pgrp->pg_id == mpid) {
15216528Skarels 				mpid++;
15316528Skarels 				if (mpid >= pidchecked)
15416528Skarels 					goto retry;
15516528Skarels 			}
15616578Ssam 			if (rpp->p_pid > mpid && pidchecked > rpp->p_pid)
15716528Skarels 				pidchecked = rpp->p_pid;
15835810Smarc 			if (rpp->p_pgrp->pg_id > mpid &&
15935810Smarc 			    pidchecked > rpp->p_pgrp->pg_id)
16035810Smarc 				pidchecked = rpp->p_pgrp->pg_id;
16116528Skarels 		}
16216528Skarels 		if (!doingzomb) {
16316528Skarels 			doingzomb = 1;
16416528Skarels 			rpp = zombproc;
16516528Skarels 			goto again;
16616528Skarels 		}
16712791Ssam 	}
16816528Skarels 	if ((rpp = freeproc) == NULL)
16912791Ssam 		panic("no procs");
17012791Ssam 
17116528Skarels 	freeproc = rpp->p_nxt;			/* off freeproc */
17216528Skarels 	rpp->p_nxt = allproc;			/* onto allproc */
17316528Skarels 	rpp->p_nxt->p_prev = &rpp->p_nxt;	/*   (allproc is never NULL) */
17416528Skarels 	rpp->p_prev = &allproc;
17516528Skarels 	allproc = rpp;
17616528Skarels 
17712791Ssam 	/*
17812791Ssam 	 * Make a proc table entry for the new process.
17912791Ssam 	 */
18012791Ssam 	rip = u.u_procp;
18129946Skarels #if defined(tahoe)
18229946Skarels 	rpp->p_ckey = rip->p_ckey;
18329946Skarels 	rpp->p_dkey = 0;
18429946Skarels #endif
18512791Ssam 	rpp->p_stat = SIDL;
18612791Ssam 	timerclear(&rpp->p_realtimer.it_value);
18742206Smarc 	rpp->p_flag = SLOAD | (rip->p_flag & (SPAGV|SHPUX));
18842206Smarc 	if (rip->p_session->s_ttyvp != NULL && rip->p_flag & SCTTY)
18942206Smarc 		rpp->p_flag |= SCTTY;
19012791Ssam 	if (isvfork) {
19112791Ssam 		rpp->p_flag |= SVFORK;
19212791Ssam 		rpp->p_ndx = rip->p_ndx;
19312791Ssam 	} else
19412791Ssam 		rpp->p_ndx = rpp - proc;
19540812Smarc 	bcopy(rip->p_comm, rpp->p_comm, MAXCOMLEN+1);
19640812Smarc 	bcopy(rip->p_logname, rpp->p_logname, MAXLOGNAME);
19712791Ssam 	rpp->p_uid = rip->p_uid;
19838929Skarels 	rpp->p_ruid = rip->p_ruid;
19938929Skarels 	rpp->p_rgid = rip->p_rgid;
20012791Ssam 	rpp->p_pgrp = rip->p_pgrp;
20135810Smarc 	rpp->p_pgrpnxt = rip->p_pgrpnxt;
20235810Smarc 	rip->p_pgrpnxt = rpp;
20312791Ssam 	rpp->p_nice = rip->p_nice;
20412791Ssam 	rpp->p_textp = isvfork ? 0 : rip->p_textp;
20512791Ssam 	rpp->p_pid = mpid;
20612791Ssam 	rpp->p_ppid = rip->p_pid;
20712791Ssam 	rpp->p_pptr = rip;
20812791Ssam 	rpp->p_osptr = rip->p_cptr;
20912791Ssam 	if (rip->p_cptr)
21012791Ssam 		rip->p_cptr->p_ysptr = rpp;
21112791Ssam 	rpp->p_ysptr = NULL;
21212791Ssam 	rpp->p_cptr = NULL;
21312791Ssam 	rip->p_cptr = rpp;
21412791Ssam 	rpp->p_time = 0;
21541180Smarc 	bzero((caddr_t)&rpp->p_utime, sizeof (struct timeval));
21641180Smarc 	bzero((caddr_t)&rpp->p_stime, sizeof (struct timeval));
21712791Ssam 	rpp->p_cpu = 0;
21812882Ssam 	rpp->p_sigmask = rip->p_sigmask;
21912882Ssam 	rpp->p_sigcatch = rip->p_sigcatch;
22012882Ssam 	rpp->p_sigignore = rip->p_sigignore;
22112882Ssam 	/* take along any pending signals like stops? */
22212791Ssam 	if (isvfork) {
22341571Smckusick 		rpp->p_tsize = rpp->p_dsize = rpp->p_mmsize = rpp->p_ssize = 0;
22441571Smckusick 		rpp->p_szpt = clrnd(ctopt(HIGHPAGES));
22512791Ssam 		forkstat.cntvfork++;
22612791Ssam 		forkstat.sizvfork += rip->p_dsize + rip->p_ssize;
22712791Ssam 	} else {
22812791Ssam 		rpp->p_tsize = rip->p_tsize;
22912791Ssam 		rpp->p_dsize = rip->p_dsize;
23041571Smckusick 		rpp->p_mmsize = rip->p_mmsize;
23112791Ssam 		rpp->p_ssize = rip->p_ssize;
23212791Ssam 		rpp->p_szpt = rip->p_szpt;
23312791Ssam 		forkstat.cntfork++;
23412791Ssam 		forkstat.sizfork += rip->p_dsize + rip->p_ssize;
23512791Ssam 	}
23637592Smarc #ifdef KTRACE
23740812Smarc 	if (rip->p_traceflag&KTRFAC_INHERIT) {
23840812Smarc 		rpp->p_traceflag = rip->p_traceflag;
23938422Smarc 		if ((rpp->p_tracep = rip->p_tracep) != NULL)
24038422Smarc 			VREF(rpp->p_tracep);
24137592Smarc 	} else {
24237592Smarc 		rpp->p_tracep = NULL;
24337592Smarc 		rpp->p_traceflag = 0;
24437592Smarc 	}
24537592Smarc #endif
24612791Ssam 	rpp->p_rssize = 0;
24712791Ssam 	rpp->p_maxrss = rip->p_maxrss;
24812791Ssam 	rpp->p_wchan = 0;
24912791Ssam 	rpp->p_slptime = 0;
25012791Ssam 	rpp->p_pctcpu = 0;
25112791Ssam 	rpp->p_cpticks = 0;
25240812Smarc 	{
25340812Smarc 	struct proc **hash = &pidhash[PIDHASH(rpp->p_pid)];
25440812Smarc 
25540812Smarc 	rpp->p_hash = *hash;
25640812Smarc 	*hash = rpp;
25740812Smarc 	}
25812791Ssam 	multprog++;
25912791Ssam 
26012791Ssam 	/*
26112791Ssam 	 * Increase reference counts on shared objects.
26212791Ssam 	 */
26321102Skarels 	for (n = 0; n <= u.u_lastfile; n++) {
26412791Ssam 		fp = u.u_ofile[n];
26512791Ssam 		if (fp == NULL)
26612791Ssam 			continue;
26712791Ssam 		fp->f_count++;
26812791Ssam 	}
26938347Smckusick 	VREF(u.u_cdir);
27012791Ssam 	if (u.u_rdir)
27138347Smckusick 		VREF(u.u_rdir);
27237728Smckusick 	crhold(u.u_cred);
27312791Ssam 
27412791Ssam 	/*
27512791Ssam 	 * This begins the section where we must prevent the parent
27612791Ssam 	 * from being swapped.
27712791Ssam 	 */
27812791Ssam 	rip->p_flag |= SKEEP;
27941180Smarc 	if (procdup(rpp, isvfork)) {
28041180Smarc 		(void) splclock();
28141180Smarc 		u.u_start = time;
28241180Smarc 		(void) spl0();
28312791Ssam 		return (1);
28441180Smarc 	}
28512791Ssam 
28612791Ssam 	/*
28712791Ssam 	 * Make child runnable and add to run queue.
28812791Ssam 	 */
28926277Skarels 	(void) splclock();
29012791Ssam 	rpp->p_stat = SRUN;
29112791Ssam 	setrq(rpp);
29212791Ssam 	(void) spl0();
29312791Ssam 
29412791Ssam 	/*
29512791Ssam 	 * Cause child to take a non-local goto as soon as it runs.
29612791Ssam 	 * On older systems this was done with SSWAP bit in proc
29712791Ssam 	 * table; on VAX we use u.u_pcb.pcb_sswap so don't need
29812791Ssam 	 * to do rpp->p_flag |= SSWAP.  Actually do nothing here.
29912791Ssam 	 */
30012791Ssam 	/* rpp->p_flag |= SSWAP; */
30112791Ssam 
30212791Ssam 	/*
30312791Ssam 	 * Now can be swapped.
30412791Ssam 	 */
30512791Ssam 	rip->p_flag &= ~SKEEP;
30612791Ssam 
30712791Ssam 	/*
30812791Ssam 	 * If vfork make chain from parent process to child
30912791Ssam 	 * (where virtal memory is temporarily).  Wait for
31012791Ssam 	 * child to finish, steal virtual memory back,
31112791Ssam 	 * and wakeup child to let it die.
31212791Ssam 	 */
31312791Ssam 	if (isvfork) {
31412791Ssam 		u.u_procp->p_xlink = rpp;
31512791Ssam 		u.u_procp->p_flag |= SNOVM;
31612791Ssam 		while (rpp->p_flag & SVFORK)
31712791Ssam 			sleep((caddr_t)rpp, PZERO - 1);
31812791Ssam 		if ((rpp->p_flag & SLOAD) == 0)
31912791Ssam 			panic("newproc vfork");
32012791Ssam 		uaccess(rpp, Vfmap, &vfutl);
32112791Ssam 		u.u_procp->p_xlink = 0;
32212791Ssam 		vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap);
32312791Ssam 		u.u_procp->p_flag &= ~SNOVM;
32412791Ssam 		rpp->p_ndx = rpp - proc;
32512791Ssam 		rpp->p_flag |= SVFDONE;
32612791Ssam 		wakeup((caddr_t)rpp);
32712791Ssam 	}
32812791Ssam 
32912791Ssam 	/*
33012791Ssam 	 * 0 return means parent.
33112791Ssam 	 */
33212791Ssam 	return (0);
33312791Ssam }
334