fix bug that can cause recursive .forward files to fail
[unix-history] / usr / src / sys / kern / kern_exit.c
index 384d807..7aa1695 100644 (file)
@@ -1,71 +1,83 @@
 /*
 /*
- * Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1982, 1986, 1989, 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)kern_exit.c 7.38 (Berkeley) %G%
+ *     @(#)kern_exit.c 8.2 (Berkeley) %G%
  */
 
  */
 
-#include "param.h"
-#include "systm.h"
-#include "map.h"
-#include "ioctl.h"
-#include "tty.h"
-#include "time.h"
-#include "resource.h"
-#include "kernel.h"
-#include "proc.h"
-#include "buf.h"
-#include "wait.h"
-#include "file.h"
-#include "vnode.h"
-#include "syslog.h"
-#include "malloc.h"
-#include "resourcevar.h"
-
-#include "machine/cpu.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/map.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/tty.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/kernel.h>
+#include <sys/buf.h>
+#include <sys/wait.h>
+#include <sys/file.h>
+#include <sys/vnode.h>
+#include <sys/syslog.h>
+#include <sys/malloc.h>
+#include <sys/resourcevar.h>
+#include <sys/ptrace.h>
+
+#include <machine/cpu.h>
 #ifdef COMPAT_43
 #ifdef COMPAT_43
-#include "machine/reg.h"
-#include "machine/psl.h"
+#include <machine/reg.h>
+#include <machine/psl.h>
 #endif
 
 #endif
 
-#include "vm/vm.h"
-#include "vm/vm_kern.h"
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+
+__dead void cpu_exit __P((struct proc *));
+__dead void exit1 __P((struct proc *, int));
 
 /*
 
 /*
- * Exit system call: pass back caller's arg
+ * exit --
+ *     Death of process.
  */
  */
-/* ARGSUSED */
-rexit(p, uap, retval)
+struct rexit_args {
+       int     rval;
+};
+__dead void
+exit(p, uap, retval)
        struct proc *p;
        struct proc *p;
-       struct args {
-               int     rval;
-       } *uap;
+       struct rexit_args *uap;
        int *retval;
 {
 
        int *retval;
 {
 
-       exit(p, W_EXITCODE(uap->rval, 0));
+       exit1(p, W_EXITCODE(uap->rval, 0));
        /* NOTREACHED */
 }
 
 /*
        /* NOTREACHED */
 }
 
 /*
- * Exit: deallocate address space and other resources,
- * change proc state to zombie, and unlink proc from allproc
- * and parent's lists.  Save exit status and rusage for wait().
- * Check for child processes and orphan them.
+ * Exit: deallocate address space and other resources, change proc state
+ * to zombie, and unlink proc from allproc and parent's lists.  Save exit
+ * status and rusage for wait().  Check for child processes and orphan them.
  */
  */
-exit(p, rv)
+__dead void
+exit1(p, rv)
        register struct proc *p;
        int rv;
 {
        register struct proc *q, *nq;
        register struct proc **pp;
        register struct proc *p;
        int rv;
 {
        register struct proc *q, *nq;
        register struct proc **pp;
+       register struct vmspace *vm;
        int s;
 
        int s;
 
+       if (p->p_pid == 1)
+               panic("init died (signal %d, exit %d)",
+                   WTERMSIG(rv), WEXITSTATUS(rv));
 #ifdef PGINPROF
        vmsizmon();
 #endif
 #ifdef PGINPROF
        vmsizmon();
 #endif
+       if (p->p_flag & SPROFIL)
+               stopprofclock(p);
        MALLOC(p->p_ru, struct rusage *, sizeof(struct rusage),
                M_ZOMBIE, M_WAITOK);
        /*
        MALLOC(p->p_ru, struct rusage *, sizeof(struct rusage),
                M_ZOMBIE, M_WAITOK);
        /*
@@ -85,8 +97,9 @@ exit(p, rv)
        fdfree(p);
 
        /* The next two chunks should probably be moved to vmspace_exit. */
        fdfree(p);
 
        /* The next two chunks should probably be moved to vmspace_exit. */
+       vm = p->p_vmspace;
 #ifdef SYSVSHM
 #ifdef SYSVSHM
-       if (p->p_vmspace->vm_shm)
+       if (vm->vm_shm)
                shmexit(p);
 #endif
        /*
                shmexit(p);
 #endif
        /*
@@ -97,12 +110,10 @@ exit(p, rv)
         * Can't free the entire vmspace as the kernel stack
         * may be mapped within that space also.
         */
         * Can't free the entire vmspace as the kernel stack
         * may be mapped within that space also.
         */
-       if (p->p_vmspace->vm_refcnt == 1)
-               (void) vm_map_remove(&p->p_vmspace->vm_map, VM_MIN_ADDRESS,
+       if (vm->vm_refcnt == 1)
+               (void) vm_map_remove(&vm->vm_map, VM_MIN_ADDRESS,
                    VM_MAXUSER_ADDRESS);
 
                    VM_MAXUSER_ADDRESS);
 
-       if (p->p_pid == 1)
-               panic("init died");
        if (SESS_LEADER(p)) {
                register struct session *sp = p->p_session;
 
        if (SESS_LEADER(p)) {
                register struct session *sp = p->p_session;
 
@@ -131,23 +142,15 @@ exit(p, rv)
        }
        fixjobc(p, p->p_pgrp, 0);
        p->p_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
        }
        fixjobc(p, p->p_pgrp, 0);
        p->p_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
-       (void) acct(p);
+       (void)acct_process(p);
 #ifdef KTRACE
        /* 
         * release trace file
         */
 #ifdef KTRACE
        /* 
         * release trace file
         */
+       p->p_traceflag = 0;     /* don't trace the vrele() */
        if (p->p_tracep)
                vrele(p->p_tracep);
 #endif
        if (p->p_tracep)
                vrele(p->p_tracep);
 #endif
-       /*
-        * Clear curproc after we've done all operations
-        * that could block, and before tearing down
-        * the rest of the process state.
-        */
-       curproc = NULL;
-       if (--p->p_limit->p_refcnt == 0)
-               FREE(p->p_limit, M_SUBPROC);
-
        /*
         * Remove proc from allproc queue and pidhash chain.
         * Place onto zombproc.  Unlink from parent's child list.
        /*
         * Remove proc from allproc queue and pidhash chain.
         * Place onto zombproc.  Unlink from parent's child list.
@@ -159,6 +162,7 @@ exit(p, rv)
        p->p_prev = &zombproc;
        zombproc = p;
        p->p_stat = SZOMB;
        p->p_prev = &zombproc;
        zombproc = p;
        p->p_stat = SZOMB;
+
        for (pp = &pidhash[PIDHASH(p->p_pid)]; *pp; pp = &(*pp)->p_hash)
                if (*pp == p) {
                        *pp = p->p_hash;
        for (pp = &pidhash[PIDHASH(p->p_pid)]; *pp; pp = &(*pp)->p_hash)
                if (*pp == p) {
                        *pp = p->p_hash;
@@ -192,13 +196,12 @@ done:
        p->p_cptr = NULL;
 
        /*
        p->p_cptr = NULL;
 
        /*
-        * Save exit status and final rusage info,
-        * adding in child rusage info and self times.
+        * Save exit status and final rusage info, adding in child rusage
+        * info and self times.
         */
        p->p_xstat = rv;
        *p->p_ru = p->p_stats->p_ru;
         */
        p->p_xstat = rv;
        *p->p_ru = p->p_stats->p_ru;
-       p->p_ru->ru_stime = p->p_stime;
-       p->p_ru->ru_utime = p->p_utime;
+       calcru(p, &p->p_ru->ru_utime, &p->p_ru->ru_stime, NULL);
        ruadd(p->p_ru, &p->p_stats->p_cru);
 
        /*
        ruadd(p->p_ru, &p->p_stats->p_cru);
 
        /*
@@ -210,59 +213,77 @@ done:
        /* move this to cpu_exit */
        p->p_addr->u_pcb.pcb_savacc.faddr = (float *)NULL;
 #endif
        /* move this to cpu_exit */
        p->p_addr->u_pcb.pcb_savacc.faddr = (float *)NULL;
 #endif
+       /*
+        * Clear curproc after we've done all operations
+        * that could block, and before tearing down the rest
+        * of the process state that might be used from clock, etc.
+        * Also, can't clear curproc while we're still runnable,
+        * as we're not on a run queue (we are current, just not
+        * a proper proc any longer!).
+        *
+        * Other substructures are freed from wait().
+        */
+       curproc = NULL;
+       if (--p->p_limit->p_refcnt == 0)
+               FREE(p->p_limit, M_SUBPROC);
+
        /*
         * Finally, call machine-dependent code to release the remaining
         * resources including address space, the kernel stack and pcb.
         * The address space is released by "vmspace_free(p->p_vmspace)";
         * This is machine-dependent, as we may have to change stacks
         * or ensure that the current one isn't reallocated before we
        /*
         * Finally, call machine-dependent code to release the remaining
         * resources including address space, the kernel stack and pcb.
         * The address space is released by "vmspace_free(p->p_vmspace)";
         * This is machine-dependent, as we may have to change stacks
         * or ensure that the current one isn't reallocated before we
-        * finish.  cpu_exit will end with a call to swtch(), finishing
+        * finish.  cpu_exit will end with a call to cpu_swtch(), finishing
         * our execution (pun intended).
         */
        cpu_exit(p);
         * our execution (pun intended).
         */
        cpu_exit(p);
-       /* NOTREACHED */
 }
 
 }
 
+struct wait_args {
+       int     pid;
+       int     *status;
+       int     options;
+       struct  rusage *rusage;
+#ifdef COMPAT_43
+       int     compat;         /* pseudo */
+#endif
+};
+
 #ifdef COMPAT_43
 #ifdef COMPAT_43
+#if defined(hp300) || defined(luna68k)
+#include <machine/frame.h>
+#define GETPS(rp)      ((struct frame *)(rp))->f_sr
+#else
+#define GETPS(rp)      (rp)[PS]
+#endif
+
 owait(p, uap, retval)
        struct proc *p;
 owait(p, uap, retval)
        struct proc *p;
-       register struct args {
-               int     pid;
-               int     *status;
-               int     options;
-               struct  rusage *rusage;
-               int     compat;
-       } *uap;
+       register struct wait_args *uap;
        int *retval;
 {
 
 #ifdef PSL_ALLCC
        int *retval;
 {
 
 #ifdef PSL_ALLCC
-       if ((p->p_regs[PS] & PSL_ALLCC) != PSL_ALLCC) {
+       if ((GETPS(p->p_md.md_regs) & PSL_ALLCC) != PSL_ALLCC) {
                uap->options = 0;
                uap->options = 0;
-               uap->rusage = 0;
+               uap->rusage = NULL;
        } else {
        } else {
-               uap->options = p->p_regs[R0];
-               uap->rusage = (struct rusage *)p->p_regs[R1];
+               uap->options = p->p_md.md_regs[R0];
+               uap->rusage = (struct rusage *)p->p_md.md_regs[R1];
        }
 #else
        uap->options = 0;
        }
 #else
        uap->options = 0;
-       uap->rusage = 0;
+       uap->rusage = NULL;
 #endif
        uap->pid = WAIT_ANY;
 #endif
        uap->pid = WAIT_ANY;
-       uap->status = 0;
+       uap->status = NULL;
        uap->compat = 1;
        return (wait1(p, uap, retval));
 }
 
 wait4(p, uap, retval)
        struct proc *p;
        uap->compat = 1;
        return (wait1(p, uap, retval));
 }
 
 wait4(p, uap, retval)
        struct proc *p;
-       struct args {
-               int     pid;
-               int     *status;
-               int     options;
-               struct  rusage *rusage;
-               int     compat;
-       } *uap;
+       struct wait_args *uap;
        int *retval;
 {
 
        int *retval;
 {
 
@@ -273,26 +294,14 @@ wait4(p, uap, retval)
 #define        wait1   wait4
 #endif
 
 #define        wait1   wait4
 #endif
 
-/*
- * Wait: check child processes to see if any have exited,
- * stopped under trace, or (optionally) stopped by a signal.
- * Pass back status and deallocate exited child's proc structure.
- */
+int
 wait1(q, uap, retval)
        register struct proc *q;
 wait1(q, uap, retval)
        register struct proc *q;
-       register struct args {
-               int     pid;
-               int     *status;
-               int     options;
-               struct  rusage *rusage;
-#ifdef COMPAT_43
-               int compat;
-#endif
-       } *uap;
+       register struct wait_args *uap;
        int retval[];
 {
        register int nfound;
        int retval[];
 {
        register int nfound;
-       register struct proc *p;
+       register struct proc *p, *t;
        int status, error;
 
        if (uap->pid == 0)
        int status, error;
 
        if (uap->pid == 0)
@@ -324,9 +333,29 @@ loop:
                        if (uap->rusage && (error = copyout((caddr_t)p->p_ru,
                            (caddr_t)uap->rusage, sizeof (struct rusage))))
                                return (error);
                        if (uap->rusage && (error = copyout((caddr_t)p->p_ru,
                            (caddr_t)uap->rusage, sizeof (struct rusage))))
                                return (error);
+                       /*
+                        * If we got the child via a ptrace 'attach',
+                        * we need to give it back to the old parent.
+                        */
+                       if (p->p_oppid && (t = pfind(p->p_oppid))) {
+                               p->p_oppid = 0;
+                               proc_reparent(p, t);
+                               psignal(t, SIGCHLD);
+                               wakeup((caddr_t)t);
+                               return (0);
+                       }
                        p->p_xstat = 0;
                        ruadd(&q->p_stats->p_cru, p->p_ru);
                        FREE(p->p_ru, M_ZOMBIE);
                        p->p_xstat = 0;
                        ruadd(&q->p_stats->p_cru, p->p_ru);
                        FREE(p->p_ru, M_ZOMBIE);
+
+                       /*
+                        * Decrement the count of procs running with this uid.
+                        */
+                       (void)chgproccnt(p->p_cred->p_ruid, -1);
+
+                       /*
+                        * Free up credentials.
+                        */
                        if (--p->p_cred->p_refcnt == 0) {
                                crfree(p->p_cred->pc_ucred);
                                FREE(p->p_cred, M_SUBPROC);
                        if (--p->p_cred->p_refcnt == 0) {
                                crfree(p->p_cred->pc_ucred);
                                FREE(p->p_cred, M_SUBPROC);
@@ -385,3 +414,37 @@ loop:
                return (error);
        goto loop;
 }
                return (error);
        goto loop;
 }
+
+/*
+ * make process 'parent' the new parent of process 'child'.
+ */
+void
+proc_reparent(child, parent)
+       register struct proc *child;
+       register struct proc *parent;
+{
+       register struct proc *o;
+       register struct proc *y;
+
+       if (child->p_pptr == parent)
+               return;
+
+       /* fix up the child linkage for the old parent */
+       o = child->p_osptr;
+       y = child->p_ysptr;
+       if (y)
+               y->p_osptr = o;
+       if (o)
+               o->p_ysptr = y;
+       if (child->p_pptr->p_cptr == child)
+               child->p_pptr->p_cptr = o;
+
+       /* fix up child linkage for new parent */
+       o = parent->p_cptr;
+       if (o)
+               o->p_ysptr = child;
+       child->p_osptr = o;
+       child->p_ysptr = NULL;
+       parent->p_cptr = child;
+       child->p_pptr = parent;
+}