summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_exit.c
diff options
context:
space:
mode:
authorguenther <guenther@openbsd.org>2010-07-26 01:56:27 +0000
committerguenther <guenther@openbsd.org>2010-07-26 01:56:27 +0000
commit207e4b38a785bf665de26471f4fc5fde67fa99f0 (patch)
tree5b61a93df6c22438e6a0955afca220cb2f2207a0 /sys/kern/kern_exit.c
parentAdd missing braces so a loop will function as intended. (diff)
downloadwireguard-openbsd-207e4b38a785bf665de26471f4fc5fde67fa99f0.tar.xz
wireguard-openbsd-207e4b38a785bf665de26471f4fc5fde67fa99f0.zip
Correct the links between threads, processes, pgrps, and sessions,
so that the process-level stuff is to/from struct process and not struct proc. This fixes a bunch of problem cases in rthreads. Based on earlier work by blambert and myself, but mostly written at c2k10. Tested by many: deraadt, sthen, krw, ray, and in snapshots
Diffstat (limited to 'sys/kern/kern_exit.c')
-rw-r--r--sys/kern/kern_exit.c227
1 files changed, 120 insertions, 107 deletions
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index bf36116bd53..3302bc6eb00 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_exit.c,v 1.95 2010/07/19 23:00:15 guenther Exp $ */
+/* $OpenBSD: kern_exit.c,v 1.96 2010/07/26 01:56:27 guenther Exp $ */
/* $NetBSD: kern_exit.c,v 1.39 1996/04/22 01:38:25 christos Exp $ */
/*
@@ -120,34 +120,37 @@ void
exit1(struct proc *p, int rv, int flags)
{
struct proc *q, *nq;
+ struct process *pr, *qr, *nqr;
if (p->p_pid == 1)
panic("init died (signal %d, exit %d)",
WTERMSIG(rv), WEXITSTATUS(rv));
+ atomic_setbits_int(&p->p_flag, P_WEXIT);
+
/* unlink ourselves from the active threads */
- TAILQ_REMOVE(&p->p_p->ps_threads, p, p_thr_link);
- if (TAILQ_EMPTY(&p->p_p->ps_threads))
- wakeup(&p->p_p->ps_threads);
+ pr = p->p_p;
+ TAILQ_REMOVE(&pr->ps_threads, p, p_thr_link);
+ if (TAILQ_EMPTY(&pr->ps_threads))
+ wakeup(&pr->ps_threads);
/*
* if one thread calls exit, we take down everybody.
* we have to be careful not to get recursively caught.
* this is kinda sick.
*/
if (flags == EXIT_NORMAL && (p->p_flag & P_THREAD) &&
- (p->p_p->ps_mainproc->p_flag & P_WEXIT) == 0) {
+ (pr->ps_mainproc->p_flag & P_WEXIT) == 0) {
/*
* we are one of the threads. we SIGKILL the parent,
* it will wake us up again, then we proceed.
*/
- atomic_setbits_int(&p->p_p->ps_mainproc->p_flag, P_IGNEXITRV);
- p->p_p->ps_mainproc->p_xstat = rv;
- ptsignal(p->p_p->ps_mainproc, SIGKILL, SPROPAGATED);
- tsleep(p->p_p, PUSER, "thrdying", 0);
+ atomic_setbits_int(&pr->ps_mainproc->p_flag, P_IGNEXITRV);
+ pr->ps_mainproc->p_xstat = rv;
+ ptsignal(pr->ps_mainproc, SIGKILL, SPROPAGATED);
+ tsleep(pr, PUSER, "thrdying", 0);
} else if ((p->p_flag & P_THREAD) == 0) {
- atomic_setbits_int(&p->p_flag, P_WEXIT);
if (flags == EXIT_NORMAL) {
- q = TAILQ_FIRST(&p->p_p->ps_threads);
+ q = TAILQ_FIRST(&pr->ps_threads);
for (; q != NULL; q = nq) {
nq = TAILQ_NEXT(q, p_thr_link);
atomic_setbits_int(&q->p_flag, P_IGNEXITRV);
@@ -155,23 +158,22 @@ exit1(struct proc *p, int rv, int flags)
ptsignal(q, SIGKILL, SPROPAGATED);
}
}
- wakeup(p->p_p);
- while (!TAILQ_EMPTY(&p->p_p->ps_threads))
- tsleep(&p->p_p->ps_threads, PUSER, "thrdeath", 0);
+ wakeup(pr);
+ while (!TAILQ_EMPTY(&pr->ps_threads))
+ tsleep(&pr->ps_threads, PUSER, "thrdeath", 0);
+ /*
+ * If parent is waiting for us to exit or exec, P_PPWAIT
+ * is set; we wake up the parent early to avoid deadlock.
+ */
+ if (p->p_flag & P_PPWAIT) {
+ atomic_clearbits_int(&p->p_flag, P_PPWAIT);
+ wakeup(pr->ps_pptr);
+ }
}
if (p->p_flag & P_PROFIL)
stopprofclock(p);
p->p_ru = pool_get(&rusage_pool, PR_WAITOK);
- /*
- * If parent is waiting for us to exit or exec, P_PPWAIT is set; we
- * wake up the parent early to avoid deadlock.
- */
- atomic_setbits_int(&p->p_flag, P_WEXIT);
- if (p->p_flag & P_PPWAIT) {
- atomic_clearbits_int(&p->p_flag, P_PPWAIT);
- wakeup(p->p_pptr);
- }
p->p_sigignore = ~0;
p->p_siglist = 0;
timeout_del(&p->p_realit_to);
@@ -183,46 +185,52 @@ exit1(struct proc *p, int rv, int flags)
*/
fdfree(p);
+ if ((p->p_flag & P_THREAD) == 0) {
#ifdef SYSVSEM
- if ((p->p_flag & P_THREAD) == 0)
- semexit(p->p_p);
+ semexit(pr);
#endif
- if (SESS_LEADER(p)) {
- struct session *sp = p->p_session;
+ if (SESS_LEADER(pr)) {
+ struct session *sp = pr->ps_session;
- if (sp->s_ttyvp) {
- /*
- * Controlling process.
- * Signal foreground pgrp,
- * drain controlling terminal
- * and revoke access to controlling terminal.
- */
- if (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);
+ if (sp->s_ttyvp) {
/*
- * The tty could have been revoked
- * if we blocked.
+ * Controlling process.
+ * Signal foreground pgrp,
+ * drain controlling terminal
+ * and revoke access to controlling terminal.
*/
+ if (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);
+ /*
+ * The tty could have been revoked
+ * if we blocked.
+ */
+ if (sp->s_ttyvp)
+ VOP_REVOKE(sp->s_ttyvp,
+ REVOKEALL);
+ }
if (sp->s_ttyvp)
- VOP_REVOKE(sp->s_ttyvp, REVOKEALL);
+ vrele(sp->s_ttyvp);
+ sp->s_ttyvp = NULL;
+ /*
+ * s_ttyp is not zero'd; we use this to
+ * indicate that the session once had a
+ * controlling terminal. (for logging and
+ * informational purposes)
+ */
}
- if (sp->s_ttyvp)
- vrele(sp->s_ttyvp);
- sp->s_ttyvp = NULL;
- /*
- * s_ttyp is not zero'd; we use this to indicate
- * that the session once had a controlling terminal.
- * (for logging and informational purposes)
- */
+ sp->s_leader = NULL;
}
- sp->s_leader = NULL;
- }
- fixjobc(p, p->p_pgrp, 0);
+ fixjobc(pr, pr->ps_pgrp, 0);
+
#ifdef ACCOUNTING
- (void)acct_process(p);
+ (void)acct_process(p);
#endif
+ }
+
#ifdef KTRACE
/*
* release trace file
@@ -254,19 +262,22 @@ exit1(struct proc *p, int rv, int flags)
/*
* Give orphaned children to init(8).
*/
- q = LIST_FIRST(&p->p_children);
- if (q) /* only need this if any child is S_ZOMB */
- wakeup(initproc);
- for (; q != 0; q = nq) {
- nq = LIST_NEXT(q, p_sibling);
- proc_reparent(q, initproc);
- /*
- * Traced processes are killed
- * since their existence means someone is screwing up.
- */
- if (q->p_flag & P_TRACED) {
- atomic_clearbits_int(&q->p_flag, P_TRACED);
- psignal(q, SIGKILL);
+ if ((p->p_flag & P_THREAD) == 0) {
+ qr = LIST_FIRST(&pr->ps_children);
+ if (qr) /* only need this if any child is S_ZOMB */
+ wakeup(initproc->p_p);
+ for (; qr != 0; qr = nqr) {
+ nqr = LIST_NEXT(qr, ps_sibling);
+ proc_reparent(qr, initproc->p_p);
+ /*
+ * Traced processes are killed
+ * since their existence means someone is screwing up.
+ */
+ if (qr->ps_mainproc->p_flag & P_TRACED) {
+ atomic_clearbits_int(&qr->ps_mainproc->p_flag,
+ P_TRACED);
+ prsignal(qr, SIGKILL);
+ }
}
}
@@ -286,27 +297,27 @@ exit1(struct proc *p, int rv, int flags)
*/
p->p_pctcpu = 0;
- /*
- * notify interested parties of our demise.
- */
- if (p == p->p_p->ps_mainproc)
- KNOTE(&p->p_p->ps_klist, NOTE_EXIT);
+ if ((p->p_flag & P_THREAD) == 0) {
+ /* notify interested parties of our demise */
+ KNOTE(&pr->ps_klist, NOTE_EXIT);
- /*
- * Notify parent that we're gone. If we have P_NOZOMBIE or parent has
- * the P_NOCLDWAIT flag set, notify process 1 instead (and hope it
- * will handle this situation).
- */
- if ((p->p_flag & P_NOZOMBIE) || (p->p_pptr->p_flag & P_NOCLDWAIT)) {
- struct proc *pp = p->p_pptr;
- proc_reparent(p, initproc);
/*
- * If this was the last child of our parent, notify
- * parent, so in case he was wait(2)ing, he will
- * continue.
+ * Notify parent that we're gone. If we have P_NOZOMBIE
+ * or parent has the P_NOCLDWAIT flag set, notify process 1
+ * instead (and hope it will handle this situation).
*/
- if (LIST_EMPTY(&pp->p_children))
- wakeup(pp);
+ if ((p->p_flag & P_NOZOMBIE) ||
+ (pr->ps_pptr->ps_mainproc->p_flag & P_NOCLDWAIT)) {
+ struct process *ppr = pr->ps_pptr;
+ proc_reparent(pr, initproc->p_p);
+ /*
+ * If this was the last child of our parent, notify
+ * parent, so in case he was wait(2)ing, he will
+ * continue.
+ */
+ if (LIST_EMPTY(&ppr->ps_children))
+ wakeup(ppr);
+ }
}
/*
@@ -407,9 +418,9 @@ reaper(void)
p->p_stat = SZOMB;
if (P_EXITSIG(p) != 0)
- psignal(p->p_pptr, P_EXITSIG(p));
+ prsignal(p->p_p->ps_pptr, P_EXITSIG(p));
/* Wake up the parent so it can get exit status. */
- wakeup(p->p_pptr);
+ wakeup(p->p_p->ps_pptr);
} else {
/* Noone will wait for us. Just zap the process now */
proc_zap(p);
@@ -429,21 +440,23 @@ sys_wait4(struct proc *q, void *v, register_t *retval)
syscallarg(struct rusage *) rusage;
} */ *uap = v;
int nfound;
+ struct process *pr;
struct proc *p;
int status, error;
if (SCARG(uap, pid) == 0)
- SCARG(uap, pid) = -q->p_pgid;
+ SCARG(uap, pid) = -q->p_p->ps_pgid;
if (SCARG(uap, options) &~ (WUNTRACED|WNOHANG|WALTSIG|WCONTINUED))
return (EINVAL);
loop:
nfound = 0;
- LIST_FOREACH(p, &q->p_children, p_sibling) {
+ LIST_FOREACH(pr, &q->p_p->ps_children, ps_sibling) {
+ p = pr->ps_mainproc;
if ((p->p_flag & P_NOZOMBIE) ||
(SCARG(uap, pid) != WAIT_ANY &&
p->p_pid != SCARG(uap, pid) &&
- p->p_pgid != -SCARG(uap, pid)))
+ pr->ps_pgid != -SCARG(uap, pid)))
continue;
/*
@@ -505,7 +518,7 @@ loop:
retval[0] = 0;
return (0);
}
- if ((error = tsleep(q, PWAIT | PCATCH, "wait", 0)) != 0)
+ if ((error = tsleep(q->p_p, PWAIT | PCATCH, "wait", 0)) != 0)
return (error);
goto loop;
}
@@ -513,19 +526,19 @@ loop:
void
proc_finish_wait(struct proc *waiter, struct proc *p)
{
- struct proc *t;
+ struct process *tr;
/*
* 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))) {
+ if (p->p_oppid && (tr = prfind(p->p_oppid))) {
atomic_clearbits_int(&p->p_flag, P_TRACED);
p->p_oppid = 0;
- proc_reparent(p, t);
+ proc_reparent(p->p_p, tr);
if (p->p_exitsig != 0)
- psignal(t, p->p_exitsig);
- wakeup(t);
+ prsignal(tr, p->p_exitsig);
+ wakeup(tr);
} else {
scheduler_wait_hook(waiter, p);
p->p_xstat = 0;
@@ -538,24 +551,24 @@ proc_finish_wait(struct proc *waiter, struct proc *p)
* make process 'parent' the new parent of process 'child'.
*/
void
-proc_reparent(struct proc *child, struct proc *parent)
+proc_reparent(struct process *child, struct process *parent)
{
- if (child->p_pptr == parent)
+ if (child->ps_pptr == parent)
return;
- if (parent == initproc)
- child->p_exitsig = SIGCHLD;
+ if (parent == initproc->p_p)
+ child->ps_mainproc->p_exitsig = SIGCHLD;
- LIST_REMOVE(child, p_sibling);
- LIST_INSERT_HEAD(&parent->p_children, child, p_sibling);
- child->p_pptr = parent;
+ LIST_REMOVE(child, ps_sibling);
+ LIST_INSERT_HEAD(&parent->ps_children, child, ps_sibling);
+ child->ps_pptr = parent;
}
void
proc_zap(struct proc *p)
{
- struct process *pr;
+ struct process *pr = p->p_p;
pool_put(&rusage_pool, p->p_ru);
if (p->p_ptstat)
@@ -565,9 +578,11 @@ proc_zap(struct proc *p)
* Finally finished with old proc entry.
* Unlink it from its process group and free it.
*/
- leavepgrp(p);
+ if ((p->p_flag & P_THREAD) == 0)
+ leavepgrp(pr);
LIST_REMOVE(p, p_list); /* off zombproc */
- LIST_REMOVE(p, p_sibling);
+ if ((p->p_flag & P_THREAD) == 0)
+ LIST_REMOVE(pr, ps_sibling);
/*
* Decrement the count of procs running with this uid.
@@ -584,7 +599,6 @@ proc_zap(struct proc *p)
* Remove us from our process list, possibly killing the process
* in the process (pun intended).
*/
- pr = p->p_p;
if (--pr->ps_refcnt == 0) {
KASSERT(TAILQ_EMPTY(&pr->ps_threads));
limfree(pr->ps_limit);
@@ -596,4 +610,3 @@ proc_zap(struct proc *p)
pool_put(&proc_pool, p);
nprocs--;
}
-