diff options
author | 2014-05-25 18:57:07 +0000 | |
---|---|---|
committer | 2014-05-25 18:57:07 +0000 | |
commit | 494499d6f03ff30a15dfd0b8498eb92629bc23ee (patch) | |
tree | 99af3be01634769e8e0578e834cc925c86cd55f3 | |
parent | In access(), use the real UID/GID for the path search too. (diff) | |
download | wireguard-openbsd-494499d6f03ff30a15dfd0b8498eb92629bc23ee.tar.xz wireguard-openbsd-494499d6f03ff30a15dfd0b8498eb92629bc23ee.zip |
Handle threaded processes correctly when processing kerninfo status requests
(aka ^T), summing CPU and check runnable/running status of all threads.
ok deraadt@
-rw-r--r-- | sys/kern/tty.c | 197 |
1 files changed, 107 insertions, 90 deletions
diff --git a/sys/kern/tty.c b/sys/kern/tty.c index 00874e8f3d6..9afcad6eb8b 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tty.c,v 1.105 2014/03/22 06:05:45 guenther Exp $ */ +/* $OpenBSD: tty.c,v 1.106 2014/05/25 18:57:07 guenther Exp $ */ /* $NetBSD: tty.c,v 1.68.4.2 1996/06/06 16:04:52 thorpej Exp $ */ /*- @@ -70,7 +70,6 @@ static void ttyblock(struct tty *); void ttyunblock(struct tty *); static void ttyecho(int, struct tty *); static void ttyrubo(struct tty *, int); -static int proc_compare(struct proc *, struct proc *); void ttkqflush(struct klist *klist); int filt_ttyread(struct knote *kn, long hint); void filt_ttyrdetach(struct knote *kn); @@ -2106,13 +2105,36 @@ ttsetwater(struct tty *tp) } /* + * Get the total estcpu for a process, summing across threads. + * Returns true if at least one thread is runnable/running. + */ +static int +process_sum(struct process *pr, fixpt_t *estcpup) +{ + struct proc *p; + fixpt_t estcpu; + int ret; + + ret = 0; + estcpu = 0; + TAILQ_FOREACH(p, &pr->ps_threads, p_thr_link) { + if (p->p_stat == SRUN || p->p_stat == SONPROC) + ret = 1; + estcpu += p->p_pctcpu; + } + + *estcpup = estcpu; + return (ret); +} + +/* * Report on state of foreground process group. */ void ttyinfo(struct tty *tp) { - struct process *pr; - struct proc *pick; + struct process *pr, *pickpr; + struct proc *p, *pick; struct timespec utime, stime; int tmp; @@ -2130,20 +2152,52 @@ ttyinfo(struct tty *tp) else if ((pr = LIST_FIRST(&tp->t_pgrp->pg_members)) == NULL) ttyprintf(tp, "empty foreground process group\n"); else { - int pctcpu; + const char *state; + fixpt_t pctcpu, pctcpu2; + int run, run2; + int calc_pctcpu; long rss; - /* Pick interesting process. */ - for (pick = NULL; pr != NULL; pr = LIST_NEXT(pr, ps_pglist)) - if (proc_compare(pick, pr->ps_mainproc)) - pick = pr->ps_mainproc; + /* + * Pick the most active process: + * - prefer at least one running/runnable thread + * - prefer higher total pctcpu + * - prefer non-zombie + * Otherwise take the most recently added to this process group + */ + pickpr = pr; + run = process_sum(pickpr, &pctcpu); + while ((pr = LIST_NEXT(pr, ps_pglist)) != NULL) { + run2 = process_sum(pr, &pctcpu2); + if (run) { + /* + * pick is running; is p running w/same or + * more cpu? + */ + if (run2 && pctcpu2 >= pctcpu) + goto update_pickpr; + continue; + } + /* pick isn't running; is p running *or* w/more cpu? */ + if (run2 || pctcpu2 > pctcpu) + goto update_pickpr; + + /* if p has less cpu or is zombie, then it's worse */ + if (pctcpu2 < pctcpu || P_ZOMBIE(pr->ps_mainproc)) + continue; +update_pickpr: + pickpr = pr; + run = run2; + pctcpu = pctcpu2; + } /* Calculate percentage cpu, resident set size. */ - pctcpu = (pick->p_pctcpu * 10000 + FSCALE / 2) >> FSHIFT; - rss = pick->p_stat == SIDL || P_ZOMBIE(pick) ? 0 : - vm_resident_count(pick->p_vmspace); + calc_pctcpu = (pctcpu * 10000 + FSCALE / 2) >> FSHIFT; + rss = (!P_ZOMBIE(pickpr->ps_mainproc) && + pickpr->ps_mainproc->p_stat != SIDL) ? 0 : + vm_resident_count(pickpr->ps_vmspace); - calctsru(&pick->p_p->ps_tu, &utime, &stime, NULL); + calctsru(&pickpr->ps_tu, &utime, &stime, NULL); /* Round up and print user time. */ utime.tv_nsec += 5000000; @@ -2159,92 +2213,55 @@ ttyinfo(struct tty *tp) stime.tv_nsec -= 1000000000; } + /* + * Find the most active thread: + * - prefer runnable + * - prefer higher pctcpu + * - prefer living + * Otherwise take the newest thread + */ + pick = p = TAILQ_FIRST(&pickpr->ps_threads); + run = p->p_stat == SRUN || p->p_stat == SONPROC; + pctcpu = p->p_pctcpu; + while ((p = TAILQ_NEXT(p, p_thr_link)) != NULL) { + run2 = p->p_stat == SRUN || p->p_stat == SONPROC; + pctcpu2 = p->p_pctcpu; + if (run) { + /* + * pick is running; is p running w/same or + * more cpu? + */ + if (run2 && pctcpu2 >= pctcpu) + goto update_pick; + continue; + } + /* pick isn't running; is p running *or* w/more cpu? */ + if (run2 || pctcpu2 > pctcpu) + goto update_pick; + + /* if p has less cpu or is exiting, then it's worse */ + if (pctcpu2 < pctcpu || p->p_flag & P_WEXIT) + continue; +update_pick: + pick = p; + run = run2; + pctcpu = p->p_pctcpu; + } + state = pick->p_stat == SONPROC ? "running" : + pick->p_stat == SRUN ? "runnable" : + pick->p_wmesg ? pick->p_wmesg : "iowait"; + ttyprintf(tp, " cmd: %s %d [%s] %lld.%02ldu %lld.%02lds %d%% %ldk\n", - pick->p_comm, pick->p_pid, - pick->p_stat == SONPROC ? "running" : - pick->p_stat == SRUN ? "runnable" : - pick->p_wmesg ? pick->p_wmesg : "iowait", + pick->p_comm, pickpr->ps_pid, state, (long long)utime.tv_sec, utime.tv_nsec / 10000000, (long long)stime.tv_sec, stime.tv_nsec / 10000000, - pctcpu / 100, rss); + calc_pctcpu / 100, rss); } tp->t_rocount = 0; /* so pending input will be retyped if BS */ } /* - * Returns 1 if p2 is "better" than p1 - * - * The algorithm for picking the "interesting" process is thus: - * - * 1) Only foreground processes are eligible - implied. - * 2) Runnable processes are favored over anything else. The runner - * with the highest cpu utilization is picked (p_estcpu). Ties are - * broken by picking the highest pid. - * 3) The sleeper with the shortest sleep time is next. With ties, - * we pick out just "short-term" sleepers (P_SINTR == 0). - * 4) Further ties are broken by picking the highest pid. - */ -#define ISRUN(p) (((p)->p_stat == SRUN) || ((p)->p_stat == SIDL) || \ - ((p)->p_stat == SONPROC)) -#define TESTAB(a, b) ((a)<<1 | (b)) -#define ONLYA 2 -#define ONLYB 1 -#define BOTH 3 - -static int -proc_compare(struct proc *p1, struct proc *p2) -{ - - if (p1 == NULL) - return (1); - /* - * see if at least one of them is runnable - */ - switch (TESTAB(ISRUN(p1), ISRUN(p2))) { - case ONLYA: - return (0); - case ONLYB: - return (1); - case BOTH: - /* - * tie - favor one with highest recent cpu utilization - */ - if (p2->p_estcpu > p1->p_estcpu) - return (1); - if (p1->p_estcpu > p2->p_estcpu) - return (0); - return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ - } - /* - * weed out zombies - */ - switch (TESTAB(P_ZOMBIE(p1), P_ZOMBIE(p2))) { - case ONLYA: - return (1); - case ONLYB: - return (0); - case BOTH: - return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ - } - /* - * pick the one with the smallest sleep time - */ - if (p2->p_slptime > p1->p_slptime) - return (0); - if (p1->p_slptime > p2->p_slptime) - return (1); - /* - * favor one sleeping in a non-interruptible sleep - */ - if (p1->p_flag & P_SINTR && (p2->p_flag & P_SINTR) == 0) - return (1); - if (p2->p_flag & P_SINTR && (p1->p_flag & P_SINTR) == 0) - return (0); - return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ -} - -/* * Output char to tty; console putchar style. */ int |