Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_proc.c
Show First 20 Lines • Show All 639 Lines • ▼ Show 20 Lines | |||||
static bool | static bool | ||||
isjobproc(struct proc *q, struct pgrp *pgrp) | isjobproc(struct proc *q, struct pgrp *pgrp) | ||||
{ | { | ||||
sx_assert(&proctree_lock, SX_LOCKED); | sx_assert(&proctree_lock, SX_LOCKED); | ||||
return (q->p_pgrp != pgrp && | return (q->p_pgrp != pgrp && | ||||
q->p_pgrp->pg_session == pgrp->pg_session); | q->p_pgrp->pg_session == pgrp->pg_session); | ||||
} | } | ||||
static struct proc * | |||||
jobc_reaper(struct proc *p) | |||||
{ | |||||
struct proc *pp; | |||||
sx_assert(&proctree_lock, SX_LOCKED); | |||||
for (pp = p;;) { | |||||
pp = pp->p_reaper; | |||||
if (pp->p_reaper == pp || | |||||
(pp->p_treeflag & P_TREE_GRPEXITED) == 0) | |||||
return (pp); | |||||
} | |||||
} | |||||
static struct proc * | |||||
jobc_parent(struct proc *p) | |||||
{ | |||||
struct proc *pp; | |||||
sx_assert(&proctree_lock, SX_LOCKED); | |||||
pp = proc_realparent(p); | |||||
if (pp->p_pptr == NULL || | |||||
(pp->p_treeflag & P_TREE_GRPEXITED) == 0) | |||||
return (pp); | |||||
return (jobc_reaper(pp)); | |||||
} | |||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
static void | static void | ||||
check_pgrp_jobc(struct pgrp *pgrp) | check_pgrp_jobc(struct pgrp *pgrp) | ||||
{ | { | ||||
struct proc *q; | struct proc *q; | ||||
int cnt; | int cnt; | ||||
sx_assert(&proctree_lock, SX_LOCKED); | sx_assert(&proctree_lock, SX_LOCKED); | ||||
PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); | PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); | ||||
cnt = 0; | cnt = 0; | ||||
PGRP_LOCK(pgrp); | PGRP_LOCK(pgrp); | ||||
LIST_FOREACH(q, &pgrp->pg_members, p_pglist) { | LIST_FOREACH(q, &pgrp->pg_members, p_pglist) { | ||||
if ((q->p_treeflag & P_TREE_GRPEXITED) != 0 || | if ((q->p_treeflag & P_TREE_GRPEXITED) != 0 || | ||||
q->p_pptr == NULL) | q->p_pptr == NULL) | ||||
continue; | continue; | ||||
if (isjobproc(q->p_pptr, pgrp)) | if (isjobproc(jobc_parent(q), pgrp)) | ||||
cnt++; | cnt++; | ||||
} | } | ||||
KASSERT(pgrp->pg_jobc == cnt, ("pgrp %d %p pg_jobc %d cnt %d", | KASSERT(pgrp->pg_jobc == cnt, ("pgrp %d %p pg_jobc %d cnt %d", | ||||
pgrp->pg_id, pgrp, pgrp->pg_jobc, cnt)); | pgrp->pg_id, pgrp, pgrp->pg_jobc, cnt)); | ||||
PGRP_UNLOCK(pgrp); | PGRP_UNLOCK(pgrp); | ||||
} | } | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 106 Lines • ▼ Show 20 Lines | if (entering) { | ||||
MPASS(pgrp->pg_jobc > 0); | MPASS(pgrp->pg_jobc > 0); | ||||
--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); | ||||
} | } | ||||
static void | |||||
fixjobc_enterpgrp_q(struct pgrp *pgrp, struct proc *p, struct proc *q, bool adj) | |||||
{ | |||||
struct pgrp *childpgrp; | |||||
bool future_jobc; | |||||
sx_assert(&proctree_lock, SX_LOCKED); | |||||
if ((q->p_treeflag & P_TREE_GRPEXITED) != 0) | |||||
return; | |||||
childpgrp = q->p_pgrp; | |||||
future_jobc = childpgrp != pgrp && | |||||
childpgrp->pg_session == pgrp->pg_session; | |||||
if ((adj && !isjobproc(p, childpgrp) && future_jobc) || | |||||
(!adj && isjobproc(p, childpgrp) && !future_jobc)) | |||||
pgadjustjobc(childpgrp, adj); | |||||
} | |||||
/* | /* | ||||
* 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. | ||||
* We increment eligibility counts before decrementing, otherwise we | * We increment eligibility counts before decrementing, otherwise we | ||||
* could reach 0 spuriously during the decrement. | * could reach 0 spuriously during the decrement. | ||||
*/ | */ | ||||
static void | static void | ||||
fixjobc_enterpgrp(struct proc *p, struct pgrp *pgrp) | fixjobc_enterpgrp(struct proc *p, struct pgrp *pgrp) | ||||
{ | { | ||||
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) | if (p->p_pgrp == pgrp) | ||||
return; | return; | ||||
if (isjobproc(p->p_pptr, pgrp)) | if (isjobproc(jobc_parent(p), pgrp)) | ||||
pgadjustjobc(pgrp, true); | pgadjustjobc(pgrp, true); | ||||
LIST_FOREACH(q, &p->p_children, p_sibling) { | LIST_FOREACH(q, &p->p_children, p_sibling) { | ||||
if ((q->p_treeflag & P_TREE_GRPEXITED) != 0) | if ((q->p_treeflag & P_TREE_ORPHANED) != 0) | ||||
continue; | continue; | ||||
childpgrp = q->p_pgrp; | fixjobc_enterpgrp_q(pgrp, p, q, true); | ||||
future_jobc = childpgrp != pgrp && | |||||
childpgrp->pg_session == pgrp->pg_session; | |||||
if (!isjobproc(p, childpgrp) && future_jobc) | |||||
pgadjustjobc(childpgrp, true); | |||||
} | } | ||||
LIST_FOREACH(q, &p->p_orphans, p_orphan) | |||||
fixjobc_enterpgrp_q(pgrp, p, q, true); | |||||
if (isjobproc(p->p_pptr, p->p_pgrp)) | if (isjobproc(jobc_parent(p), p->p_pgrp)) | ||||
pgadjustjobc(p->p_pgrp, false); | pgadjustjobc(p->p_pgrp, false); | ||||
LIST_FOREACH(q, &p->p_children, p_sibling) { | LIST_FOREACH(q, &p->p_children, p_sibling) { | ||||
if ((q->p_treeflag & P_TREE_GRPEXITED) != 0) | if ((q->p_treeflag & P_TREE_ORPHANED) != 0) | ||||
continue; | continue; | ||||
childpgrp = q->p_pgrp; | fixjobc_enterpgrp_q(pgrp, p, q, false); | ||||
future_jobc = childpgrp != pgrp && | |||||
childpgrp->pg_session == pgrp->pg_session; | |||||
if (isjobproc(p, childpgrp) && !future_jobc) | |||||
pgadjustjobc(childpgrp, false); | |||||
} | } | ||||
LIST_FOREACH(q, &p->p_orphans, p_orphan) | |||||
fixjobc_enterpgrp_q(pgrp, p, q, false); | |||||
} | } | ||||
static void | static void | ||||
fixjobc_kill_q(struct proc *p, struct proc *q, bool adj) | |||||
{ | |||||
struct pgrp *childpgrp; | |||||
sx_assert(&proctree_lock, SX_LOCKED); | |||||
if ((q->p_treeflag & P_TREE_GRPEXITED) != 0) | |||||
return; | |||||
childpgrp = q->p_pgrp; | |||||
if ((adj && isjobproc(jobc_reaper(q), childpgrp) && | |||||
!isjobproc(p, childpgrp)) || (!adj && !isjobproc(jobc_reaper(q), | |||||
childpgrp) && isjobproc(p, childpgrp))) | |||||
pgadjustjobc(childpgrp, adj); | |||||
} | |||||
static void | |||||
fixjobc_kill(struct proc *p) | fixjobc_kill(struct proc *p) | ||||
{ | { | ||||
struct proc *q; | struct proc *q; | ||||
struct pgrp *childpgrp, *pgrp; | struct pgrp *pgrp; | ||||
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 = p->p_pgrp; | pgrp = p->p_pgrp; | ||||
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); | ||||
check_pgrp_jobc(pgrp); | |||||
/* | /* | ||||
* p no longer affects process group orphanage for children. | * p no longer affects process group orphanage for children. | ||||
* It is marked by the flag because p is only physically | * It is marked by the flag because p is only physically | ||||
* removed from its process group on wait(2). | * removed from its process group on wait(2). | ||||
*/ | */ | ||||
MPASS((p->p_treeflag & P_TREE_GRPEXITED) == 0); | |||||
p->p_treeflag |= P_TREE_GRPEXITED; | 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. | ||||
*/ | */ | ||||
if (isjobproc(p->p_pptr, pgrp)) | if (isjobproc(jobc_parent(p), pgrp)) | ||||
pgadjustjobc(pgrp, false); | pgadjustjobc(pgrp, false); | ||||
/* | /* | ||||
* Check this process' children to see whether they qualify | * Check this process' children to see whether they qualify | ||||
* their process groups after reparenting to reaper. If so, | * their process groups after reparenting to reaper. If so, | ||||
* adjust counts for children's 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) { | ||||
if ((q->p_treeflag & P_TREE_GRPEXITED) != 0) | if ((q->p_treeflag & P_TREE_ORPHANED) != 0) | ||||
continue; | continue; | ||||
childpgrp = q->p_pgrp; | fixjobc_kill_q(p, q, true); | ||||
if (isjobproc(q->p_reaper, childpgrp) && | |||||
!isjobproc(p, childpgrp)) | |||||
pgadjustjobc(childpgrp, true); | |||||
} | } | ||||
LIST_FOREACH(q, &p->p_orphans, p_orphan) | |||||
fixjobc_kill_q(p, q, true); | |||||
LIST_FOREACH(q, &p->p_children, p_sibling) { | LIST_FOREACH(q, &p->p_children, p_sibling) { | ||||
if ((q->p_treeflag & P_TREE_GRPEXITED) != 0) | if ((q->p_treeflag & P_TREE_ORPHANED) != 0) | ||||
continue; | continue; | ||||
childpgrp = q->p_pgrp; | fixjobc_kill_q(p, q, false); | ||||
if (!isjobproc(q->p_reaper, childpgrp) && | |||||
isjobproc(p, childpgrp)) | |||||
pgadjustjobc(childpgrp, false); | |||||
} | } | ||||
LIST_FOREACH(q, &p->p_orphans, p_orphan) | |||||
fixjobc_kill_q(p, q, false); | |||||
check_pgrp_jobc(pgrp); | |||||
} | } | ||||
void | void | ||||
killjobc(void) | killjobc(void) | ||||
{ | { | ||||
struct session *sp; | struct session *sp; | ||||
struct tty *tp; | struct tty *tp; | ||||
struct proc *p; | struct proc *p; | ||||
▲ Show 20 Lines • Show All 98 Lines • ▼ Show 20 Lines | if (refcount_release(&s->s_count)) { | ||||
proc_id_clear(PROC_ID_SESSION, s->s_sid); | proc_id_clear(PROC_ID_SESSION, s->s_sid); | ||||
mtx_destroy(&s->s_mtx); | mtx_destroy(&s->s_mtx); | ||||
free(s, M_SESSION); | free(s, M_SESSION); | ||||
} | } | ||||
} | } | ||||
#ifdef DDB | #ifdef DDB | ||||
static void | |||||
db_print_pgrp_one(struct pgrp *pgrp, struct proc *p) | |||||
{ | |||||
db_printf( | |||||
" pid %d at %p pr %d pgrp %p e %d jc %d\n", | |||||
p->p_pid, p, p->p_pptr == NULL ? -1 : p->p_pptr->p_pid, | |||||
p->p_pgrp, (p->p_treeflag & P_TREE_GRPEXITED) != 0, | |||||
p->p_pptr == NULL ? 0 : isjobproc(p->p_pptr, pgrp)); | |||||
} | |||||
DB_SHOW_COMMAND(pgrpdump, pgrpdump) | DB_SHOW_COMMAND(pgrpdump, pgrpdump) | ||||
{ | { | ||||
struct pgrp *pgrp; | struct pgrp *pgrp; | ||||
struct proc *p; | struct proc *p; | ||||
int i; | int i; | ||||
for (i = 0; i <= pgrphash; i++) { | for (i = 0; i <= pgrphash; i++) { | ||||
if (!LIST_EMPTY(&pgrphashtbl[i])) { | if (!LIST_EMPTY(&pgrphashtbl[i])) { | ||||
printf("\tindx %d\n", i); | db_printf("indx %d\n", i); | ||||
LIST_FOREACH(pgrp, &pgrphashtbl[i], pg_hash) { | LIST_FOREACH(pgrp, &pgrphashtbl[i], pg_hash) { | ||||
printf( | db_printf( | ||||
"\tpgrp %p, pgid %ld, sess %p, sesscnt %d, mem %p\n", | " pgrp %p, pgid %d, sess %p, sesscnt %d, mem %p\n", | ||||
(void *)pgrp, (long)pgrp->pg_id, | pgrp, (int)pgrp->pg_id, pgrp->pg_session, | ||||
(void *)pgrp->pg_session, | |||||
pgrp->pg_session->s_count, | pgrp->pg_session->s_count, | ||||
(void *)LIST_FIRST(&pgrp->pg_members)); | LIST_FIRST(&pgrp->pg_members)); | ||||
LIST_FOREACH(p, &pgrp->pg_members, p_pglist) { | LIST_FOREACH(p, &pgrp->pg_members, p_pglist) | ||||
printf("\t\tpid %ld addr %p pgrp %p\n", | db_print_pgrp_one(pgrp, p); | ||||
(long)p->p_pid, (void *)p, | |||||
(void *)p->p_pgrp); | |||||
} | |||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
#endif /* DDB */ | #endif /* DDB */ | ||||
/* | /* | ||||
* Calculate the kinfo_proc members which contain process-wide | * Calculate the kinfo_proc members which contain process-wide | ||||
▲ Show 20 Lines • Show All 2,324 Lines • Show Last 20 Lines |