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
This commit is contained in:
mjg 2016-01-20 23:33:58 +00:00
parent 4e1a382dbc
commit eabf748a18
3 changed files with 75 additions and 53 deletions

View File

@ -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

View File

@ -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,

View File

@ -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);