diff options
| author | 2010-07-26 01:56:27 +0000 | |
|---|---|---|
| committer | 2010-07-26 01:56:27 +0000 | |
| commit | 207e4b38a785bf665de26471f4fc5fde67fa99f0 (patch) | |
| tree | 5b61a93df6c22438e6a0955afca220cb2f2207a0 /sys/kern/kern_exit.c | |
| parent | Add missing braces so a loop will function as intended. (diff) | |
| download | wireguard-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.c | 227 |
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--; } - |
