Print this page
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/prstat/prstat.c
+++ new/usr/src/cmd/prstat/prstat.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
|
↓ open down ↓ |
18 lines elided |
↑ open up ↑ |
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2013 Gary Mills
24 24 *
25 25 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
26 26 * Use is subject to license terms.
27 27 *
28 28 * Portions Copyright 2009 Chad Mynhier
29 - * Copyright 2012 Joyent, Inc. All rights reserved.
30 29 */
31 30
32 31 #include <sys/types.h>
33 32 #include <sys/resource.h>
34 33 #include <sys/loadavg.h>
35 34 #include <sys/time.h>
36 35 #include <sys/pset.h>
37 36 #include <sys/vm_usage.h>
38 37 #include <zone.h>
39 38 #include <libzonecfg.h>
40 39
41 40 #include <stdio.h>
42 41 #include <stdlib.h>
43 42 #include <unistd.h>
44 43 #include <dirent.h>
45 44 #include <string.h>
46 45 #include <errno.h>
47 46 #include <poll.h>
48 47 #include <ctype.h>
49 48 #include <fcntl.h>
50 49 #include <limits.h>
51 50 #include <signal.h>
52 51 #include <time.h>
53 52 #include <project.h>
54 53
55 54 #include <langinfo.h>
56 55 #include <libintl.h>
57 56 #include <locale.h>
58 57
59 58 #include "prstat.h"
60 59 #include "prutil.h"
61 60 #include "prtable.h"
62 61 #include "prsort.h"
63 62 #include "prfile.h"
64 63
65 64 /*
66 65 * x86 <sys/regs.h> ERR conflicts with <curses.h> ERR. For the purposes
67 66 * of this file, we care about the curses.h ERR so include that last.
68 67 */
69 68
70 69 #if defined(ERR)
71 70 #undef ERR
72 71 #endif
73 72
74 73 #ifndef TEXT_DOMAIN /* should be defined by cc -D */
75 74 #define TEXT_DOMAIN "SYS_TEST" /* use this only if it wasn't */
76 75 #endif
77 76
78 77 #include <curses.h>
79 78 #include <term.h>
80 79
81 80 #define LOGIN_WIDTH 8
82 81 #define ZONE_WIDTH 28
83 82 #define PROJECT_WIDTH 28
84 83
85 84 #define PSINFO_HEADER_PROC \
86 85 " PID USERNAME SIZE RSS STATE PRI NICE TIME CPU PROCESS/NLWP "
87 86 #define PSINFO_HEADER_PROC_LGRP \
88 87 " PID USERNAME SIZE RSS STATE PRI NICE TIME CPU LGRP PROCESS/NLWP "
89 88 #define PSINFO_HEADER_LWP \
90 89 " PID USERNAME SIZE RSS STATE PRI NICE TIME CPU PROCESS/LWPID "
91 90 #define PSINFO_HEADER_LWP_LGRP \
92 91 " PID USERNAME SIZE RSS STATE PRI NICE TIME CPU LGRP PROCESS/LWPID "
93 92 #define USAGE_HEADER_PROC \
94 93 " PID USERNAME USR SYS TRP TFL DFL LCK SLP LAT VCX ICX SCL SIG PROCESS/NLWP "
95 94 #define USAGE_HEADER_LWP \
96 95 " PID USERNAME USR SYS TRP TFL DFL LCK SLP LAT VCX ICX SCL SIG PROCESS/LWPID "
97 96 #define USER_HEADER_PROC \
98 97 " NPROC USERNAME SWAP RSS MEMORY TIME CPU "
99 98 #define USER_HEADER_LWP \
100 99 " NLWP USERNAME SWAP RSS MEMORY TIME CPU "
101 100 #define TASK_HEADER_PROC \
102 101 "TASKID NPROC SWAP RSS MEMORY TIME CPU PROJECT "
103 102 #define TASK_HEADER_LWP \
104 103 "TASKID NLWP SWAP RSS MEMORY TIME CPU PROJECT "
105 104 #define PROJECT_HEADER_PROC \
106 105 "PROJID NPROC SWAP RSS MEMORY TIME CPU PROJECT "
107 106 #define PROJECT_HEADER_LWP \
108 107 "PROJID NLWP SWAP RSS MEMORY TIME CPU PROJECT "
109 108 #define ZONE_HEADER_PROC \
110 109 "ZONEID NPROC SWAP RSS MEMORY TIME CPU ZONE "
111 110 #define ZONE_HEADER_LWP \
112 111 "ZONEID NLWP SWAP RSS MEMORY TIME CPU ZONE "
113 112 #define PSINFO_LINE \
114 113 "%6d %-8s %5s %5s %-6s %3s %3s %9s %3.3s%% %-.16s/%d"
115 114 #define PSINFO_LINE_LGRP \
116 115 "%6d %-8s %5s %5s %-6s %3s %3s %9s %3.3s%% %4d %-.16s/%d"
117 116 #define USAGE_LINE \
118 117 "%6d %-8s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s "\
119 118 "%3.3s %3.3s %-.12s/%d"
120 119 #define USER_LINE \
121 120 "%6d %-8s %5.5s %5.5s %3.3s%% %9s %3.3s%%"
122 121 #define TASK_LINE \
123 122 "%6d %8d %5s %5s %3.3s%% %9s %3.3s%% %28s"
124 123 #define PROJECT_LINE \
125 124 "%6d %8d %5s %5s %3.3s%% %9s %3.3s%% %28s"
126 125 #define ZONE_LINE \
127 126 "%6d %8d %5s %5s %3.3s%% %9s %3.3s%% %28s"
128 127
129 128 #define TOTAL_LINE \
130 129 "Total: %d processes, %d lwps, load averages: %3.2f, %3.2f, %3.2f"
131 130
132 131 /* global variables */
133 132
134 133 static char *t_ulon; /* termcap: start underline */
135 134 static char *t_uloff; /* termcap: end underline */
136 135 static char *t_up; /* termcap: cursor 1 line up */
137 136 static char *t_eol; /* termcap: clear end of line */
138 137 static char *t_smcup; /* termcap: cursor mvcap on */
139 138 static char *t_rmcup; /* termcap: cursor mvcap off */
140 139 static char *t_home; /* termcap: move cursor home */
141 140 static char *movecur = NULL; /* termcap: move up string */
142 141 static char *empty_string = "\0"; /* termcap: empty string */
143 142 static uint_t print_movecur = FALSE; /* print movecur or not */
144 143 static int is_curses_on = FALSE; /* current curses state */
145 144
146 145 static table_t pid_tbl = {0, 0, NULL}; /* selected processes */
147 146 static table_t cpu_tbl = {0, 0, NULL}; /* selected processors */
148 147 static table_t set_tbl = {0, 0, NULL}; /* selected processor sets */
149 148 static table_t prj_tbl = {0, 0, NULL}; /* selected projects */
150 149 static table_t tsk_tbl = {0, 0, NULL}; /* selected tasks */
151 150 static table_t lgr_tbl = {0, 0, NULL}; /* selected lgroups */
152 151 static zonetbl_t zone_tbl = {0, 0, NULL}; /* selected zones */
153 152 static uidtbl_t euid_tbl = {0, 0, NULL}; /* selected effective users */
154 153 static uidtbl_t ruid_tbl = {0, 0, NULL}; /* selected real users */
155 154
156 155 static uint_t total_procs; /* total number of procs */
157 156 static uint_t total_lwps; /* total number of lwps */
158 157 static float total_cpu; /* total cpu usage */
159 158 static float total_mem; /* total memory usage */
160 159
161 160 static list_t lwps; /* list of lwps/processes */
162 161 static list_t users; /* list of users */
163 162 static list_t tasks; /* list of tasks */
164 163 static list_t projects; /* list of projects */
165 164 static list_t zones; /* list of zones */
166 165 static list_t lgroups; /* list of lgroups */
167 166
168 167 static volatile uint_t sigwinch = 0;
169 168 static volatile uint_t sigtstp = 0;
170 169 static volatile uint_t sigterm = 0;
171 170
172 171 static long pagesize;
173 172
174 173 /* default settings */
175 174
176 175 static optdesc_t opts = {
177 176 5, /* interval between updates, seconds */
178 177 15, /* number of lines in top part */
179 178 5, /* number of lines in bottom part */
180 179 -1, /* number of iterations; infinitely */
181 180 OPT_PSINFO | OPT_FULLSCREEN | OPT_USEHOME | OPT_TERMCAP,
182 181 -1 /* sort in decreasing order */
183 182 };
184 183
185 184
186 185 static int
187 186 proc_snprintf(char *_RESTRICT_KYWD s, size_t n,
188 187 const char *_RESTRICT_KYWD fmt, ...)
189 188 {
190 189 static boolean_t ptools_zroot_valid = B_FALSE;
191 190 static const char *ptools_zroot = NULL;
192 191 va_list args;
193 192 int ret, nret = 0;
194 193
195 194 if (ptools_zroot_valid == B_FALSE) {
196 195 ptools_zroot_valid = B_TRUE;
197 196 ptools_zroot = zone_get_nroot();
198 197 }
199 198
200 199 if (ptools_zroot != NULL) {
201 200 nret = snprintf(s, n, "%s", ptools_zroot);
202 201 if (nret > n)
203 202 return (nret);
204 203 }
205 204 va_start(args, fmt);
206 205 ret = vsnprintf(s + nret, n - nret, fmt, args);
207 206 va_end(args);
208 207
209 208 return (ret + nret);
210 209 }
211 210
212 211 /*
213 212 * Print timestamp as decimal reprentation of time_t value (-d u was specified)
214 213 * or the standard date format (-d d was specified).
215 214 */
216 215 static void
217 216 print_timestamp(void)
218 217 {
219 218 time_t t = time(NULL);
220 219 static char *fmt = NULL;
221 220
222 221 /* We only need to retrieve this once per invocation */
223 222 if (fmt == NULL)
224 223 fmt = nl_langinfo(_DATE_FMT);
225 224
226 225 if (opts.o_outpmode & OPT_UDATE) {
227 226 (void) printf("%ld", t);
228 227 } else if (opts.o_outpmode & OPT_DDATE) {
229 228 char dstr[64];
230 229 int len;
231 230
232 231 len = strftime(dstr, sizeof (dstr), fmt, localtime(&t));
233 232 if (len > 0)
234 233 (void) printf("%s", dstr);
235 234 }
236 235 (void) putp(t_eol);
237 236 (void) putchar('\n');
238 237 }
239 238
240 239 static void
241 240 psetloadavg(long psetid, void *ptr)
242 241 {
243 242 double psetloadavg[3];
244 243 double *loadavg = ptr;
245 244
246 245 if (pset_getloadavg((psetid_t)psetid, psetloadavg, 3) != -1) {
247 246 *loadavg++ += psetloadavg[0];
248 247 *loadavg++ += psetloadavg[1];
249 248 *loadavg += psetloadavg[2];
250 249 }
251 250 }
252 251
253 252 /*
254 253 * Queries the memory virtual and rss size for each member of a list.
255 254 * This will override the values computed by /proc aggregation.
256 255 */
|
↓ open down ↓ |
217 lines elided |
↑ open up ↑ |
257 256 static void
258 257 list_getsize(list_t *list)
259 258 {
260 259 id_info_t *id;
261 260 vmusage_t *results, *next;
262 261 vmusage_t *match;
263 262 size_t nres = 0;
264 263 size_t i;
265 264 uint_t flags = 0;
266 265 int ret;
267 - size_t physmem;
266 + size_t physmem = sysconf(_SC_PHYS_PAGES) * pagesize;
268 267
269 - if (!(opts.o_outpmode & OPT_VMUSAGE))
270 - return;
271 -
272 - physmem = sysconf(_SC_PHYS_PAGES) * pagesize;
273 -
274 268 /*
275 269 * Determine what swap/rss results to calculate. getvmusage() will
276 270 * prune results returned to non-global zones automatically, so
277 271 * there is no need to pass different flags when calling from a
278 272 * non-global zone.
279 273 *
280 274 * Currently list_getsize() is only called with a single flag. This
281 275 * is because -Z, -J, -T, and -a are mutually exclusive. Regardless
282 276 * of this, we handle multiple flags.
283 277 */
284 278 if (opts.o_outpmode & OPT_USERS) {
285 279 /*
286 280 * Gather rss for all users in all zones. Treat the same
287 281 * uid in different zones as the same user.
288 282 */
289 283 flags |= VMUSAGE_COL_RUSERS;
290 284
291 285 } else if (opts.o_outpmode & OPT_TASKS) {
292 286 /* Gather rss for all tasks in all zones */
293 287 flags |= VMUSAGE_ALL_TASKS;
294 288
295 289 } else if (opts.o_outpmode & OPT_PROJECTS) {
296 290 /*
297 291 * Gather rss for all projects in all zones. Treat the same
298 292 * projid in diffrent zones as the same project.
299 293 */
300 294 flags |= VMUSAGE_COL_PROJECTS;
301 295
302 296 } else if (opts.o_outpmode & OPT_ZONES) {
303 297 /* Gather rss for all zones */
304 298 flags |= VMUSAGE_ALL_ZONES;
305 299
306 300 } else {
307 301 Die(gettext(
308 302 "Cannot determine rss flags for output options %x\n"),
309 303 opts.o_outpmode);
310 304 }
311 305
312 306 /*
313 307 * getvmusage() returns an array of result structures. One for
314 308 * each zone, project, task, or user on the system, depending on
315 309 * flags.
316 310 *
317 311 * If getvmusage() fails, prstat will use the size already gathered
318 312 * from psinfo
319 313 */
320 314 if (getvmusage(flags, opts.o_interval, NULL, &nres) != 0)
321 315 return;
322 316
323 317 results = (vmusage_t *)Malloc(sizeof (vmusage_t) * nres);
324 318 for (;;) {
325 319 ret = getvmusage(flags, opts.o_interval, results, &nres);
326 320 if (ret == 0)
327 321 break;
328 322 if (errno == EOVERFLOW) {
329 323 results = (vmusage_t *)Realloc(results,
330 324 sizeof (vmusage_t) * nres);
331 325 continue;
332 326 }
333 327 /*
334 328 * Failure for some other reason. Prstat will use the size
335 329 * already gathered from psinfo.
336 330 */
337 331 free(results);
338 332 return;
339 333 }
340 334 for (id = list->l_head; id != NULL; id = id->id_next) {
341 335
342 336 match = NULL;
343 337 next = results;
344 338 for (i = 0; i < nres; i++, next++) {
345 339 switch (flags) {
346 340 case VMUSAGE_COL_RUSERS:
347 341 if (next->vmu_id == id->id_uid)
348 342 match = next;
349 343 break;
350 344 case VMUSAGE_ALL_TASKS:
351 345 if (next->vmu_id == id->id_taskid)
352 346 match = next;
353 347 break;
354 348 case VMUSAGE_COL_PROJECTS:
355 349 if (next->vmu_id == id->id_projid)
356 350 match = next;
357 351 break;
358 352 case VMUSAGE_ALL_ZONES:
359 353 if (next->vmu_id == id->id_zoneid)
360 354 match = next;
361 355 break;
362 356 default:
363 357 Die(gettext(
364 358 "Unknown vmusage flags %d\n"), flags);
365 359 }
366 360 }
367 361 if (match != NULL) {
368 362 id->id_size = match->vmu_swap_all / 1024;
369 363 id->id_rssize = match->vmu_rss_all / 1024;
370 364 id->id_pctmem = (100.0 * (float)match->vmu_rss_all) /
371 365 (float)physmem;
372 366 /* Output using data from getvmusage() */
373 367 id->id_sizematch = B_TRUE;
374 368 }
375 369 /*
376 370 * If no match is found, prstat will use the size already
377 371 * gathered from psinfo.
378 372 */
379 373 }
380 374 free(results);
381 375 }
382 376
383 377 /*
384 378 * A routine to display the contents of the list on the screen
385 379 */
386 380 static void
387 381 list_print(list_t *list)
388 382 {
389 383 lwp_info_t *lwp;
390 384 id_info_t *id;
391 385 char usr[4], sys[4], trp[4], tfl[4];
392 386 char dfl[4], lck[4], slp[4], lat[4];
393 387 char vcx[4], icx[4], scl[4], sig[4];
394 388 char psize[6], prssize[6], pmem[6], pcpu[6], ptime[12];
395 389 char pstate[7], pnice[4], ppri[4];
396 390 char pname[LOGNAME_MAX+1];
397 391 char projname[PROJNAME_MAX+1];
398 392 char zonename[ZONENAME_MAX+1];
399 393 float cpu, mem;
400 394 double loadavg[3] = {0, 0, 0};
401 395 int i, lwpid;
402 396
403 397 if (list->l_size == 0)
404 398 return;
405 399
406 400 if (foreach_element(&set_tbl, &loadavg, psetloadavg) == 0) {
407 401 /*
408 402 * If processor sets aren't specified, we display system-wide
409 403 * load averages.
410 404 */
411 405 (void) getloadavg(loadavg, 3);
412 406 }
413 407
414 408 if (((opts.o_outpmode & OPT_UDATE) || (opts.o_outpmode & OPT_DDATE)) &&
415 409 ((list->l_type == LT_LWPS) || !(opts.o_outpmode & OPT_SPLIT)))
416 410 print_timestamp();
417 411 if (opts.o_outpmode & OPT_TTY)
418 412 (void) putchar('\r');
419 413 (void) putp(t_ulon);
420 414
421 415 switch (list->l_type) {
422 416 case LT_PROJECTS:
423 417 if (opts.o_outpmode & OPT_LWPS)
424 418 (void) printf(PROJECT_HEADER_LWP);
425 419 else
426 420 (void) printf(PROJECT_HEADER_PROC);
427 421 break;
428 422 case LT_TASKS:
429 423 if (opts.o_outpmode & OPT_LWPS)
430 424 (void) printf(TASK_HEADER_LWP);
431 425 else
432 426 (void) printf(TASK_HEADER_PROC);
433 427 break;
434 428 case LT_ZONES:
435 429 if (opts.o_outpmode & OPT_LWPS)
436 430 (void) printf(ZONE_HEADER_LWP);
437 431 else
438 432 (void) printf(ZONE_HEADER_PROC);
439 433 break;
440 434 case LT_USERS:
441 435 if (opts.o_outpmode & OPT_LWPS)
442 436 (void) printf(USER_HEADER_LWP);
443 437 else
444 438 (void) printf(USER_HEADER_PROC);
445 439 break;
446 440 case LT_LWPS:
447 441 if (opts.o_outpmode & OPT_LWPS) {
448 442 if (opts.o_outpmode & OPT_PSINFO) {
449 443 if (opts.o_outpmode & OPT_LGRP)
450 444 (void) printf(PSINFO_HEADER_LWP_LGRP);
451 445 else
452 446 (void) printf(PSINFO_HEADER_LWP);
453 447 }
454 448 if (opts.o_outpmode & OPT_MSACCT)
455 449 (void) printf(USAGE_HEADER_LWP);
456 450 } else {
457 451 if (opts.o_outpmode & OPT_PSINFO) {
458 452 if (opts.o_outpmode & OPT_LGRP)
459 453 (void) printf(PSINFO_HEADER_PROC_LGRP);
460 454 else
461 455 (void) printf(PSINFO_HEADER_PROC);
462 456 }
463 457 if (opts.o_outpmode & OPT_MSACCT)
464 458 (void) printf(USAGE_HEADER_PROC);
465 459 }
466 460 break;
467 461 }
468 462
469 463 (void) putp(t_uloff);
470 464 (void) putp(t_eol);
471 465 (void) putchar('\n');
472 466
473 467 for (i = 0; i < list->l_used; i++) {
474 468 switch (list->l_type) {
475 469 case LT_PROJECTS:
476 470 case LT_TASKS:
477 471 case LT_USERS:
478 472 case LT_ZONES:
479 473 id = list->l_ptrs[i];
480 474 /*
481 475 * CPU usage and memory usage normalization
482 476 */
483 477 if (total_cpu >= 100)
484 478 cpu = (100 * id->id_pctcpu) / total_cpu;
485 479 else
486 480 cpu = id->id_pctcpu;
487 481 if (id->id_sizematch == B_FALSE && total_mem >= 100)
488 482 mem = (100 * id->id_pctmem) / total_mem;
489 483 else
490 484 mem = id->id_pctmem;
491 485 if (list->l_type == LT_USERS) {
492 486 pwd_getname(id->id_uid, pname, sizeof (pname),
493 487 opts.o_outpmode & OPT_NORESOLVE,
494 488 opts.o_outpmode & (OPT_TERMCAP|OPT_TRUNC),
495 489 LOGIN_WIDTH);
496 490 } else if (list->l_type == LT_ZONES) {
497 491 getzonename(id->id_zoneid, zonename,
498 492 sizeof (zonename),
499 493 opts.o_outpmode & (OPT_TERMCAP|OPT_TRUNC),
500 494 ZONE_WIDTH);
501 495 } else {
502 496 getprojname(id->id_projid, projname,
503 497 sizeof (projname),
504 498 opts.o_outpmode & OPT_NORESOLVE,
505 499 opts.o_outpmode & (OPT_TERMCAP|OPT_TRUNC),
506 500 PROJECT_WIDTH);
507 501 }
508 502 Format_size(psize, id->id_size, 6);
509 503 Format_size(prssize, id->id_rssize, 6);
510 504 Format_pct(pmem, mem, 4);
511 505 Format_pct(pcpu, cpu, 4);
512 506 Format_time(ptime, id->id_time, 10);
513 507 if (opts.o_outpmode & OPT_TTY)
514 508 (void) putchar('\r');
515 509 if (list->l_type == LT_PROJECTS)
516 510 (void) printf(PROJECT_LINE, (int)id->id_projid,
517 511 id->id_nproc, psize, prssize, pmem, ptime,
518 512 pcpu, projname);
519 513 else if (list->l_type == LT_TASKS)
520 514 (void) printf(TASK_LINE, (int)id->id_taskid,
521 515 id->id_nproc, psize, prssize, pmem, ptime,
522 516 pcpu, projname);
523 517 else if (list->l_type == LT_ZONES)
524 518 (void) printf(ZONE_LINE, (int)id->id_zoneid,
525 519 id->id_nproc, psize, prssize, pmem, ptime,
526 520 pcpu, zonename);
527 521 else
528 522 (void) printf(USER_LINE, id->id_nproc, pname,
529 523 psize, prssize, pmem, ptime, pcpu);
530 524 (void) putp(t_eol);
531 525 (void) putchar('\n');
532 526 break;
533 527 case LT_LWPS:
534 528 lwp = list->l_ptrs[i];
535 529 if (opts.o_outpmode & OPT_LWPS)
536 530 lwpid = lwp->li_info.pr_lwp.pr_lwpid;
537 531 else
538 532 lwpid = lwp->li_info.pr_nlwp +
539 533 lwp->li_info.pr_nzomb;
540 534 pwd_getname(lwp->li_info.pr_uid, pname, sizeof (pname),
541 535 opts.o_outpmode & OPT_NORESOLVE,
542 536 opts.o_outpmode & (OPT_TERMCAP|OPT_TRUNC),
543 537 LOGIN_WIDTH);
544 538 if (opts.o_outpmode & OPT_PSINFO) {
545 539 Format_size(psize, lwp->li_info.pr_size, 6);
546 540 Format_size(prssize, lwp->li_info.pr_rssize, 6);
547 541 Format_state(pstate,
548 542 lwp->li_info.pr_lwp.pr_sname,
549 543 lwp->li_info.pr_lwp.pr_onpro, 7);
550 544 if (strcmp(lwp->li_info.pr_lwp.pr_clname,
551 545 "RT") == 0 ||
552 546 strcmp(lwp->li_info.pr_lwp.pr_clname,
553 547 "SYS") == 0 ||
554 548 lwp->li_info.pr_lwp.pr_sname == 'Z')
555 549 (void) strcpy(pnice, " -");
556 550 else
557 551 Format_num(pnice,
558 552 lwp->li_info.pr_lwp.pr_nice - NZERO,
559 553 4);
560 554 Format_num(ppri, lwp->li_info.pr_lwp.pr_pri, 4);
561 555 Format_pct(pcpu,
562 556 FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu), 4);
563 557 if (opts.o_outpmode & OPT_LWPS)
564 558 Format_time(ptime,
565 559 lwp->li_info.pr_lwp.pr_time.tv_sec,
566 560 10);
567 561 else
568 562 Format_time(ptime,
569 563 lwp->li_info.pr_time.tv_sec, 10);
570 564 if (opts.o_outpmode & OPT_TTY)
571 565 (void) putchar('\r');
572 566 stripfname(lwp->li_info.pr_fname);
573 567 if (opts.o_outpmode & OPT_LGRP) {
574 568 (void) printf(PSINFO_LINE_LGRP,
575 569 (int)lwp->li_info.pr_pid, pname,
576 570 psize, prssize, pstate,
577 571 ppri, pnice, ptime, pcpu,
578 572 (int)lwp->li_info.pr_lwp.pr_lgrp,
579 573 lwp->li_info.pr_fname, lwpid);
580 574 } else {
581 575 (void) printf(PSINFO_LINE,
582 576 (int)lwp->li_info.pr_pid, pname,
583 577 psize, prssize,
584 578 pstate, ppri, pnice,
585 579 ptime, pcpu,
586 580 lwp->li_info.pr_fname, lwpid);
587 581 }
588 582 (void) putp(t_eol);
589 583 (void) putchar('\n');
590 584 }
591 585 if (opts.o_outpmode & OPT_MSACCT) {
592 586 Format_pct(usr, lwp->li_usr, 4);
593 587 Format_pct(sys, lwp->li_sys, 4);
594 588 Format_pct(slp, lwp->li_slp, 4);
595 589 Format_num(vcx, lwp->li_vcx, 4);
596 590 Format_num(icx, lwp->li_icx, 4);
597 591 Format_num(scl, lwp->li_scl, 4);
598 592 Format_num(sig, lwp->li_sig, 4);
599 593 Format_pct(trp, lwp->li_trp, 4);
600 594 Format_pct(tfl, lwp->li_tfl, 4);
601 595 Format_pct(dfl, lwp->li_dfl, 4);
602 596 Format_pct(lck, lwp->li_lck, 4);
603 597 Format_pct(lat, lwp->li_lat, 4);
604 598 if (opts.o_outpmode & OPT_TTY)
605 599 (void) putchar('\r');
606 600 stripfname(lwp->li_info.pr_fname);
607 601 (void) printf(USAGE_LINE,
608 602 (int)lwp->li_info.pr_pid, pname,
609 603 usr, sys, trp, tfl, dfl, lck,
610 604 slp, lat, vcx, icx, scl, sig,
611 605 lwp->li_info.pr_fname, lwpid);
612 606 (void) putp(t_eol);
613 607 (void) putchar('\n');
614 608 }
615 609 break;
616 610 }
617 611 }
618 612
619 613 if (opts.o_outpmode & OPT_TTY)
620 614 (void) putchar('\r');
621 615 if (opts.o_outpmode & OPT_TERMCAP) {
622 616 switch (list->l_type) {
623 617 case LT_PROJECTS:
624 618 case LT_USERS:
625 619 case LT_TASKS:
626 620 case LT_ZONES:
627 621 while (i++ < opts.o_nbottom) {
628 622 (void) putp(t_eol);
629 623 (void) putchar('\n');
630 624 }
631 625 break;
632 626 case LT_LWPS:
633 627 while (i++ < opts.o_ntop) {
634 628 (void) putp(t_eol);
635 629 (void) putchar('\n');
636 630 }
637 631 }
638 632 }
639 633
640 634 if (opts.o_outpmode & OPT_TTY)
641 635 (void) putchar('\r');
642 636
643 637 if ((opts.o_outpmode & OPT_SPLIT) && list->l_type == LT_LWPS)
644 638 return;
645 639
646 640 (void) printf(TOTAL_LINE, total_procs, total_lwps,
647 641 loadavg[LOADAVG_1MIN], loadavg[LOADAVG_5MIN],
648 642 loadavg[LOADAVG_15MIN]);
649 643 (void) putp(t_eol);
650 644 (void) putchar('\n');
651 645 if (opts.o_outpmode & OPT_TTY)
652 646 (void) putchar('\r');
653 647 (void) putp(t_eol);
654 648 (void) fflush(stdout);
655 649 }
656 650
657 651 static lwp_info_t *
658 652 list_add_lwp(list_t *list, pid_t pid, id_t lwpid)
659 653 {
660 654 lwp_info_t *lwp;
661 655
662 656 if (list->l_head == NULL) {
663 657 list->l_head = list->l_tail = lwp = Zalloc(sizeof (lwp_info_t));
664 658 } else {
665 659 lwp = Zalloc(sizeof (lwp_info_t));
666 660 lwp->li_prev = list->l_tail;
667 661 ((lwp_info_t *)list->l_tail)->li_next = lwp;
668 662 list->l_tail = lwp;
669 663 }
670 664 lwp->li_info.pr_pid = pid;
671 665 lwp->li_info.pr_lwp.pr_lwpid = lwpid;
672 666 lwpid_add(lwp, pid, lwpid);
673 667 list->l_count++;
674 668 return (lwp);
675 669 }
676 670
677 671 static void
678 672 list_remove_lwp(list_t *list, lwp_info_t *lwp)
679 673 {
680 674 if (lwp->li_prev)
681 675 lwp->li_prev->li_next = lwp->li_next;
682 676 else
683 677 list->l_head = lwp->li_next; /* removing the head */
684 678 if (lwp->li_next)
685 679 lwp->li_next->li_prev = lwp->li_prev;
686 680 else
687 681 list->l_tail = lwp->li_prev; /* removing the tail */
688 682 lwpid_del(lwp->li_info.pr_pid, lwp->li_info.pr_lwp.pr_lwpid);
689 683 if (lwpid_pidcheck(lwp->li_info.pr_pid) == 0)
690 684 fds_rm(lwp->li_info.pr_pid);
691 685 list->l_count--;
692 686 free(lwp);
693 687 }
694 688
695 689 static void
696 690 list_clear(list_t *list)
697 691 {
698 692 if (list->l_type == LT_LWPS) {
699 693 lwp_info_t *lwp = list->l_tail;
700 694 lwp_info_t *lwp_tmp;
701 695
702 696 fd_closeall();
703 697 while (lwp) {
704 698 lwp_tmp = lwp;
705 699 lwp = lwp->li_prev;
706 700 list_remove_lwp(&lwps, lwp_tmp);
707 701 }
708 702 } else {
709 703 id_info_t *id = list->l_head;
710 704 id_info_t *nextid;
711 705
712 706 while (id) {
713 707 nextid = id->id_next;
714 708 free(id);
715 709 id = nextid;
716 710 }
717 711 list->l_count = 0;
718 712 list->l_head = list->l_tail = NULL;
719 713 }
720 714 }
721 715
722 716 static void
723 717 list_update(list_t *list, lwp_info_t *lwp)
724 718 {
725 719 id_info_t *id;
726 720
727 721 if (list->l_head == NULL) { /* first element */
728 722 list->l_head = list->l_tail = id = Zalloc(sizeof (id_info_t));
729 723 goto update;
730 724 }
731 725
732 726 for (id = list->l_head; id; id = id->id_next) {
733 727 if ((list->l_type == LT_USERS) &&
734 728 (id->id_uid != lwp->li_info.pr_uid))
735 729 continue;
736 730 if ((list->l_type == LT_TASKS) &&
737 731 (id->id_taskid != lwp->li_info.pr_taskid))
738 732 continue;
739 733 if ((list->l_type == LT_PROJECTS) &&
740 734 (id->id_projid != lwp->li_info.pr_projid))
741 735 continue;
742 736 if ((list->l_type == LT_ZONES) &&
743 737 (id->id_zoneid != lwp->li_info.pr_zoneid))
744 738 continue;
745 739 if ((list->l_type == LT_LGRPS) &&
746 740 (id->id_lgroup != lwp->li_info.pr_lwp.pr_lgrp))
747 741 continue;
748 742 id->id_nproc++;
749 743 id->id_taskid = lwp->li_info.pr_taskid;
750 744 id->id_projid = lwp->li_info.pr_projid;
751 745 id->id_zoneid = lwp->li_info.pr_zoneid;
752 746 id->id_lgroup = lwp->li_info.pr_lwp.pr_lgrp;
753 747
754 748 if (lwp->li_flags & LWP_REPRESENT) {
755 749 id->id_size += lwp->li_info.pr_size;
756 750 id->id_rssize += lwp->li_info.pr_rssize;
757 751 }
758 752 id->id_pctcpu += FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu);
759 753 if (opts.o_outpmode & OPT_LWPS)
760 754 id->id_time += TIME2SEC(lwp->li_info.pr_lwp.pr_time);
761 755 else
762 756 id->id_time += TIME2SEC(lwp->li_info.pr_time);
763 757 id->id_pctmem += FRC2PCT(lwp->li_info.pr_pctmem);
764 758 id->id_key += lwp->li_key;
765 759 total_cpu += FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu);
766 760 total_mem += FRC2PCT(lwp->li_info.pr_pctmem);
767 761 return;
768 762 }
769 763
770 764 id = list->l_tail;
771 765 id->id_next = Zalloc(sizeof (id_info_t));
772 766 id->id_next->id_prev = list->l_tail;
773 767 id->id_next->id_next = NULL;
774 768 list->l_tail = id->id_next;
775 769 id = list->l_tail;
776 770 update:
777 771 id->id_uid = lwp->li_info.pr_uid;
778 772 id->id_projid = lwp->li_info.pr_projid;
779 773 id->id_taskid = lwp->li_info.pr_taskid;
780 774 id->id_zoneid = lwp->li_info.pr_zoneid;
781 775 id->id_lgroup = lwp->li_info.pr_lwp.pr_lgrp;
782 776 id->id_nproc++;
783 777 id->id_sizematch = B_FALSE;
784 778 if (lwp->li_flags & LWP_REPRESENT) {
785 779 id->id_size = lwp->li_info.pr_size;
786 780 id->id_rssize = lwp->li_info.pr_rssize;
787 781 }
788 782 id->id_pctcpu = FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu);
789 783 if (opts.o_outpmode & OPT_LWPS)
790 784 id->id_time = TIME2SEC(lwp->li_info.pr_lwp.pr_time);
791 785 else
792 786 id->id_time = TIME2SEC(lwp->li_info.pr_time);
793 787 id->id_pctmem = FRC2PCT(lwp->li_info.pr_pctmem);
794 788 id->id_key = lwp->li_key;
795 789 total_cpu += id->id_pctcpu;
796 790 total_mem += id->id_pctmem;
797 791 list->l_count++;
798 792 }
799 793
800 794 static void
801 795 lwp_update(lwp_info_t *lwp, pid_t pid, id_t lwpid, struct prusage *usage)
802 796 {
803 797 float period;
804 798
805 799 if (!lwpid_is_active(pid, lwpid)) {
806 800 /*
807 801 * If we are reading cpu times for the first time then
808 802 * calculate average cpu times based on whole process
809 803 * execution time.
810 804 */
811 805 (void) memcpy(&lwp->li_usage, usage, sizeof (prusage_t));
812 806 period = TIME2NSEC(usage->pr_rtime);
813 807 period = period/(float)100;
814 808
815 809 if (period == 0) { /* zombie */
816 810 period = 1;
817 811 lwp->li_usr = 0;
818 812 lwp->li_sys = 0;
819 813 lwp->li_slp = 0;
820 814 } else {
821 815 lwp->li_usr = TIME2NSEC(usage->pr_utime)/period;
822 816 lwp->li_sys = TIME2NSEC(usage->pr_stime)/period;
823 817 lwp->li_slp = TIME2NSEC(usage->pr_slptime)/period;
824 818 }
825 819 lwp->li_trp = TIME2NSEC(usage->pr_ttime)/period;
826 820 lwp->li_tfl = TIME2NSEC(usage->pr_tftime)/period;
827 821 lwp->li_dfl = TIME2NSEC(usage->pr_dftime)/period;
828 822 lwp->li_lck = TIME2NSEC(usage->pr_ltime)/period;
829 823 lwp->li_lat = TIME2NSEC(usage->pr_wtime)/period;
830 824 period = (period / NANOSEC)*(float)100; /* now in seconds */
831 825 lwp->li_vcx = (ulong_t)
832 826 (opts.o_interval * (usage->pr_vctx/period));
833 827 lwp->li_icx = (ulong_t)
834 828 (opts.o_interval * (usage->pr_ictx/period));
835 829 lwp->li_scl = (ulong_t)
836 830 (opts.o_interval * (usage->pr_sysc/period));
837 831 lwp->li_sig = (ulong_t)
838 832 (opts.o_interval * (usage->pr_sigs/period));
839 833 (void) lwpid_set_active(pid, lwpid);
840 834 } else {
841 835 /*
842 836 * If this is not a first time we are reading a process's
843 837 * CPU times then recalculate CPU times based on fresh data
844 838 * obtained from procfs and previous CPU time usage values.
845 839 */
846 840 period = TIME2NSEC(usage->pr_rtime)-
847 841 TIME2NSEC(lwp->li_usage.pr_rtime);
848 842 period = period/(float)100;
849 843
850 844 if (period == 0) { /* zombie */
851 845 period = 1;
852 846 lwp->li_usr = 0;
853 847 lwp->li_sys = 0;
854 848 lwp->li_slp = 0;
855 849 } else {
856 850 lwp->li_usr = (TIME2NSEC(usage->pr_utime)-
857 851 TIME2NSEC(lwp->li_usage.pr_utime))/period;
858 852 lwp->li_sys = (TIME2NSEC(usage->pr_stime) -
859 853 TIME2NSEC(lwp->li_usage.pr_stime))/period;
860 854 lwp->li_slp = (TIME2NSEC(usage->pr_slptime) -
861 855 TIME2NSEC(lwp->li_usage.pr_slptime))/period;
862 856 }
863 857 lwp->li_trp = (TIME2NSEC(usage->pr_ttime) -
864 858 TIME2NSEC(lwp->li_usage.pr_ttime))/period;
865 859 lwp->li_tfl = (TIME2NSEC(usage->pr_tftime) -
866 860 TIME2NSEC(lwp->li_usage.pr_tftime))/period;
867 861 lwp->li_dfl = (TIME2NSEC(usage->pr_dftime) -
868 862 TIME2NSEC(lwp->li_usage.pr_dftime))/period;
869 863 lwp->li_lck = (TIME2NSEC(usage->pr_ltime) -
870 864 TIME2NSEC(lwp->li_usage.pr_ltime))/period;
871 865 lwp->li_lat = (TIME2NSEC(usage->pr_wtime) -
872 866 TIME2NSEC(lwp->li_usage.pr_wtime))/period;
873 867 lwp->li_vcx = usage->pr_vctx - lwp->li_usage.pr_vctx;
874 868 lwp->li_icx = usage->pr_ictx - lwp->li_usage.pr_ictx;
875 869 lwp->li_scl = usage->pr_sysc - lwp->li_usage.pr_sysc;
876 870 lwp->li_sig = usage->pr_sigs - lwp->li_usage.pr_sigs;
877 871 (void) memcpy(&lwp->li_usage, usage, sizeof (prusage_t));
878 872 }
879 873 }
880 874
881 875 static int
882 876 read_procfile(fd_t **fd, char *pidstr, char *file, void *buf, size_t bufsize)
883 877 {
884 878 char procfile[PATH_MAX];
885 879
886 880 (void) proc_snprintf(procfile, PATH_MAX,
887 881 "/proc/%s/%s", pidstr, file);
888 882 if ((*fd = fd_open(procfile, O_RDONLY, *fd)) == NULL)
889 883 return (1);
890 884 if (pread(fd_getfd(*fd), buf, bufsize, 0) != bufsize) {
891 885 fd_close(*fd);
892 886 return (1);
893 887 }
894 888 return (0);
895 889 }
896 890
897 891 static void
898 892 add_proc(psinfo_t *psinfo)
899 893 {
900 894 lwp_info_t *lwp;
901 895 id_t lwpid;
902 896 pid_t pid = psinfo->pr_pid;
903 897
904 898 lwpid = psinfo->pr_lwp.pr_lwpid;
905 899 if ((lwp = lwpid_get(pid, lwpid)) == NULL)
906 900 lwp = list_add_lwp(&lwps, pid, lwpid);
907 901 lwp->li_flags |= LWP_ALIVE | LWP_REPRESENT;
908 902 (void) memcpy(&lwp->li_info, psinfo, sizeof (psinfo_t));
909 903 lwp->li_info.pr_lwp.pr_pctcpu = lwp->li_info.pr_pctcpu;
910 904 }
911 905
912 906 static void
913 907 add_lwp(psinfo_t *psinfo, lwpsinfo_t *lwpsinfo, int flags)
914 908 {
915 909 lwp_info_t *lwp;
916 910 pid_t pid = psinfo->pr_pid;
917 911 id_t lwpid = lwpsinfo->pr_lwpid;
918 912
919 913 if ((lwp = lwpid_get(pid, lwpid)) == NULL)
920 914 lwp = list_add_lwp(&lwps, pid, lwpid);
921 915 lwp->li_flags &= ~LWP_REPRESENT;
922 916 lwp->li_flags |= LWP_ALIVE;
923 917 lwp->li_flags |= flags;
924 918 (void) memcpy(&lwp->li_info, psinfo,
925 919 sizeof (psinfo_t) - sizeof (lwpsinfo_t));
926 920 (void) memcpy(&lwp->li_info.pr_lwp, lwpsinfo, sizeof (lwpsinfo_t));
927 921 }
928 922
929 923 static void
930 924 prstat_scandir(DIR *procdir)
931 925 {
932 926 char *pidstr;
933 927 pid_t pid;
934 928 id_t lwpid;
935 929 size_t entsz;
936 930 long nlwps, nent, i;
937 931 char *buf, *ptr;
938 932
939 933 fds_t *fds;
940 934 lwp_info_t *lwp;
941 935 dirent_t *direntp;
942 936
943 937 prheader_t header;
944 938 psinfo_t psinfo;
945 939 prusage_t usage;
946 940 lwpsinfo_t *lwpsinfo;
947 941 prusage_t *lwpusage;
948 942
949 943 total_procs = 0;
950 944 total_lwps = 0;
951 945 total_cpu = 0;
952 946 total_mem = 0;
953 947
954 948 convert_zone(&zone_tbl);
955 949 for (rewinddir(procdir); (direntp = readdir(procdir)); ) {
956 950 pidstr = direntp->d_name;
957 951 if (pidstr[0] == '.') /* skip "." and ".." */
958 952 continue;
959 953 pid = atoi(pidstr);
960 954 if (pid == 0 || pid == 2 || pid == 3)
961 955 continue; /* skip sched, pageout and fsflush */
962 956 if (has_element(&pid_tbl, pid) == 0)
963 957 continue; /* check if we really want this pid */
964 958 fds = fds_get(pid); /* get ptr to file descriptors */
965 959
966 960 if (read_procfile(&fds->fds_psinfo, pidstr,
967 961 "psinfo", &psinfo, sizeof (psinfo_t)) != 0)
968 962 continue;
969 963 if (!has_uid(&ruid_tbl, psinfo.pr_uid) ||
970 964 !has_uid(&euid_tbl, psinfo.pr_euid) ||
971 965 !has_element(&prj_tbl, psinfo.pr_projid) ||
972 966 !has_element(&tsk_tbl, psinfo.pr_taskid) ||
973 967 !has_zone(&zone_tbl, psinfo.pr_zoneid)) {
974 968 fd_close(fds->fds_psinfo);
975 969 continue;
976 970 }
977 971 nlwps = psinfo.pr_nlwp + psinfo.pr_nzomb;
978 972
979 973 if (nlwps > 1 && (opts.o_outpmode & (OPT_LWPS | OPT_PSETS))) {
980 974 int rep_lwp = 0;
981 975
982 976 if (read_procfile(&fds->fds_lpsinfo, pidstr, "lpsinfo",
983 977 &header, sizeof (prheader_t)) != 0) {
984 978 fd_close(fds->fds_psinfo);
985 979 continue;
986 980 }
987 981
988 982 nent = header.pr_nent;
989 983 entsz = header.pr_entsize * nent;
990 984 ptr = buf = Malloc(entsz);
991 985 if (pread(fd_getfd(fds->fds_lpsinfo), buf,
992 986 entsz, sizeof (struct prheader)) != entsz) {
993 987 fd_close(fds->fds_lpsinfo);
994 988 fd_close(fds->fds_psinfo);
995 989 free(buf);
996 990 continue;
997 991 }
998 992
999 993 nlwps = 0;
1000 994 for (i = 0; i < nent; i++, ptr += header.pr_entsize) {
1001 995 /*LINTED ALIGNMENT*/
1002 996 lwpsinfo = (lwpsinfo_t *)ptr;
1003 997 if (!has_element(&cpu_tbl,
1004 998 lwpsinfo->pr_onpro) ||
1005 999 !has_element(&set_tbl,
1006 1000 lwpsinfo->pr_bindpset) ||
1007 1001 !has_element(&lgr_tbl, lwpsinfo->pr_lgrp))
1008 1002 continue;
1009 1003 nlwps++;
1010 1004 if ((opts.o_outpmode & (OPT_PSETS | OPT_LWPS))
1011 1005 == OPT_PSETS) {
1012 1006 /*
1013 1007 * If one of process's LWPs is bound
1014 1008 * to a given processor set, report the
1015 1009 * whole process. We may be doing this
1016 1010 * a few times but we'll get an accurate
1017 1011 * lwp count in return.
1018 1012 */
1019 1013 add_proc(&psinfo);
1020 1014 } else {
1021 1015 if (rep_lwp == 0) {
1022 1016 rep_lwp = 1;
1023 1017 add_lwp(&psinfo, lwpsinfo,
1024 1018 LWP_REPRESENT);
1025 1019 } else {
1026 1020 add_lwp(&psinfo, lwpsinfo, 0);
1027 1021 }
1028 1022 }
1029 1023 }
1030 1024 free(buf);
1031 1025 if (nlwps == 0) {
1032 1026 fd_close(fds->fds_lpsinfo);
1033 1027 fd_close(fds->fds_psinfo);
1034 1028 continue;
1035 1029 }
1036 1030 } else {
1037 1031 if (!has_element(&cpu_tbl, psinfo.pr_lwp.pr_onpro) ||
1038 1032 !has_element(&set_tbl, psinfo.pr_lwp.pr_bindpset) ||
1039 1033 !has_element(&lgr_tbl, psinfo.pr_lwp.pr_lgrp)) {
1040 1034 fd_close(fds->fds_psinfo);
1041 1035 continue;
1042 1036 }
1043 1037 add_proc(&psinfo);
1044 1038 }
1045 1039 if (!(opts.o_outpmode & OPT_MSACCT)) {
1046 1040 total_procs++;
1047 1041 total_lwps += nlwps;
1048 1042 continue;
1049 1043 }
1050 1044 /*
1051 1045 * Get more information about processes from /proc/pid/usage.
1052 1046 * If process has more than one lwp, then we may have to
1053 1047 * also look at the /proc/pid/lusage file.
1054 1048 */
1055 1049 if ((opts.o_outpmode & OPT_LWPS) && (nlwps > 1)) {
1056 1050 if (read_procfile(&fds->fds_lusage, pidstr, "lusage",
1057 1051 &header, sizeof (prheader_t)) != 0) {
1058 1052 fd_close(fds->fds_lpsinfo);
1059 1053 fd_close(fds->fds_psinfo);
1060 1054 continue;
1061 1055 }
1062 1056 nent = header.pr_nent;
1063 1057 entsz = header.pr_entsize * nent;
1064 1058 buf = Malloc(entsz);
1065 1059 if (pread(fd_getfd(fds->fds_lusage), buf,
1066 1060 entsz, sizeof (struct prheader)) != entsz) {
1067 1061 fd_close(fds->fds_lusage);
1068 1062 fd_close(fds->fds_lpsinfo);
1069 1063 fd_close(fds->fds_psinfo);
1070 1064 free(buf);
1071 1065 continue;
1072 1066 }
1073 1067 for (i = 1, ptr = buf + header.pr_entsize; i < nent;
1074 1068 i++, ptr += header.pr_entsize) {
1075 1069 /*LINTED ALIGNMENT*/
1076 1070 lwpusage = (prusage_t *)ptr;
1077 1071 lwpid = lwpusage->pr_lwpid;
1078 1072 /*
1079 1073 * New LWPs created after we read lpsinfo
1080 1074 * will be ignored. Don't want to do
1081 1075 * everything all over again.
1082 1076 */
1083 1077 if ((lwp = lwpid_get(pid, lwpid)) == NULL)
1084 1078 continue;
1085 1079 lwp_update(lwp, pid, lwpid, lwpusage);
1086 1080 }
1087 1081 free(buf);
1088 1082 } else {
1089 1083 if (read_procfile(&fds->fds_usage, pidstr, "usage",
1090 1084 &usage, sizeof (prusage_t)) != 0) {
1091 1085 fd_close(fds->fds_lpsinfo);
1092 1086 fd_close(fds->fds_psinfo);
1093 1087 continue;
1094 1088 }
1095 1089 lwpid = psinfo.pr_lwp.pr_lwpid;
1096 1090 if ((lwp = lwpid_get(pid, lwpid)) == NULL)
1097 1091 continue;
1098 1092 lwp_update(lwp, pid, lwpid, &usage);
1099 1093 }
1100 1094 total_procs++;
1101 1095 total_lwps += nlwps;
1102 1096 }
1103 1097 fd_update();
1104 1098 }
1105 1099
1106 1100 /*
1107 1101 * This procedure removes all dead lwps from the linked list of all lwps.
1108 1102 * It also creates linked list of ids if necessary.
1109 1103 */
1110 1104 static void
1111 1105 list_refresh(list_t *list)
1112 1106 {
1113 1107 lwp_info_t *lwp, *lwp_next;
1114 1108
1115 1109 if (!(list->l_type & LT_LWPS))
1116 1110 return;
1117 1111
1118 1112 for (lwp = list->l_head; lwp != NULL; ) {
1119 1113 if (lwp->li_flags & LWP_ALIVE) {
1120 1114 /*
1121 1115 * Process all live LWPs.
1122 1116 * When we're done, mark them as dead.
1123 1117 * They will be marked "alive" on the next
1124 1118 * /proc scan if they still exist.
1125 1119 */
1126 1120 lwp->li_key = list_getkeyval(list, lwp);
1127 1121 if (opts.o_outpmode & OPT_USERS)
1128 1122 list_update(&users, lwp);
1129 1123 if (opts.o_outpmode & OPT_TASKS)
1130 1124 list_update(&tasks, lwp);
1131 1125 if (opts.o_outpmode & OPT_PROJECTS)
1132 1126 list_update(&projects, lwp);
1133 1127 if (opts.o_outpmode & OPT_ZONES)
1134 1128 list_update(&zones, lwp);
1135 1129 if (opts.o_outpmode & OPT_LGRP)
1136 1130 list_update(&lgroups, lwp);
1137 1131 lwp->li_flags &= ~LWP_ALIVE;
1138 1132 lwp = lwp->li_next;
1139 1133
1140 1134 } else {
1141 1135 lwp_next = lwp->li_next;
1142 1136 list_remove_lwp(&lwps, lwp);
1143 1137 lwp = lwp_next;
1144 1138 }
1145 1139 }
1146 1140 }
1147 1141
1148 1142 static void
1149 1143 curses_on()
1150 1144 {
1151 1145 if ((opts.o_outpmode & OPT_TERMCAP) && (is_curses_on == FALSE)) {
1152 1146 (void) initscr();
1153 1147 (void) nonl();
1154 1148 (void) putp(t_smcup);
1155 1149 is_curses_on = TRUE;
1156 1150 }
1157 1151 }
1158 1152
1159 1153 static void
1160 1154 curses_off()
1161 1155 {
1162 1156 if ((is_curses_on == TRUE) && (opts.o_outpmode & OPT_TERMCAP)) {
1163 1157 (void) putp(t_rmcup);
1164 1158 (void) endwin();
1165 1159 is_curses_on = FALSE;
1166 1160 }
1167 1161 (void) fflush(stdout);
1168 1162 }
1169 1163
1170 1164 static int
1171 1165 nlines()
1172 1166 {
1173 1167 struct winsize ws;
1174 1168 char *envp;
1175 1169 int n;
1176 1170 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1) {
1177 1171 if (ws.ws_row > 0)
1178 1172 return (ws.ws_row);
1179 1173 }
1180 1174 if (envp = getenv("LINES")) {
1181 1175 if ((n = Atoi(envp)) > 0) {
1182 1176 opts.o_outpmode &= ~OPT_USEHOME;
1183 1177 return (n);
1184 1178 }
1185 1179 }
1186 1180 return (-1);
1187 1181 }
1188 1182
1189 1183 static void
1190 1184 setmovecur()
1191 1185 {
1192 1186 int i, n;
1193 1187 if ((opts.o_outpmode & OPT_FULLSCREEN) &&
1194 1188 (opts.o_outpmode & OPT_USEHOME)) {
1195 1189 movecur = t_home;
1196 1190 return;
1197 1191 }
1198 1192 if (opts.o_outpmode & OPT_SPLIT) {
1199 1193 if (opts.o_ntop == 0)
1200 1194 n = opts.o_nbottom + 1;
1201 1195 else
1202 1196 n = opts.o_ntop + opts.o_nbottom + 2;
1203 1197 } else {
1204 1198 if (opts.o_outpmode & OPT_USERS)
1205 1199 n = opts.o_nbottom + 1;
1206 1200 else
1207 1201 n = opts.o_ntop + 1;
1208 1202 }
1209 1203 if (((opts.o_outpmode & OPT_UDATE) || (opts.o_outpmode & OPT_DDATE)))
1210 1204 n++;
1211 1205
1212 1206 if (movecur != NULL && movecur != empty_string && movecur != t_home)
1213 1207 free(movecur);
1214 1208 movecur = Zalloc(strlen(t_up) * (n + 5));
1215 1209 for (i = 0; i <= n; i++)
1216 1210 (void) strcat(movecur, t_up);
1217 1211 }
1218 1212
1219 1213 static int
1220 1214 setsize()
1221 1215 {
1222 1216 static int oldn = 0;
1223 1217 int n;
1224 1218
1225 1219 if (opts.o_outpmode & OPT_FULLSCREEN) {
1226 1220 n = nlines();
1227 1221 if (n == oldn)
1228 1222 return (0);
1229 1223 oldn = n;
1230 1224 if (n == -1) {
1231 1225 opts.o_outpmode &= ~OPT_USEHOME;
1232 1226 setmovecur(); /* set default window size */
1233 1227 return (1);
1234 1228 }
1235 1229 n = n - 3; /* minus header, total and cursor lines */
1236 1230 if ((opts.o_outpmode & OPT_UDATE) ||
1237 1231 (opts.o_outpmode & OPT_DDATE))
1238 1232 n--; /* minus timestamp */
1239 1233 if (n < 1)
1240 1234 Die(gettext("window is too small (try -n)\n"));
1241 1235 if (opts.o_outpmode & OPT_SPLIT) {
1242 1236 if (n < 8) {
1243 1237 Die(gettext("window is too small (try -n)\n"));
1244 1238 } else {
1245 1239 opts.o_ntop = (n / 4) * 3;
1246 1240 opts.o_nbottom = n - 1 - opts.o_ntop;
1247 1241 }
1248 1242 } else {
1249 1243 if (opts.o_outpmode & OPT_USERS)
1250 1244 opts.o_nbottom = n;
1251 1245 else
1252 1246 opts.o_ntop = n;
1253 1247 }
1254 1248 }
1255 1249 setmovecur();
1256 1250 return (1);
1257 1251 }
1258 1252
1259 1253 static void
1260 1254 ldtermcap()
1261 1255 {
1262 1256 int err;
1263 1257 if (setupterm(NULL, STDIN_FILENO, &err) == ERR) {
1264 1258 switch (err) {
1265 1259 case 0:
1266 1260 Warn(gettext("failed to load terminal info, "
1267 1261 "defaulting to -c option\n"));
1268 1262 break;
1269 1263 case -1:
1270 1264 Warn(gettext("terminfo database not found, "
1271 1265 "defaulting to -c option\n"));
1272 1266 break;
1273 1267 default:
1274 1268 Warn(gettext("failed to initialize terminal, "
1275 1269 "defaulting to -c option\n"));
1276 1270 }
1277 1271 opts.o_outpmode &= ~OPT_TERMCAP;
1278 1272 t_up = t_eol = t_smcup = t_rmcup = movecur = empty_string;
1279 1273 t_ulon = t_uloff = empty_string;
1280 1274 return;
1281 1275 }
1282 1276 t_ulon = tigetstr("smul");
1283 1277 t_uloff = tigetstr("rmul");
1284 1278 t_up = tigetstr("cuu1");
1285 1279 t_eol = tigetstr("el");
1286 1280 t_smcup = tigetstr("smcup");
1287 1281 t_rmcup = tigetstr("rmcup");
1288 1282 t_home = tigetstr("home");
1289 1283 if ((t_up == (char *)-1) || (t_eol == (char *)-1) ||
1290 1284 (t_smcup == (char *)-1) || (t_rmcup == (char *)-1)) {
1291 1285 opts.o_outpmode &= ~OPT_TERMCAP;
1292 1286 t_up = t_eol = t_smcup = t_rmcup = movecur = empty_string;
1293 1287 return;
1294 1288 }
1295 1289 if (t_up == NULL || t_eol == NULL) {
1296 1290 opts.o_outpmode &= ~OPT_TERMCAP;
1297 1291 t_eol = t_up = movecur = empty_string;
1298 1292 return;
1299 1293 }
1300 1294 if (t_ulon == (char *)-1 || t_uloff == (char *)-1 ||
1301 1295 t_ulon == NULL || t_uloff == NULL) {
1302 1296 t_ulon = t_uloff = empty_string; /* can live without it */
1303 1297 }
1304 1298 if (t_smcup == NULL || t_rmcup == NULL)
1305 1299 t_smcup = t_rmcup = empty_string;
1306 1300 if (t_home == (char *)-1 || t_home == NULL) {
1307 1301 opts.o_outpmode &= ~OPT_USEHOME;
1308 1302 t_home = empty_string;
1309 1303 }
1310 1304 }
1311 1305
1312 1306 static void
1313 1307 sig_handler(int sig)
1314 1308 {
1315 1309 switch (sig) {
1316 1310 case SIGTSTP: sigtstp = 1;
1317 1311 break;
1318 1312 case SIGWINCH: sigwinch = 1;
1319 1313 break;
1320 1314 case SIGINT:
1321 1315 case SIGTERM: sigterm = 1;
1322 1316 break;
1323 1317 }
1324 1318 }
1325 1319
1326 1320 static void
1327 1321 set_signals()
1328 1322 {
1329 1323 (void) signal(SIGTSTP, sig_handler);
1330 1324 (void) signal(SIGINT, sig_handler);
1331 1325 (void) signal(SIGTERM, sig_handler);
1332 1326 if (opts.o_outpmode & OPT_FULLSCREEN)
1333 1327 (void) signal(SIGWINCH, sig_handler);
1334 1328 }
1335 1329
1336 1330 static void
1337 1331 fill_table(table_t *table, char *arg, char option)
1338 1332 {
1339 1333 char *p = strtok(arg, ", ");
1340 1334
1341 1335 if (p == NULL)
1342 1336 Die(gettext("invalid argument for -%c\n"), option);
1343 1337
1344 1338 add_element(table, (long)Atoi(p));
1345 1339 while (p = strtok(NULL, ", "))
1346 1340 add_element(table, (long)Atoi(p));
1347 1341 }
1348 1342
1349 1343 static void
1350 1344 fill_prj_table(char *arg)
1351 1345 {
1352 1346 projid_t projid;
1353 1347 char *p = strtok(arg, ", ");
1354 1348
1355 1349 if (p == NULL)
1356 1350 Die(gettext("invalid argument for -j\n"));
1357 1351
1358 1352 if ((projid = getprojidbyname(p)) == -1)
1359 1353 projid = Atoi(p);
1360 1354 add_element(&prj_tbl, (long)projid);
1361 1355
1362 1356 while (p = strtok(NULL, ", ")) {
1363 1357 if ((projid = getprojidbyname(p)) == -1)
1364 1358 projid = Atoi(p);
1365 1359 add_element(&prj_tbl, (long)projid);
1366 1360 }
1367 1361 }
1368 1362
1369 1363 static void
1370 1364 fill_set_table(char *arg)
1371 1365 {
1372 1366 char *p = strtok(arg, ", ");
1373 1367 psetid_t id;
1374 1368
1375 1369 if (p == NULL)
1376 1370 Die(gettext("invalid argument for -C\n"));
1377 1371
1378 1372 if ((id = Atoi(p)) == 0)
1379 1373 id = PS_NONE;
1380 1374 add_element(&set_tbl, id);
1381 1375 while (p = strtok(NULL, ", ")) {
1382 1376 if ((id = Atoi(p)) == 0)
1383 1377 id = PS_NONE;
1384 1378 if (!has_element(&set_tbl, id))
1385 1379 add_element(&set_tbl, id);
1386 1380 }
1387 1381 }
1388 1382
1389 1383 static void
1390 1384 Exit()
1391 1385 {
1392 1386 curses_off();
1393 1387 list_clear(&lwps);
1394 1388 list_clear(&users);
1395 1389 list_clear(&tasks);
1396 1390 list_clear(&projects);
1397 1391 list_clear(&zones);
1398 1392 fd_exit();
1399 1393 }
1400 1394
1401 1395
1402 1396 int
1403 1397 main(int argc, char **argv)
1404 1398 {
1405 1399 DIR *procdir;
1406 1400 char *p;
1407 1401 char *sortk = "cpu"; /* default sort key */
1408 1402 int opt;
1409 1403 int timeout;
1410 1404 struct pollfd pollset;
1411 1405 char key;
1412 1406 char procpath[PATH_MAX];
|
↓ open down ↓ |
1129 lines elided |
↑ open up ↑ |
1413 1407
1414 1408 (void) setlocale(LC_ALL, "");
1415 1409 (void) textdomain(TEXT_DOMAIN);
1416 1410 Progname(argv[0]);
1417 1411 lwpid_init();
1418 1412 fd_init(Setrlimit());
1419 1413
1420 1414 pagesize = sysconf(_SC_PAGESIZE);
1421 1415
1422 1416 while ((opt = getopt(argc, argv,
1423 - "vVcd:HmarRLtu:U:n:p:C:P:h:s:S:j:k:TJWz:Z")) != (int)EOF) {
1417 + "vcd:HmarRLtu:U:n:p:C:P:h:s:S:j:k:TJWz:Z")) != (int)EOF) {
1424 1418 switch (opt) {
1425 1419 case 'r':
1426 1420 opts.o_outpmode |= OPT_NORESOLVE;
1427 1421 break;
1428 1422 case 'R':
1429 1423 opts.o_outpmode |= OPT_REALTIME;
1430 1424 break;
1431 1425 case 'c':
1432 1426 opts.o_outpmode &= ~OPT_TERMCAP;
1433 1427 opts.o_outpmode &= ~OPT_FULLSCREEN;
1434 1428 break;
1435 1429 case 'd':
1436 1430 if (optarg) {
1437 1431 if (*optarg == 'u')
1438 1432 opts.o_outpmode |= OPT_UDATE;
1439 1433 else if (*optarg == 'd')
1440 1434 opts.o_outpmode |= OPT_DDATE;
1441 1435 else
1442 1436 Usage();
1443 1437 } else {
1444 1438 Usage();
1445 1439 }
1446 1440 break;
1447 1441 case 'h':
1448 1442 fill_table(&lgr_tbl, optarg, 'h');
1449 1443 break;
1450 1444 case 'H':
1451 1445 opts.o_outpmode |= OPT_LGRP;
1452 1446 break;
1453 1447 case 'm':
1454 1448 case 'v':
1455 1449 opts.o_outpmode &= ~OPT_PSINFO;
1456 1450 opts.o_outpmode |= OPT_MSACCT;
1457 1451 break;
1458 1452 case 't':
1459 1453 opts.o_outpmode &= ~OPT_PSINFO;
1460 1454 opts.o_outpmode |= OPT_USERS;
1461 1455 break;
1462 1456 case 'a':
1463 1457 opts.o_outpmode |= OPT_SPLIT | OPT_USERS;
1464 1458 break;
1465 1459 case 'T':
1466 1460 opts.o_outpmode |= OPT_SPLIT | OPT_TASKS;
1467 1461 break;
1468 1462 case 'J':
1469 1463 opts.o_outpmode |= OPT_SPLIT | OPT_PROJECTS;
1470 1464 break;
1471 1465 case 'n':
1472 1466 if ((p = strtok(optarg, ",")) == NULL)
1473 1467 Die(gettext("invalid argument for -n\n"));
1474 1468 opts.o_ntop = Atoi(p);
1475 1469 if (p = strtok(NULL, ","))
1476 1470 opts.o_nbottom = Atoi(p);
1477 1471 else if (opts.o_ntop == 0)
1478 1472 opts.o_nbottom = 5;
1479 1473 opts.o_outpmode &= ~OPT_FULLSCREEN;
1480 1474 break;
1481 1475 case 's':
1482 1476 opts.o_sortorder = -1;
1483 1477 sortk = optarg;
1484 1478 break;
1485 1479 case 'S':
1486 1480 opts.o_sortorder = 1;
1487 1481 sortk = optarg;
1488 1482 break;
1489 1483 case 'u':
1490 1484 if ((p = strtok(optarg, ", ")) == NULL)
1491 1485 Die(gettext("invalid argument for -u\n"));
1492 1486 add_uid(&euid_tbl, p);
|
↓ open down ↓ |
59 lines elided |
↑ open up ↑ |
1493 1487 while (p = strtok(NULL, ", "))
1494 1488 add_uid(&euid_tbl, p);
1495 1489 break;
1496 1490 case 'U':
1497 1491 if ((p = strtok(optarg, ", ")) == NULL)
1498 1492 Die(gettext("invalid argument for -U\n"));
1499 1493 add_uid(&ruid_tbl, p);
1500 1494 while (p = strtok(NULL, ", "))
1501 1495 add_uid(&ruid_tbl, p);
1502 1496 break;
1503 - case 'V':
1504 - opts.o_outpmode |= OPT_VMUSAGE;
1505 - break;
1506 1497 case 'p':
1507 1498 fill_table(&pid_tbl, optarg, 'p');
1508 1499 break;
1509 1500 case 'C':
1510 1501 fill_set_table(optarg);
1511 1502 opts.o_outpmode |= OPT_PSETS;
1512 1503 break;
1513 1504 case 'P':
1514 1505 fill_table(&cpu_tbl, optarg, 'P');
1515 1506 break;
1516 1507 case 'k':
1517 1508 fill_table(&tsk_tbl, optarg, 'k');
1518 1509 break;
1519 1510 case 'j':
1520 1511 fill_prj_table(optarg);
1521 1512 break;
1522 1513 case 'L':
1523 1514 opts.o_outpmode |= OPT_LWPS;
1524 1515 break;
1525 1516 case 'W':
1526 1517 opts.o_outpmode |= OPT_TRUNC;
1527 1518 break;
1528 1519 case 'z':
1529 1520 if ((p = strtok(optarg, ", ")) == NULL)
1530 1521 Die(gettext("invalid argument for -z\n"));
1531 1522 add_zone(&zone_tbl, p);
1532 1523 while (p = strtok(NULL, ", "))
1533 1524 add_zone(&zone_tbl, p);
1534 1525 break;
1535 1526 case 'Z':
1536 1527 opts.o_outpmode |= OPT_SPLIT | OPT_ZONES;
1537 1528 break;
1538 1529 default:
1539 1530 Usage();
1540 1531 }
1541 1532 }
1542 1533
1543 1534 (void) atexit(Exit);
1544 1535 if ((opts.o_outpmode & OPT_USERS) &&
1545 1536 !(opts.o_outpmode & OPT_SPLIT))
1546 1537 opts.o_nbottom = opts.o_ntop;
1547 1538 if (!(opts.o_outpmode & OPT_SPLIT) && opts.o_ntop == 0)
1548 1539 Die(gettext("invalid argument for -n\n"));
1549 1540 if (opts.o_nbottom == 0)
1550 1541 Die(gettext("invalid argument for -n\n"));
1551 1542 if (!(opts.o_outpmode & OPT_SPLIT) && (opts.o_outpmode & OPT_USERS) &&
1552 1543 ((opts.o_outpmode & (OPT_PSINFO | OPT_MSACCT))))
1553 1544 Die(gettext("-t option cannot be used with -v or -m\n"));
1554 1545
1555 1546 if ((opts.o_outpmode & OPT_SPLIT) && (opts.o_outpmode & OPT_USERS) &&
1556 1547 !((opts.o_outpmode & (OPT_PSINFO | OPT_MSACCT))))
1557 1548 Die(gettext("-t option cannot be used with "
1558 1549 "-a, -J, -T or -Z\n"));
1559 1550
1560 1551 if ((opts.o_outpmode & OPT_USERS) &&
1561 1552 (opts.o_outpmode & (OPT_TASKS | OPT_PROJECTS | OPT_ZONES)))
1562 1553 Die(gettext("-a option cannot be used with "
1563 1554 "-t, -J, -T or -Z\n"));
1564 1555
1565 1556 if (((opts.o_outpmode & OPT_TASKS) &&
1566 1557 (opts.o_outpmode & (OPT_PROJECTS|OPT_ZONES))) ||
1567 1558 ((opts.o_outpmode & OPT_PROJECTS) &&
1568 1559 (opts.o_outpmode & (OPT_TASKS|OPT_ZONES)))) {
1569 1560 Die(gettext(
1570 1561 "-J, -T and -Z options are mutually exclusive\n"));
1571 1562 }
1572 1563
1573 1564 /*
1574 1565 * There is not enough space to combine microstate information and
1575 1566 * lgroup information and still fit in 80-column output.
1576 1567 */
1577 1568 if ((opts.o_outpmode & OPT_LGRP) && (opts.o_outpmode & OPT_MSACCT)) {
1578 1569 Die(gettext("-H and -m options are mutually exclusive\n"));
1579 1570 }
1580 1571
1581 1572 if (argc > optind)
1582 1573 opts.o_interval = Atoi(argv[optind++]);
1583 1574 if (argc > optind)
1584 1575 opts.o_count = Atoi(argv[optind++]);
1585 1576 if (opts.o_count == 0)
1586 1577 Die(gettext("invalid counter value\n"));
1587 1578 if (argc > optind)
1588 1579 Usage();
1589 1580 if (opts.o_outpmode & OPT_REALTIME)
1590 1581 Priocntl("RT");
1591 1582 if (isatty(STDOUT_FILENO) == 1 && isatty(STDIN_FILENO))
1592 1583 opts.o_outpmode |= OPT_TTY; /* interactive */
1593 1584 if (!(opts.o_outpmode & OPT_TTY)) {
1594 1585 opts.o_outpmode &= ~OPT_TERMCAP; /* no termcap for pipes */
1595 1586 opts.o_outpmode &= ~OPT_FULLSCREEN;
1596 1587 }
1597 1588 if (opts.o_outpmode & OPT_TERMCAP)
1598 1589 ldtermcap(); /* can turn OPT_TERMCAP off */
1599 1590 if (opts.o_outpmode & OPT_TERMCAP)
1600 1591 (void) setsize();
1601 1592 list_alloc(&lwps, opts.o_ntop);
1602 1593 list_alloc(&users, opts.o_nbottom);
1603 1594 list_alloc(&tasks, opts.o_nbottom);
1604 1595 list_alloc(&projects, opts.o_nbottom);
1605 1596 list_alloc(&zones, opts.o_nbottom);
1606 1597 list_alloc(&lgroups, opts.o_nbottom);
1607 1598 list_setkeyfunc(sortk, &opts, &lwps, LT_LWPS);
1608 1599 list_setkeyfunc(NULL, &opts, &users, LT_USERS);
1609 1600 list_setkeyfunc(NULL, &opts, &tasks, LT_TASKS);
1610 1601 list_setkeyfunc(NULL, &opts, &projects, LT_PROJECTS);
1611 1602 list_setkeyfunc(NULL, &opts, &zones, LT_ZONES);
1612 1603 list_setkeyfunc(NULL, &opts, &lgroups, LT_LGRPS);
1613 1604 if (opts.o_outpmode & OPT_TERMCAP)
1614 1605 curses_on();
1615 1606 (void) proc_snprintf(procpath, sizeof (procpath), "/proc");
1616 1607 if ((procdir = opendir(procpath)) == NULL)
1617 1608 Die(gettext("cannot open /proc directory\n"));
1618 1609 if (opts.o_outpmode & OPT_TTY) {
1619 1610 (void) printf(gettext("Please wait...\r"));
1620 1611 if (!(opts.o_outpmode & OPT_TERMCAP))
1621 1612 (void) putchar('\n');
1622 1613 (void) fflush(stdout);
1623 1614 }
1624 1615 set_signals();
1625 1616 pollset.fd = STDIN_FILENO;
1626 1617 pollset.events = POLLIN;
1627 1618 timeout = opts.o_interval * MILLISEC;
1628 1619
1629 1620 /*
1630 1621 * main program loop
1631 1622 */
1632 1623 do {
1633 1624 if (sigterm == 1)
1634 1625 break;
1635 1626 if (sigtstp == 1) {
1636 1627 curses_off();
1637 1628 (void) signal(SIGTSTP, SIG_DFL);
1638 1629 (void) kill(0, SIGTSTP);
1639 1630 /*
1640 1631 * prstat stops here until it receives SIGCONT signal.
1641 1632 */
1642 1633 sigtstp = 0;
1643 1634 (void) signal(SIGTSTP, sig_handler);
1644 1635 curses_on();
1645 1636 print_movecur = FALSE;
1646 1637 if (opts.o_outpmode & OPT_FULLSCREEN)
1647 1638 sigwinch = 1;
1648 1639 }
1649 1640 if (sigwinch == 1) {
1650 1641 if (setsize() == 1) {
1651 1642 list_free(&lwps);
1652 1643 list_free(&users);
1653 1644 list_free(&tasks);
1654 1645 list_free(&projects);
1655 1646 list_free(&zones);
1656 1647 list_alloc(&lwps, opts.o_ntop);
1657 1648 list_alloc(&users, opts.o_nbottom);
1658 1649 list_alloc(&tasks, opts.o_nbottom);
1659 1650 list_alloc(&projects, opts.o_nbottom);
1660 1651 list_alloc(&zones, opts.o_nbottom);
1661 1652 }
1662 1653 sigwinch = 0;
1663 1654 (void) signal(SIGWINCH, sig_handler);
1664 1655 }
1665 1656 prstat_scandir(procdir);
1666 1657 list_refresh(&lwps);
1667 1658 if (print_movecur)
1668 1659 (void) putp(movecur);
1669 1660 print_movecur = TRUE;
1670 1661 if ((opts.o_outpmode & OPT_PSINFO) ||
1671 1662 (opts.o_outpmode & OPT_MSACCT)) {
1672 1663 list_sort(&lwps);
1673 1664 list_print(&lwps);
1674 1665 }
1675 1666 if (opts.o_outpmode & OPT_USERS) {
1676 1667 list_getsize(&users);
1677 1668 list_sort(&users);
1678 1669 list_print(&users);
1679 1670 list_clear(&users);
1680 1671 }
1681 1672 if (opts.o_outpmode & OPT_TASKS) {
1682 1673 list_getsize(&tasks);
1683 1674 list_sort(&tasks);
1684 1675 list_print(&tasks);
1685 1676 list_clear(&tasks);
1686 1677 }
1687 1678 if (opts.o_outpmode & OPT_PROJECTS) {
1688 1679 list_getsize(&projects);
1689 1680 list_sort(&projects);
1690 1681 list_print(&projects);
1691 1682 list_clear(&projects);
1692 1683 }
1693 1684 if (opts.o_outpmode & OPT_ZONES) {
1694 1685 list_getsize(&zones);
1695 1686 list_sort(&zones);
1696 1687 list_print(&zones);
1697 1688 list_clear(&zones);
1698 1689 }
1699 1690 if (opts.o_count == 1)
1700 1691 break;
1701 1692 /*
1702 1693 * If poll() returns -1 and sets errno to EINTR here because
1703 1694 * the process received a signal, it is Ok to abort this
1704 1695 * timeout and loop around because we check the signals at the
1705 1696 * top of the loop.
1706 1697 */
1707 1698 if (opts.o_outpmode & OPT_TTY) {
1708 1699 if (poll(&pollset, (nfds_t)1, timeout) > 0) {
1709 1700 if (read(STDIN_FILENO, &key, 1) == 1) {
1710 1701 if (tolower(key) == 'q')
1711 1702 break;
1712 1703 }
1713 1704 }
1714 1705 } else {
1715 1706 (void) sleep(opts.o_interval);
1716 1707 }
1717 1708 } while (opts.o_count == (-1) || --opts.o_count);
1718 1709
1719 1710 if (opts.o_outpmode & OPT_TTY)
1720 1711 (void) putchar('\r');
1721 1712 return (0);
1722 1713 }
|
↓ open down ↓ |
207 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX