]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * The contents of this file constitute Original Code as defined in and | |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
11 | * | |
12 | * This Original Code and all software distributed under the License are | |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the | |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
19 | * | |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | /* Copyright (c) 1995, 1997 Apple Computer, Inc. All Rights Reserved */ | |
23 | /* | |
24 | * Copyright (c) 1982, 1986, 1989, 1991, 1993 | |
25 | * The Regents of the University of California. All rights reserved. | |
26 | * (c) UNIX System Laboratories, Inc. | |
27 | * All or some portions of this file are derived from material licensed | |
28 | * to the University of California by American Telephone and Telegraph | |
29 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with | |
30 | * the permission of UNIX System Laboratories, Inc. | |
31 | * | |
32 | * Redistribution and use in source and binary forms, with or without | |
33 | * modification, are permitted provided that the following conditions | |
34 | * are met: | |
35 | * 1. Redistributions of source code must retain the above copyright | |
36 | * notice, this list of conditions and the following disclaimer. | |
37 | * 2. Redistributions in binary form must reproduce the above copyright | |
38 | * notice, this list of conditions and the following disclaimer in the | |
39 | * documentation and/or other materials provided with the distribution. | |
40 | * 3. All advertising materials mentioning features or use of this software | |
41 | * must display the following acknowledgement: | |
42 | * This product includes software developed by the University of | |
43 | * California, Berkeley and its contributors. | |
44 | * 4. Neither the name of the University nor the names of its contributors | |
45 | * may be used to endorse or promote products derived from this software | |
46 | * without specific prior written permission. | |
47 | * | |
48 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
49 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
50 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
51 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
52 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
53 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
54 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
55 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
56 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
57 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
58 | * SUCH DAMAGE. | |
59 | * | |
60 | * @(#)kern_fork.c 8.8 (Berkeley) 2/14/95 | |
61 | */ | |
62 | ||
63 | #include <sys/param.h> | |
64 | #include <sys/systm.h> | |
65 | #include <sys/filedesc.h> | |
66 | #include <sys/kernel.h> | |
67 | #include <sys/malloc.h> | |
68 | #include <sys/proc.h> | |
69 | #include <sys/user.h> | |
70 | #include <sys/resourcevar.h> | |
71 | #include <sys/vnode.h> | |
72 | #include <sys/file.h> | |
73 | #include <sys/acct.h> | |
74 | #include <sys/ktrace.h> | |
75 | ||
76 | #include <mach/mach_types.h> | |
77 | #include <kern/mach_param.h> | |
78 | ||
79 | #include <machine/spl.h> | |
80 | ||
81 | thread_t cloneproc(struct proc *, int); | |
82 | thread_t procdup(); | |
83 | ||
84 | #define DOFORK 0x1 /* fork() system call */ | |
85 | #define DOVFORK 0x2 /* vfork() system call */ | |
86 | static int fork1(struct proc *, long, register_t *); | |
87 | ||
88 | /* | |
89 | * fork system call. | |
90 | */ | |
91 | int | |
92 | fork(p, uap, retval) | |
93 | struct proc *p; | |
94 | void *uap; | |
95 | register_t *retval; | |
96 | { | |
97 | return (fork1(p, (long)DOFORK, retval)); | |
98 | } | |
99 | ||
100 | /* | |
101 | * vfork system call | |
102 | */ | |
103 | int | |
104 | vfork(p, uap, retval) | |
105 | struct proc *p; | |
106 | void *uap; | |
107 | register_t *retval; | |
108 | { | |
109 | return (fork1(p, (long)DOVFORK, retval)); | |
110 | } | |
111 | ||
112 | static int | |
113 | fork1(p1, flags, retval) | |
114 | struct proc *p1; | |
115 | long flags; | |
116 | register_t *retval; | |
117 | { | |
118 | register struct proc *p2; | |
119 | register uid_t uid; | |
120 | thread_t newth, self = current_thread(); | |
121 | int s, count; | |
122 | task_t t; | |
123 | ||
124 | /* | |
125 | * Although process entries are dynamically created, we still keep | |
126 | * a global limit on the maximum number we will create. Don't allow | |
127 | * a nonprivileged user to use the last process; don't let root | |
128 | * exceed the limit. The variable nprocs is the current number of | |
129 | * processes, maxproc is the limit. | |
130 | */ | |
131 | uid = p1->p_cred->p_ruid; | |
132 | if ((nprocs >= maxproc - 1 && uid != 0) || nprocs >= maxproc) { | |
133 | tablefull("proc"); | |
134 | retval[1] = 0; | |
135 | return (EAGAIN); | |
136 | } | |
137 | ||
138 | /* | |
139 | * Increment the count of procs running with this uid. Don't allow | |
140 | * a nonprivileged user to exceed their current limit. | |
141 | */ | |
142 | count = chgproccnt(uid, 1); | |
143 | if (uid != 0 && count > p1->p_rlimit[RLIMIT_NPROC].rlim_cur) { | |
144 | (void)chgproccnt(uid, -1); | |
145 | return (EAGAIN); | |
146 | } | |
147 | ||
148 | /* The newly created process comes with signal lock held */ | |
149 | newth = cloneproc(p1, 1); | |
150 | thread_dup(current_act(), newth); | |
151 | /* p2 = newth->task->proc; */ | |
152 | p2 = (struct proc *)(get_bsdtask_info(get_threadtask(newth))); | |
153 | ||
154 | thread_set_child(newth, p2->p_pid); | |
155 | ||
156 | s = splhigh(); | |
157 | p2->p_stats->p_start = time; | |
158 | splx(s); | |
159 | p2->p_acflag = AFORK; | |
160 | ||
161 | /* | |
162 | * Preserve synchronization semantics of vfork. If waiting for | |
163 | * child to exec or exit, set P_PPWAIT on child, and sleep on our | |
164 | * proc (in case of exit). | |
165 | */ | |
166 | if (flags == DOVFORK) | |
167 | p2->p_flag |= P_PPWAIT; | |
168 | /* drop the signal lock on the child */ | |
169 | signal_unlock(p2); | |
170 | ||
171 | (void) thread_resume(newth); | |
172 | ||
173 | /* drop the extra references we got during the creation */ | |
174 | if (t = get_threadtask(newth)) { | |
175 | task_deallocate(t); | |
176 | } | |
177 | act_deallocate(newth); | |
178 | ||
179 | while (p2->p_flag & P_PPWAIT) | |
180 | tsleep(p1, PWAIT, "ppwait", 0); | |
181 | ||
182 | retval[0] = p2->p_pid; | |
183 | retval[1] = 0; /* mark parent */ | |
184 | ||
185 | return (0); | |
186 | } | |
187 | ||
188 | /* | |
189 | * cloneproc() | |
190 | * | |
191 | * Create a new process from a specified process. | |
192 | * On return newly created child process has signal | |
193 | * lock held to block delivery of signal to it if called with | |
194 | * lock set. fork() code needs to explicity remove this lock | |
195 | * before signals can be delivered | |
196 | */ | |
197 | thread_t | |
198 | cloneproc(p1, lock) | |
199 | register struct proc *p1; | |
200 | register int lock; | |
201 | { | |
202 | register struct proc *p2, *newproc; | |
203 | static int nextpid = 0, pidchecked = 0; | |
204 | thread_t th; | |
205 | ||
206 | /* Allocate new proc. */ | |
207 | MALLOC_ZONE(newproc, struct proc *, | |
208 | sizeof *newproc, M_PROC, M_WAITOK); | |
209 | MALLOC_ZONE(newproc->p_cred, struct pcred *, | |
210 | sizeof *newproc->p_cred, M_SUBPROC, M_WAITOK); | |
211 | MALLOC_ZONE(newproc->p_stats, struct pstats *, | |
212 | sizeof *newproc->p_stats, M_SUBPROC, M_WAITOK); | |
213 | MALLOC_ZONE(newproc->p_sigacts, struct sigacts *, | |
214 | sizeof *newproc->p_sigacts, M_SUBPROC, M_WAITOK); | |
215 | ||
216 | /* | |
217 | * Find an unused process ID. We remember a range of unused IDs | |
218 | * ready to use (from nextpid+1 through pidchecked-1). | |
219 | */ | |
220 | nextpid++; | |
221 | retry: | |
222 | /* | |
223 | * If the process ID prototype has wrapped around, | |
224 | * restart somewhat above 0, as the low-numbered procs | |
225 | * tend to include daemons that don't exit. | |
226 | */ | |
227 | if (nextpid >= PID_MAX) { | |
228 | nextpid = 100; | |
229 | pidchecked = 0; | |
230 | } | |
231 | if (nextpid >= pidchecked) { | |
232 | int doingzomb = 0; | |
233 | ||
234 | pidchecked = PID_MAX; | |
235 | /* | |
236 | * Scan the active and zombie procs to check whether this pid | |
237 | * is in use. Remember the lowest pid that's greater | |
238 | * than nextpid, so we can avoid checking for a while. | |
239 | */ | |
240 | p2 = allproc.lh_first; | |
241 | again: | |
242 | for (; p2 != 0; p2 = p2->p_list.le_next) { | |
243 | while (p2->p_pid == nextpid || | |
244 | p2->p_pgrp->pg_id == nextpid) { | |
245 | nextpid++; | |
246 | if (nextpid >= pidchecked) | |
247 | goto retry; | |
248 | } | |
249 | if (p2->p_pid > nextpid && pidchecked > p2->p_pid) | |
250 | pidchecked = p2->p_pid; | |
251 | if (p2->p_pgrp && p2->p_pgrp->pg_id > nextpid && | |
252 | pidchecked > p2->p_pgrp->pg_id) | |
253 | pidchecked = p2->p_pgrp->pg_id; | |
254 | } | |
255 | if (!doingzomb) { | |
256 | doingzomb = 1; | |
257 | p2 = zombproc.lh_first; | |
258 | goto again; | |
259 | } | |
260 | } | |
261 | ||
262 | nprocs++; | |
263 | p2 = newproc; | |
264 | p2->p_stat = SIDL; | |
265 | p2->p_pid = nextpid; | |
266 | ||
267 | /* | |
268 | * Make a proc table entry for the new process. | |
269 | * Start by zeroing the section of proc that is zero-initialized, | |
270 | * then copy the section that is copied directly from the parent. | |
271 | */ | |
272 | bzero(&p2->p_startzero, | |
273 | (unsigned) ((caddr_t)&p2->p_endzero - (caddr_t)&p2->p_startzero)); | |
274 | bcopy(&p1->p_startcopy, &p2->p_startcopy, | |
275 | (unsigned) ((caddr_t)&p2->p_endcopy - (caddr_t)&p2->p_startcopy)); | |
276 | p2->vm_shm = (void *)NULL; /* Make sure it is zero */ | |
277 | ||
278 | /* | |
279 | * Duplicate sub-structures as needed. | |
280 | * Increase reference counts on shared objects. | |
281 | * The p_stats and p_sigacts substructs are set in vm_fork. | |
282 | */ | |
283 | p2->p_flag = P_INMEM; | |
284 | if (p1->p_flag & P_PROFIL) | |
285 | startprofclock(p2); | |
286 | bcopy(p1->p_cred, p2->p_cred, sizeof(*p2->p_cred)); | |
287 | p2->p_cred->p_refcnt = 1; | |
288 | crhold(p1->p_ucred); | |
289 | lockinit(&p2->p_cred->pc_lock, PLOCK, "proc cred", 0, 0); | |
290 | ||
291 | /* bump references to the text vnode (for procfs) */ | |
292 | p2->p_textvp = p1->p_textvp; | |
293 | if (p2->p_textvp) | |
294 | VREF(p2->p_textvp); | |
295 | ||
296 | p2->p_fd = fdcopy(p1); | |
297 | if (p1->vm_shm) { | |
298 | shmfork(p1,p2); | |
299 | } | |
300 | /* | |
301 | * If p_limit is still copy-on-write, bump refcnt, | |
302 | * otherwise get a copy that won't be modified. | |
303 | * (If PL_SHAREMOD is clear, the structure is shared | |
304 | * copy-on-write.) | |
305 | */ | |
306 | if (p1->p_limit->p_lflags & PL_SHAREMOD) | |
307 | p2->p_limit = limcopy(p1->p_limit); | |
308 | else { | |
309 | p2->p_limit = p1->p_limit; | |
310 | p2->p_limit->p_refcnt++; | |
311 | } | |
312 | ||
313 | bzero(&p2->p_stats->pstat_startzero, | |
314 | (unsigned) ((caddr_t)&p2->p_stats->pstat_endzero - | |
315 | (caddr_t)&p2->p_stats->pstat_startzero)); | |
316 | bcopy(&p1->p_stats->pstat_startcopy, &p2->p_stats->pstat_startcopy, | |
317 | ((caddr_t)&p2->p_stats->pstat_endcopy - | |
318 | (caddr_t)&p2->p_stats->pstat_startcopy)); | |
319 | ||
320 | if (p1->p_sigacts != NULL) | |
321 | (void)memcpy(p2->p_sigacts, | |
322 | p1->p_sigacts, sizeof *p2->p_sigacts); | |
323 | else | |
324 | (void)memset(p2->p_sigacts, 0, sizeof *p2->p_sigacts); | |
325 | ||
326 | if (p1->p_session->s_ttyvp != NULL && p1->p_flag & P_CONTROLT) | |
327 | p2->p_flag |= P_CONTROLT; | |
328 | ||
329 | p2->p_xstat = 0; | |
330 | p2->p_ru = NULL; | |
331 | ||
332 | p2->p_debugger = 0; /* don't inherit */ | |
333 | lockinit(&p2->signal_lock, PVM, "signal", 0, 0); | |
334 | /* block all signals to reach the process */ | |
335 | if (lock) | |
336 | signal_lock(p2); | |
337 | p2->sigwait = FALSE; | |
338 | p2->sigwait_thread = NULL; | |
339 | p2->exit_thread = NULL; | |
340 | p2->user_stack = p1->user_stack; | |
341 | p2->p_sigpending = 0; | |
342 | ||
343 | #if KTRACE | |
344 | /* | |
345 | * Copy traceflag and tracefile if enabled. | |
346 | * If not inherited, these were zeroed above. | |
347 | */ | |
348 | if (p1->p_traceflag&KTRFAC_INHERIT) { | |
349 | p2->p_traceflag = p1->p_traceflag; | |
350 | if ((p2->p_tracep = p1->p_tracep) != NULL) | |
351 | VREF(p2->p_tracep); | |
352 | } | |
353 | #endif | |
354 | ||
355 | th = procdup(p2, p1); /* child, parent */ | |
356 | LIST_INSERT_AFTER(p1, p2, p_pglist); | |
357 | p2->p_pptr = p1; | |
358 | LIST_INSERT_HEAD(&p1->p_children, p2, p_sibling); | |
359 | LIST_INIT(&p2->p_children); | |
360 | LIST_INSERT_HEAD(&allproc, p2, p_list); | |
361 | LIST_INSERT_HEAD(PIDHASH(p2->p_pid), p2, p_hash); | |
362 | TAILQ_INIT(&p2->p_evlist); | |
363 | /* | |
364 | * Make child runnable, set start time. | |
365 | */ | |
366 | p2->p_stat = SRUN; | |
367 | ||
368 | return(th); | |
369 | } | |
370 | ||
371 | #include <kern/zalloc.h> | |
372 | ||
373 | struct zone *uthread_zone; | |
374 | int uthread_zone_inited = 0; | |
375 | ||
376 | void | |
377 | uthread_zone_init() | |
378 | { | |
379 | if (!uthread_zone_inited) { | |
380 | uthread_zone = zinit(sizeof(struct uthread), | |
381 | THREAD_MAX * sizeof(struct uthread), | |
382 | THREAD_CHUNK * sizeof(struct uthread), | |
383 | "uthreads"); | |
384 | uthread_zone_inited = 1; | |
385 | } | |
386 | } | |
387 | ||
388 | void * | |
389 | uthread_alloc(void) | |
390 | { | |
391 | void *ut; | |
392 | ||
393 | if (!uthread_zone_inited) | |
394 | uthread_zone_init(); | |
395 | ||
396 | ut = (void *)zalloc(uthread_zone); | |
397 | bzero(ut, sizeof(struct uthread)); | |
398 | return (ut); | |
399 | } | |
400 | ||
401 | void | |
402 | uthread_free(void *uthread) | |
403 | { | |
404 | struct _select *sel; | |
405 | struct uthread *uth = (struct uthread *)uthread; | |
406 | ||
407 | sel = &uth->uu_state.ss_select; | |
408 | /* cleanup the select bit space */ | |
409 | if (sel->nbytes) { | |
410 | FREE(sel->ibits, M_TEMP); | |
411 | FREE(sel->obits, M_TEMP); | |
412 | } | |
413 | ||
414 | /* and free the uthread itself */ | |
415 | zfree(uthread_zone, (vm_offset_t)uthread); | |
416 | } |