]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/kern_exit.c
xnu-517.9.5.tar.gz
[apple/xnu.git] / bsd / kern / kern_exit.c
index 3f6aa72361a9680a301d9e8d1f2036df2fe9d2b1..157ec5f05ce9a51c2f90ce9b69010607fc4184dc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <sys/resourcevar.h>
 #include <sys/ptrace.h>
 #include <sys/user.h>
+#include <sys/aio_kern.h>
+
+#include <bsm/audit_kernel.h>
+#include <bsm/audit_kevents.h>
 
 #include <mach/mach_types.h>
 #include <kern/thread.h>
 #include <kern/assert.h>
 #if KTRACE   
 #include <sys/ktrace.h>
+#include <sys/ubc.h>
 #endif
 
 extern char init_task_failure_data[];
 int exit1 __P((struct proc *, int, int *));
+void proc_prepareexit(struct proc *p);
+int vfork_exit(struct proc *p, int rv);
+void vproc_exit(struct proc *p);
 
 /*
  * exit --
@@ -131,8 +139,7 @@ exit1(p, rv, retval)
        int * retval;
 {
        register struct proc *q, *nq;
-       thread_t self = current_thread();
-       thread_act_t th_act_self = current_act();
+       thread_act_t self = current_act();
        struct task *task = p->task;
        register int i,s;
        struct uthread *ut;
@@ -143,22 +150,25 @@ exit1(p, rv, retval)
         * right here.
         */
 
-        ut = get_bsdthread_info(th_act_self);
+        ut = get_bsdthread_info(self);
         if (ut->uu_flag & P_VFORK) {
-                       (void)vfork_exit(p, rv);
-                       vfork_return(th_act_self, p->p_pptr, p , retval);
+               if (!vfork_exit(p, rv)) {
+                       vfork_return(self, p->p_pptr, p , retval);
                        unix_syscall_return(0);
                        /* NOT REACHED */
+               }  
+               return(EINVAL);
         }
+       AUDIT_SYSCALL_EXIT(0, p, ut); /* Exit is always successfull */
         signal_lock(p);
        while (p->exit_thread != self) {
                if (sig_try_locked(p) <= 0) {
-                       if (get_threadtask(th_act_self) != task) {
+                       if (get_threadtask(self) != task) {
                                 signal_unlock(p);
                                return(0);
                         }
                        signal_unlock(p);
-                       thread_terminate(th_act_self);
+                       thread_terminate(self);
                        thread_funnel_set(kernel_flock, FALSE);
                        thread_exception_return();
                        /* NOTREACHED */
@@ -176,27 +186,12 @@ exit1(p, rv, retval)
        s = splsched();
        p->p_flag |= P_WEXIT;
        splx(s);
-       (void)proc_prepareexit(p);
+       proc_prepareexit(p);
        p->p_xstat = rv;
 
        /* task terminate will call proc_terminate and that cleans it up */
        task_terminate_internal(task);
 
-       /*
-        * we come back and returns to AST which 
-        * should cleanup the rest 
-        */
-#if 0
-       if (task == current_task()) {
-               thread_exception_return();
-               /*NOTREACHED*/
-       }
-
-       while (task == current_task()) {
-               thread_terminate_self();
-               /*NOTREACHED*/
-       }
-#endif
        return(0);
 }
 
@@ -205,8 +200,12 @@ proc_prepareexit(struct proc *p)
 {
        int s;
        struct uthread *ut;
-       thread_t self = current_thread();
-       thread_act_t th_act_self = current_act();
+       exception_data_t        code[EXCEPTION_CODE_MAX];
+       thread_act_t self = current_act();
+
+       code[0] = 0xFF000001;                   /* Set terminate code */
+       code[1] = p->p_pid;                             /* Pass out the pid     */
+       (void)sys_perf_notify(p->task, &code, 2);       /* Notify the perf server */
 
        /*
         * Remove proc from allproc queue and from pidhash chain.
@@ -215,6 +214,7 @@ proc_prepareexit(struct proc *p)
         * in partially cleaned state.
         */
        LIST_REMOVE(p, p_list);
+       LIST_INSERT_HEAD(&zombproc, p, p_list); /* Place onto zombproc. */
        LIST_REMOVE(p, p_hash);
 
 #ifdef PGINPROF
@@ -227,7 +227,7 @@ proc_prepareexit(struct proc *p)
        p->p_flag &= ~(P_TRACED | P_PPWAIT);
        p->p_sigignore = ~0;
        p->p_siglist = 0;
-       ut = get_bsdthread_info(th_act_self);
+       ut = get_bsdthread_info(self);
        ut->uu_siglist = 0;
        untimeout(realitexpire, (caddr_t)p->p_pid);
 }
@@ -236,8 +236,6 @@ void
 proc_exit(struct proc *p)
 {
        register struct proc *q, *nq, *pp;
-       thread_t self = current_thread();
-       thread_act_t th_act_self = current_act();
        struct task *task = p->task;
        register int i,s;
        boolean_t funnel_state;
@@ -257,6 +255,12 @@ proc_exit(struct proc *p)
        MALLOC_ZONE(p->p_ru, struct rusage *,
                        sizeof (*p->p_ru), M_ZOMBIE, M_WAITOK);
 
+       /*
+        * need to cancel async IO requests that can be cancelled and wait for those
+        * already active.  MAY BLOCK!
+        */
+       _aio_exit( p );
+
        /*
         * Close open files and release open-file table.
         * This may block!
@@ -317,6 +321,9 @@ proc_exit(struct proc *p)
        if (p->p_tracep) {
                struct vnode *tvp = p->p_tracep;
                p->p_tracep = NULL;
+
+               if (UBCINFOEXISTS(tvp))
+                       ubc_rele(tvp);
                vrele(tvp);
        }
 #endif
@@ -334,9 +341,6 @@ proc_exit(struct proc *p)
                if (q->p_flag & P_TRACED) {
                        q->p_flag &= ~P_TRACED;
                        if (q->sigwait_thread) {
-                               thread_t sig_shuttle;
-
-                               sig_shuttle = (thread_t)getshuttle_thread((thread_act_t)q->sigwait_thread);
                                /*
                                 * The sigwait_thread could be stopped at a
                                 * breakpoint. Wake it up to kill.
@@ -345,7 +349,7 @@ proc_exit(struct proc *p)
                                 * the process would result into a deadlock on q->sigwait.
                                 */
                                thread_resume((thread_act_t)q->sigwait_thread);
-                               clear_wait(sig_shuttle, THREAD_INTERRUPTED);
+                               clear_wait(q->sigwait_thread, THREAD_INTERRUPTED);
                                threadsignal((thread_act_t)q->sigwait_thread, SIGKILL, 0);
                        }
                        psignal(q, SIGKILL);
@@ -418,6 +422,9 @@ proc_exit(struct proc *p)
                FREE_ZONE(p->p_limit, sizeof *p->p_limit, M_SUBPROC);
        p->p_limit = NULL;
 
+       /* Free the auditing info */
+       audit_proc_free(p);
+
        /*
         * Finish up by terminating the task
         * and halt this thread (only if a
@@ -427,12 +434,20 @@ proc_exit(struct proc *p)
        //task->proc = NULL;
        set_bsdtask_info(task, NULL);
 
+       KNOTE(&p->p_klist, NOTE_EXIT);
+
        /*
         * Notify parent that we're gone.
         */
        if (p->p_pptr->p_flag & P_NOCLDWAIT) {
                struct proc * pp = p->p_pptr;
 
+               /*
+                * Add child resource usage to parent before giving
+                * zombie to init
+                */
+               ruadd(&p->p_pptr->p_stats->p_cru, p->p_ru);
+
                proc_reparent(p, initproc);
                /* If there are no more children wakeup parent */
                if (LIST_EMPTY(&pp->p_children))
@@ -449,8 +464,7 @@ proc_exit(struct proc *p)
        psignal(pp, SIGCHLD);
 
 
-       /* Place onto zombproc. */
-       LIST_INSERT_HEAD(&zombproc, p, p_list);
+       /* mark as a zombie */
        p->p_stat = SZOMB;
 
        /* and now wakeup the parent */
@@ -508,7 +522,7 @@ owait3(p, uap, retval)
 {
        struct wait4_args *a;
 
-       a = (struct wait4_args *)get_bsduthreadarg(current_act);
+       a = (struct wait4_args *)get_bsduthreadarg(current_act());
 
        a->rusage = uap->rusage;
        a->options = uap->options;
@@ -537,7 +551,7 @@ wait1continue(result)
        thread = current_act();
        vt = (void *)get_bsduthreadarg(thread);
        retval = (int *)get_bsduthreadrval(thread);
-       wait1((struct proc *)p, (struct wait4_args *)vt, retval, 0);
+       return(wait1((struct proc *)p, (struct wait4_args *)vt, retval, 0));
 }
 
 int
@@ -732,8 +746,11 @@ init_process(void)
 {
        register struct proc *p = current_proc();
 
-       if (suser(p->p_ucred, &p->p_acflag))
+       AUDIT_MACH_SYSCALL_ENTER(AUE_INITPROCESS);
+       if (suser(p->p_ucred, &p->p_acflag)) {
+               AUDIT_MACH_SYSCALL_EXIT(KERN_NO_ACCESS);
                return(KERN_NO_ACCESS);
+       }
 
        if (p->p_pid != 1 && p->p_pgid != p->p_pid)
                enterpgrp(p, p->p_pid, 0);
@@ -748,6 +765,7 @@ init_process(void)
        p->p_sibling.le_next = NULL;
        p->p_pptr = kernproc;
 
+       AUDIT_MACH_SYSCALL_EXIT(KERN_SUCCESS);
        return(KERN_SUCCESS);
 }
 
@@ -768,52 +786,32 @@ process_terminate_self(void)
  * status and rusage for wait().  Check for child processes and orphan them.
  */
 
-void
+int
 vfork_exit(p, rv)
        struct proc *p;
        int rv;
 {
        register struct proc *q, *nq;
-       thread_t self = current_thread();
-       thread_act_t th_act_self = current_act();
+       thread_act_t self = current_act();
        struct task *task = p->task;
        register int i,s;
        struct uthread *ut;
+       exception_data_t        code[EXCEPTION_CODE_MAX];
 
-       /*
-        * If a thread in this task has already
-        * called exit(), then halt any others
-        * right here.
-        */
-
-        ut = get_bsdthread_info(th_act_self);
-#ifdef FIXME
-        signal_lock(p);
-       while (p->exit_thread != self) {
-               if (sig_try_locked(p) <= 0) {
-                       if (get_threadtask(th_act_self) != task) {
-                                signal_unlock(p);
-                               return;
-                        }
-                       signal_unlock(p);
-                       thread_terminate(th_act_self);
-                       thread_funnel_set(kernel_flock, FALSE);
-                       thread_exception_return();
-                       /* NOTREACHED */
-               }
-               sig_lock_to_exit(p);
-       }
-        signal_unlock(p);
-       if (p->p_pid == 1) {
-               printf("pid 1 exited (signal %d, exit %d)",
-                   WTERMSIG(rv), WEXITSTATUS(rv));
-panic("init died\nState at Last Exception:\n\n%s", init_task_failure_data);
-       }
-#endif /* FIXME */
-
+       ut = get_bsdthread_info(self);
+       if (p->exit_thread) {
+               return(1);
+       } 
+       p->exit_thread = self;
+       
        s = splsched();
        p->p_flag |= P_WEXIT;
        splx(s);
+
+       code[0] = 0xFF000001;                   /* Set terminate code */
+       code[1] = p->p_pid;                             /* Pass out the pid     */
+       (void)sys_perf_notify(p->task, &code, 2);       /* Notify the perf server */
+
        /*
         * Remove proc from allproc queue and from pidhash chain.
         * Need to do this before we do anything that can block.
@@ -821,6 +819,7 @@ panic("init died\nState at Last Exception:\n\n%s", init_task_failure_data);
         * in partially cleaned state.
         */
        LIST_REMOVE(p, p_list);
+       LIST_INSERT_HEAD(&zombproc, p, p_list); /* Place onto zombproc. */
        LIST_REMOVE(p, p_hash);
        /*
         * If parent is waiting for us to exit or exec,
@@ -835,15 +834,14 @@ panic("init died\nState at Last Exception:\n\n%s", init_task_failure_data);
 
        p->p_xstat = rv;
 
-       (void)vproc_exit(p);
+       vproc_exit(p);
+       return(0);
 }
 
 void 
 vproc_exit(struct proc *p)
 {
        register struct proc *q, *nq, *pp;
-       thread_t self = current_thread();
-       thread_act_t th_act_self = current_act();
        struct task *task = p->task;
        register int i,s;
        boolean_t funnel_state;
@@ -904,6 +902,9 @@ vproc_exit(struct proc *p)
        if (p->p_tracep) {
                struct vnode *tvp = p->p_tracep;
                p->p_tracep = NULL;
+
+               if (UBCINFOEXISTS(tvp))
+                       ubc_rele(tvp);
                vrele(tvp);
        }
 #endif
@@ -921,9 +922,6 @@ vproc_exit(struct proc *p)
                if (q->p_flag & P_TRACED) {
                        q->p_flag &= ~P_TRACED;
                        if (q->sigwait_thread) {
-                               thread_t sig_shuttle;
-
-                               sig_shuttle = (thread_t) getshuttle_thread((thread_act_t)q->sigwait_thread);
                                /*
                                 * The sigwait_thread could be stopped at a
                                 * breakpoint. Wake it up to kill.
@@ -932,7 +930,7 @@ vproc_exit(struct proc *p)
                                 * the process would result into a deadlock on q->sigwait.
                                 */
                                thread_resume((thread_act_t)q->sigwait_thread);
-                               clear_wait(sig_shuttle, THREAD_INTERRUPTED);
+                               clear_wait(q->sigwait_thread, THREAD_INTERRUPTED);
                                threadsignal((thread_act_t)q->sigwait_thread, SIGKILL, 0);
                        }
                        psignal(q, SIGKILL);
@@ -1026,8 +1024,7 @@ vproc_exit(struct proc *p)
        }
        psignal(p->p_pptr, SIGCHLD);
 
-       /* Place onto zombproc. */
-       LIST_INSERT_HEAD(&zombproc, p, p_list);
+       /* mark as a zombie */
        p->p_stat = SZOMB;
 
        /* and now wakeup the parent */