proc: eliminate the zombproc list

It is not needed by anything in the kernel and it slightly drives up contention
on both proctree and allproc locks.

Reviewed by:	kib
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D21447
This commit is contained in:
Mateusz Guzik 2019-08-28 16:18:23 +00:00
parent b5d239cb97
commit 88cc62e5a5
6 changed files with 138 additions and 152 deletions

View File

@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$");
static void dumpthread(volatile struct proc *p, volatile struct thread *td,
int all);
static void db_ps_proc(struct proc *p);
static int ps_mode;
/*
@ -105,146 +106,157 @@ dump_args(volatile struct proc *p)
void
db_ps(db_expr_t addr, bool hasaddr, db_expr_t count, char *modif)
{
volatile struct proc *p, *pp;
volatile struct thread *td;
struct ucred *cred;
struct pgrp *pgrp;
char state[9];
int np, rflag, sflag, dflag, lflag, wflag;
struct proc *p;
int i, j;
ps_mode = modif[0] == 'a' ? PRINT_ARGS : PRINT_NONE;
np = nprocs;
if (!LIST_EMPTY(&allproc))
p = LIST_FIRST(&allproc);
else
p = &proc0;
#ifdef __LP64__
db_printf(" pid ppid pgrp uid state wmesg wchan cmd\n");
#else
db_printf(" pid ppid pgrp uid state wmesg wchan cmd\n");
#endif
while (--np >= 0 && !db_pager_quit) {
if (p == NULL) {
db_printf("oops, ran out of processes early!\n");
break;
if (!LIST_EMPTY(&allproc))
p = LIST_FIRST(&allproc);
else
p = &proc0;
for (; p != NULL && !db_pager_quit; p = LIST_NEXT(p, p_list))
db_ps_proc(p);
/*
* Do zombies.
*/
for (i = 0; i < pidhashlock + 1 && !db_pager_quit; i++) {
for (j = i; j <= pidhash && !db_pager_quit; j += pidhashlock + 1) {
LIST_FOREACH(p, &pidhashtbl[j], p_hash) {
if (p->p_state == PRS_ZOMBIE)
db_ps_proc(p);
}
}
pp = p->p_pptr;
if (pp == NULL)
pp = p;
}
}
cred = p->p_ucred;
pgrp = p->p_pgrp;
db_printf("%5d %5d %5d %5d ", p->p_pid, pp->p_pid,
pgrp != NULL ? pgrp->pg_id : 0,
cred != NULL ? cred->cr_ruid : 0);
static void
db_ps_proc(struct proc *p)
{
volatile struct proc *pp;
volatile struct thread *td;
struct ucred *cred;
struct pgrp *pgrp;
char state[9];
int rflag, sflag, dflag, lflag, wflag;
/* Determine our primary process state. */
switch (p->p_state) {
case PRS_NORMAL:
if (P_SHOULDSTOP(p))
state[0] = 'T';
else {
/*
* One of D, L, R, S, W. For a
* multithreaded process we will use
* the state of the thread with the
* highest precedence. The
* precendence order from high to low
* is R, L, D, S, W. If no thread is
* in a sane state we use '?' for our
* primary state.
*/
rflag = sflag = dflag = lflag = wflag = 0;
FOREACH_THREAD_IN_PROC(p, td) {
if (td->td_state == TDS_RUNNING ||
td->td_state == TDS_RUNQ ||
td->td_state == TDS_CAN_RUN)
rflag++;
if (TD_ON_LOCK(td))
lflag++;
if (TD_IS_SLEEPING(td)) {
if (!(td->td_flags & TDF_SINTR))
dflag++;
else
sflag++;
}
if (TD_AWAITING_INTR(td))
wflag++;
pp = p->p_pptr;
if (pp == NULL)
pp = p;
cred = p->p_ucred;
pgrp = p->p_pgrp;
db_printf("%5d %5d %5d %5d ", p->p_pid, pp->p_pid,
pgrp != NULL ? pgrp->pg_id : 0,
cred != NULL ? cred->cr_ruid : 0);
/* Determine our primary process state. */
switch (p->p_state) {
case PRS_NORMAL:
if (P_SHOULDSTOP(p))
state[0] = 'T';
else {
/*
* One of D, L, R, S, W. For a
* multithreaded process we will use
* the state of the thread with the
* highest precedence. The
* precendence order from high to low
* is R, L, D, S, W. If no thread is
* in a sane state we use '?' for our
* primary state.
*/
rflag = sflag = dflag = lflag = wflag = 0;
FOREACH_THREAD_IN_PROC(p, td) {
if (td->td_state == TDS_RUNNING ||
td->td_state == TDS_RUNQ ||
td->td_state == TDS_CAN_RUN)
rflag++;
if (TD_ON_LOCK(td))
lflag++;
if (TD_IS_SLEEPING(td)) {
if (!(td->td_flags & TDF_SINTR))
dflag++;
else
sflag++;
}
if (rflag)
state[0] = 'R';
else if (lflag)
state[0] = 'L';
else if (dflag)
state[0] = 'D';
else if (sflag)
state[0] = 'S';
else if (wflag)
state[0] = 'W';
else
state[0] = '?';
if (TD_AWAITING_INTR(td))
wflag++;
}
break;
case PRS_NEW:
state[0] = 'N';
break;
case PRS_ZOMBIE:
state[0] = 'Z';
break;
default:
state[0] = 'U';
break;
if (rflag)
state[0] = 'R';
else if (lflag)
state[0] = 'L';
else if (dflag)
state[0] = 'D';
else if (sflag)
state[0] = 'S';
else if (wflag)
state[0] = 'W';
else
state[0] = '?';
}
state[1] = '\0';
break;
case PRS_NEW:
state[0] = 'N';
break;
case PRS_ZOMBIE:
state[0] = 'Z';
break;
default:
state[0] = 'U';
break;
}
state[1] = '\0';
/* Additional process state flags. */
if (!(p->p_flag & P_INMEM))
strlcat(state, "W", sizeof(state));
if (p->p_flag & P_TRACED)
strlcat(state, "X", sizeof(state));
if (p->p_flag & P_WEXIT && p->p_state != PRS_ZOMBIE)
strlcat(state, "E", sizeof(state));
if (p->p_flag & P_PPWAIT)
strlcat(state, "V", sizeof(state));
if (p->p_flag & P_SYSTEM || p->p_lock > 0)
strlcat(state, "L", sizeof(state));
if (p->p_pgrp != NULL && p->p_session != NULL &&
SESS_LEADER(p))
strlcat(state, "s", sizeof(state));
/* Cheated here and didn't compare pgid's. */
if (p->p_flag & P_CONTROLT)
strlcat(state, "+", sizeof(state));
if (cred != NULL && jailed(cred))
strlcat(state, "J", sizeof(state));
db_printf(" %-6.6s ", state);
if (p->p_flag & P_HADTHREADS) {
/* Additional process state flags. */
if (!(p->p_flag & P_INMEM))
strlcat(state, "W", sizeof(state));
if (p->p_flag & P_TRACED)
strlcat(state, "X", sizeof(state));
if (p->p_flag & P_WEXIT && p->p_state != PRS_ZOMBIE)
strlcat(state, "E", sizeof(state));
if (p->p_flag & P_PPWAIT)
strlcat(state, "V", sizeof(state));
if (p->p_flag & P_SYSTEM || p->p_lock > 0)
strlcat(state, "L", sizeof(state));
if (p->p_pgrp != NULL && p->p_session != NULL &&
SESS_LEADER(p))
strlcat(state, "s", sizeof(state));
/* Cheated here and didn't compare pgid's. */
if (p->p_flag & P_CONTROLT)
strlcat(state, "+", sizeof(state));
if (cred != NULL && jailed(cred))
strlcat(state, "J", sizeof(state));
db_printf(" %-6.6s ", state);
if (p->p_flag & P_HADTHREADS) {
#ifdef __LP64__
db_printf(" (threaded) ");
db_printf(" (threaded) ");
#else
db_printf(" (threaded) ");
db_printf(" (threaded) ");
#endif
if (p->p_flag & P_SYSTEM)
db_printf("[");
db_printf("%s", p->p_comm);
if (p->p_flag & P_SYSTEM)
db_printf("]");
if (ps_mode == PRINT_ARGS) {
db_printf(" ");
dump_args(p);
}
db_printf("\n");
if (p->p_flag & P_SYSTEM)
db_printf("[");
db_printf("%s", p->p_comm);
if (p->p_flag & P_SYSTEM)
db_printf("]");
if (ps_mode == PRINT_ARGS) {
db_printf(" ");
dump_args(p);
}
FOREACH_THREAD_IN_PROC(p, td) {
dumpthread(p, td, p->p_flag & P_HADTHREADS);
if (db_pager_quit)
break;
}
p = LIST_NEXT(p, p_list);
if (p == NULL && np > 0)
p = LIST_FIRST(&zombproc);
db_printf("\n");
}
FOREACH_THREAD_IN_PROC(p, td) {
dumpthread(p, td, p->p_flag & P_HADTHREADS);
if (db_pager_quit)
break;
}
}

View File

@ -125,11 +125,7 @@ db_lookup_thread(db_expr_t addr, bool check_pid)
if (td != NULL)
return (td);
if (check_pid) {
FOREACH_PROC_IN_SYSTEM(p) {
if (p->p_pid == decaddr)
return (FIRST_THREAD_IN_PROC(p));
}
LIST_FOREACH(p, &zombproc, p_list) {
LIST_FOREACH(p, PIDHASH(decaddr), p_hash) {
if (p->p_pid == decaddr)
return (FIRST_THREAD_IN_PROC(p));
}
@ -151,11 +147,7 @@ db_lookup_proc(db_expr_t addr)
decaddr = db_hex2dec(addr);
if (decaddr != -1) {
FOREACH_PROC_IN_SYSTEM(p) {
if (p->p_pid == decaddr)
return (p);
}
LIST_FOREACH(p, &zombproc, p_list) {
LIST_FOREACH(p, PIDHASH(decaddr), p_hash) {
if (p->p_pid == decaddr)
return (p);
}

View File

@ -447,13 +447,10 @@ exit1(struct thread *td, int rval, int signo)
WITNESS_WARN(WARN_PANIC, NULL, "process (pid %d) exiting", p->p_pid);
/*
* Move proc from allproc queue to zombproc.
* Remove from allproc. It still sits in the hash.
*/
sx_xlock(&allproc_lock);
sx_xlock(&zombproc_lock);
LIST_REMOVE(p, p_list);
LIST_INSERT_HEAD(&zombproc, p, p_list);
sx_xunlock(&zombproc_lock);
sx_xunlock(&allproc_lock);
sx_xlock(&proctree_lock);
@ -903,9 +900,6 @@ proc_reap(struct thread *td, struct proc *p, int *status, int options)
* Remove other references to this process to ensure we have an
* exclusive reference.
*/
sx_xlock(&zombproc_lock);
LIST_REMOVE(p, p_list); /* off zombproc */
sx_xunlock(&zombproc_lock);
sx_xlock(PIDHASHLOCK(p->p_pid));
LIST_REMOVE(p, p_hash);
sx_xunlock(PIDHASHLOCK(p->p_pid));

View File

@ -124,9 +124,7 @@ u_long pidhashlock;
struct pgrphashhead *pgrphashtbl;
u_long pgrphash;
struct proclist allproc;
struct proclist zombproc;
struct sx __exclusive_cache_line allproc_lock;
struct sx __exclusive_cache_line zombproc_lock;
struct sx __exclusive_cache_line proctree_lock;
struct mtx __exclusive_cache_line ppeers_lock;
struct mtx __exclusive_cache_line procid_lock;
@ -177,12 +175,10 @@ procinit(void)
u_long i;
sx_init(&allproc_lock, "allproc");
sx_init(&zombproc_lock, "zombproc");
sx_init(&proctree_lock, "proctree");
mtx_init(&ppeers_lock, "p_peers", NULL, MTX_DEF);
mtx_init(&procid_lock, "procid", NULL, MTX_DEF);
LIST_INIT(&allproc);
LIST_INIT(&zombproc);
pidhashtbl = hashinit(maxproc / 4, M_PROC, &pidhash);
pidhashlock = (pidhash + 1) / 64;
if (pidhashlock > 0)

View File

@ -1256,17 +1256,11 @@ racctd(void)
sx_slock(&allproc_lock);
sx_slock(&zombproc_lock);
LIST_FOREACH(p, &zombproc, p_list) {
PROC_LOCK(p);
racct_set(p, RACCT_PCTCPU, 0);
PROC_UNLOCK(p);
}
sx_sunlock(&zombproc_lock);
FOREACH_PROC_IN_SYSTEM(p) {
PROC_LOCK(p);
if (p->p_state != PRS_NORMAL) {
if (p->p_state == PRS_ZOMBIE)
racct_set(p, RACCT_PCTCPU, 0);
PROC_UNLOCK(p);
continue;
}

View File

@ -967,7 +967,6 @@ extern u_long pgrphash;
extern struct sx allproc_lock;
extern int allproc_gen;
extern struct sx zombproc_lock;
extern struct sx proctree_lock;
extern struct mtx ppeers_lock;
extern struct mtx procid_lock;
@ -985,7 +984,6 @@ LIST_HEAD(proclist, proc);
TAILQ_HEAD(procqueue, proc);
TAILQ_HEAD(threadqueue, thread);
extern struct proclist allproc; /* List of all processes. */
extern struct proclist zombproc; /* List of zombie processes. */
extern struct proc *initproc, *pageproc; /* Process slots for init, pager. */
extern struct uma_zone *proc_zone;