summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_exit.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/kern_exit.c')
-rw-r--r--sys/kern/kern_exit.c265
1 files changed, 200 insertions, 65 deletions
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index 4ed48ac..e5be44e 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -35,13 +35,16 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)kern_exit.c 8.10 (Berkeley) 2/23/95
+ * @(#)kern_exit.c 8.7 (Berkeley) 2/12/94
+ * $Id: kern_exit.c,v 1.48 1997/05/22 07:25:20 phk Exp $
*/
+#include "opt_ktrace.h"
+
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/map.h>
-#include <sys/ioctl.h>
+#include <sys/sysproto.h>
+#include <sys/sysent.h>
#include <sys/proc.h>
#include <sys/tty.h>
#include <sys/time.h>
@@ -54,31 +57,48 @@
#include <sys/syslog.h>
#include <sys/malloc.h>
#include <sys/resourcevar.h>
+#include <sys/signalvar.h>
#include <sys/ptrace.h>
+#include <sys/acct.h> /* for acct_process() function prototype */
+#include <sys/filedesc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
-#include <machine/cpu.h>
#ifdef COMPAT_43
#include <machine/reg.h>
#include <machine/psl.h>
#endif
#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/vm_prot.h>
+#include <sys/lock.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
#include <vm/vm_kern.h>
-__dead void cpu_exit __P((struct proc *));
-__dead void exit1 __P((struct proc *, int));
+static int wait1 __P((struct proc *, struct wait_args *, int [], int));
+
+/*
+ * callout list for things to do at exit time
+ */
+typedef struct exit_list_element {
+ struct exit_list_element *next;
+ exitlist_fn function;
+} *ele_p;
+
+static ele_p exit_list;
/*
* exit --
* Death of process.
*/
-struct rexit_args {
- int rval;
-};
-__dead void
+void
exit(p, uap, retval)
struct proc *p;
- struct rexit_args *uap;
+ struct rexit_args /* {
+ int rval;
+ } */ *uap;
int *retval;
{
@@ -91,21 +111,64 @@ exit(p, uap, retval)
* 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.
*/
-__dead void
+void
exit1(p, rv)
register struct proc *p;
int rv;
{
register struct proc *q, *nq;
- register struct proc **pp;
register struct vmspace *vm;
+ ele_p ep = exit_list;
- if (p->p_pid == 1)
- panic("init died (signal %d, exit %d)",
+ if (p->p_pid == 1) {
+ printf("init died (signal %d, exit %d)\n",
WTERMSIG(rv), WEXITSTATUS(rv));
+ panic("Going nowhere without my init!");
+ }
+
+ /* are we a task leader? */
+ if(p == p->p_leader) {
+ struct kill_args killArgs;
+ killArgs.signum = SIGKILL;
+ q = p->p_peers;
+ while(q) {
+ killArgs.pid = q->p_pid;
+ /*
+ * The interface for kill is better
+ * than the internal signal
+ */
+ kill(p, &killArgs, &rv);
+ nq = q;
+ q = q->p_peers;
+ /*
+ * orphan the threads so we don't mess up
+ * when they call exit
+ */
+ nq->p_peers = 0;
+ nq->p_leader = nq;
+ }
+
+ /* otherwise are we a peer? */
+ } else if(p->p_peers) {
+ q = p->p_leader;
+ while(q->p_peers != p)
+ q = q->p_peers;
+ q->p_peers = p->p_peers;
+ }
+
#ifdef PGINPROF
vmsizmon();
#endif
+ /*
+ * Check if any LKMs need anything done at process exit.
+ * e.g. SYSV IPC stuff
+ * XXX what if one of these generates an error?
+ */
+ while (ep) {
+ (*ep->function)(p);
+ ep = ep->next;
+ }
+
if (p->p_flag & P_PROFIL)
stopprofclock(p);
MALLOC(p->p_ru, struct rusage *, sizeof(struct rusage),
@@ -126,12 +189,13 @@ exit1(p, rv)
*/
fdfree(p);
+ /*
+ * XXX Shutdown SYSV semaphores
+ */
+ semexit(p);
+
/* The next two chunks should probably be moved to vmspace_exit. */
vm = p->p_vmspace;
-#ifdef SYSVSHM
- if (vm->vm_shm)
- shmexit(p);
-#endif
/*
* Release user portion of address space.
* This releases references to vnodes,
@@ -140,9 +204,14 @@ exit1(p, rv)
* Can't free the entire vmspace as the kernel stack
* may be mapped within that space also.
*/
- if (vm->vm_refcnt == 1)
+ if (vm->vm_refcnt == 1) {
+ if (vm->vm_shm)
+ shmexit(p);
+ pmap_remove_pages(&vm->vm_pmap, VM_MIN_ADDRESS,
+ VM_MAXUSER_ADDRESS);
(void) vm_map_remove(&vm->vm_map, VM_MIN_ADDRESS,
VM_MAXUSER_ADDRESS);
+ }
if (SESS_LEADER(p)) {
register struct session *sp = p->p_session;
@@ -154,7 +223,7 @@ exit1(p, rv)
* drain controlling terminal
* and revoke access to controlling terminal.
*/
- if (sp->s_ttyp->t_session == sp) {
+ if (sp->s_ttyp && (sp->s_ttyp->t_session == sp)) {
if (sp->s_ttyp->t_pgrp)
pgsignal(sp->s_ttyp->t_pgrp, SIGHUP, 1);
(void) ttywait(sp->s_ttyp);
@@ -177,10 +246,15 @@ exit1(p, rv)
sp->s_leader = NULL;
}
fixjobc(p, p->p_pgrp, 0);
+ if (p->p_limit->p_refcnt > 1 &&
+ (p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
+ p->p_limit->p_refcnt--;
+ p->p_limit = limcopy(p->p_limit);
+ }
p->p_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
(void)acct_process(p);
#ifdef KTRACE
- /*
+ /*
* release trace file
*/
p->p_traceflag = 0; /* don't trace the vrele() */
@@ -244,8 +318,10 @@ exit1(p, rv)
* Other substructures are freed from wait().
*/
curproc = NULL;
- if (--p->p_limit->p_refcnt == 0)
+ if (--p->p_limit->p_refcnt == 0) {
FREE(p->p_limit, M_SUBPROC);
+ p->p_limit = NULL;
+ }
/*
* Finally, call machine-dependent code to release the remaining
@@ -253,22 +329,12 @@ exit1(p, rv)
* 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 cpu_swtch(), finishing
+ * finish. cpu_exit will end with a call to cpu_switch(), finishing
* our execution (pun intended).
*/
cpu_exit(p);
}
-struct wait_args {
- int pid;
- int *status;
- int options;
- struct rusage *rusage;
-#ifdef COMPAT_43
- int compat; /* pseudo */
-#endif
-};
-
#ifdef COMPAT_43
#if defined(hp300) || defined(luna68k)
#include <machine/frame.h>
@@ -277,48 +343,55 @@ struct wait_args {
#define GETPS(rp) (rp)[PS]
#endif
-compat_43_wait(p, uap, retval)
+int
+owait(p, uap, retval)
struct proc *p;
- register struct wait_args *uap;
+ register struct owait_args /* {
+ int dummy;
+ } */ *uap;
int *retval;
{
+ struct wait_args w;
#ifdef PSL_ALLCC
if ((GETPS(p->p_md.md_regs) & PSL_ALLCC) != PSL_ALLCC) {
- uap->options = 0;
- uap->rusage = NULL;
+ w.options = 0;
+ w.rusage = NULL;
} else {
- uap->options = p->p_md.md_regs[R0];
- uap->rusage = (struct rusage *)p->p_md.md_regs[R1];
+ w.options = p->p_md.md_regs[R0];
+ w.rusage = (struct rusage *)p->p_md.md_regs[R1];
}
#else
- uap->options = 0;
- uap->rusage = NULL;
+ w.options = 0;
+ w.rusage = NULL;
#endif
- uap->pid = WAIT_ANY;
- uap->status = NULL;
- uap->compat = 1;
- return (wait1(p, uap, retval));
+ w.pid = WAIT_ANY;
+ w.status = NULL;
+ return (wait1(p, &w, retval, 1));
}
+#endif /* COMPAT_43 */
+int
wait4(p, uap, retval)
struct proc *p;
struct wait_args *uap;
int *retval;
{
- uap->compat = 0;
- return (wait1(p, uap, retval));
+ return (wait1(p, uap, retval, 0));
}
-#else
-#define wait1 wait4
-#endif
-int
-wait1(q, uap, retval)
+static int
+wait1(q, uap, retval, compat)
register struct proc *q;
- register struct wait_args *uap;
+ register struct wait_args /* {
+ int pid;
+ int *status;
+ int options;
+ struct rusage *rusage;
+ } */ *uap;
int retval[];
+ int compat;
{
register int nfound;
register struct proc *p, *t;
@@ -338,16 +411,22 @@ loop:
continue;
nfound++;
if (p->p_stat == SZOMB) {
+ /* charge childs scheduling cpu usage to parent */
+ if (curproc->p_pid != 1) {
+ curproc->p_estcpu = min(curproc->p_estcpu +
+ p->p_estcpu, UCHAR_MAX);
+ }
+
retval[0] = p->p_pid;
#ifdef COMPAT_43
- if (uap->compat)
+ if (compat)
retval[1] = p->p_xstat;
else
#endif
if (uap->status) {
status = p->p_xstat; /* convert to int */
- if (error = copyout((caddr_t)&status,
- (caddr_t)uap->status, sizeof(status)))
+ if ((error = copyout((caddr_t)&status,
+ (caddr_t)uap->status, sizeof(status))))
return (error);
}
if (uap->rusage && (error = copyout((caddr_t)p->p_ru,
@@ -367,6 +446,7 @@ loop:
p->p_xstat = 0;
ruadd(&q->p_stats->p_cru, p->p_ru);
FREE(p->p_ru, M_ZOMBIE);
+ p->p_ru = NULL;
/*
* Decrement the count of procs running with this uid.
@@ -374,20 +454,21 @@ loop:
(void)chgproccnt(p->p_cred->p_ruid, -1);
/*
+ * Release reference to text vnode
+ */
+ if (p->p_textvp)
+ vrele(p->p_textvp);
+
+ /*
* Free up credentials.
*/
if (--p->p_cred->p_refcnt == 0) {
crfree(p->p_cred->pc_ucred);
FREE(p->p_cred, M_SUBPROC);
+ p->p_cred = NULL;
}
/*
- * Release reference to text vnode
- */
- if (p->p_textvp)
- vrele(p->p_textvp);
-
- /*
* Finally finished with old proc entry.
* Unlink it from its process group and free it.
*/
@@ -410,7 +491,7 @@ loop:
p->p_flag |= P_WAITED;
retval[0] = p->p_pid;
#ifdef COMPAT_43
- if (uap->compat) {
+ if (compat) {
retval[1] = W_STOPCODE(p->p_xstat);
error = 0;
} else
@@ -430,7 +511,7 @@ loop:
retval[0] = 0;
return (0);
}
- if (error = tsleep((caddr_t)q, PWAIT | PCATCH, "wait", 0))
+ if ((error = tsleep((caddr_t)q, PWAIT | PCATCH, "wait", 0)))
return (error);
goto loop;
}
@@ -451,3 +532,57 @@ proc_reparent(child, parent)
LIST_INSERT_HEAD(&parent->p_children, child, p_sibling);
child->p_pptr = parent;
}
+
+/*
+ * The next two functions are to handle adding/deleting items on the
+ * exit callout list
+ *
+ * at_exit():
+ * Take the arguments given and put them onto the exit callout list,
+ * However first make sure that it's not already there.
+ * returns 0 on success.
+ */
+int
+at_exit(exitlist_fn function)
+{
+ ele_p ep;
+
+ /* Be noisy if the programmer has lost track of things */
+ if (rm_at_exit(function))
+ printf("exit callout entry already present\n");
+ ep = malloc(sizeof(*ep), M_TEMP, M_NOWAIT);
+ if (ep == NULL)
+ return (ENOMEM);
+ ep->next = exit_list;
+ ep->function = function;
+ exit_list = ep;
+ return (0);
+}
+/*
+ * Scan the exit callout list for the given items and remove them.
+ * Returns the number of items removed.
+ * Logically this can only be 0 or 1.
+ */
+int
+rm_at_exit(exitlist_fn function)
+{
+ ele_p *epp, ep;
+ int count;
+
+ count = 0;
+ epp = &exit_list;
+ ep = *epp;
+ while (ep) {
+ if (ep->function == function) {
+ *epp = ep->next;
+ free(ep, M_TEMP);
+ count++;
+ } else {
+ epp = &ep->next;
+ }
+ ep = *epp;
+ }
+ return (count);
+}
+
+
OpenPOWER on IntegriCloud