tsleep
[unix-history] / usr / src / sys / kern / kern_fork.c
CommitLineData
da7c5cc6 1/*
c4ec2128
KM
2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3 * All rights reserved.
da7c5cc6 4 *
c4ec2128
KM
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 *
e3fb2940 17 * @(#)kern_fork.c 7.10 (Berkeley) %G%
da7c5cc6 18 */
50108d5c 19
94368568
JB
20#include "param.h"
21#include "systm.h"
22#include "map.h"
94368568
JB
23#include "user.h"
24#include "kernel.h"
25#include "proc.h"
c4ec2128 26#include "vnode.h"
94368568
JB
27#include "seg.h"
28#include "vm.h"
29#include "text.h"
30#include "file.h"
31#include "acct.h"
c4ec2128 32#include "../ufs/quota.h"
50108d5c 33
d301d150
KM
34#include "machine/reg.h"
35#include "machine/pte.h"
36#include "machine/psl.h"
37
50108d5c
SL
38/*
39 * fork system call.
40 */
41fork()
42{
43
44 u.u_cdmap = zdmap;
45 u.u_csmap = zdmap;
46 if (swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap) == 0) {
47 u.u_r.r_val2 = 0;
48 return;
49 }
50 fork1(0);
51}
52
53vfork()
54{
55
56 fork1(1);
57}
58
59fork1(isvfork)
60 int isvfork;
61{
62 register struct proc *p1, *p2;
63 register a;
64
65 a = 0;
1d348849
MK
66 if (u.u_uid != 0) {
67 for (p1 = allproc; p1; p1 = p1->p_nxt)
68 if (p1->p_uid == u.u_uid)
69 a++;
70 for (p1 = zombproc; p1; p1 = p1->p_nxt)
71 if (p1->p_uid == u.u_uid)
50108d5c 72 a++;
50108d5c
SL
73 }
74 /*
75 * Disallow if
76 * No processes at all;
77 * not su and too many procs owned; or
78 * not su and would take last slot.
79 */
1d348849 80 p2 = freeproc;
50108d5c
SL
81 if (p2==NULL)
82 tablefull("proc");
1d348849 83 if (p2==NULL || (u.u_uid!=0 && (p2->p_nxt == NULL || a>MAXUPRC))) {
50108d5c
SL
84 u.u_error = EAGAIN;
85 if (!isvfork) {
8011f5df
MK
86 (void) vsexpand((size_t)0, &u.u_cdmap, 1);
87 (void) vsexpand((size_t)0, &u.u_csmap, 1);
50108d5c
SL
88 }
89 goto out;
90 }
91 p1 = u.u_procp;
92 if (newproc(isvfork)) {
93 u.u_r.r_val1 = p1->p_pid;
94 u.u_r.r_val2 = 1; /* child */
e8109af3 95 u.u_start = time;
50108d5c
SL
96 u.u_acflag = AFORK;
97 return;
98 }
99 u.u_r.r_val1 = p2->p_pid;
100
101out:
102 u.u_r.r_val2 = 0;
103}
104
105/*
106 * Create a new process-- the internal version of
107 * sys fork.
108 * It returns 1 in the new process, 0 in the old.
109 */
110newproc(isvfork)
111 int isvfork;
112{
50108d5c
SL
113 register struct proc *rpp, *rip;
114 register int n;
115 register struct file *fp;
1d348849 116 static int pidchecked = 0;
50108d5c 117
50108d5c
SL
118 /*
119 * First, just locate a slot for a process
120 * and copy the useful info from this process into it.
121 * The panic "cannot happen" because fork has already
122 * checked for the existence of a slot.
123 */
50108d5c 124 mpid++;
1d348849 125retry:
50108d5c 126 if (mpid >= 30000) {
1d348849
MK
127 mpid = 100;
128 pidchecked = 0;
50108d5c 129 }
1d348849
MK
130 if (mpid >= pidchecked) {
131 int doingzomb = 0;
e9539440 132
1d348849
MK
133 pidchecked = 30000;
134 /*
135 * Scan the proc table to check whether this pid
136 * is in use. Remember the lowest pid that's greater
137 * than mpid, so we can avoid checking for a while.
138 */
139 rpp = allproc;
140again:
141 for (; rpp != NULL; rpp = rpp->p_nxt) {
8fe87cbb 142 if (rpp->p_pid == mpid || rpp->p_pgrp->pg_id == mpid) {
1d348849
MK
143 mpid++;
144 if (mpid >= pidchecked)
145 goto retry;
146 }
e9539440 147 if (rpp->p_pid > mpid && pidchecked > rpp->p_pid)
1d348849 148 pidchecked = rpp->p_pid;
8fe87cbb
MT
149 if (rpp->p_pgrp->pg_id > mpid &&
150 pidchecked > rpp->p_pgrp->pg_id)
151 pidchecked = rpp->p_pgrp->pg_id;
1d348849
MK
152 }
153 if (!doingzomb) {
154 doingzomb = 1;
155 rpp = zombproc;
156 goto again;
157 }
50108d5c 158 }
1d348849 159 if ((rpp = freeproc) == NULL)
50108d5c
SL
160 panic("no procs");
161
1d348849
MK
162 freeproc = rpp->p_nxt; /* off freeproc */
163 rpp->p_nxt = allproc; /* onto allproc */
164 rpp->p_nxt->p_prev = &rpp->p_nxt; /* (allproc is never NULL) */
165 rpp->p_prev = &allproc;
166 allproc = rpp;
167
50108d5c
SL
168 /*
169 * Make a proc table entry for the new process.
170 */
171 rip = u.u_procp;
172#ifdef QUOTA
173 rpp->p_quota = rip->p_quota;
174 rpp->p_quota->q_cnt++;
fb1db32c
MK
175#endif
176#if defined(tahoe)
177 rpp->p_ckey = rip->p_ckey;
178 rpp->p_dkey = 0;
50108d5c
SL
179#endif
180 rpp->p_stat = SIDL;
181 timerclear(&rpp->p_realtimer.it_value);
e3fb2940 182 rpp->p_flag = SLOAD | (rip->p_flag & (SPAGV|SCTTY));
50108d5c
SL
183 if (isvfork) {
184 rpp->p_flag |= SVFORK;
185 rpp->p_ndx = rip->p_ndx;
186 } else
187 rpp->p_ndx = rpp - proc;
188 rpp->p_uid = rip->p_uid;
d9d1cf27
MK
189 rpp->p_ruid = rip->p_ruid;
190 rpp->p_rgid = rip->p_rgid;
50108d5c 191 rpp->p_pgrp = rip->p_pgrp;
8fe87cbb
MT
192 rpp->p_pgrpnxt = rip->p_pgrpnxt;
193 rip->p_pgrpnxt = rpp;
50108d5c
SL
194 rpp->p_nice = rip->p_nice;
195 rpp->p_textp = isvfork ? 0 : rip->p_textp;
196 rpp->p_pid = mpid;
197 rpp->p_ppid = rip->p_pid;
198 rpp->p_pptr = rip;
199 rpp->p_osptr = rip->p_cptr;
200 if (rip->p_cptr)
201 rip->p_cptr->p_ysptr = rpp;
202 rpp->p_ysptr = NULL;
203 rpp->p_cptr = NULL;
204 rip->p_cptr = rpp;
205 rpp->p_time = 0;
206 rpp->p_cpu = 0;
dd012d1e
SL
207 rpp->p_sigmask = rip->p_sigmask;
208 rpp->p_sigcatch = rip->p_sigcatch;
209 rpp->p_sigignore = rip->p_sigignore;
210 /* take along any pending signals like stops? */
50108d5c
SL
211 if (isvfork) {
212 rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0;
213 rpp->p_szpt = clrnd(ctopt(UPAGES));
214 forkstat.cntvfork++;
215 forkstat.sizvfork += rip->p_dsize + rip->p_ssize;
216 } else {
217 rpp->p_tsize = rip->p_tsize;
218 rpp->p_dsize = rip->p_dsize;
219 rpp->p_ssize = rip->p_ssize;
220 rpp->p_szpt = rip->p_szpt;
221 forkstat.cntfork++;
222 forkstat.sizfork += rip->p_dsize + rip->p_ssize;
223 }
98111078
MT
224#ifdef KTRACE
225 if (rip->p_flag&SKTR) {
226 rpp->p_flag |= SKTR;
20b702d3
MT
227 if ((rpp->p_tracep = rip->p_tracep) != NULL)
228 VREF(rpp->p_tracep);
98111078
MT
229 rpp->p_traceflag = rip->p_traceflag;
230 } else {
231 rpp->p_tracep = NULL;
232 rpp->p_traceflag = 0;
233 }
234#endif
50108d5c
SL
235 rpp->p_rssize = 0;
236 rpp->p_maxrss = rip->p_maxrss;
237 rpp->p_wchan = 0;
238 rpp->p_slptime = 0;
239 rpp->p_pctcpu = 0;
240 rpp->p_cpticks = 0;
241 n = PIDHASH(rpp->p_pid);
1d348849 242 rpp->p_idhash = pidhash[n];
50108d5c
SL
243 pidhash[n] = rpp - proc;
244 multprog++;
245
246 /*
247 * Increase reference counts on shared objects.
248 */
8694aaad 249 for (n = 0; n <= u.u_lastfile; n++) {
50108d5c
SL
250 fp = u.u_ofile[n];
251 if (fp == NULL)
252 continue;
253 fp->f_count++;
50108d5c 254 }
8fe1c702 255 VREF(u.u_cdir);
50108d5c 256 if (u.u_rdir)
8fe1c702 257 VREF(u.u_rdir);
c4ec2128 258 crhold(u.u_cred);
50108d5c
SL
259
260 /*
50108d5c
SL
261 * This begins the section where we must prevent the parent
262 * from being swapped.
263 */
264 rip->p_flag |= SKEEP;
265 if (procdup(rpp, isvfork))
266 return (1);
267
268 /*
269 * Make child runnable and add to run queue.
270 */
01b0e233 271 (void) splclock();
50108d5c
SL
272 rpp->p_stat = SRUN;
273 setrq(rpp);
274 (void) spl0();
275
276 /*
277 * Cause child to take a non-local goto as soon as it runs.
278 * On older systems this was done with SSWAP bit in proc
279 * table; on VAX we use u.u_pcb.pcb_sswap so don't need
280 * to do rpp->p_flag |= SSWAP. Actually do nothing here.
281 */
282 /* rpp->p_flag |= SSWAP; */
283
284 /*
285 * Now can be swapped.
286 */
287 rip->p_flag &= ~SKEEP;
288
289 /*
290 * If vfork make chain from parent process to child
291 * (where virtal memory is temporarily). Wait for
292 * child to finish, steal virtual memory back,
293 * and wakeup child to let it die.
294 */
295 if (isvfork) {
296 u.u_procp->p_xlink = rpp;
297 u.u_procp->p_flag |= SNOVM;
298 while (rpp->p_flag & SVFORK)
299 sleep((caddr_t)rpp, PZERO - 1);
300 if ((rpp->p_flag & SLOAD) == 0)
301 panic("newproc vfork");
302 uaccess(rpp, Vfmap, &vfutl);
303 u.u_procp->p_xlink = 0;
304 vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap);
305 u.u_procp->p_flag &= ~SNOVM;
306 rpp->p_ndx = rpp - proc;
307 rpp->p_flag |= SVFDONE;
308 wakeup((caddr_t)rpp);
309 }
310
311 /*
312 * 0 return means parent.
313 */
314 return (0);
315}