xref: /csrg-svn/sys/kern/kern_fork.c (revision 12791)
1*12791Ssam /*	kern_fork.c	4.1	83/05/27	*/
2*12791Ssam 
3*12791Ssam #include "../machine/reg.h"
4*12791Ssam #include "../machine/pte.h"
5*12791Ssam #include "../machine/psl.h"
6*12791Ssam 
7*12791Ssam #include "../h/param.h"
8*12791Ssam #include "../h/systm.h"
9*12791Ssam #include "../h/map.h"
10*12791Ssam #include "../h/dir.h"
11*12791Ssam #include "../h/user.h"
12*12791Ssam #include "../h/kernel.h"
13*12791Ssam #include "../h/proc.h"
14*12791Ssam #include "../h/inode.h"
15*12791Ssam #include "../h/seg.h"
16*12791Ssam #include "../h/vm.h"
17*12791Ssam #include "../h/text.h"
18*12791Ssam #include "../h/file.h"
19*12791Ssam #include "../h/acct.h"
20*12791Ssam #include "../h/quota.h"
21*12791Ssam 
22*12791Ssam /*
23*12791Ssam  * fork system call.
24*12791Ssam  */
25*12791Ssam fork()
26*12791Ssam {
27*12791Ssam 
28*12791Ssam 	u.u_cdmap = zdmap;
29*12791Ssam 	u.u_csmap = zdmap;
30*12791Ssam 	if (swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap) == 0) {
31*12791Ssam 		u.u_r.r_val2 = 0;
32*12791Ssam 		return;
33*12791Ssam 	}
34*12791Ssam 	fork1(0);
35*12791Ssam }
36*12791Ssam 
37*12791Ssam vfork()
38*12791Ssam {
39*12791Ssam 
40*12791Ssam 	fork1(1);
41*12791Ssam }
42*12791Ssam 
43*12791Ssam fork1(isvfork)
44*12791Ssam 	int isvfork;
45*12791Ssam {
46*12791Ssam 	register struct proc *p1, *p2;
47*12791Ssam 	register a;
48*12791Ssam 
49*12791Ssam 	a = 0;
50*12791Ssam 	p2 = NULL;
51*12791Ssam 	for (p1 = proc; p1 < procNPROC; p1++) {
52*12791Ssam 		if (p1->p_stat==NULL && p2==NULL)
53*12791Ssam 			p2 = p1;
54*12791Ssam 		else {
55*12791Ssam 			if (p1->p_uid==u.u_uid && p1->p_stat!=NULL)
56*12791Ssam 				a++;
57*12791Ssam 		}
58*12791Ssam 	}
59*12791Ssam 	/*
60*12791Ssam 	 * Disallow if
61*12791Ssam 	 *  No processes at all;
62*12791Ssam 	 *  not su and too many procs owned; or
63*12791Ssam 	 *  not su and would take last slot.
64*12791Ssam 	 */
65*12791Ssam 	if (p2==NULL)
66*12791Ssam 		tablefull("proc");
67*12791Ssam 	if (p2==NULL || (u.u_uid!=0 && (p2==procNPROC-1 || a>MAXUPRC))) {
68*12791Ssam 		u.u_error = EAGAIN;
69*12791Ssam 		if (!isvfork) {
70*12791Ssam 			(void) vsexpand(0, &u.u_cdmap, 1);
71*12791Ssam 			(void) vsexpand(0, &u.u_csmap, 1);
72*12791Ssam 		}
73*12791Ssam 		goto out;
74*12791Ssam 	}
75*12791Ssam 	p1 = u.u_procp;
76*12791Ssam 	if (newproc(isvfork)) {
77*12791Ssam 		u.u_r.r_val1 = p1->p_pid;
78*12791Ssam 		u.u_r.r_val2 = 1;  /* child */
79*12791Ssam 		u.u_start = time.tv_sec;
80*12791Ssam 		u.u_acflag = AFORK;
81*12791Ssam 		return;
82*12791Ssam 	}
83*12791Ssam 	u.u_r.r_val1 = p2->p_pid;
84*12791Ssam 
85*12791Ssam out:
86*12791Ssam 	u.u_r.r_val2 = 0;
87*12791Ssam }
88*12791Ssam 
89*12791Ssam /*
90*12791Ssam  * Create a new process-- the internal version of
91*12791Ssam  * sys fork.
92*12791Ssam  * It returns 1 in the new process, 0 in the old.
93*12791Ssam  */
94*12791Ssam newproc(isvfork)
95*12791Ssam 	int isvfork;
96*12791Ssam {
97*12791Ssam 	register struct proc *p;
98*12791Ssam 	register struct proc *rpp, *rip;
99*12791Ssam 	register int n;
100*12791Ssam 	register struct file *fp;
101*12791Ssam 
102*12791Ssam 	p = NULL;
103*12791Ssam 	/*
104*12791Ssam 	 * First, just locate a slot for a process
105*12791Ssam 	 * and copy the useful info from this process into it.
106*12791Ssam 	 * The panic "cannot happen" because fork has already
107*12791Ssam 	 * checked for the existence of a slot.
108*12791Ssam 	 */
109*12791Ssam retry:
110*12791Ssam 	mpid++;
111*12791Ssam 	if (mpid >= 30000) {
112*12791Ssam 		mpid = 0;
113*12791Ssam 		goto retry;
114*12791Ssam 	}
115*12791Ssam 	for (rpp = proc; rpp < procNPROC; rpp++) {
116*12791Ssam 		if (rpp->p_stat == NULL && p==NULL)
117*12791Ssam 			p = rpp;
118*12791Ssam 		if (rpp->p_pid==mpid || rpp->p_pgrp==mpid)
119*12791Ssam 			goto retry;
120*12791Ssam 	}
121*12791Ssam 	if ((rpp = p) == NULL)
122*12791Ssam 		panic("no procs");
123*12791Ssam 
124*12791Ssam 	/*
125*12791Ssam 	 * Make a proc table entry for the new process.
126*12791Ssam 	 */
127*12791Ssam 	rip = u.u_procp;
128*12791Ssam #ifdef QUOTA
129*12791Ssam 	rpp->p_quota = rip->p_quota;
130*12791Ssam 	rpp->p_quota->q_cnt++;
131*12791Ssam #endif
132*12791Ssam 	rpp->p_stat = SIDL;
133*12791Ssam 	timerclear(&rpp->p_realtimer.it_value);
134*12791Ssam 	rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SNUSIG));
135*12791Ssam 	if (isvfork) {
136*12791Ssam 		rpp->p_flag |= SVFORK;
137*12791Ssam 		rpp->p_ndx = rip->p_ndx;
138*12791Ssam 	} else
139*12791Ssam 		rpp->p_ndx = rpp - proc;
140*12791Ssam 	rpp->p_uid = rip->p_uid;
141*12791Ssam 	rpp->p_pgrp = rip->p_pgrp;
142*12791Ssam 	rpp->p_nice = rip->p_nice;
143*12791Ssam 	rpp->p_textp = isvfork ? 0 : rip->p_textp;
144*12791Ssam 	rpp->p_pid = mpid;
145*12791Ssam 	rpp->p_ppid = rip->p_pid;
146*12791Ssam 	rpp->p_pptr = rip;
147*12791Ssam 	rpp->p_osptr = rip->p_cptr;
148*12791Ssam 	if (rip->p_cptr)
149*12791Ssam 		rip->p_cptr->p_ysptr = rpp;
150*12791Ssam 	rpp->p_ysptr = NULL;
151*12791Ssam 	rpp->p_cptr = NULL;
152*12791Ssam 	rip->p_cptr = rpp;
153*12791Ssam 	rpp->p_time = 0;
154*12791Ssam 	rpp->p_cpu = 0;
155*12791Ssam 	rpp->p_siga0 = rip->p_siga0;
156*12791Ssam 	rpp->p_siga1 = rip->p_siga1;
157*12791Ssam 	/* take along any pending signals, like stops? */
158*12791Ssam 	if (isvfork) {
159*12791Ssam 		rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0;
160*12791Ssam 		rpp->p_szpt = clrnd(ctopt(UPAGES));
161*12791Ssam 		forkstat.cntvfork++;
162*12791Ssam 		forkstat.sizvfork += rip->p_dsize + rip->p_ssize;
163*12791Ssam 	} else {
164*12791Ssam 		rpp->p_tsize = rip->p_tsize;
165*12791Ssam 		rpp->p_dsize = rip->p_dsize;
166*12791Ssam 		rpp->p_ssize = rip->p_ssize;
167*12791Ssam 		rpp->p_szpt = rip->p_szpt;
168*12791Ssam 		forkstat.cntfork++;
169*12791Ssam 		forkstat.sizfork += rip->p_dsize + rip->p_ssize;
170*12791Ssam 	}
171*12791Ssam 	rpp->p_rssize = 0;
172*12791Ssam 	rpp->p_maxrss = rip->p_maxrss;
173*12791Ssam 	rpp->p_wchan = 0;
174*12791Ssam 	rpp->p_slptime = 0;
175*12791Ssam 	rpp->p_pctcpu = 0;
176*12791Ssam 	rpp->p_cpticks = 0;
177*12791Ssam 	n = PIDHASH(rpp->p_pid);
178*12791Ssam 	p->p_idhash = pidhash[n];
179*12791Ssam 	pidhash[n] = rpp - proc;
180*12791Ssam 	multprog++;
181*12791Ssam 
182*12791Ssam 	/*
183*12791Ssam 	 * Increase reference counts on shared objects.
184*12791Ssam 	 */
185*12791Ssam 	for (n = 0; n < NOFILE; n++) {
186*12791Ssam 		fp = u.u_ofile[n];
187*12791Ssam 		if (fp == NULL)
188*12791Ssam 			continue;
189*12791Ssam 		fp->f_count++;
190*12791Ssam 		if (u.u_pofile[n]&UF_SHLOCK)
191*12791Ssam 			((struct inode *)fp->f_data)->i_shlockc++;
192*12791Ssam 		if (u.u_pofile[n]&UF_EXLOCK)
193*12791Ssam 			((struct inode *)fp->f_data)->i_exlockc++;
194*12791Ssam 	}
195*12791Ssam 	u.u_cdir->i_count++;
196*12791Ssam 	if (u.u_rdir)
197*12791Ssam 		u.u_rdir->i_count++;
198*12791Ssam 
199*12791Ssam 	/*
200*12791Ssam 	 * Partially simulate the environment
201*12791Ssam 	 * of the new process so that when it is actually
202*12791Ssam 	 * created (by copying) it will look right.
203*12791Ssam 	 * This begins the section where we must prevent the parent
204*12791Ssam 	 * from being swapped.
205*12791Ssam 	 */
206*12791Ssam 	rip->p_flag |= SKEEP;
207*12791Ssam 	if (procdup(rpp, isvfork))
208*12791Ssam 		return (1);
209*12791Ssam 
210*12791Ssam 	/*
211*12791Ssam 	 * Make child runnable and add to run queue.
212*12791Ssam 	 */
213*12791Ssam 	(void) spl6();
214*12791Ssam 	rpp->p_stat = SRUN;
215*12791Ssam 	setrq(rpp);
216*12791Ssam 	(void) spl0();
217*12791Ssam 
218*12791Ssam 	/*
219*12791Ssam 	 * Cause child to take a non-local goto as soon as it runs.
220*12791Ssam 	 * On older systems this was done with SSWAP bit in proc
221*12791Ssam 	 * table; on VAX we use u.u_pcb.pcb_sswap so don't need
222*12791Ssam 	 * to do rpp->p_flag |= SSWAP.  Actually do nothing here.
223*12791Ssam 	 */
224*12791Ssam 	/* rpp->p_flag |= SSWAP; */
225*12791Ssam 
226*12791Ssam 	/*
227*12791Ssam 	 * Now can be swapped.
228*12791Ssam 	 */
229*12791Ssam 	rip->p_flag &= ~SKEEP;
230*12791Ssam 
231*12791Ssam 	/*
232*12791Ssam 	 * If vfork make chain from parent process to child
233*12791Ssam 	 * (where virtal memory is temporarily).  Wait for
234*12791Ssam 	 * child to finish, steal virtual memory back,
235*12791Ssam 	 * and wakeup child to let it die.
236*12791Ssam 	 */
237*12791Ssam 	if (isvfork) {
238*12791Ssam 		u.u_procp->p_xlink = rpp;
239*12791Ssam 		u.u_procp->p_flag |= SNOVM;
240*12791Ssam 		while (rpp->p_flag & SVFORK)
241*12791Ssam 			sleep((caddr_t)rpp, PZERO - 1);
242*12791Ssam 		if ((rpp->p_flag & SLOAD) == 0)
243*12791Ssam 			panic("newproc vfork");
244*12791Ssam 		uaccess(rpp, Vfmap, &vfutl);
245*12791Ssam 		u.u_procp->p_xlink = 0;
246*12791Ssam 		vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap);
247*12791Ssam 		u.u_procp->p_flag &= ~SNOVM;
248*12791Ssam 		rpp->p_ndx = rpp - proc;
249*12791Ssam 		rpp->p_flag |= SVFDONE;
250*12791Ssam 		wakeup((caddr_t)rpp);
251*12791Ssam 	}
252*12791Ssam 
253*12791Ssam 	/*
254*12791Ssam 	 * 0 return means parent.
255*12791Ssam 	 */
256*12791Ssam 	return (0);
257*12791Ssam }
258