|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /* Copyright (c) 1995, 1997 Apple Computer, Inc. All Rights Reserved */
26: /*
27: * Copyright (c) 1982, 1986, 1989, 1991, 1993
28: * The Regents of the University of California. All rights reserved.
29: * (c) UNIX System Laboratories, Inc.
30: * All or some portions of this file are derived from material licensed
31: * to the University of California by American Telephone and Telegraph
32: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
33: * the permission of UNIX System Laboratories, Inc.
34: *
35: * Redistribution and use in source and binary forms, with or without
36: * modification, are permitted provided that the following conditions
37: * are met:
38: * 1. Redistributions of source code must retain the above copyright
39: * notice, this list of conditions and the following disclaimer.
40: * 2. Redistributions in binary form must reproduce the above copyright
41: * notice, this list of conditions and the following disclaimer in the
42: * documentation and/or other materials provided with the distribution.
43: * 3. All advertising materials mentioning features or use of this software
44: * must display the following acknowledgement:
45: * This product includes software developed by the University of
46: * California, Berkeley and its contributors.
47: * 4. Neither the name of the University nor the names of its contributors
48: * may be used to endorse or promote products derived from this software
49: * without specific prior written permission.
50: *
51: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61: * SUCH DAMAGE.
62: *
63: * @(#)kern_exit.c 8.10 (Berkeley) 2/23/95
64: */
65:
66: #include <machine/reg.h>
67: #include <machine/psl.h>
68:
69: #include "compat_43.h"
70:
71: #include <sys/param.h>
72: #include <sys/systm.h>
73: #include <sys/ioctl.h>
74: #include <sys/proc.h>
75: #include <sys/tty.h>
76: #include <sys/time.h>
77: #include <sys/resource.h>
78: #include <sys/kernel.h>
79: #include <sys/buf.h>
80: #include <sys/wait.h>
81: #include <sys/file.h>
82: #include <sys/vnode.h>
83: #include <sys/syslog.h>
84: #include <sys/malloc.h>
85: #include <sys/resourcevar.h>
86: #include <sys/ptrace.h>
87: #include <sys/user.h>
88:
89: #include <mach/mach_types.h>
90:
91: void cpu_exit __P((struct proc *));
92: void exit1 __P((struct proc *, int));
93:
94: /*
95: * exit --
96: * Death of process.
97: */
98: struct exit_args {
99: int rval;
100: };
101: void
102: exit(p, uap, retval)
103: struct proc *p;
104: struct exit_args *uap;
105: int *retval;
106: {
107: exit1(p, W_EXITCODE(uap->rval, 0));
108: /*NOTREACHED*/
109: }
110:
111: /*
112: * Exit: deallocate address space and other resources, change proc state
113: * to zombie, and unlink proc from allproc and parent's lists. Save exit
114: * status and rusage for wait(). Check for child processes and orphan them.
115: */
116: void
117: exit1(p, rv)
118: register struct proc *p;
119: int rv;
120: {
121: register struct proc *q, *nq;
122: thread_t self = current_thread();
123: struct task *task = p->task;
124: register int i;
125:
126: /*
127: * If a thread in this task has already
128: * called exit(), then halt any others
129: * right here.
130: */
131: while (p->exit_thread != self) {
132: if (sig_try_lock(p) <= 0) {
133: if (self->task != task)
134: return;
135: while (TRUE) {
136: thread_halt_self_with_continuation(
137: (void (*)(void)) 0);
138: /* NOTREACHED */
139: }
140: }
141: sig_lock_to_exit(p);
142: }
143:
144: /*
145: * Halt the task, except for the current thread.
146: */
147: (void) task_halt(task);
148:
149: if (p->p_pid == 1) {
150: printf("pid 1 exited (signal %d, exit %d)",
151: WTERMSIG(rv), WEXITSTATUS(rv));
152: panic("init died");
153: }
154:
155: /*
156: * Remove proc from allproc queue and from pidhash chain.
157: * Need to do this before we do anything that can block.
158: * Not doing causes things like mount() find this on allproc
159: * in partially cleaned state.
160: */
161: LIST_REMOVE(p, p_list);
162: LIST_REMOVE(p, p_hash);
163:
164: #ifdef PGINPROF
165: vmsizmon();
166: #endif
167: MALLOC_ZONE(p->p_ru, struct rusage *,
168: sizeof *p->p_ru, M_ZOMBIE, M_WAITOK);
169: /*
170: * If parent is waiting for us to exit or exec,
171: * P_PPWAIT is set; we will wakeup the parent below.
172: */
173: p->p_flag &= ~(P_TRACED | P_PPWAIT);
174: p->p_flag |= P_WEXIT;
175: p->p_sigignore = ~0;
176: p->p_siglist = 0;
177: self->_uthread->uu_sig = 0;
178: untimeout(realitexpire, (caddr_t)p);
179:
180: /*
181: * Close open files and release open-file table.
182: * This may block!
183: */
184: fdfree(p);
185:
186: if (SESS_LEADER(p)) {
187: register struct session *sp = p->p_session;
188:
189: if (sp->s_ttyvp) {
190: /*
191: * Controlling process.
192: * Signal foreground pgrp,
193: * drain controlling terminal
194: * and revoke access to controlling terminal.
195: */
196: if (sp->s_ttyp->t_session == sp) {
197: if (sp->s_ttyp->t_pgrp)
198: pgsignal(sp->s_ttyp->t_pgrp, SIGHUP, 1);
199: (void) ttywait(sp->s_ttyp);
200: /*
201: * The tty could have been revoked
202: * if we blocked.
203: */
204: if (sp->s_ttyvp)
205: VOP_REVOKE(sp->s_ttyvp, REVOKEALL);
206: }
207: if (sp->s_ttyvp)
208: vrele(sp->s_ttyvp);
209: sp->s_ttyvp = NULL;
210: /*
211: * s_ttyp is not zero'd; we use this to indicate
212: * that the session once had a controlling terminal.
213: * (for logging and informational purposes)
214: */
215: }
216: sp->s_leader = NULL;
217: }
218:
219: fixjobc(p, p->p_pgrp, 0);
220: p->p_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
221: #if KTRACE
222: /*
223: * release trace file
224: */
225: p->p_traceflag = 0; /* don't trace the vrele() */
226: if (p->p_tracep)
227: vrele(p->p_tracep);
228: #endif
229:
230: /* Place onto zombproc. */
231: LIST_INSERT_HEAD(&zombproc, p, p_list);
232: p->p_stat = SZOMB;
233:
234: q = p->p_children.lh_first;
235: if (q) /* only need this if any child is S_ZOMB */
236: wakeup((caddr_t) initproc);
237: for (; q != 0; q = nq) {
238: nq = q->p_sibling.le_next;
239: proc_reparent(q, initproc);
240: /*
241: * Traced processes are killed
242: * since their existence means someone is screwing up.
243: */
244: if (q->p_flag & P_TRACED) {
245: q->p_flag &= ~P_TRACED;
246: if (q->sigwait_thread) {
247: /*
248: * The sigwait_thread could be stopped at a
249: * breakpoint. Wake it up to kill.
250: * Need to do this as it could be a thread which is not
251: * the first thread in the task. So any attempts to kill
252: * the process would result into a deadlock on q->sigwait.
253: */
254: thread_resume((struct thread *)q->sigwait_thread);
255: clear_wait(q->sigwait_thread, THREAD_SHOULD_TERMINATE, FALSE);
256: threadsignal(q->sigwait_thread, SIGKILL, 0);
257: }
258: psignal(q, SIGKILL);
259: }
260: }
261:
262: /*
263: * Save exit status and final rusage info, adding in child rusage
264: * info and self times.
265: */
266: p->p_xstat = rv;
267: *p->p_ru = p->p_stats->p_ru;
268: calcru(p, &p->p_ru->ru_utime, &p->p_ru->ru_stime, NULL);
269: ruadd(p->p_ru, &p->p_stats->p_cru);
270:
271: /*
272: * Free up profiling buffers.
273: */
274: {
275: struct uprof *p0 = &p->p_stats->p_prof, *p1, *pn;
276:
277: p1 = p0->pr_next;
278: p0->pr_next = NULL;
279: p0->pr_scale = 0;
280:
281: for (; p1 != NULL; p1 = pn) {
282: pn = p1->pr_next;
283: kfree((vm_offset_t)p1, sizeof *p1);
284: }
285: }
286:
287: /*
288: * Notify parent that we're gone.
289: */
290: psignal(p->p_pptr, SIGCHLD);
291: wakeup((caddr_t)p->p_pptr);
292:
293: /*
294: * Notify procfs debugger
295: */
296: if (p->p_flag & P_FSTRACE)
297: wakeup((caddr_t)p);
298:
299: task->proc = NULL;
300: /*
301: * Other substructures are freed from wait().
302: */
303: FREE_ZONE(p->p_stats, sizeof *p->p_stats, M_SUBPROC);
304: p->p_stats = NULL;
305:
306: FREE_ZONE(p->p_sigacts, sizeof *p->p_sigacts, M_SUBPROC);
307: p->p_sigacts = NULL;
308:
309: if (--p->p_limit->p_refcnt == 0)
310: FREE_ZONE(p->p_limit, sizeof *p->p_limit, M_SUBPROC);
311: p->p_limit = NULL;
312:
313: /*
314: * Finish up by terminating the task
315: * and halt this thread (only if a
316: * member of the task exiting).
317: */
318: cpu_exit(p);
319: }
320:
321: void
322: cpu_exit(p)
323: register struct proc *p;
324: {
325: struct thread *self = current_thread();
326: struct task *task = p->task;
327:
328: p->task = TASK_NULL;
329: task_deallocate(task);
330:
331: (void) task_terminate(task);
332: while (task == self->task) {
333: thread_halt_self_with_continuation((void (*)()) 0);
334: /*NOTREACHED*/
335: }
336: }
337:
338: struct wait4_args {
339: int pid;
340: int *status;
341: int options;
342: struct rusage *rusage;
343: };
344:
345: #if COMPAT_43
346: int
347: owait(p, uap, retval)
348: struct proc *p;
349: void *uap;
350: int *retval;
351: {
352: struct wait4_args a;
353:
354: a.options = 0;
355: a.rusage = NULL;
356: a.pid = WAIT_ANY;
357: a.status = NULL;
358: return (wait1(p, &a, retval, 1));
359: }
360:
361: int
362: wait4(p, uap, retval)
363: struct proc *p;
364: struct wait4_args *uap;
365: int *retval;
366: {
367: return (wait1(p, uap, retval, 0));
368: }
369:
370: struct owait3_args {
371: int *status;
372: int options;
373: struct rusage *rusage;
374: };
375:
376: int
377: owait3(p, uap, retval)
378: struct proc *p;
379: struct owait3_args *uap;
380: int *retval;
381: {
382: struct wait4_args a;
383:
384: a.options = uap->options;
385: a.rusage = uap->rusage;
386: a.pid = WAIT_ANY;
387: a.status = uap->status;
388:
389: return (wait1(p, &a, retval, 1));
390: }
391:
392: #else
393: #define wait1 wait4
394: #endif
395:
396: int
397: wait1(q, uap, retval, compat)
398: register struct proc *q;
399: register struct wait4_args *uap;
400: register_t *retval;
401: #if COMPAT_43
402: int compat;
403: #endif
404: {
405: register int nfound;
406: register struct proc *p, *t;
407: int status, error;
408:
409: if (uap->pid == 0)
410: uap->pid = -q->p_pgid;
411:
412: loop:
413: nfound = 0;
414: for (p = q->p_children.lh_first; p != 0; p = p->p_sibling.le_next) {
415: if (uap->pid != WAIT_ANY &&
416: p->p_pid != uap->pid &&
417: p->p_pgid != -(uap->pid))
418: continue;
419: nfound++;
420: if (p->p_stat == SZOMB) {
421: retval[0] = p->p_pid;
422: #if COMPAT_43
423: if (compat)
424: retval[1] = p->p_xstat;
425: else
426: #endif
427: if (uap->status) {
428: status = p->p_xstat; /* convert to int */
429: if (error = copyout((caddr_t)&status,
430: (caddr_t)uap->status,
431: sizeof(status)))
432: return (error);
433: }
434: if (uap->rusage &&
435: (error = copyout((caddr_t)p->p_ru,
436: (caddr_t)uap->rusage,
437: sizeof (struct rusage))))
438: return (error);
439: /*
440: * If we got the child via a ptrace 'attach',
441: * we need to give it back to the old parent.
442: */
443: if (p->p_oppid && (t = pfind(p->p_oppid))) {
444: p->p_oppid = 0;
445: proc_reparent(p, t);
446: psignal(t, SIGCHLD);
447: wakeup((caddr_t)t);
448: return (0);
449: }
450: p->p_xstat = 0;
451: if (p->p_ru) {
452: ruadd(&q->p_stats->p_cru, p->p_ru);
453: FREE_ZONE(p->p_ru, sizeof *p->p_ru, M_ZOMBIE);
454: p->p_ru = NULL;
455: } else {
456: printf("Warning : lost p_ru for %s\n", p->p_comm);
457: }
458:
459: /*
460: * Decrement the count of procs running with this uid.
461: */
462: (void)chgproccnt(p->p_cred->p_ruid, -1);
463:
464: /*
465: * Free up credentials.
466: */
467: if (--p->p_cred->p_refcnt == 0) {
468: struct ucred *ucr = p->p_ucred;
469: struct pcred *pcr;
470:
471: if (ucr != NOCRED) {
472: p->p_ucred = NOCRED;
473: crfree(ucr);
474: }
475: pcr = p->p_cred;
476: p->p_cred = NULL;
477: FREE_ZONE(pcr, sizeof *pcr, M_SUBPROC);
478: }
479:
480: /*
481: * Release reference to text vnode
482: */
483: if (p->p_textvp)
484: vrele(p->p_textvp);
485:
486: /*
487: * Finally finished with old proc entry.
488: * Unlink it from its process group and free it.
489: */
490: leavepgrp(p);
491: LIST_REMOVE(p, p_list); /* off zombproc */
492: LIST_REMOVE(p, p_sibling);
493: FREE_ZONE(p, sizeof *p, M_PROC);
494: nprocs--;
495: return (0);
496: }
497: if (p->p_stat == SSTOP && (p->p_flag & P_WAITED) == 0 &&
498: (p->p_flag & P_TRACED || uap->options & WUNTRACED)) {
499: p->p_flag |= P_WAITED;
500: retval[0] = p->p_pid;
501: #if COMPAT_43
502: if (compat) {
503: retval[1] = W_STOPCODE(p->p_xstat);
504: error = 0;
505: } else
506: #endif
507: if (uap->status) {
508: status = W_STOPCODE(p->p_xstat);
509: error = copyout((caddr_t)&status,
510: (caddr_t)uap->status,
511: sizeof(status));
512: } else
513: error = 0;
514: return (error);
515: }
516: }
517: if (nfound == 0)
518: return (ECHILD);
519: if (uap->options & WNOHANG) {
520: retval[0] = 0;
521: return (0);
522: }
523: if (error = tsleep((caddr_t)q, PWAIT | PCATCH, "wait", 0))
524: return (error);
525: goto loop;
526: }
527:
528: /*
529: * make process 'parent' the new parent of process 'child'.
530: */
531: void
532: proc_reparent(child, parent)
533: register struct proc *child;
534: register struct proc *parent;
535: {
536:
537: if (child->p_pptr == parent)
538: return;
539:
540: LIST_REMOVE(child, p_sibling);
541: LIST_INSERT_HEAD(&parent->p_children, child, p_sibling);
542: child->p_pptr = parent;
543: }
544:
545: kern_return_t
546: init_process(void)
547: /*
548: * Make the current process an "init" process, meaning
549: * that it doesn't have a parent, and that it won't be
550: * gunned down by kill(-1, 0).
551: */
552: {
553: register struct proc *p = current_proc();
554:
555: if (suser(p->p_ucred, &p->p_acflag))
556: return(KERN_NO_ACCESS);
557:
558: if (p->p_pid != 1 && p->p_pgid != p->p_pid)
559: enterpgrp(p, p->p_pid, 0);
560: p->p_flag |= P_SYSTEM;
561:
562: /*
563: * Take us out of the sibling chain, and
564: * out of our parent's child chain.
565: */
566: LIST_REMOVE(p, p_sibling);
567: p->p_sibling.le_prev = NULL;
568: p->p_sibling.le_next = NULL;
569: p->p_pptr = kernproc;
570:
571: return(KERN_SUCCESS);
572: }
573:
574: void
575: process_terminate_self(void)
576: {
577: struct thread *self = current_thread();
578: struct task *task = self->task;
579: struct proc *p = task->proc;
580:
581: if (p != NULL) {
582: exit1(p, W_EXITCODE(0, SIGKILL));
583: /*NOTREACHED*/
584: }
585: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.