Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_proc.c
Show First 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | |||||||||
SDT_PROVIDER_DEFINE(proc); | SDT_PROVIDER_DEFINE(proc); | ||||||||
MALLOC_DEFINE(M_PGRP, "pgrp", "process group header"); | MALLOC_DEFINE(M_PGRP, "pgrp", "process group header"); | ||||||||
MALLOC_DEFINE(M_SESSION, "session", "session header"); | MALLOC_DEFINE(M_SESSION, "session", "session header"); | ||||||||
static MALLOC_DEFINE(M_PROC, "proc", "Proc structures"); | static MALLOC_DEFINE(M_PROC, "proc", "Proc structures"); | ||||||||
MALLOC_DEFINE(M_SUBPROC, "subproc", "Proc sub-structures"); | MALLOC_DEFINE(M_SUBPROC, "subproc", "Proc sub-structures"); | ||||||||
static void fixjobc_enterpgrp(struct proc *p, struct pgrp *pgrp); | |||||||||
static void doenterpgrp(struct proc *, struct pgrp *); | static void doenterpgrp(struct proc *, struct pgrp *); | ||||||||
static void orphanpg(struct pgrp *pg); | static void orphanpg(struct pgrp *pg); | ||||||||
static void fill_kinfo_aggregate(struct proc *p, struct kinfo_proc *kp); | static void fill_kinfo_aggregate(struct proc *p, struct kinfo_proc *kp); | ||||||||
static void fill_kinfo_proc_only(struct proc *p, struct kinfo_proc *kp); | static void fill_kinfo_proc_only(struct proc *p, struct kinfo_proc *kp); | ||||||||
static void fill_kinfo_thread(struct thread *td, struct kinfo_proc *kp, | static void fill_kinfo_thread(struct thread *td, struct kinfo_proc *kp, | ||||||||
int preferthread); | int preferthread); | ||||||||
static void pgadjustjobc(struct pgrp *pgrp, int entering); | static void pgadjustjobc(struct pgrp *pgrp, bool entering); | ||||||||
static void pgdelete(struct pgrp *); | static void pgdelete(struct pgrp *); | ||||||||
static int proc_ctor(void *mem, int size, void *arg, int flags); | static int proc_ctor(void *mem, int size, void *arg, int flags); | ||||||||
static void proc_dtor(void *mem, int size, void *arg); | static void proc_dtor(void *mem, int size, void *arg); | ||||||||
static int proc_init(void *mem, int size, int flags); | static int proc_init(void *mem, int size, int flags); | ||||||||
static void proc_fini(void *mem, int size); | static void proc_fini(void *mem, int size); | ||||||||
static void pargs_free(struct pargs *pa); | static void pargs_free(struct pargs *pa); | ||||||||
/* | /* | ||||||||
▲ Show 20 Lines • Show All 508 Lines • ▼ Show 20 Lines | KASSERT(pgrp != p->p_pgrp, | ||||||||
("%s: p belongs to pgrp.", __func__)); | ("%s: p belongs to pgrp.", __func__)); | ||||||||
doenterpgrp(p, pgrp); | doenterpgrp(p, pgrp); | ||||||||
return (0); | return (0); | ||||||||
} | } | ||||||||
/* | /* | ||||||||
* If true, any child of q which belongs to group pgrp, qualifies the | |||||||||
* process group pgrp as not orphaned. | |||||||||
*/ | |||||||||
static bool | |||||||||
isjobproc(struct proc *q, struct pgrp *pgrp) | |||||||||
{ | |||||||||
sx_assert(&proctree_lock, SX_LOCKED); | |||||||||
return (q->p_pgrp != pgrp && | |||||||||
q->p_pgrp->pg_session == pgrp->pg_session); | |||||||||
} | |||||||||
#ifdef INVARIANTS | |||||||||
static void | |||||||||
check_pgrp_jobc(struct pgrp *pgrp) | |||||||||
{ | |||||||||
struct proc *q; | |||||||||
int cnt; | |||||||||
sx_assert(&proctree_lock, SX_LOCKED); | |||||||||
PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); | |||||||||
cnt = 0; | |||||||||
PGRP_LOCK(pgrp); | |||||||||
LIST_FOREACH(q, &pgrp->pg_members, p_pglist) { | |||||||||
if ((q->p_treeflag & P_TREE_GRPEXITED) != 0 || | |||||||||
q->p_pptr == NULL) | |||||||||
continue; | |||||||||
if (isjobproc(q->p_pptr, pgrp)) | |||||||||
cnt++; | |||||||||
} | |||||||||
KASSERT(pgrp->pg_jobc == cnt, ("pgrp %d %p pg_jobc %d cnt %d", | |||||||||
pgrp->pg_id, pgrp, pgrp->pg_jobc, cnt)); | |||||||||
PGRP_UNLOCK(pgrp); | |||||||||
} | |||||||||
#endif | |||||||||
/* | |||||||||
* Move p to a process group | * Move p to a process group | ||||||||
*/ | */ | ||||||||
static void | static void | ||||||||
doenterpgrp(struct proc *p, struct pgrp *pgrp) | doenterpgrp(struct proc *p, struct pgrp *pgrp) | ||||||||
{ | { | ||||||||
struct pgrp *savepgrp; | struct pgrp *savepgrp; | ||||||||
sx_assert(&proctree_lock, SX_XLOCKED); | sx_assert(&proctree_lock, SX_XLOCKED); | ||||||||
PROC_LOCK_ASSERT(p, MA_NOTOWNED); | PROC_LOCK_ASSERT(p, MA_NOTOWNED); | ||||||||
PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); | PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); | ||||||||
PGRP_LOCK_ASSERT(p->p_pgrp, MA_NOTOWNED); | PGRP_LOCK_ASSERT(p->p_pgrp, MA_NOTOWNED); | ||||||||
SESS_LOCK_ASSERT(p->p_session, MA_NOTOWNED); | SESS_LOCK_ASSERT(p->p_session, MA_NOTOWNED); | ||||||||
savepgrp = p->p_pgrp; | savepgrp = p->p_pgrp; | ||||||||
#ifdef INVARIANTS | |||||||||
kevans: These aren't defined for `!INVARIANTS` builds | |||||||||
check_pgrp_jobc(pgrp); | |||||||||
check_pgrp_jobc(savepgrp); | |||||||||
#endif | |||||||||
/* | /* | ||||||||
* Adjust eligibility of affected pgrps to participate in job control. | * Adjust eligibility of affected pgrps to participate in job control. | ||||||||
* Increment eligibility counts before decrementing, otherwise we | |||||||||
* could reach 0 spuriously during the first call. | |||||||||
*/ | */ | ||||||||
fixjobc(p, pgrp, 1); | fixjobc_enterpgrp(p, pgrp); | ||||||||
fixjobc(p, p->p_pgrp, 0); | |||||||||
PGRP_LOCK(pgrp); | PGRP_LOCK(pgrp); | ||||||||
PGRP_LOCK(savepgrp); | PGRP_LOCK(savepgrp); | ||||||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||||||
LIST_REMOVE(p, p_pglist); | LIST_REMOVE(p, p_pglist); | ||||||||
p->p_pgrp = pgrp; | p->p_pgrp = pgrp; | ||||||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||||||
LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist); | LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist); | ||||||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | pgdelete(struct pgrp *pgrp) | ||||||||
proc_id_clear(PROC_ID_GROUP, pgrp->pg_id); | proc_id_clear(PROC_ID_GROUP, pgrp->pg_id); | ||||||||
mtx_destroy(&pgrp->pg_mtx); | mtx_destroy(&pgrp->pg_mtx); | ||||||||
free(pgrp, M_PGRP); | free(pgrp, M_PGRP); | ||||||||
sess_release(savesess); | sess_release(savesess); | ||||||||
} | } | ||||||||
static void | static void | ||||||||
pgadjustjobc(struct pgrp *pgrp, int entering) | pgadjustjobc(struct pgrp *pgrp, bool entering) | ||||||||
{ | { | ||||||||
PGRP_LOCK(pgrp); | PGRP_LOCK(pgrp); | ||||||||
if (entering) { | if (entering) { | ||||||||
#ifdef notyet | |||||||||
MPASS(pgrp->pg_jobc >= 0); | MPASS(pgrp->pg_jobc >= 0); | ||||||||
#endif | |||||||||
pgrp->pg_jobc++; | pgrp->pg_jobc++; | ||||||||
} else { | } else { | ||||||||
#ifdef notyet | |||||||||
MPASS(pgrp->pg_jobc > 0); | MPASS(pgrp->pg_jobc > 0); | ||||||||
#endif | |||||||||
--pgrp->pg_jobc; | --pgrp->pg_jobc; | ||||||||
if (pgrp->pg_jobc == 0) | if (pgrp->pg_jobc == 0) | ||||||||
orphanpg(pgrp); | orphanpg(pgrp); | ||||||||
} | } | ||||||||
PGRP_UNLOCK(pgrp); | PGRP_UNLOCK(pgrp); | ||||||||
} | } | ||||||||
/* | /* | ||||||||
* Adjust pgrp jobc counters when specified process changes process group. | * Adjust pgrp jobc counters when specified process changes process group. | ||||||||
* We count the number of processes in each process group that "qualify" | * We count the number of processes in each process group that "qualify" | ||||||||
* the group for terminal job control (those with a parent in a different | * the group for terminal job control (those with a parent in a different | ||||||||
* process group of the same session). If that count reaches zero, the | * process group of the same session). If that count reaches zero, the | ||||||||
* process group becomes orphaned. Check both the specified process' | * process group becomes orphaned. Check both the specified process' | ||||||||
* process group and that of its children. | * process group and that of its children. | ||||||||
* entering == 0 => p is leaving specified group. | * We increment eligibility counts before decrementing, otherwise we | ||||||||
* entering == 1 => p is entering specified group. | * could reach 0 spuriously during the decrement. | ||||||||
*/ | */ | ||||||||
void | static void | ||||||||
fixjobc(struct proc *p, struct pgrp *pgrp, int entering) | fixjobc_enterpgrp(struct proc *p, struct pgrp *pgrp) | ||||||||
{ | { | ||||||||
struct pgrp *hispgrp; | |||||||||
struct session *mysession; | |||||||||
struct proc *q; | struct proc *q; | ||||||||
struct pgrp *childpgrp; | |||||||||
bool future_jobc; | |||||||||
sx_assert(&proctree_lock, SX_LOCKED); | sx_assert(&proctree_lock, SX_LOCKED); | ||||||||
PROC_LOCK_ASSERT(p, MA_NOTOWNED); | PROC_LOCK_ASSERT(p, MA_NOTOWNED); | ||||||||
PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); | PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); | ||||||||
SESS_LOCK_ASSERT(pgrp->pg_session, MA_NOTOWNED); | SESS_LOCK_ASSERT(pgrp->pg_session, MA_NOTOWNED); | ||||||||
if (p->p_pgrp == pgrp) | |||||||||
return; | |||||||||
if (isjobproc(p->p_pptr, pgrp)) | |||||||||
pgadjustjobc(pgrp, true); | |||||||||
LIST_FOREACH(q, &p->p_children, p_sibling) { | |||||||||
if ((q->p_treeflag & P_TREE_GRPEXITED) != 0) | |||||||||
continue; | |||||||||
childpgrp = q->p_pgrp; | |||||||||
future_jobc = childpgrp != pgrp && | |||||||||
childpgrp->pg_session == pgrp->pg_session; | |||||||||
if (!isjobproc(p, childpgrp) && future_jobc) | |||||||||
pgadjustjobc(childpgrp, true); | |||||||||
} | |||||||||
if (isjobproc(p->p_pptr, p->p_pgrp)) | |||||||||
pgadjustjobc(p->p_pgrp, false); | |||||||||
LIST_FOREACH(q, &p->p_children, p_sibling) { | |||||||||
if ((q->p_treeflag & P_TREE_GRPEXITED) != 0) | |||||||||
continue; | |||||||||
childpgrp = q->p_pgrp; | |||||||||
future_jobc = childpgrp != pgrp && | |||||||||
childpgrp->pg_session == pgrp->pg_session; | |||||||||
if (isjobproc(p, childpgrp) && !future_jobc) | |||||||||
pgadjustjobc(childpgrp, false); | |||||||||
} | |||||||||
} | |||||||||
static void | |||||||||
fixjobc_kill(struct proc *p) | |||||||||
{ | |||||||||
struct proc *q; | |||||||||
struct pgrp *childpgrp, *pgrp; | |||||||||
sx_assert(&proctree_lock, SX_LOCKED); | |||||||||
PROC_LOCK_ASSERT(p, MA_NOTOWNED); | |||||||||
pgrp = p->p_pgrp; | |||||||||
PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); | |||||||||
SESS_LOCK_ASSERT(pgrp->pg_session, MA_NOTOWNED); | |||||||||
/* | /* | ||||||||
* p no longer affects process group orphanage for children. | |||||||||
* It is marked by the flag because p is only physically | |||||||||
* removed from its process group on wait(2). | |||||||||
*/ | |||||||||
p->p_treeflag |= P_TREE_GRPEXITED; | |||||||||
/* | |||||||||
* Check p's parent to see whether p qualifies its own process | * Check p's parent to see whether p qualifies its own process | ||||||||
* group; if so, adjust count for p's process group. | * group; if so, adjust count for p's process group. | ||||||||
*/ | */ | ||||||||
mysession = pgrp->pg_session; | if (isjobproc(p->p_pptr, pgrp)) | ||||||||
if ((hispgrp = p->p_pptr->p_pgrp) != pgrp && | pgadjustjobc(pgrp, false); | ||||||||
hispgrp->pg_session == mysession) | |||||||||
pgadjustjobc(pgrp, entering); | |||||||||
/* | /* | ||||||||
* Check this process' children to see whether they qualify | * Check this process' children to see whether they qualify | ||||||||
* their process groups; if so, adjust counts for children's | * their process groups after reparenting to reapper. If so, | ||||||||
jillesUnsubmitted Done Inline Actions
typo jilles: typo | |||||||||
* process groups. | * adjust counts for children's process groups. | ||||||||
*/ | */ | ||||||||
LIST_FOREACH(q, &p->p_children, p_sibling) { | LIST_FOREACH(q, &p->p_children, p_sibling) { | ||||||||
hispgrp = q->p_pgrp; | if ((q->p_treeflag & P_TREE_GRPEXITED) != 0) | ||||||||
if (hispgrp == pgrp || | |||||||||
hispgrp->pg_session != mysession) | |||||||||
continue; | continue; | ||||||||
if (q->p_state == PRS_ZOMBIE) | childpgrp = q->p_pgrp; | ||||||||
if (isjobproc(q->p_reaper, childpgrp) && | |||||||||
!isjobproc(p, childpgrp)) | |||||||||
pgadjustjobc(childpgrp, true); | |||||||||
} | |||||||||
LIST_FOREACH(q, &p->p_children, p_sibling) { | |||||||||
if ((q->p_treeflag & P_TREE_GRPEXITED) != 0) | |||||||||
continue; | continue; | ||||||||
pgadjustjobc(hispgrp, entering); | childpgrp = q->p_pgrp; | ||||||||
if (!isjobproc(q->p_reaper, childpgrp) && | |||||||||
isjobproc(p, childpgrp)) | |||||||||
pgadjustjobc(childpgrp, false); | |||||||||
} | } | ||||||||
} | } | ||||||||
void | void | ||||||||
killjobc(void) | killjobc(void) | ||||||||
{ | { | ||||||||
struct session *sp; | struct session *sp; | ||||||||
struct tty *tp; | struct tty *tp; | ||||||||
struct proc *p; | struct proc *p; | ||||||||
struct vnode *ttyvp; | struct vnode *ttyvp; | ||||||||
p = curproc; | p = curproc; | ||||||||
MPASS(p->p_flag & P_WEXIT); | MPASS(p->p_flag & P_WEXIT); | ||||||||
/* | sx_assert(&proctree_lock, SX_LOCKED); | ||||||||
* 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)) { | if (SESS_LEADER(p)) { | ||||||||
sp = p->p_session; | sp = p->p_session; | ||||||||
/* | /* | ||||||||
* s_ttyp is not zero'd; we use this to indicate that | * s_ttyp is not zero'd; we use this to indicate that | ||||||||
* the session once had a controlling terminal. (for | * the session once had a controlling terminal. (for | ||||||||
* logging and informational purposes) | * logging and informational purposes) | ||||||||
*/ | */ | ||||||||
Show All 29 Lines | if (ttyvp != NULL) { | ||||||||
if (vn_lock(ttyvp, LK_EXCLUSIVE) == 0) { | if (vn_lock(ttyvp, LK_EXCLUSIVE) == 0) { | ||||||||
VOP_REVOKE(ttyvp, REVOKEALL); | VOP_REVOKE(ttyvp, REVOKEALL); | ||||||||
VOP_UNLOCK(ttyvp); | VOP_UNLOCK(ttyvp); | ||||||||
} | } | ||||||||
devfs_ctty_unref(ttyvp); | devfs_ctty_unref(ttyvp); | ||||||||
sx_xlock(&proctree_lock); | sx_xlock(&proctree_lock); | ||||||||
} | } | ||||||||
} | } | ||||||||
fixjobc(p, p->p_pgrp, 0); | fixjobc_kill(p); | ||||||||
sx_xunlock(&proctree_lock); | |||||||||
} | } | ||||||||
/* | /* | ||||||||
* A process group has become orphaned; | * A process group has become orphaned; | ||||||||
* if there are any stopped processes in the group, | * if there are any stopped processes in the group, | ||||||||
* hang-up all process in that group. | * hang-up all process in that group. | ||||||||
*/ | */ | ||||||||
static void | static void | ||||||||
▲ Show 20 Lines • Show All 2,403 Lines • Show Last 20 Lines |
These aren't defined for !INVARIANTS builds