Commit | Line | Data |
---|---|---|
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 | * | |
d9c2f47f | 17 | * @(#)kern_fork.c 7.18 (Berkeley) %G% |
da7c5cc6 | 18 | */ |
50108d5c | 19 | |
94368568 JB |
20 | #include "param.h" |
21 | #include "systm.h" | |
22 | #include "map.h" | |
d9c2f47f | 23 | #include "user.h" |
94368568 JB |
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" | |
56a12c82 | 32 | #include "ktrace.h" |
c4ec2128 | 33 | #include "../ufs/quota.h" |
50108d5c | 34 | |
d301d150 KM |
35 | #include "machine/reg.h" |
36 | #include "machine/pte.h" | |
37 | #include "machine/psl.h" | |
38 | ||
50108d5c SL |
39 | /* |
40 | * fork system call. | |
41 | */ | |
c9714ae3 KM |
42 | /* ARGSUSED */ |
43 | fork(p, uap, retval) | |
44 | struct proc *p; | |
45 | struct args *uap; | |
46 | int retval[]; | |
50108d5c | 47 | { |
c9714ae3 | 48 | int error; |
50108d5c SL |
49 | |
50 | u.u_cdmap = zdmap; | |
51 | u.u_csmap = zdmap; | |
c9714ae3 KM |
52 | if (error = swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap)) { |
53 | retval[1] = 0; | |
d9c2f47f | 54 | return (error); |
50108d5c | 55 | } |
d9c2f47f | 56 | return (fork1(p, 0, retval)); |
50108d5c SL |
57 | } |
58 | ||
c9714ae3 KM |
59 | /* ARGSUSED */ |
60 | vfork(p, uap, retval) | |
61 | struct proc *p; | |
62 | struct args *uap; | |
63 | int retval[]; | |
50108d5c SL |
64 | { |
65 | ||
d9c2f47f | 66 | return (fork1(p, 1, retval)); |
50108d5c SL |
67 | } |
68 | ||
c9714ae3 KM |
69 | fork1(p1, isvfork, retval) |
70 | register struct proc *p1; | |
71 | int isvfork, retval[]; | |
50108d5c | 72 | { |
c9714ae3 KM |
73 | register struct proc *p2; |
74 | register int a; | |
50108d5c SL |
75 | |
76 | a = 0; | |
c9714ae3 KM |
77 | if (p1->p_uid != 0) { |
78 | for (p2 = allproc; p2; p2 = p2->p_nxt) | |
79 | if (p2->p_uid == p1->p_uid) | |
1d348849 | 80 | a++; |
c9714ae3 KM |
81 | for (p2 = zombproc; p2; p2 = p2->p_nxt) |
82 | if (p2->p_uid == p1->p_uid) | |
50108d5c | 83 | a++; |
50108d5c SL |
84 | } |
85 | /* | |
86 | * Disallow if | |
87 | * No processes at all; | |
88 | * not su and too many procs owned; or | |
89 | * not su and would take last slot. | |
90 | */ | |
1d348849 | 91 | p2 = freeproc; |
50108d5c SL |
92 | if (p2==NULL) |
93 | tablefull("proc"); | |
c9714ae3 KM |
94 | if (p2 == NULL || |
95 | (p1->p_uid != 0 && (p2->p_nxt == NULL || a > MAXUPRC))) { | |
50108d5c | 96 | if (!isvfork) { |
e5b27ef1 KB |
97 | (void) vsexpand((segsz_t)0, &u.u_cdmap, 1); |
98 | (void) vsexpand((segsz_t)0, &u.u_csmap, 1); | |
50108d5c | 99 | } |
c9714ae3 KM |
100 | retval[1] = 0; |
101 | return (EAGAIN); | |
50108d5c | 102 | } |
50108d5c | 103 | if (newproc(isvfork)) { |
c9714ae3 KM |
104 | retval[0] = p1->p_pid; |
105 | retval[1] = 1; /* child */ | |
50108d5c | 106 | u.u_acflag = AFORK; |
c9714ae3 | 107 | return (0); |
50108d5c | 108 | } |
c9714ae3 KM |
109 | retval[0] = p2->p_pid; |
110 | retval[1] = 0; | |
111 | return (0); | |
50108d5c SL |
112 | } |
113 | ||
114 | /* | |
115 | * Create a new process-- the internal version of | |
116 | * sys fork. | |
117 | * It returns 1 in the new process, 0 in the old. | |
118 | */ | |
119 | newproc(isvfork) | |
120 | int isvfork; | |
121 | { | |
50108d5c SL |
122 | register struct proc *rpp, *rip; |
123 | register int n; | |
124 | register struct file *fp; | |
1d348849 | 125 | static int pidchecked = 0; |
50108d5c | 126 | |
50108d5c SL |
127 | /* |
128 | * First, just locate a slot for a process | |
129 | * and copy the useful info from this process into it. | |
130 | * The panic "cannot happen" because fork has already | |
131 | * checked for the existence of a slot. | |
132 | */ | |
50108d5c | 133 | mpid++; |
1d348849 | 134 | retry: |
50108d5c | 135 | if (mpid >= 30000) { |
1d348849 MK |
136 | mpid = 100; |
137 | pidchecked = 0; | |
50108d5c | 138 | } |
1d348849 MK |
139 | if (mpid >= pidchecked) { |
140 | int doingzomb = 0; | |
e9539440 | 141 | |
1d348849 MK |
142 | pidchecked = 30000; |
143 | /* | |
144 | * Scan the proc table to check whether this pid | |
145 | * is in use. Remember the lowest pid that's greater | |
146 | * than mpid, so we can avoid checking for a while. | |
147 | */ | |
148 | rpp = allproc; | |
149 | again: | |
150 | for (; rpp != NULL; rpp = rpp->p_nxt) { | |
8fe87cbb | 151 | if (rpp->p_pid == mpid || rpp->p_pgrp->pg_id == mpid) { |
1d348849 MK |
152 | mpid++; |
153 | if (mpid >= pidchecked) | |
154 | goto retry; | |
155 | } | |
e9539440 | 156 | if (rpp->p_pid > mpid && pidchecked > rpp->p_pid) |
1d348849 | 157 | pidchecked = rpp->p_pid; |
8fe87cbb MT |
158 | if (rpp->p_pgrp->pg_id > mpid && |
159 | pidchecked > rpp->p_pgrp->pg_id) | |
160 | pidchecked = rpp->p_pgrp->pg_id; | |
1d348849 MK |
161 | } |
162 | if (!doingzomb) { | |
163 | doingzomb = 1; | |
164 | rpp = zombproc; | |
165 | goto again; | |
166 | } | |
50108d5c | 167 | } |
1d348849 | 168 | if ((rpp = freeproc) == NULL) |
50108d5c SL |
169 | panic("no procs"); |
170 | ||
1d348849 MK |
171 | freeproc = rpp->p_nxt; /* off freeproc */ |
172 | rpp->p_nxt = allproc; /* onto allproc */ | |
173 | rpp->p_nxt->p_prev = &rpp->p_nxt; /* (allproc is never NULL) */ | |
174 | rpp->p_prev = &allproc; | |
175 | allproc = rpp; | |
176 | ||
50108d5c SL |
177 | /* |
178 | * Make a proc table entry for the new process. | |
179 | */ | |
180 | rip = u.u_procp; | |
fb1db32c MK |
181 | #if defined(tahoe) |
182 | rpp->p_ckey = rip->p_ckey; | |
183 | rpp->p_dkey = 0; | |
50108d5c SL |
184 | #endif |
185 | rpp->p_stat = SIDL; | |
186 | timerclear(&rpp->p_realtimer.it_value); | |
5b5b14bc MT |
187 | rpp->p_flag = SLOAD | (rip->p_flag & (SPAGV|SHPUX)); |
188 | if (rip->p_session->s_ttyvp != NULL && rip->p_flag & SCTTY) | |
189 | rpp->p_flag |= SCTTY; | |
50108d5c SL |
190 | if (isvfork) { |
191 | rpp->p_flag |= SVFORK; | |
192 | rpp->p_ndx = rip->p_ndx; | |
193 | } else | |
194 | rpp->p_ndx = rpp - proc; | |
56a12c82 MT |
195 | bcopy(rip->p_comm, rpp->p_comm, MAXCOMLEN+1); |
196 | bcopy(rip->p_logname, rpp->p_logname, MAXLOGNAME); | |
50108d5c | 197 | rpp->p_uid = rip->p_uid; |
d9d1cf27 MK |
198 | rpp->p_ruid = rip->p_ruid; |
199 | rpp->p_rgid = rip->p_rgid; | |
50108d5c | 200 | rpp->p_pgrp = rip->p_pgrp; |
8fe87cbb MT |
201 | rpp->p_pgrpnxt = rip->p_pgrpnxt; |
202 | rip->p_pgrpnxt = rpp; | |
50108d5c SL |
203 | rpp->p_nice = rip->p_nice; |
204 | rpp->p_textp = isvfork ? 0 : rip->p_textp; | |
205 | rpp->p_pid = mpid; | |
206 | rpp->p_ppid = rip->p_pid; | |
207 | rpp->p_pptr = rip; | |
208 | rpp->p_osptr = rip->p_cptr; | |
209 | if (rip->p_cptr) | |
210 | rip->p_cptr->p_ysptr = rpp; | |
211 | rpp->p_ysptr = NULL; | |
212 | rpp->p_cptr = NULL; | |
213 | rip->p_cptr = rpp; | |
214 | rpp->p_time = 0; | |
d848aba6 MT |
215 | bzero((caddr_t)&rpp->p_utime, sizeof (struct timeval)); |
216 | bzero((caddr_t)&rpp->p_stime, sizeof (struct timeval)); | |
50108d5c | 217 | rpp->p_cpu = 0; |
dd012d1e SL |
218 | rpp->p_sigmask = rip->p_sigmask; |
219 | rpp->p_sigcatch = rip->p_sigcatch; | |
220 | rpp->p_sigignore = rip->p_sigignore; | |
221 | /* take along any pending signals like stops? */ | |
50108d5c | 222 | if (isvfork) { |
3340490c KM |
223 | rpp->p_tsize = rpp->p_dsize = rpp->p_mmsize = rpp->p_ssize = 0; |
224 | rpp->p_szpt = clrnd(ctopt(HIGHPAGES)); | |
50108d5c SL |
225 | forkstat.cntvfork++; |
226 | forkstat.sizvfork += rip->p_dsize + rip->p_ssize; | |
227 | } else { | |
228 | rpp->p_tsize = rip->p_tsize; | |
229 | rpp->p_dsize = rip->p_dsize; | |
3340490c | 230 | rpp->p_mmsize = rip->p_mmsize; |
50108d5c SL |
231 | rpp->p_ssize = rip->p_ssize; |
232 | rpp->p_szpt = rip->p_szpt; | |
233 | forkstat.cntfork++; | |
234 | forkstat.sizfork += rip->p_dsize + rip->p_ssize; | |
235 | } | |
98111078 | 236 | #ifdef KTRACE |
56a12c82 MT |
237 | if (rip->p_traceflag&KTRFAC_INHERIT) { |
238 | rpp->p_traceflag = rip->p_traceflag; | |
20b702d3 MT |
239 | if ((rpp->p_tracep = rip->p_tracep) != NULL) |
240 | VREF(rpp->p_tracep); | |
98111078 MT |
241 | } else { |
242 | rpp->p_tracep = NULL; | |
243 | rpp->p_traceflag = 0; | |
244 | } | |
245 | #endif | |
50108d5c SL |
246 | rpp->p_rssize = 0; |
247 | rpp->p_maxrss = rip->p_maxrss; | |
248 | rpp->p_wchan = 0; | |
249 | rpp->p_slptime = 0; | |
250 | rpp->p_pctcpu = 0; | |
251 | rpp->p_cpticks = 0; | |
56a12c82 MT |
252 | { |
253 | struct proc **hash = &pidhash[PIDHASH(rpp->p_pid)]; | |
254 | ||
255 | rpp->p_hash = *hash; | |
256 | *hash = rpp; | |
257 | } | |
50108d5c SL |
258 | multprog++; |
259 | ||
260 | /* | |
261 | * Increase reference counts on shared objects. | |
262 | */ | |
8694aaad | 263 | for (n = 0; n <= u.u_lastfile; n++) { |
50108d5c SL |
264 | fp = u.u_ofile[n]; |
265 | if (fp == NULL) | |
266 | continue; | |
267 | fp->f_count++; | |
50108d5c | 268 | } |
8fe1c702 | 269 | VREF(u.u_cdir); |
50108d5c | 270 | if (u.u_rdir) |
8fe1c702 | 271 | VREF(u.u_rdir); |
c4ec2128 | 272 | crhold(u.u_cred); |
50108d5c SL |
273 | |
274 | /* | |
50108d5c SL |
275 | * This begins the section where we must prevent the parent |
276 | * from being swapped. | |
277 | */ | |
278 | rip->p_flag |= SKEEP; | |
d848aba6 MT |
279 | if (procdup(rpp, isvfork)) { |
280 | (void) splclock(); | |
281 | u.u_start = time; | |
282 | (void) spl0(); | |
50108d5c | 283 | return (1); |
d848aba6 | 284 | } |
50108d5c SL |
285 | |
286 | /* | |
287 | * Make child runnable and add to run queue. | |
288 | */ | |
01b0e233 | 289 | (void) splclock(); |
50108d5c SL |
290 | rpp->p_stat = SRUN; |
291 | setrq(rpp); | |
292 | (void) spl0(); | |
293 | ||
294 | /* | |
295 | * Cause child to take a non-local goto as soon as it runs. | |
296 | * On older systems this was done with SSWAP bit in proc | |
297 | * table; on VAX we use u.u_pcb.pcb_sswap so don't need | |
298 | * to do rpp->p_flag |= SSWAP. Actually do nothing here. | |
299 | */ | |
300 | /* rpp->p_flag |= SSWAP; */ | |
301 | ||
302 | /* | |
303 | * Now can be swapped. | |
304 | */ | |
305 | rip->p_flag &= ~SKEEP; | |
306 | ||
307 | /* | |
308 | * If vfork make chain from parent process to child | |
309 | * (where virtal memory is temporarily). Wait for | |
310 | * child to finish, steal virtual memory back, | |
311 | * and wakeup child to let it die. | |
312 | */ | |
313 | if (isvfork) { | |
314 | u.u_procp->p_xlink = rpp; | |
315 | u.u_procp->p_flag |= SNOVM; | |
316 | while (rpp->p_flag & SVFORK) | |
317 | sleep((caddr_t)rpp, PZERO - 1); | |
318 | if ((rpp->p_flag & SLOAD) == 0) | |
319 | panic("newproc vfork"); | |
320 | uaccess(rpp, Vfmap, &vfutl); | |
321 | u.u_procp->p_xlink = 0; | |
322 | vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap); | |
323 | u.u_procp->p_flag &= ~SNOVM; | |
324 | rpp->p_ndx = rpp - proc; | |
325 | rpp->p_flag |= SVFDONE; | |
326 | wakeup((caddr_t)rpp); | |
327 | } | |
328 | ||
329 | /* | |
330 | * 0 return means parent. | |
331 | */ | |
332 | return (0); | |
333 | } |