xref: /csrg-svn/sys/kern/kern_fork.c (revision 12882)
1*12882Ssam /*	kern_fork.c	4.2	83/06/02	*/
212791Ssam 
312791Ssam #include "../machine/reg.h"
412791Ssam #include "../machine/pte.h"
512791Ssam #include "../machine/psl.h"
612791Ssam 
712791Ssam #include "../h/param.h"
812791Ssam #include "../h/systm.h"
912791Ssam #include "../h/map.h"
1012791Ssam #include "../h/dir.h"
1112791Ssam #include "../h/user.h"
1212791Ssam #include "../h/kernel.h"
1312791Ssam #include "../h/proc.h"
1412791Ssam #include "../h/inode.h"
1512791Ssam #include "../h/seg.h"
1612791Ssam #include "../h/vm.h"
1712791Ssam #include "../h/text.h"
1812791Ssam #include "../h/file.h"
1912791Ssam #include "../h/acct.h"
2012791Ssam #include "../h/quota.h"
2112791Ssam 
2212791Ssam /*
2312791Ssam  * fork system call.
2412791Ssam  */
2512791Ssam fork()
2612791Ssam {
2712791Ssam 
2812791Ssam 	u.u_cdmap = zdmap;
2912791Ssam 	u.u_csmap = zdmap;
3012791Ssam 	if (swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap) == 0) {
3112791Ssam 		u.u_r.r_val2 = 0;
3212791Ssam 		return;
3312791Ssam 	}
3412791Ssam 	fork1(0);
3512791Ssam }
3612791Ssam 
3712791Ssam vfork()
3812791Ssam {
3912791Ssam 
4012791Ssam 	fork1(1);
4112791Ssam }
4212791Ssam 
4312791Ssam fork1(isvfork)
4412791Ssam 	int isvfork;
4512791Ssam {
4612791Ssam 	register struct proc *p1, *p2;
4712791Ssam 	register a;
4812791Ssam 
4912791Ssam 	a = 0;
5012791Ssam 	p2 = NULL;
5112791Ssam 	for (p1 = proc; p1 < procNPROC; p1++) {
5212791Ssam 		if (p1->p_stat==NULL && p2==NULL)
5312791Ssam 			p2 = p1;
5412791Ssam 		else {
5512791Ssam 			if (p1->p_uid==u.u_uid && p1->p_stat!=NULL)
5612791Ssam 				a++;
5712791Ssam 		}
5812791Ssam 	}
5912791Ssam 	/*
6012791Ssam 	 * Disallow if
6112791Ssam 	 *  No processes at all;
6212791Ssam 	 *  not su and too many procs owned; or
6312791Ssam 	 *  not su and would take last slot.
6412791Ssam 	 */
6512791Ssam 	if (p2==NULL)
6612791Ssam 		tablefull("proc");
6712791Ssam 	if (p2==NULL || (u.u_uid!=0 && (p2==procNPROC-1 || a>MAXUPRC))) {
6812791Ssam 		u.u_error = EAGAIN;
6912791Ssam 		if (!isvfork) {
7012791Ssam 			(void) vsexpand(0, &u.u_cdmap, 1);
7112791Ssam 			(void) vsexpand(0, &u.u_csmap, 1);
7212791Ssam 		}
7312791Ssam 		goto out;
7412791Ssam 	}
7512791Ssam 	p1 = u.u_procp;
7612791Ssam 	if (newproc(isvfork)) {
7712791Ssam 		u.u_r.r_val1 = p1->p_pid;
7812791Ssam 		u.u_r.r_val2 = 1;  /* child */
7912791Ssam 		u.u_start = time.tv_sec;
8012791Ssam 		u.u_acflag = AFORK;
8112791Ssam 		return;
8212791Ssam 	}
8312791Ssam 	u.u_r.r_val1 = p2->p_pid;
8412791Ssam 
8512791Ssam out:
8612791Ssam 	u.u_r.r_val2 = 0;
8712791Ssam }
8812791Ssam 
8912791Ssam /*
9012791Ssam  * Create a new process-- the internal version of
9112791Ssam  * sys fork.
9212791Ssam  * It returns 1 in the new process, 0 in the old.
9312791Ssam  */
9412791Ssam newproc(isvfork)
9512791Ssam 	int isvfork;
9612791Ssam {
9712791Ssam 	register struct proc *p;
9812791Ssam 	register struct proc *rpp, *rip;
9912791Ssam 	register int n;
10012791Ssam 	register struct file *fp;
10112791Ssam 
10212791Ssam 	p = NULL;
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 	 */
10912791Ssam retry:
11012791Ssam 	mpid++;
11112791Ssam 	if (mpid >= 30000) {
11212791Ssam 		mpid = 0;
11312791Ssam 		goto retry;
11412791Ssam 	}
11512791Ssam 	for (rpp = proc; rpp < procNPROC; rpp++) {
11612791Ssam 		if (rpp->p_stat == NULL && p==NULL)
11712791Ssam 			p = rpp;
11812791Ssam 		if (rpp->p_pid==mpid || rpp->p_pgrp==mpid)
11912791Ssam 			goto retry;
12012791Ssam 	}
12112791Ssam 	if ((rpp = p) == NULL)
12212791Ssam 		panic("no procs");
12312791Ssam 
12412791Ssam 	/*
12512791Ssam 	 * Make a proc table entry for the new process.
12612791Ssam 	 */
12712791Ssam 	rip = u.u_procp;
12812791Ssam #ifdef QUOTA
12912791Ssam 	rpp->p_quota = rip->p_quota;
13012791Ssam 	rpp->p_quota->q_cnt++;
13112791Ssam #endif
13212791Ssam 	rpp->p_stat = SIDL;
13312791Ssam 	timerclear(&rpp->p_realtimer.it_value);
134*12882Ssam 	rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SOUSIG));
13512791Ssam 	if (isvfork) {
13612791Ssam 		rpp->p_flag |= SVFORK;
13712791Ssam 		rpp->p_ndx = rip->p_ndx;
13812791Ssam 	} else
13912791Ssam 		rpp->p_ndx = rpp - proc;
14012791Ssam 	rpp->p_uid = rip->p_uid;
14112791Ssam 	rpp->p_pgrp = rip->p_pgrp;
14212791Ssam 	rpp->p_nice = rip->p_nice;
14312791Ssam 	rpp->p_textp = isvfork ? 0 : rip->p_textp;
14412791Ssam 	rpp->p_pid = mpid;
14512791Ssam 	rpp->p_ppid = rip->p_pid;
14612791Ssam 	rpp->p_pptr = rip;
14712791Ssam 	rpp->p_osptr = rip->p_cptr;
14812791Ssam 	if (rip->p_cptr)
14912791Ssam 		rip->p_cptr->p_ysptr = rpp;
15012791Ssam 	rpp->p_ysptr = NULL;
15112791Ssam 	rpp->p_cptr = NULL;
15212791Ssam 	rip->p_cptr = rpp;
15312791Ssam 	rpp->p_time = 0;
15412791Ssam 	rpp->p_cpu = 0;
155*12882Ssam 	rpp->p_sigmask = rip->p_sigmask;
156*12882Ssam 	rpp->p_sigcatch = rip->p_sigcatch;
157*12882Ssam 	rpp->p_sigignore = rip->p_sigignore;
158*12882Ssam 	/* take along any pending signals like stops? */
15912791Ssam 	if (isvfork) {
16012791Ssam 		rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0;
16112791Ssam 		rpp->p_szpt = clrnd(ctopt(UPAGES));
16212791Ssam 		forkstat.cntvfork++;
16312791Ssam 		forkstat.sizvfork += rip->p_dsize + rip->p_ssize;
16412791Ssam 	} else {
16512791Ssam 		rpp->p_tsize = rip->p_tsize;
16612791Ssam 		rpp->p_dsize = rip->p_dsize;
16712791Ssam 		rpp->p_ssize = rip->p_ssize;
16812791Ssam 		rpp->p_szpt = rip->p_szpt;
16912791Ssam 		forkstat.cntfork++;
17012791Ssam 		forkstat.sizfork += rip->p_dsize + rip->p_ssize;
17112791Ssam 	}
17212791Ssam 	rpp->p_rssize = 0;
17312791Ssam 	rpp->p_maxrss = rip->p_maxrss;
17412791Ssam 	rpp->p_wchan = 0;
17512791Ssam 	rpp->p_slptime = 0;
17612791Ssam 	rpp->p_pctcpu = 0;
17712791Ssam 	rpp->p_cpticks = 0;
17812791Ssam 	n = PIDHASH(rpp->p_pid);
17912791Ssam 	p->p_idhash = pidhash[n];
18012791Ssam 	pidhash[n] = rpp - proc;
18112791Ssam 	multprog++;
18212791Ssam 
18312791Ssam 	/*
18412791Ssam 	 * Increase reference counts on shared objects.
18512791Ssam 	 */
18612791Ssam 	for (n = 0; n < NOFILE; n++) {
18712791Ssam 		fp = u.u_ofile[n];
18812791Ssam 		if (fp == NULL)
18912791Ssam 			continue;
19012791Ssam 		fp->f_count++;
19112791Ssam 		if (u.u_pofile[n]&UF_SHLOCK)
19212791Ssam 			((struct inode *)fp->f_data)->i_shlockc++;
19312791Ssam 		if (u.u_pofile[n]&UF_EXLOCK)
19412791Ssam 			((struct inode *)fp->f_data)->i_exlockc++;
19512791Ssam 	}
19612791Ssam 	u.u_cdir->i_count++;
19712791Ssam 	if (u.u_rdir)
19812791Ssam 		u.u_rdir->i_count++;
19912791Ssam 
20012791Ssam 	/*
20112791Ssam 	 * Partially simulate the environment
20212791Ssam 	 * of the new process so that when it is actually
20312791Ssam 	 * created (by copying) it will look right.
20412791Ssam 	 * This begins the section where we must prevent the parent
20512791Ssam 	 * from being swapped.
20612791Ssam 	 */
20712791Ssam 	rip->p_flag |= SKEEP;
20812791Ssam 	if (procdup(rpp, isvfork))
20912791Ssam 		return (1);
21012791Ssam 
21112791Ssam 	/*
21212791Ssam 	 * Make child runnable and add to run queue.
21312791Ssam 	 */
21412791Ssam 	(void) spl6();
21512791Ssam 	rpp->p_stat = SRUN;
21612791Ssam 	setrq(rpp);
21712791Ssam 	(void) spl0();
21812791Ssam 
21912791Ssam 	/*
22012791Ssam 	 * Cause child to take a non-local goto as soon as it runs.
22112791Ssam 	 * On older systems this was done with SSWAP bit in proc
22212791Ssam 	 * table; on VAX we use u.u_pcb.pcb_sswap so don't need
22312791Ssam 	 * to do rpp->p_flag |= SSWAP.  Actually do nothing here.
22412791Ssam 	 */
22512791Ssam 	/* rpp->p_flag |= SSWAP; */
22612791Ssam 
22712791Ssam 	/*
22812791Ssam 	 * Now can be swapped.
22912791Ssam 	 */
23012791Ssam 	rip->p_flag &= ~SKEEP;
23112791Ssam 
23212791Ssam 	/*
23312791Ssam 	 * If vfork make chain from parent process to child
23412791Ssam 	 * (where virtal memory is temporarily).  Wait for
23512791Ssam 	 * child to finish, steal virtual memory back,
23612791Ssam 	 * and wakeup child to let it die.
23712791Ssam 	 */
23812791Ssam 	if (isvfork) {
23912791Ssam 		u.u_procp->p_xlink = rpp;
24012791Ssam 		u.u_procp->p_flag |= SNOVM;
24112791Ssam 		while (rpp->p_flag & SVFORK)
24212791Ssam 			sleep((caddr_t)rpp, PZERO - 1);
24312791Ssam 		if ((rpp->p_flag & SLOAD) == 0)
24412791Ssam 			panic("newproc vfork");
24512791Ssam 		uaccess(rpp, Vfmap, &vfutl);
24612791Ssam 		u.u_procp->p_xlink = 0;
24712791Ssam 		vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap);
24812791Ssam 		u.u_procp->p_flag &= ~SNOVM;
24912791Ssam 		rpp->p_ndx = rpp - proc;
25012791Ssam 		rpp->p_flag |= SVFDONE;
25112791Ssam 		wakeup((caddr_t)rpp);
25212791Ssam 	}
25312791Ssam 
25412791Ssam 	/*
25512791Ssam 	 * 0 return means parent.
25612791Ssam 	 */
25712791Ssam 	return (0);
25812791Ssam }
259