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