From 17182b1351c71381d2b6276adf0164a8a7ee51c3 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Wed, 20 Jan 2016 23:33:58 +0000 Subject: [PATCH] session: avoid proctree lock on proc exit when possible We can get away with the common case with only proc lock held. Reviewed by: kib --- sys/kern/kern_exit.c | 54 +------------------------------- sys/kern/kern_proc.c | 73 ++++++++++++++++++++++++++++++++++++++++++++ sys/sys/proc.h | 1 + 3 files changed, 75 insertions(+), 53 deletions(-) diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index ee87e582051..1cd9b62fbf7 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -189,7 +189,6 @@ exit1(struct thread *td, int rval, int signo) { struct proc *p, *nq, *q, *t; struct thread *tdt; - struct vnode *ttyvp = NULL; mtx_assert(&Giant, MA_NOTOWNED); KASSERT(rval == 0 || signo == 0, ("exit1 rv %d sig %d", rval, signo)); @@ -394,60 +393,9 @@ exit1(struct thread *td, int rval, int signo) } vmspace_exit(td); - - sx_xlock(&proctree_lock); - if (SESS_LEADER(p)) { - struct session *sp = p->p_session; - struct tty *tp; - - /* - * s_ttyp is not zero'd; we use this to indicate that - * the session once had a controlling terminal. (for - * logging and informational purposes) - */ - SESS_LOCK(sp); - ttyvp = sp->s_ttyvp; - tp = sp->s_ttyp; - sp->s_ttyvp = NULL; - sp->s_ttydp = NULL; - sp->s_leader = NULL; - SESS_UNLOCK(sp); - - /* - * Signal foreground pgrp and revoke access to - * controlling terminal if it has not been revoked - * already. - * - * Because the TTY may have been revoked in the mean - * time and could already have a new session associated - * with it, make sure we don't send a SIGHUP to a - * foreground process group that does not belong to this - * session. - */ - - if (tp != NULL) { - tty_lock(tp); - if (tp->t_session == sp) - tty_signal_pgrp(tp, SIGHUP); - tty_unlock(tp); - } - - if (ttyvp != NULL) { - sx_xunlock(&proctree_lock); - if (vn_lock(ttyvp, LK_EXCLUSIVE) == 0) { - VOP_REVOKE(ttyvp, REVOKEALL); - VOP_UNLOCK(ttyvp, 0); - } - sx_xlock(&proctree_lock); - } - } - fixjobc(p, p->p_pgrp, 0); - sx_xunlock(&proctree_lock); + killjobc(); (void)acct_process(td); - /* Release the TTY now we've unlocked everything. */ - if (ttyvp != NULL) - vrele(ttyvp); #ifdef KTRACE ktrprocexit(td); #endif diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index 6937fb4f207..a4f8576dfb7 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -686,6 +686,79 @@ fixjobc(struct proc *p, struct pgrp *pgrp, int entering) } } +void +killjobc(void) +{ + struct session *sp; + struct tty *tp; + struct proc *p; + struct vnode *ttyvp; + + p = curproc; + MPASS(p->p_flag & P_WEXIT); + /* + * Do a quick check to see if there is anything to do with the + * proctree_lock held. pgrp and LIST_EMPTY checks are for fixjobc(). + */ + PROC_LOCK(p); + if (!SESS_LEADER(p) && + (p->p_pgrp == p->p_pptr->p_pgrp) && + LIST_EMPTY(&p->p_children)) { + PROC_UNLOCK(p); + return; + } + PROC_UNLOCK(p); + + sx_xlock(&proctree_lock); + if (SESS_LEADER(p)) { + sp = p->p_session; + + /* + * s_ttyp is not zero'd; we use this to indicate that + * the session once had a controlling terminal. (for + * logging and informational purposes) + */ + SESS_LOCK(sp); + ttyvp = sp->s_ttyvp; + tp = sp->s_ttyp; + sp->s_ttyvp = NULL; + sp->s_ttydp = NULL; + sp->s_leader = NULL; + SESS_UNLOCK(sp); + + /* + * Signal foreground pgrp and revoke access to + * controlling terminal if it has not been revoked + * already. + * + * Because the TTY may have been revoked in the mean + * time and could already have a new session associated + * with it, make sure we don't send a SIGHUP to a + * foreground process group that does not belong to this + * session. + */ + + if (tp != NULL) { + tty_lock(tp); + if (tp->t_session == sp) + tty_signal_pgrp(tp, SIGHUP); + tty_unlock(tp); + } + + if (ttyvp != NULL) { + sx_xunlock(&proctree_lock); + if (vn_lock(ttyvp, LK_EXCLUSIVE) == 0) { + VOP_REVOKE(ttyvp, REVOKEALL); + VOP_UNLOCK(ttyvp, 0); + } + vrele(ttyvp); + sx_xlock(&proctree_lock); + } + } + fixjobc(p, p->p_pgrp, 0); + sx_xunlock(&proctree_lock); +} + /* * A process group has become orphaned; * if there are any stopped processes in the group, diff --git a/sys/sys/proc.h b/sys/sys/proc.h index fc5c90db2b4..f2f4a9d1720 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -938,6 +938,7 @@ void fork_return(struct thread *, struct trapframe *); int inferior(struct proc *p); void kern_yield(int); void kick_proc0(void); +void killjobc(void); int leavepgrp(struct proc *p); int maybe_preempt(struct thread *td); void maybe_yield(void); -- 2.45.2