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