1 /* $NetBSD: m_netbsd.c,v 1.30 2024/02/04 05:43:05 mrg Exp $ */ 2 3 /* 4 * top - a top users display for Unix 5 * 6 * SYNOPSIS: For a NetBSD-1.5 (or later) system 7 * 8 * DESCRIPTION: 9 * Originally written for BSD4.4 system by Christos Zoulas. 10 * Based on the FreeBSD 2.0 version by Steven Wallace and Wolfram Schneider. 11 * NetBSD-1.0 port by Arne Helme. Process ordering by Luke Mewburn. 12 * NetBSD-1.3 port by Luke Mewburn, based on code by Matthew Green. 13 * NetBSD-1.4/UVM port by matthew green. 14 * NetBSD-1.5 port by Simon Burge. 15 * NetBSD-1.6/UBC port by Tomas Svensson. 16 * - 17 * This is the machine-dependent module for NetBSD-1.5 and later 18 * works for: 19 * NetBSD-1.6ZC 20 * and should work for: 21 * NetBSD-2.0 (when released) 22 * - 23 * NetBSD-4.0 updates from Christos Zoulas. 24 * NetBSD-5.0 updates from Andrew Doran, Mindaugas Rasiukevicius and 25 * Christos Zoulas. 26 * NetBSD-6.0 updates from matthew green, Christos Zoulas, and 27 * Mindaugas Rasiukevicius. 28 * NetBSD-8 updates from Leonardo Taccari. 29 * NetBSD-10 updates from Christos Zoulas and matthew green. 30 * 31 * top does not need to be installed setuid or setgid with this module. 32 * 33 * LIBS: -lkvm 34 * 35 * CFLAGS: -DHAVE_GETOPT -DORDER -DHAVE_STRERROR 36 * 37 * AUTHORS: Christos Zoulas <christos@ee.cornell.edu> 38 * Steven Wallace <swallace@freebsd.org> 39 * Wolfram Schneider <wosch@cs.tu-berlin.de> 40 * Arne Helme <arne@acm.org> 41 * Luke Mewburn <lukem@NetBSD.org> 42 * matthew green <mrg@eterna23.net> 43 * Simon Burge <simonb@NetBSD.org> 44 * Tomas Svensson <ts@unix1.net> 45 * Andrew Doran <ad@NetBSD.org> 46 * 47 * 48 * $Id: m_netbsd.c,v 1.30 2024/02/04 05:43:05 mrg Exp $ 49 */ 50 #include <sys/cdefs.h> 51 52 #ifndef lint 53 __RCSID("$NetBSD: m_netbsd.c,v 1.30 2024/02/04 05:43:05 mrg Exp $"); 54 #endif 55 56 #include <sys/param.h> 57 #include <sys/resource.h> 58 #include <sys/sysctl.h> 59 #include <sys/sched.h> 60 #include <sys/swap.h> 61 #include <sys/socket.h> 62 63 #include <net/route.h> 64 65 #include <uvm/uvm_extern.h> 66 67 #include <err.h> 68 #include <errno.h> 69 #include <kvm.h> 70 #include <math.h> 71 #include <ctype.h> 72 #include <nlist.h> 73 #include <stdio.h> 74 #include <stdlib.h> 75 #include <string.h> 76 #include <unistd.h> 77 78 #include "os.h" 79 #include "top.h" 80 #include "machine.h" 81 #include "utils.h" 82 #include "display.h" 83 #include "loadavg.h" 84 #include "username.h" 85 86 static void percentages64(int, int *, u_int64_t *, u_int64_t *, 87 u_int64_t *); 88 89 /* get_process_info passes back a handle. This is what it looks like: */ 90 91 struct handle { 92 struct process_select *sel; 93 struct kinfo_proc2 **next_proc; /* points to next valid proc pointer */ 94 int remaining; /* number of pointers remaining */ 95 }; 96 97 /* define what weighted CPU is. */ 98 #define weighted_cpu(pfx, pct, pp) ((pp)->pfx ## swtime == 0 ? 0.0 : \ 99 ((pct) / (1.0 - exp((pp)->pfx ## swtime * logcpu)))) 100 101 /* what we consider to be process size: */ 102 /* NetBSD introduced p_vm_msize with RLIMIT_AS */ 103 #ifdef RLIMIT_AS 104 #define PROCSIZE(pp) \ 105 ((pp)->p_vm_msize) 106 #else 107 #define PROCSIZE(pp) \ 108 ((pp)->p_vm_tsize + (pp)->p_vm_dsize + (pp)->p_vm_ssize) 109 #endif 110 111 112 /* 113 * These definitions control the format of the per-process area 114 */ 115 116 static char Proc_header[] = 117 " PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND"; 118 /* 0123456 -- field to fill in starts at header+6 */ 119 #define PROC_UNAME_START 6 120 #define Proc_format \ 121 "%5d %-8.8s %3d %4d%7s %5s %-9.9s%7s %5.*f%% %5.*f%% %s" 122 123 static char Thread_header[] = 124 " PID LID X PRI STATE TIME WCPU CPU NAME COMMAND"; 125 /* 0123456 -- field to fill in starts at header+6 */ 126 #define THREAD_UNAME_START 12 127 #define Thread_format \ 128 "%5d %5d %-8.8s %3d %-9.9s%7s %5.2f%% %5.2f%% %-9.9s %s" 129 130 /* 131 * Process state names for the "STATE" column of the display. 132 */ 133 134 const char *state_abbrev[] = { 135 "", "IDLE", "RUN", "SLEEP", "STOP", "ZOMB", "DEAD", "CPU" 136 }; 137 138 static kvm_t *kd; 139 140 static char *(*userprint)(int); 141 142 /* these are retrieved from the kernel in _init */ 143 144 static double logcpu; 145 static int hz; 146 static int ccpu; 147 148 /* these are for calculating CPU state percentages */ 149 150 static int ncpu = 0; 151 static u_int64_t *cp_time; 152 static u_int64_t *cp_old; 153 static u_int64_t *cp_diff; 154 155 /* these are for detailing the process states */ 156 157 int process_states[8]; 158 const char *procstatenames[] = { 159 "", " idle, ", " runnable, ", " sleeping, ", " stopped, ", 160 " zombie, ", " dead, ", " on CPU, ", 161 NULL 162 }; 163 164 /* these are for detailing the CPU states */ 165 166 int *cpu_states; 167 const char *cpustatenames[] = { 168 "user", "nice", "system", "interrupt", "idle", NULL 169 }; 170 171 /* these are for detailing the memory statistics */ 172 173 long memory_stats[7]; 174 const char *memorynames[] = { 175 "K Act, ", "K Inact, ", "K Wired, ", "K Exec, ", "K File, ", 176 "K Free, ", 177 NULL 178 }; 179 180 long swap_stats[9]; 181 const char *swapnames[] = { 182 "K Total, ", "K Used, ", "K Free ", " Pools: ", "K Used ", 183 " Network: ", "K In, ", "K Out, ", 184 NULL 185 }; 186 187 188 /* these are names given to allowed sorting orders -- first is default */ 189 const char *ordernames[] = { 190 "cpu", 191 "pri", 192 "res", 193 "size", 194 "state", 195 "time", 196 "pid", 197 "command", 198 "username", 199 NULL 200 }; 201 202 /* forward definitions for comparison functions */ 203 static int compare_cpu(struct proc **, struct proc **); 204 static int compare_prio(struct proc **, struct proc **); 205 static int compare_res(struct proc **, struct proc **); 206 static int compare_size(struct proc **, struct proc **); 207 static int compare_state(struct proc **, struct proc **); 208 static int compare_time(struct proc **, struct proc **); 209 static int compare_pid(struct proc **, struct proc **); 210 static int compare_command(struct proc **, struct proc **); 211 static int compare_username(struct proc **, struct proc **); 212 213 int (*proc_compares[])(struct proc **, struct proc **) = { 214 compare_cpu, 215 compare_prio, 216 compare_res, 217 compare_size, 218 compare_state, 219 compare_time, 220 compare_pid, 221 compare_command, 222 compare_username, 223 NULL 224 }; 225 226 static char *format_next_lwp(caddr_t, char *(*)(int)); 227 static char *format_next_proc(caddr_t, char *(*)(int)); 228 229 static caddr_t get_proc_info(struct system_info *, struct process_select *, 230 int (*)(struct proc **, struct proc **)); 231 static caddr_t get_lwp_info(struct system_info *, struct process_select *, 232 int (*)(struct proc **, struct proc **)); 233 234 /* these are for keeping track of the proc array */ 235 236 static int nproc; 237 static int onproc = -1; 238 static int nlwp; 239 static int onlwp = -1; 240 static int pref_len; 241 static int lref_len; 242 static struct kinfo_proc2 *pbase; 243 static struct kinfo_lwp *lbase; 244 static struct kinfo_proc2 **pref; 245 static struct kinfo_lwp **lref; 246 static int maxswap; 247 static void *swapp; 248 static int procgen; 249 static int thread_nproc; 250 static int thread_onproc = -1; 251 static struct kinfo_proc2 *thread_pbase; 252 253 /* these are for getting the memory statistics */ 254 255 static int pageshift; /* log base 2 of the pagesize */ 256 257 int threadmode; 258 259 /* define pagetok in terms of pageshift */ 260 261 #define pagetok(size) ((size) << pageshift) 262 263 /* 264 * Print swapped processes as <pname> and 265 * system processes as [pname] 266 */ 267 static const char * 268 get_pretty(const struct kinfo_proc2 *pp) 269 { 270 if ((pp->p_flag & P_SYSTEM) != 0) 271 return "[]"; 272 if ((pp->p_flag & P_INMEM) == 0) 273 return "<>"; 274 return ""; 275 } 276 277 static const char * 278 get_command(const struct process_select *sel, struct kinfo_proc2 *pp) 279 { 280 static char cmdbuf[128]; 281 const char *pretty; 282 char **argv; 283 if (pp == NULL) 284 return "<gone>"; 285 pretty = get_pretty(pp); 286 287 if (sel->fullcmd == 0 || kd == NULL || (argv = kvm_getargv2(kd, pp, 288 sizeof(cmdbuf))) == NULL) { 289 if (pretty[0] != '\0' && pp->p_comm[0] != pretty[0]) 290 snprintf(cmdbuf, sizeof(cmdbuf), "%c%s%c", pretty[0], 291 printable(pp->p_comm), pretty[1]); 292 else 293 strlcpy(cmdbuf, printable(pp->p_comm), sizeof(cmdbuf)); 294 } else { 295 char *d = cmdbuf; 296 if (pretty[0] != '\0' && argv[0][0] != pretty[0]) 297 *d++ = pretty[0]; 298 while (*argv) { 299 const char *s = printable(*argv++); 300 while (d < cmdbuf + sizeof(cmdbuf) - 2 && 301 (*d++ = *s++) != '\0') 302 continue; 303 if (d > cmdbuf && d < cmdbuf + sizeof(cmdbuf) - 2 && 304 d[-1] == '\0') 305 d[-1] = ' '; 306 } 307 if (pretty[0] != '\0' && pretty[0] == cmdbuf[0]) 308 *d++ = pretty[1]; 309 *d++ = '\0'; 310 } 311 return cmdbuf; 312 } 313 314 int 315 machine_init(statics) 316 struct statics *statics; 317 { 318 int pagesize; 319 int mib[2]; 320 size_t size; 321 struct clockinfo clockinfo; 322 struct timespec boottime; 323 324 if ((kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open")) == NULL) 325 return -1; 326 327 mib[0] = CTL_HW; 328 mib[1] = HW_NCPU; 329 size = sizeof(ncpu); 330 if (sysctl(mib, 2, &ncpu, &size, NULL, 0) == -1) { 331 fprintf(stderr, "top: sysctl hw.ncpu failed: %s\n", 332 strerror(errno)); 333 return(-1); 334 } 335 statics->ncpu = ncpu; 336 cp_time = malloc(sizeof(cp_time[0]) * CPUSTATES * ncpu); 337 mib[0] = CTL_KERN; 338 mib[1] = KERN_CP_TIME; 339 size = sizeof(cp_time[0]) * CPUSTATES * ncpu; 340 if (sysctl(mib, 2, cp_time, &size, NULL, 0) < 0) { 341 fprintf(stderr, "top: sysctl kern.cp_time failed: %s\n", 342 strerror(errno)); 343 return(-1); 344 } 345 346 /* Handle old call that returned only aggregate */ 347 if (size == sizeof(cp_time[0]) * CPUSTATES) 348 ncpu = 1; 349 350 cpu_states = malloc(sizeof(cpu_states[0]) * CPUSTATES * ncpu); 351 cp_old = calloc(CPUSTATES * ncpu, sizeof(cp_old[0])); 352 cp_diff = malloc(sizeof(cp_diff[0]) * CPUSTATES * ncpu); 353 if (cpu_states == NULL || cp_time == NULL || cp_old == NULL || 354 cp_diff == NULL) { 355 fprintf(stderr, "top: machine_init: %s\n", 356 strerror(errno)); 357 return(-1); 358 } 359 360 mib[0] = CTL_KERN; 361 mib[1] = KERN_CCPU; 362 size = sizeof(ccpu); 363 if (sysctl(mib, 2, &ccpu, &size, NULL, 0) == -1) { 364 fprintf(stderr, "top: sysctl kern.ccpu failed: %s\n", 365 strerror(errno)); 366 return(-1); 367 } 368 369 mib[0] = CTL_KERN; 370 mib[1] = KERN_CLOCKRATE; 371 size = sizeof(clockinfo); 372 if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) == -1) { 373 fprintf(stderr, "top: sysctl kern.clockrate failed: %s\n", 374 strerror(errno)); 375 return(-1); 376 } 377 hz = clockinfo.stathz; 378 379 /* this is used in calculating WCPU -- calculate it ahead of time */ 380 logcpu = log(loaddouble(ccpu)); 381 382 pbase = NULL; 383 lbase = NULL; 384 pref = NULL; 385 nproc = 0; 386 onproc = -1; 387 nlwp = 0; 388 onlwp = -1; 389 /* get the page size with "getpagesize" and calculate pageshift from it */ 390 pagesize = getpagesize(); 391 pageshift = 0; 392 while (pagesize > 1) { 393 pageshift++; 394 pagesize >>= 1; 395 } 396 397 /* we only need the amount of log(2)1024 for our conversion */ 398 pageshift -= LOG1024; 399 400 /* fill in the statics information */ 401 #ifdef notyet 402 statics->ncpu = ncpu; 403 #endif 404 statics->procstate_names = procstatenames; 405 statics->cpustate_names = cpustatenames; 406 statics->memory_names = memorynames; 407 statics->swap_names = swapnames; 408 statics->order_names = ordernames; 409 statics->flags.threads = 1; 410 statics->flags.fullcmds = 1; 411 412 mib[0] = CTL_KERN; 413 mib[1] = KERN_BOOTTIME; 414 size = sizeof(boottime); 415 if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && 416 boottime.tv_sec != 0) 417 statics->boottime = boottime.tv_sec; 418 else 419 statics->boottime = 0; 420 /* all done! */ 421 return(0); 422 } 423 424 char * 425 format_process_header(struct process_select *sel, caddr_t handle, int count) 426 427 { 428 char *header; 429 char *ptr; 430 const char *uname_field = sel->usernames ? "USERNAME" : " UID "; 431 432 if (sel->threads) { 433 header = Thread_header; 434 ptr = header + THREAD_UNAME_START; 435 } else { 436 header = Proc_header; 437 ptr = header + PROC_UNAME_START; 438 } 439 440 while (*uname_field != '\0') { 441 *ptr++ = *uname_field++; 442 } 443 444 return(header); 445 } 446 447 char * 448 format_header(char *uname_field) 449 { 450 char *header = Proc_header; 451 char *ptr = header + PROC_UNAME_START; 452 453 while (*uname_field != '\0') { 454 *ptr++ = *uname_field++; 455 } 456 457 return(header); 458 } 459 460 static void 461 get_network_kilobytes(long *kb_in, long *kb_out) 462 { 463 struct if_msghdr *ifm; 464 int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; 465 struct rt_msghdr *rtm; 466 struct if_data *ifd = NULL; 467 static char *buf = NULL; 468 static size_t olen; 469 char *next, *lim; 470 size_t len; 471 static uint64_t last_bytes_in; 472 static uint64_t last_bytes_out; 473 uint64_t cur_bytes_in = 0; 474 uint64_t cur_bytes_out = 0; 475 476 if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) 477 err(1, "sysctl"); 478 if (len > olen) { 479 free(buf); 480 if ((buf = malloc(len)) == NULL) 481 err(1, NULL); 482 olen = len; 483 } 484 if (sysctl(mib, 6, buf, &len, NULL, 0) == -1) 485 err(1, "sysctl"); 486 487 lim = buf + len; 488 for (next = buf; next < lim; next += rtm->rtm_msglen) { 489 rtm = (struct rt_msghdr *)next; 490 if (rtm->rtm_version != RTM_VERSION) 491 continue; 492 switch (rtm->rtm_type) { 493 case RTM_IFINFO: 494 ifm = (struct if_msghdr *)next; 495 ifd = &ifm->ifm_data; 496 497 cur_bytes_in += ifd->ifi_ibytes; 498 cur_bytes_out += ifd->ifi_obytes; 499 break; 500 } 501 } 502 503 *kb_in = (cur_bytes_in - last_bytes_in) / 1024; 504 *kb_out = (cur_bytes_out - last_bytes_out) / 1024; 505 last_bytes_in = cur_bytes_in; 506 last_bytes_out = cur_bytes_out; 507 } 508 509 void 510 get_system_info(struct system_info *si) 511 { 512 size_t ssize; 513 int mib[6]; 514 struct uvmexp_sysctl uvmexp; 515 struct swapent *sep; 516 u_int64_t totalsize, totalinuse; 517 int size, inuse, ncounted, i; 518 int rnswap, nswap; 519 520 mib[0] = CTL_KERN; 521 mib[1] = KERN_CP_TIME; 522 ssize = sizeof(cp_time[0]) * CPUSTATES * ncpu; 523 if (sysctl(mib, 2, cp_time, &ssize, NULL, 0) < 0) { 524 fprintf(stderr, "top: sysctl kern.cp_time failed: %s\n", 525 strerror(errno)); 526 quit(23); 527 } 528 529 if (getloadavg(si->load_avg, NUM_AVERAGES) < 0) { 530 int j; 531 532 warn("can't getloadavg"); 533 for (j = 0; j < NUM_AVERAGES; j++) 534 si->load_avg[j] = 0.0; 535 } 536 537 /* convert cp_time counts to percentages */ 538 for (i = 0; i < ncpu; i++) { 539 int j = i * CPUSTATES; 540 percentages64(CPUSTATES, cpu_states + j, cp_time + j, cp_old + j, 541 cp_diff + j); 542 } 543 544 mib[0] = CTL_VM; 545 mib[1] = VM_UVMEXP2; 546 ssize = sizeof(uvmexp); 547 if (sysctl(mib, 2, &uvmexp, &ssize, NULL, 0) < 0) { 548 fprintf(stderr, "top: sysctl vm.uvmexp2 failed: %s\n", 549 strerror(errno)); 550 quit(23); 551 } 552 553 /* convert memory stats to Kbytes */ 554 memory_stats[0] = pagetok(uvmexp.active); 555 memory_stats[1] = pagetok(uvmexp.inactive); 556 memory_stats[2] = pagetok(uvmexp.wired); 557 memory_stats[3] = pagetok(uvmexp.execpages); 558 memory_stats[4] = pagetok(uvmexp.filepages); 559 memory_stats[5] = pagetok(uvmexp.free); 560 561 swap_stats[0] = swap_stats[1] = swap_stats[2] = 0; 562 563 do { 564 nswap = swapctl(SWAP_NSWAP, 0, 0); 565 if (nswap < 1) 566 break; 567 if (nswap > maxswap) { 568 if (swapp) 569 free(swapp); 570 swapp = sep = malloc(nswap * sizeof(*sep)); 571 if (sep == NULL) 572 break; 573 maxswap = nswap; 574 } else 575 sep = swapp; 576 rnswap = swapctl(SWAP_STATS, (void *)sep, nswap); 577 if (nswap != rnswap) 578 break; 579 580 totalsize = totalinuse = ncounted = 0; 581 for (; rnswap-- > 0; sep++) { 582 ncounted++; 583 size = sep->se_nblks; 584 inuse = sep->se_inuse; 585 totalsize += size; 586 totalinuse += inuse; 587 } 588 swap_stats[0] = dbtob(totalsize) / 1024; 589 swap_stats[1] = dbtob(totalinuse) / 1024; 590 swap_stats[2] = dbtob(totalsize) / 1024 - swap_stats[1]; 591 } while (0); 592 593 swap_stats[4] = pagetok(uvmexp.poolpages); 594 595 get_network_kilobytes(&swap_stats[6], &swap_stats[7]); 596 597 memory_stats[6] = -1; 598 swap_stats[3] = swap_stats[5] = swap_stats[8] = -1; 599 600 /* set arrays and strings */ 601 si->cpustates = cpu_states; 602 si->memory = memory_stats; 603 si->swap = swap_stats; 604 si->last_pid = -1; 605 606 } 607 608 static struct kinfo_proc2 * 609 proc_from_thread(struct kinfo_lwp *pl) 610 { 611 struct kinfo_proc2 *pp = thread_pbase; 612 int i; 613 614 for (i = 0; i < thread_nproc; i++, pp++) 615 if ((pid_t)pp->p_pid == (pid_t)pl->l_pid) 616 return pp; 617 return NULL; 618 } 619 620 static int 621 uid_from_thread(struct kinfo_lwp *pl) 622 { 623 struct kinfo_proc2 *pp; 624 625 if ((pp = proc_from_thread(pl)) == NULL) 626 return -1; 627 return pp->p_ruid; 628 } 629 630 caddr_t 631 get_process_info(struct system_info *si, struct process_select *sel, int c) 632 { 633 userprint = sel->usernames ? username : itoa7; 634 635 if ((threadmode = sel->threads) != 0) 636 return get_lwp_info(si, sel, proc_compares[c]); 637 else 638 return get_proc_info(si, sel, proc_compares[c]); 639 } 640 641 static caddr_t 642 get_proc_info(struct system_info *si, struct process_select *sel, 643 int (*compare)(struct proc **, struct proc **)) 644 { 645 int i; 646 int total_procs; 647 int active_procs; 648 struct kinfo_proc2 **prefp, **n; 649 struct kinfo_proc2 *pp; 650 int op, arg; 651 652 /* these are copied out of sel for speed */ 653 int show_idle; 654 int show_system; 655 int show_uid; 656 char *show_command; 657 658 static struct handle handle; 659 660 procgen++; 661 662 if (sel->pid == (pid_t)-1) { 663 op = KERN_PROC_ALL; 664 arg = 0; 665 } else { 666 op = KERN_PROC_PID; 667 arg = sel->pid; 668 } 669 670 pbase = kvm_getproc2(kd, op, arg, sizeof(struct kinfo_proc2), &nproc); 671 if (pbase == NULL) { 672 if (sel->pid != (pid_t)-1) { 673 nproc = 0; 674 } else { 675 (void) fprintf(stderr, "top: Out of memory.\n"); 676 quit(23); 677 } 678 } 679 if (nproc > onproc) { 680 n = (struct kinfo_proc2 **) realloc(pref, 681 sizeof(struct kinfo_proc2 *) * nproc); 682 if (n == NULL) { 683 (void) fprintf(stderr, "top: Out of memory.\n"); 684 quit(23); 685 } 686 pref = n; 687 onproc = nproc; 688 } 689 /* get a pointer to the states summary array */ 690 si->procstates = process_states; 691 692 /* set up flags which define what we are going to select */ 693 show_idle = sel->idle; 694 show_system = sel->system; 695 show_uid = sel->uid != -1; 696 show_command = sel->command; 697 698 /* count up process states and get pointers to interesting procs */ 699 total_procs = 0; 700 active_procs = 0; 701 memset((char *)process_states, 0, sizeof(process_states)); 702 prefp = pref; 703 for (pp = pbase, i = 0; i < nproc; pp++, i++) { 704 705 /* 706 * Place pointers to each valid proc structure in pref[]. 707 * Process slots that are actually in use have a non-zero 708 * status field. Processes with P_SYSTEM set are system 709 * processes---these get ignored unless show_sysprocs is set. 710 */ 711 if (pp->p_stat != 0 && (show_system || ((pp->p_flag & P_SYSTEM) == 0))) { 712 total_procs++; 713 process_states[(unsigned char) pp->p_stat]++; 714 if (pp->p_stat != LSZOMB && 715 (show_idle || (pp->p_pctcpu != 0) || 716 (pp->p_stat == LSRUN || pp->p_stat == LSONPROC)) && 717 (!show_uid || pp->p_ruid == (uid_t)sel->uid) && 718 (!show_command || 719 strstr(get_command(sel, pp), 720 show_command) != NULL)) { 721 *prefp++ = pp; 722 active_procs++; 723 } 724 } 725 } 726 727 /* if requested, sort the "interesting" processes */ 728 if (compare != NULL) { 729 qsort((char *)pref, active_procs, sizeof(struct kinfo_proc2 *), 730 (int (*)(const void *, const void *))compare); 731 } 732 733 /* remember active and total counts */ 734 si->p_total = total_procs; 735 si->p_active = pref_len = active_procs; 736 737 /* pass back a handle */ 738 handle.next_proc = pref; 739 handle.remaining = active_procs; 740 handle.sel = sel; 741 return((caddr_t)&handle); 742 } 743 744 static caddr_t 745 get_lwp_info(struct system_info *si, struct process_select *sel, 746 int (*compare)(struct proc **, struct proc **)) 747 { 748 int i; 749 int total_lwps; 750 int active_lwps; 751 struct kinfo_lwp **lrefp, **n; 752 struct kinfo_lwp *lp; 753 struct kinfo_proc2 *pp; 754 755 /* these are copied out of sel for speed */ 756 int show_idle; 757 int show_system; 758 int show_uid; 759 char *show_command; 760 761 static struct handle handle; 762 763 pp = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2), 764 &thread_nproc); 765 if (pp == NULL) { 766 (void) fprintf(stderr, "top: Out of memory.\n"); 767 quit(23); 768 } 769 if (thread_pbase == NULL || thread_nproc != thread_onproc) { 770 free(thread_pbase); 771 thread_onproc = thread_nproc; 772 thread_pbase = calloc(sizeof(struct kinfo_proc2), thread_nproc); 773 if (thread_pbase == NULL) { 774 (void) fprintf(stderr, "top: Out of memory.\n"); 775 quit(23); 776 } 777 } 778 memcpy(thread_pbase, pp, sizeof(struct kinfo_proc2) * thread_nproc); 779 780 lbase = kvm_getlwps(kd, -1, 0, sizeof(struct kinfo_lwp), &nlwp); 781 if (lbase == NULL) { 782 #ifdef notyet 783 if (sel->pid != (pid_t)-1) { 784 nproc = 0; 785 nlwp = 0; 786 } 787 else 788 #endif 789 { 790 (void) fprintf(stderr, "top: Out of memory.\n"); 791 quit(23); 792 } 793 } 794 if (nlwp > onlwp) { 795 n = (struct kinfo_lwp **) realloc(lref, 796 sizeof(struct kinfo_lwp *) * nlwp); 797 if (n == NULL) { 798 (void) fprintf(stderr, "top: Out of memory.\n"); 799 quit(23); 800 } 801 lref = n; 802 onlwp = nlwp; 803 } 804 /* get a pointer to the states summary array */ 805 si->procstates = process_states; 806 807 /* set up flags which define what we are going to select */ 808 show_idle = sel->idle; 809 show_system = sel->system; 810 show_uid = sel->uid != -1; 811 show_command = sel->command; 812 813 /* count up thread states and get pointers to interesting threads */ 814 total_lwps = 0; 815 active_lwps = 0; 816 memset((char *)process_states, 0, sizeof(process_states)); 817 lrefp = lref; 818 for (lp = lbase, i = 0; i < nlwp; lp++, i++) { 819 if (sel->pid != (pid_t)-1 && sel->pid != (pid_t)lp->l_pid) 820 continue; 821 822 /* 823 * Place pointers to each valid lwp structure in lref[]. 824 * thread slots that are actually in use have a non-zero 825 * status field. threads with L_SYSTEM set are system 826 * threads---these get ignored unless show_sysprocs is set. 827 */ 828 if (lp->l_stat != 0 && 829 (show_system || ((lp->l_flag & LW_SYSTEM) == 0))) { 830 total_lwps++; 831 process_states[(unsigned char) lp->l_stat]++; 832 if (lp->l_stat != LSZOMB && 833 (show_idle || (lp->l_pctcpu != 0) || 834 (lp->l_stat == LSRUN || lp->l_stat == LSONPROC)) && 835 (!show_uid || uid_from_thread(lp) == sel->uid) && 836 (!show_command || 837 ((pp = proc_from_thread(lp)) != NULL && 838 strstr(get_command(sel, pp), 839 show_command) != NULL))) { 840 *lrefp++ = lp; 841 active_lwps++; 842 } 843 } 844 } 845 846 /* if requested, sort the "interesting" threads */ 847 if (compare != NULL) { 848 qsort((char *)lref, active_lwps, sizeof(struct kinfo_lwp *), 849 (int (*)(const void *, const void *))compare); 850 } 851 852 /* remember active and total counts */ 853 si->p_total = total_lwps; 854 si->p_active = lref_len = active_lwps; 855 856 /* pass back a handle */ 857 handle.next_proc = (struct kinfo_proc2 **)lref; 858 handle.remaining = active_lwps; 859 handle.sel = sel; 860 861 return((caddr_t)&handle); 862 } 863 864 char * 865 format_next_process(caddr_t handle, char *(*get_userid)(int)) 866 { 867 868 if (threadmode) 869 return format_next_lwp(handle, get_userid); 870 else 871 return format_next_proc(handle, get_userid); 872 } 873 874 875 char * 876 format_next_proc(caddr_t handle, char *(*get_userid)(int)) 877 { 878 struct kinfo_proc2 *pp; 879 long cputime; 880 double pct, wcpu, cpu; 881 struct handle *hp; 882 const char *statep; 883 #ifdef KI_NOCPU 884 char state[10]; 885 #endif 886 char wmesg[KI_WMESGLEN + 1]; 887 static char fmt[MAX_COLS]; /* static area where result is built */ 888 889 /* find and remember the next proc structure */ 890 hp = (struct handle *)handle; 891 pp = *(hp->next_proc++); 892 hp->remaining--; 893 894 /* get the process's user struct and set cputime */ 895 896 #if 0 897 /* This does not produce the correct results */ 898 cputime = pp->p_uticks + pp->p_sticks + pp->p_iticks; 899 #else 900 cputime = pp->p_rtime_sec; /* This does not count interrupts */ 901 #endif 902 903 /* calculate the base for CPU percentages */ 904 pct = pctdouble(pp->p_pctcpu); 905 906 if (pp->p_stat == LSSLEEP) { 907 strlcpy(wmesg, pp->p_wmesg, sizeof(wmesg)); 908 statep = wmesg; 909 } else 910 statep = state_abbrev[(unsigned)pp->p_stat]; 911 912 #ifdef KI_NOCPU 913 /* Post-1.5 change: add CPU number if appropriate */ 914 if (pp->p_cpuid != KI_NOCPU && ncpu > 1) { 915 switch (pp->p_stat) { 916 case LSONPROC: 917 case LSRUN: 918 case LSSLEEP: 919 case LSIDL: 920 (void)snprintf(state, sizeof(state), "%.6s/%u", 921 statep, (unsigned int)pp->p_cpuid); 922 statep = state; 923 break; 924 } 925 } 926 #endif 927 wcpu = 100.0 * weighted_cpu(p_, pct, pp); 928 cpu = 100.0 * pct; 929 930 /* format this entry */ 931 sprintf(fmt, 932 Proc_format, 933 pp->p_pid, 934 (*userprint)(pp->p_ruid), 935 pp->p_priority, 936 pp->p_nice - NZERO, 937 format_k(pagetok(PROCSIZE(pp))), 938 format_k(pagetok(pp->p_vm_rssize)), 939 statep, 940 format_time(cputime), 941 (wcpu >= 100.0) ? 0 : 2, wcpu, 942 (cpu >= 100.0) ? 0 : 2, cpu, 943 get_command(hp->sel, pp)); 944 945 /* return the result */ 946 return(fmt); 947 } 948 949 static char * 950 countable(char *p, size_t width) 951 { 952 size_t len = strlen(p); 953 if (len < width) { // shorter than width, ok 954 return p; 955 } 956 size_t first, last = len - 1; 957 for (first = len - 1; isdigit((unsigned char)p[first]); first--) { 958 continue; 959 } 960 if (first == len - 1) { // no digits, ok 961 return p; 962 } 963 first++; 964 last = len - first; 965 if (width < last + 1) { // if not enough for digits, done 966 return p; 967 } 968 size_t start = width - last - 1; // compute starting point 969 p[start] = '*'; // put a star 970 memmove(p + start + 1, p + first, last + 1); // move digits and NUL 971 return p; 972 } 973 974 static char * 975 format_next_lwp(caddr_t handle, char *(*get_userid)(int)) 976 { 977 struct kinfo_proc2 *pp; 978 struct kinfo_lwp *pl; 979 long cputime; 980 double pct; 981 struct handle *hp; 982 const char *statep; 983 #ifdef KI_NOCPU 984 char state[10]; 985 #endif 986 char wmesg[KI_WMESGLEN + 1]; 987 static char fmt[MAX_COLS]; /* static area where result is built */ 988 int uid; 989 990 /* find and remember the next proc structure */ 991 hp = (struct handle *)handle; 992 pl = (struct kinfo_lwp *)*(hp->next_proc++); 993 hp->remaining--; 994 pp = proc_from_thread(pl); 995 996 /* get the process's user struct and set cputime */ 997 uid = pp ? pp->p_ruid : 0; 998 999 cputime = pl->l_rtime_sec; 1000 1001 /* calculate the base for CPU percentages */ 1002 pct = pctdouble(pl->l_pctcpu); 1003 1004 if (pl->l_stat == LSSLEEP) { 1005 strlcpy(wmesg, pl->l_wmesg, sizeof(wmesg)); 1006 statep = wmesg; 1007 } else 1008 statep = state_abbrev[(unsigned)pl->l_stat]; 1009 1010 #ifdef KI_NOCPU 1011 /* Post-1.5 change: add CPU number if appropriate */ 1012 if (pl->l_cpuid != KI_NOCPU && ncpu > 1) { 1013 switch (pl->l_stat) { 1014 case LSONPROC: 1015 case LSRUN: 1016 case LSSLEEP: 1017 case LSIDL: 1018 (void)snprintf(state, sizeof(state), "%.6s/%u", 1019 statep, (unsigned int)pl->l_cpuid); 1020 statep = state; 1021 break; 1022 } 1023 } 1024 #endif 1025 1026 if (pl->l_name[0] == '\0') { 1027 pl->l_name[0] = '-'; 1028 pl->l_name[1] = '\0'; 1029 } 1030 1031 /* format this entry */ 1032 sprintf(fmt, 1033 Thread_format, 1034 pl->l_pid, 1035 pl->l_lid, 1036 (*userprint)(uid), 1037 pl->l_priority, 1038 statep, 1039 format_time(cputime), 1040 100.0 * weighted_cpu(l_, pct, pl), 1041 100.0 * pct, 1042 countable(printable(pl->l_name), 9), 1043 get_command(hp->sel, pp)); 1044 1045 /* return the result */ 1046 return(fmt); 1047 } 1048 1049 /* comparison routines for qsort */ 1050 1051 /* 1052 * There are currently four possible comparison routines. main selects 1053 * one of these by indexing in to the array proc_compares. 1054 * 1055 * Possible keys are defined as macros below. Currently these keys are 1056 * defined: percent CPU, CPU ticks, process state, resident set size, 1057 * total virtual memory usage. The process states are ordered as follows 1058 * (from least to most important): WAIT, zombie, sleep, stop, start, run. 1059 * The array declaration below maps a process state index into a number 1060 * that reflects this ordering. 1061 */ 1062 1063 /* 1064 * First, the possible comparison keys. These are defined in such a way 1065 * that they can be merely listed in the source code to define the actual 1066 * desired ordering. 1067 */ 1068 1069 #define ORDERKEY_PCTCPU(pfx) \ 1070 if (lresult = (pctcpu)(p2)->pfx ## pctcpu - (pctcpu)(p1)->pfx ## pctcpu,\ 1071 (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0) 1072 1073 #define ORDERKEY_CPTICKS(pfx) \ 1074 if (lresult = (pctcpu)(p2)->pfx ## rtime_sec \ 1075 - (pctcpu)(p1)->pfx ## rtime_sec,\ 1076 (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0) 1077 1078 #define ORDERKEY_STATE(pfx) \ 1079 if ((result = sorted_state[(int)(p2)->pfx ## stat] - \ 1080 sorted_state[(int)(p1)->pfx ## stat] ) == 0) 1081 1082 #define ORDERKEY_PRIO(pfx) \ 1083 if ((result = (p2)->pfx ## priority - (p1)->pfx ## priority) == 0) 1084 1085 #define ORDERKEY_RSSIZE \ 1086 if ((result = p2->p_vm_rssize - p1->p_vm_rssize) == 0) 1087 1088 #define ORDERKEY_MEM \ 1089 if ((result = (PROCSIZE(p2) - PROCSIZE(p1))) == 0) 1090 #define ORDERKEY_SIZE(v1, v2) \ 1091 if ((result = (v2 - v1)) == 0) 1092 1093 /* 1094 * Now the array that maps process state to a weight. 1095 * The order of the elements should match those in state_abbrev[] 1096 */ 1097 1098 static int sorted_state[] = { 1099 0, /* (not used) ? */ 1100 1, /* "start" SIDL */ 1101 4, /* "run" SRUN */ 1102 3, /* "sleep" SSLEEP */ 1103 3, /* "stop" SSTOP */ 1104 2, /* "dead" SDEAD */ 1105 1, /* "zomb" SZOMB */ 1106 5, /* "onproc" SONPROC */ 1107 }; 1108 1109 /* compare_cpu - the comparison function for sorting by CPU percentage */ 1110 1111 static int 1112 compare_cpu(pp1, pp2) 1113 struct proc **pp1, **pp2; 1114 { 1115 int result; 1116 pctcpu lresult; 1117 1118 if (threadmode) { 1119 struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1; 1120 struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2; 1121 1122 ORDERKEY_PCTCPU(l_) 1123 ORDERKEY_CPTICKS(l_) 1124 ORDERKEY_STATE(l_) 1125 ORDERKEY_PRIO(l_) 1126 return result; 1127 } else { 1128 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 1129 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 1130 1131 ORDERKEY_PCTCPU(p_) 1132 ORDERKEY_CPTICKS(p_) 1133 ORDERKEY_STATE(p_) 1134 ORDERKEY_PRIO(p_) 1135 ORDERKEY_RSSIZE 1136 ORDERKEY_MEM 1137 return result; 1138 } 1139 1140 return (result); 1141 } 1142 1143 /* compare_prio - the comparison function for sorting by process priority */ 1144 1145 static int 1146 compare_prio(pp1, pp2) 1147 struct proc **pp1, **pp2; 1148 { 1149 int result; 1150 pctcpu lresult; 1151 1152 if (threadmode) { 1153 struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1; 1154 struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2; 1155 1156 ORDERKEY_PRIO(l_) 1157 ORDERKEY_PCTCPU(l_) 1158 ORDERKEY_CPTICKS(l_) 1159 ORDERKEY_STATE(l_) 1160 return result; 1161 } else { 1162 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 1163 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 1164 1165 ORDERKEY_PRIO(p_) 1166 ORDERKEY_PCTCPU(p_) 1167 ORDERKEY_CPTICKS(p_) 1168 ORDERKEY_STATE(p_) 1169 ORDERKEY_RSSIZE 1170 ORDERKEY_MEM 1171 return result; 1172 } 1173 1174 return (result); 1175 } 1176 1177 /* compare_res - the comparison function for sorting by resident set size */ 1178 1179 static int 1180 compare_res(pp1, pp2) 1181 struct proc **pp1, **pp2; 1182 { 1183 int result; 1184 pctcpu lresult; 1185 1186 if (threadmode) { 1187 struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1; 1188 struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2; 1189 1190 ORDERKEY_PCTCPU(l_) 1191 ORDERKEY_CPTICKS(l_) 1192 ORDERKEY_STATE(l_) 1193 ORDERKEY_PRIO(l_) 1194 return result; 1195 } else { 1196 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 1197 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 1198 1199 ORDERKEY_RSSIZE 1200 ORDERKEY_MEM 1201 ORDERKEY_PCTCPU(p_) 1202 ORDERKEY_CPTICKS(p_) 1203 ORDERKEY_STATE(p_) 1204 ORDERKEY_PRIO(p_) 1205 return result; 1206 } 1207 1208 return (result); 1209 } 1210 1211 static int 1212 compare_pid(pp1, pp2) 1213 struct proc **pp1, **pp2; 1214 { 1215 if (threadmode) { 1216 struct kinfo_lwp *l1 = *(struct kinfo_lwp **) pp1; 1217 struct kinfo_lwp *l2 = *(struct kinfo_lwp **) pp2; 1218 struct kinfo_proc2 *p1 = proc_from_thread(l1); 1219 struct kinfo_proc2 *p2 = proc_from_thread(l2); 1220 if (p1 == NULL || p2 == NULL) 1221 return -1; 1222 return p2->p_pid - p1->p_pid; 1223 } else { 1224 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 1225 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 1226 return p2->p_pid - p1->p_pid; 1227 } 1228 } 1229 1230 static int 1231 compare_command(pp1, pp2) 1232 struct proc **pp1, **pp2; 1233 { 1234 if (threadmode) { 1235 struct kinfo_lwp *l1 = *(struct kinfo_lwp **) pp1; 1236 struct kinfo_lwp *l2 = *(struct kinfo_lwp **) pp2; 1237 struct kinfo_proc2 *p1 = proc_from_thread(l1); 1238 struct kinfo_proc2 *p2 = proc_from_thread(l2); 1239 if (p1 == NULL || p2 == NULL) 1240 return -1; 1241 return strcmp(p2->p_comm, p1->p_comm); 1242 } else { 1243 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 1244 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 1245 return strcmp(p2->p_comm, p1->p_comm); 1246 } 1247 } 1248 1249 static int 1250 compare_username(pp1, pp2) 1251 struct proc **pp1, **pp2; 1252 { 1253 if (threadmode) { 1254 struct kinfo_lwp *l1 = *(struct kinfo_lwp **) pp1; 1255 struct kinfo_lwp *l2 = *(struct kinfo_lwp **) pp2; 1256 struct kinfo_proc2 *p1 = proc_from_thread(l1); 1257 struct kinfo_proc2 *p2 = proc_from_thread(l2); 1258 if (p1 == NULL || p2 == NULL) 1259 return -1; 1260 return strcmp(p2->p_login, p1->p_login); 1261 } else { 1262 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 1263 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 1264 return strcmp(p2->p_login, p1->p_login); 1265 } 1266 } 1267 /* compare_size - the comparison function for sorting by total memory usage */ 1268 1269 static int 1270 compare_size(pp1, pp2) 1271 struct proc **pp1, **pp2; 1272 { 1273 int result; 1274 pctcpu lresult; 1275 1276 if (threadmode) { 1277 struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1; 1278 struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2; 1279 1280 ORDERKEY_PCTCPU(l_) 1281 ORDERKEY_CPTICKS(l_) 1282 ORDERKEY_STATE(l_) 1283 ORDERKEY_PRIO(l_) 1284 return result; 1285 } else { 1286 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 1287 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 1288 1289 ORDERKEY_MEM 1290 ORDERKEY_RSSIZE 1291 ORDERKEY_PCTCPU(p_) 1292 ORDERKEY_CPTICKS(p_) 1293 ORDERKEY_STATE(p_) 1294 ORDERKEY_PRIO(p_) 1295 return result; 1296 } 1297 1298 return (result); 1299 } 1300 1301 /* compare_state - the comparison function for sorting by process state */ 1302 1303 static int 1304 compare_state(pp1, pp2) 1305 struct proc **pp1, **pp2; 1306 { 1307 int result; 1308 pctcpu lresult; 1309 1310 if (threadmode) { 1311 struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1; 1312 struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2; 1313 1314 ORDERKEY_STATE(l_) 1315 ORDERKEY_PCTCPU(l_) 1316 ORDERKEY_CPTICKS(l_) 1317 ORDERKEY_PRIO(l_) 1318 return result; 1319 } else { 1320 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 1321 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 1322 1323 ORDERKEY_STATE(p_) 1324 ORDERKEY_PCTCPU(p_) 1325 ORDERKEY_CPTICKS(p_) 1326 ORDERKEY_PRIO(p_) 1327 ORDERKEY_RSSIZE 1328 ORDERKEY_MEM 1329 return result; 1330 } 1331 1332 return (result); 1333 } 1334 1335 /* compare_time - the comparison function for sorting by total CPU time */ 1336 1337 static int 1338 compare_time(pp1, pp2) 1339 struct proc **pp1, **pp2; 1340 { 1341 int result; 1342 pctcpu lresult; 1343 1344 if (threadmode) { 1345 struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1; 1346 struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2; 1347 1348 ORDERKEY_CPTICKS(l_) 1349 ORDERKEY_PCTCPU(l_) 1350 ORDERKEY_STATE(l_) 1351 ORDERKEY_PRIO(l_) 1352 return result; 1353 } else { 1354 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 1355 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 1356 1357 ORDERKEY_CPTICKS(p_) 1358 ORDERKEY_PCTCPU(p_) 1359 ORDERKEY_STATE(p_) 1360 ORDERKEY_PRIO(p_) 1361 ORDERKEY_MEM 1362 ORDERKEY_RSSIZE 1363 return result; 1364 } 1365 1366 return (result); 1367 } 1368 1369 1370 /* 1371 * proc_owner(pid) - returns the uid that owns process "pid", or -1 if 1372 * the process does not exist. 1373 * It is EXTREMLY IMPORTANT that this function work correctly. 1374 * If top runs setuid root (as in SVR4), then this function 1375 * is the only thing that stands in the way of a serious 1376 * security problem. It validates requests for the "kill" 1377 * and "renice" commands. 1378 */ 1379 1380 int 1381 proc_owner(pid) 1382 int pid; 1383 { 1384 int cnt; 1385 struct kinfo_proc2 **prefp; 1386 struct kinfo_proc2 *pp; 1387 1388 if (threadmode) 1389 return(-1); 1390 1391 prefp = pref; 1392 cnt = pref_len; 1393 while (--cnt >= 0) { 1394 pp = *prefp++; 1395 if (pp->p_pid == (pid_t)pid) 1396 return(pp->p_ruid); 1397 } 1398 return(-1); 1399 } 1400 1401 /* 1402 * percentages(cnt, out, new, old, diffs) - calculate percentage change 1403 * between array "old" and "new", putting the percentages i "out". 1404 * "cnt" is size of each array and "diffs" is used for scratch space. 1405 * The array "old" is updated on each call. 1406 * The routine assumes modulo arithmetic. This function is especially 1407 * useful on BSD mchines for calculating CPU state percentages. 1408 */ 1409 1410 static void 1411 percentages64(cnt, out, new, old, diffs) 1412 int cnt; 1413 int *out; 1414 u_int64_t *new; 1415 u_int64_t *old; 1416 u_int64_t *diffs; 1417 { 1418 int i; 1419 u_int64_t change; 1420 u_int64_t total_change; 1421 u_int64_t *dp; 1422 u_int64_t half_total; 1423 1424 /* initialization */ 1425 total_change = 0; 1426 dp = diffs; 1427 1428 /* calculate changes for each state and the overall change */ 1429 for (i = 0; i < cnt; i++) { 1430 /* 1431 * Don't worry about wrapping - even at hz=1GHz, a 1432 * u_int64_t will last at least 544 years. 1433 */ 1434 change = *new - *old; 1435 total_change += (*dp++ = change); 1436 *old++ = *new++; 1437 } 1438 1439 /* avoid divide by zero potential */ 1440 if (total_change == 0) 1441 total_change = 1; 1442 1443 /* calculate percentages based on overall change, rounding up */ 1444 half_total = total_change / 2; 1445 for (i = 0; i < cnt; i++) 1446 *out++ = (int)((*diffs++ * 1000 + half_total) / total_change); 1447 } 1448