A variety of further cleanups to ttyinfo():

- Rename temporary variable names ("tmp", "tmp2") to more informative
  names ("load", "pctcpu", "rss", ...)

- Unclutter indentation and return paths: rather than lots of nested
  ifs, simply return earlier if it's not going to work out.  Simplify
  general structure and avoid "deep" code.

- Comment on the thread/process selection and locking.

- Correct handling of "running"/"runnable" states, avoid "unknown"
  that people were seeing for running processes.  This was due to
  a misunderstanding of the more complex state machine / inhibitors
  behavior of KSE.

- Do perform ttyinfo() printing on KSE (P_SA) processes, it seems
  generally to work.

While I initially attempted to formulate this as two commits (one
layout, the other content), I concluded that the layout changes were
really structural changes.

Many elements submitted by:  bde
This commit is contained in:
rwatson 2004-02-04 05:46:05 +00:00
parent 3120af18e7
commit 95d7d14f32

View File

@ -2385,96 +2385,103 @@ ttsetwater(struct tty *tp)
void void
ttyinfo(struct tty *tp) ttyinfo(struct tty *tp)
{ {
struct proc *p, *pick;
struct timeval utime, stime; struct timeval utime, stime;
const char *stmp, *sprefix; struct proc *p, *pick;
long ltmp;
int tmp;
struct thread *td; struct thread *td;
const char *stateprefix, *state;
long rss;
int load, pctcpu;
if (ttycheckoutq(tp,0) == 0) if (ttycheckoutq(tp,0) == 0)
return; return;
/* Print load average. */ /* Print load average. */
tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT; load = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT;
ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100); ttyprintf(tp, "load: %d.%02d ", load / 100, load % 100);
if (tp->t_session == NULL) /*
* On return following a ttyprintf(), we set tp->t_rocount to 0 so
* that pending input will be retyped on BS.
*/
if (tp->t_session == NULL) {
ttyprintf(tp, "not a controlling terminal\n"); ttyprintf(tp, "not a controlling terminal\n");
else if (tp->t_pgrp == NULL) tp->t_rocount = 0;
ttyprintf(tp, "no foreground process group\n"); return;
else {
PGRP_LOCK(tp->t_pgrp);
if ((p = LIST_FIRST(&tp->t_pgrp->pg_members)) == 0) {
PGRP_UNLOCK(tp->t_pgrp);
ttyprintf(tp, "empty foreground process group\n");
} else {
mtx_lock_spin(&sched_lock);
/* Pick interesting process. */
for (pick = NULL; p != 0; p = LIST_NEXT(p, p_pglist))
if (proc_compare(pick, p))
pick = p;
PGRP_UNLOCK(tp->t_pgrp);
td = FIRST_THREAD_IN_PROC(pick);
sprefix = "";
if (pick->p_flag & P_SA) {
stmp = "KSE" ; /* XXXKSE */
} else {
if (td != NULL) {
if (TD_ON_RUNQ(td)) {
if (TD_IS_RUNNING(td))
stmp = "running";
else
stmp = "runnable";
} else if (TD_IS_SLEEPING(td)) {
if (TD_ON_SLEEPQ(td))
stmp = td->td_wmesg;
else
stmp = "unknown";
} else if (TD_ON_LOCK(td)) {
stmp = td->td_lockname;
sprefix = "*";
} else if (TD_IS_SUSPENDED(td)) {
stmp = "suspended";
} else if (TD_AWAITING_INTR(td)) {
stmp = "intrwait";
} else {
stmp = "unknown";
}
} else {
stmp = "threadless";
panic("ttyinfo: no thread!?");
}
}
calcru(pick, &utime, &stime, NULL);
if (pick->p_state == PRS_NEW ||
pick->p_state == PRS_ZOMBIE) {
ltmp = 0;
} else {
ltmp = pgtok(
vmspace_resident_count(pick->p_vmspace));
}
mtx_unlock_spin(&sched_lock);
ttyprintf(tp, " cmd: %s %d [%s%s] ", pick->p_comm,
pick->p_pid, sprefix, stmp);
/* Print user time. */
ttyprintf(tp, "%ld.%02ldu ",
utime.tv_sec, utime.tv_usec / 10000);
/* Print system time. */
ttyprintf(tp, "%ld.%02lds ",
(long)stime.tv_sec, stime.tv_usec / 10000);
/* Print percentage cpu, resident set size. */
ttyprintf(tp, "%d%% %ldk\n", tmp / 100, ltmp);
}
} }
tp->t_rocount = 0; /* so pending input will be retyped if BS */ if (tp->t_pgrp == NULL) {
ttyprintf(tp, "no foreground process group\n");
tp->t_rocount = 0;
return;
}
PGRP_LOCK(tp->t_pgrp);
if ((p = LIST_FIRST(&tp->t_pgrp->pg_members)) == 0) {
PGRP_UNLOCK(tp->t_pgrp);
ttyprintf(tp, "empty foreground process group\n");
tp->t_rocount = 0;
return;
}
/*
* Pick the most interesting process and copy some of its
* state for printing later. sched_lock must be held for
* most parts of this. Holding it throughout is simplest
* and prevents even unimportant inconsistencies in the
* copy of the state, but may increase interrupt latency
* too much.
*/
mtx_lock_spin(&sched_lock);
for (pick = NULL; p != 0; p = LIST_NEXT(p, p_pglist))
if (proc_compare(pick, p))
pick = p;
PGRP_UNLOCK(tp->t_pgrp);
td = FIRST_THREAD_IN_PROC(pick); /* XXXKSE */
#if 0
KASSERT(td != NULL, ("ttyinfo: no thread"));
#else
if (td == NULL) {
mtx_unlock_spin(&sched_lock);
ttyprintf(tp, "foreground process without thread\n");
tp->t_rocount = 0;
return;
}
#endif
stateprefix = "";
if (TD_IS_RUNNING(td))
state = "running";
else if (TD_ON_RUNQ(td) || TD_CAN_RUN(td))
state = "runnable";
else if (TD_IS_SLEEPING(td)) {
/* XXX: If we're sleeping, are we ever not in a queue? */
if (TD_ON_SLEEPQ(td))
state = td->td_wmesg;
else
state = "sleeping without queue";
} else if (TD_ON_LOCK(td)) {
state = td->td_lockname;
stateprefix = "*";
} else if (TD_IS_SUSPENDED(td))
state = "suspended";
else if (TD_AWAITING_INTR(td))
state = "intrwait";
else
state = "unknown";
calcru(pick, &utime, &stime, NULL);
pctcpu = (td->td_kse->ke_pctcpu * 10000 + FSCALE / 2) >> FSHIFT;
if (pick->p_state == PRS_NEW || pick->p_state == PRS_ZOMBIE)
rss = 0;
else
rss = pgtok(vmspace_resident_count(pick->p_vmspace));
mtx_unlock_spin(&sched_lock);
/* Print command, pid, state, utime, stime, %cpu, and rss. */
ttyprintf(tp,
" cmd: %s %d [%s%s] %ld.%02ldu %ld.%02lds %d%% %ldk\n",
pick->p_comm, pick->p_pid, stateprefix, state,
(long)utime.tv_sec, utime.tv_usec / 10000,
(long)stime.tv_sec, stime.tv_usec / 10000,
pctcpu / 100, rss);
tp->t_rocount = 0;
} }
/* /*