FreeBSD kernel kern code
tty_info.c
Go to the documentation of this file.
1 /*-
2  * Copyright (c) 1982, 1986, 1990, 1991, 1993
3  * The Regents of the University of California. All rights reserved.
4  * (c) UNIX System Laboratories, Inc.
5  * All or some portions of this file are derived from material licensed
6  * to the University of California by American Telephone and Telegraph
7  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8  * the permission of UNIX System Laboratories, Inc.
9  *
10  * Copyright (c) 2002 Networks Associates Technologies, Inc.
11  * All rights reserved.
12  *
13  * Portions of this software were developed for the FreeBSD Project by
14  * ThinkSec AS and NAI Labs, the Security Research Division of Network
15  * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
16  * ("CBOSS"), as part of the DARPA CHATS research program.
17  *
18  * Redistribution and use in source and binary forms, with or without
19  * modification, are permitted provided that the following conditions
20  * are met:
21  * 1. Redistributions of source code must retain the above copyright
22  * notice, this list of conditions and the following disclaimer.
23  * 2. Redistributions in binary form must reproduce the above copyright
24  * notice, this list of conditions and the following disclaimer in the
25  * documentation and/or other materials provided with the distribution.
26  * 4. Neither the name of the University nor the names of its contributors
27  * may be used to endorse or promote products derived from this software
28  * without specific prior written permission.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33  * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40  * SUCH DAMAGE.
41  */
42 
43 #include <sys/cdefs.h>
44 __FBSDID("$BSDSUniX$");
45 
46 #include <sys/param.h>
47 #include <sys/lock.h>
48 #include <sys/mutex.h>
49 #include <sys/proc.h>
50 #include <sys/resourcevar.h>
51 #include <sys/sched.h>
52 #include <sys/systm.h>
53 #include <sys/tty.h>
54 
55 #include <vm/vm.h>
56 #include <vm/pmap.h>
57 #include <vm/vm_map.h>
58 
59 /*
60  * Returns 1 if p2 is "better" than p1
61  *
62  * The algorithm for picking the "interesting" process is thus:
63  *
64  * 1) Only foreground processes are eligible - implied.
65  * 2) Runnable processes are favored over anything else. The runner
66  * with the highest cpu utilization is picked (p_estcpu). Ties are
67  * broken by picking the highest pid.
68  * 3) The sleeper with the shortest sleep time is next. With ties,
69  * we pick out just "short-term" sleepers (P_SINTR == 0).
70  * 4) Further ties are broken by picking the highest pid.
71  */
72 
73 #define TESTAB(a, b) ((a)<<1 | (b))
74 #define ONLYA 2
75 #define ONLYB 1
76 #define BOTH 3
77 
78 static int
79 proc_sum(struct proc *p, fixpt_t *estcpup)
80 {
81  struct thread *td;
82  int estcpu;
83  int val;
84 
85  val = 0;
86  estcpu = 0;
87  FOREACH_THREAD_IN_PROC(p, td) {
88  thread_lock(td);
89  if (TD_ON_RUNQ(td) ||
90  TD_IS_RUNNING(td))
91  val = 1;
92  estcpu += sched_pctcpu(td);
93  thread_unlock(td);
94  }
95  *estcpup = estcpu;
96 
97  return (val);
98 }
99 
100 static int
101 thread_compare(struct thread *td, struct thread *td2)
102 {
103  int runa, runb;
104  int slpa, slpb;
105  fixpt_t esta, estb;
106 
107  if (td == NULL)
108  return (1);
109 
110  /*
111  * Fetch running stats, pctcpu usage, and interruptable flag.
112  */
113  thread_lock(td);
114  runa = TD_IS_RUNNING(td) | TD_ON_RUNQ(td);
115  slpa = td->td_flags & TDF_SINTR;
116  esta = sched_pctcpu(td);
117  thread_unlock(td);
118  thread_lock(td2);
119  runb = TD_IS_RUNNING(td2) | TD_ON_RUNQ(td2);
120  estb = sched_pctcpu(td2);
121  slpb = td2->td_flags & TDF_SINTR;
122  thread_unlock(td2);
123  /*
124  * see if at least one of them is runnable
125  */
126  switch (TESTAB(runa, runb)) {
127  case ONLYA:
128  return (0);
129  case ONLYB:
130  return (1);
131  case BOTH:
132  break;
133  }
134  /*
135  * favor one with highest recent cpu utilization
136  */
137  if (estb > esta)
138  return (1);
139  if (esta > estb)
140  return (0);
141  /*
142  * favor one sleeping in a non-interruptible sleep
143  */
144  switch (TESTAB(slpa, slpb)) {
145  case ONLYA:
146  return (0);
147  case ONLYB:
148  return (1);
149  case BOTH:
150  break;
151  }
152 
153  return (td < td2);
154 }
155 
156 static int
157 proc_compare(struct proc *p1, struct proc *p2)
158 {
159 
160  int runa, runb;
161  fixpt_t esta, estb;
162 
163  if (p1 == NULL)
164  return (1);
165 
166  /*
167  * Fetch various stats about these processes. After we drop the
168  * lock the information could be stale but the race is unimportant.
169  */
170  PROC_LOCK(p1);
171  runa = proc_sum(p1, &esta);
172  PROC_UNLOCK(p1);
173  PROC_LOCK(p2);
174  runb = proc_sum(p2, &estb);
175  PROC_UNLOCK(p2);
176 
177  /*
178  * see if at least one of them is runnable
179  */
180  switch (TESTAB(runa, runb)) {
181  case ONLYA:
182  return (0);
183  case ONLYB:
184  return (1);
185  case BOTH:
186  break;
187  }
188  /*
189  * favor one with highest recent cpu utilization
190  */
191  if (estb > esta)
192  return (1);
193  if (esta > estb)
194  return (0);
195  /*
196  * weed out zombies
197  */
198  switch (TESTAB(p1->p_state == PRS_ZOMBIE, p2->p_state == PRS_ZOMBIE)) {
199  case ONLYA:
200  return (1);
201  case ONLYB:
202  return (0);
203  case BOTH:
204  break;
205  }
206 
207  return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
208 }
209 
210 /*
211  * Report on state of foreground process group.
212  */
213 void
214 tty_info(struct tty *tp)
215 {
216  struct timeval rtime, utime, stime;
217  struct proc *p, *ppick;
218  struct thread *td, *tdpick;
219  const char *stateprefix, *state;
220  long rss;
221  int load, pctcpu;
222  pid_t pid;
223  char comm[MAXCOMLEN + 1];
224  struct rusage ru;
225 
226  tty_lock_assert(tp, MA_OWNED);
227 
228  if (tty_checkoutq(tp) == 0)
229  return;
230 
231  /* Print load average. */
232  load = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT;
233  ttyprintf(tp, "%sload: %d.%02d ", tp->t_column == 0 ? "" : "\n",
234  load / 100, load % 100);
235 
236  if (tp->t_session == NULL) {
237  ttyprintf(tp, "not a controlling terminal\n");
238  return;
239  }
240  if (tp->t_pgrp == NULL) {
241  ttyprintf(tp, "no foreground process group\n");
242  return;
243  }
244  PGRP_LOCK(tp->t_pgrp);
245  if (LIST_EMPTY(&tp->t_pgrp->pg_members)) {
246  PGRP_UNLOCK(tp->t_pgrp);
247  ttyprintf(tp, "empty foreground process group\n");
248  return;
249  }
250 
251  /*
252  * Pick the most interesting process and copy some of its
253  * state for printing later. This operation could rely on stale
254  * data as we can't hold the proc slock or thread locks over the
255  * whole list. However, we're guaranteed not to reference an exited
256  * thread or proc since we hold the tty locked.
257  */
258  p = NULL;
259  LIST_FOREACH(ppick, &tp->t_pgrp->pg_members, p_pglist)
260  if (proc_compare(p, ppick))
261  p = ppick;
262 
263  PROC_LOCK(p);
264  PGRP_UNLOCK(tp->t_pgrp);
265  td = NULL;
266  FOREACH_THREAD_IN_PROC(p, tdpick)
267  if (thread_compare(td, tdpick))
268  td = tdpick;
269  stateprefix = "";
270  thread_lock(td);
271  if (TD_IS_RUNNING(td))
272  state = "running";
273  else if (TD_ON_RUNQ(td) || TD_CAN_RUN(td))
274  state = "runnable";
275  else if (TD_IS_SLEEPING(td)) {
276  /* XXX: If we're sleeping, are we ever not in a queue? */
277  if (TD_ON_SLEEPQ(td))
278  state = td->td_wmesg;
279  else
280  state = "sleeping without queue";
281  } else if (TD_ON_LOCK(td)) {
282  state = td->td_lockname;
283  stateprefix = "*";
284  } else if (TD_IS_SUSPENDED(td))
285  state = "suspended";
286  else if (TD_AWAITING_INTR(td))
287  state = "intrwait";
288  else if (p->p_state == PRS_ZOMBIE)
289  state = "zombie";
290  else
291  state = "unknown";
292  pctcpu = (sched_pctcpu(td) * 10000 + FSCALE / 2) >> FSHIFT;
293  thread_unlock(td);
294  if (p->p_state == PRS_NEW || p->p_state == PRS_ZOMBIE)
295  rss = 0;
296  else
297  rss = pgtok(vmspace_resident_count(p->p_vmspace));
298  microuptime(&rtime);
299  timevalsub(&rtime, &p->p_stats->p_start);
300  rufetchcalc(p, &ru, &utime, &stime);
301  pid = p->p_pid;
302  strlcpy(comm, p->p_comm, sizeof comm);
303  PROC_UNLOCK(p);
304 
305  /* Print command, pid, state, rtime, utime, stime, %cpu, and rss. */
306  ttyprintf(tp,
307  " cmd: %s %d [%s%s] %ld.%02ldr %ld.%02ldu %ld.%02lds %d%% %ldk\n",
308  comm, pid, stateprefix, state,
309  (long)rtime.tv_sec, rtime.tv_usec / 10000,
310  (long)utime.tv_sec, utime.tv_usec / 10000,
311  (long)stime.tv_sec, stime.tv_usec / 10000,
312  pctcpu / 100, rss);
313 }
static int thread_compare(struct thread *td, struct thread *td2)
Definition: tty_info.c:101
void tty_info(struct tty *tp)
Definition: tty_info.c:214
int ttyprintf(struct tty *tp, const char *fmt,...)
Definition: subr_prf.c:229
static int proc_compare(struct proc *p1, struct proc *p2)
Definition: tty_info.c:157
void timevalsub(struct timeval *t1, const struct timeval *t2)
Definition: kern_time.c:885
#define ONLYA
Definition: tty_info.c:74
struct loadavg averunnable
Definition: kern_synch.c:92
__FBSDID("$BSDSUniX$")
void rufetchcalc(struct proc *p, struct rusage *ru, struct timeval *up, struct timeval *sp)
int tty_checkoutq(struct tty *tp)
Definition: tty.c:1767
#define TESTAB(a, b)
Definition: tty_info.c:73
static int proc_sum(struct proc *p, fixpt_t *estcpup)
Definition: tty_info.c:79
void microuptime(struct timeval *tvp)
Definition: kern_tc.c:194
#define ONLYB
Definition: tty_info.c:75
#define BOTH
Definition: tty_info.c:76
fixpt_t sched_pctcpu(struct thread *td)
Definition: sched_4bsd.c:1582