1/* 2 * Copyright (c) 1984 through 2008, William LeFebvre 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * 16 * * Neither the name of William LeFebvre nor the names of other 17 * contributors may be used to endorse or promote products derived from 18 * this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33/* 34 * top - a top users display for Unix 35 * 36 * SYNOPSIS: SCO UNIX OpenServer5 37 * 38 * DESCRIPTION: 39 * This is the machine-dependent module for SCO OpenServer5. 40 * Originally written for BSD4.3 system by Christos Zoulas. 41 * Modified to m_sco.c (3.2v4.2) by Gregory Shilin <shilin@onyx.co.il> 42 * Modified to m_sco5.c (3.2v5.*) by Mike Hopkirk <hops@sco.com> 43 * Works for: 44 * SCO UNIX 3.2v5.* 45 * 46 * CFLAGS: -DHAVE_GETOPT -DORDER 47 * 48 * AUTHOR: Mike Hopkirk (hops@sco.com) 49 * hops 10-Jul-98 - added sort fields 50 * 17-Jul-98 - add philiph's chopped cmd string support 51 * (define NO_COMMAND_ARGS to enable ) 52 * 09-Dec-98 - provide RSS calculation 53 * 15-Mar-2000 - Fix broken lines and cleanup sysinfo access w macros 54 */ 55 56#include <sys/types.h> 57#include <sys/param.h> 58 59#include <stdio.h> 60#include <unistd.h> 61#include <fcntl.h> 62#include <nlist.h> 63#include <math.h> 64#include <signal.h> 65#include <string.h> 66 67#include <sys/dir.h> 68#include <sys/immu.h> 69#include <sys/region.h> 70#include <sys/proc.h> 71#include <sys/user.h> 72#include <sys/sysinfo.h> 73#include <sys/systm.h> 74#include <sys/sysmacros.h> 75#include <sys/var.h> 76#include <sys/sysi86.h> 77 78#include "top.h" 79#include "machine.h" 80#include "utils.h" 81#include "loadavg.h" 82 83/* 84typedef unsigned long ulong; 85typedef unsigned int uint; 86typedef unsigned short ushort; 87*/ 88typedef unsigned char uchar; 89 90#define VMUNIX "/unix" 91#define KMEM "/dev/kmem" 92#define MEM "/dev/mem" 93 94#define SI_ACTIVE(p) p->p_active 95#define SI_TOTAL(p) p->p_total 96 97/* get_process_info passes back a handle. This is what it looks like: */ 98struct handle { 99 struct proc **next_proc; /* points to next valid proc pointer */ 100 int remaining; /* number of pointers remaining */ 101}; 102 103/* define what weighted cpu is */ 104#define weighted_cpu(pct, pp) ((pp)->p_time == 0 ? 0.0 : \ 105 ((pct) / (1.0 - exp((pp)->p_time * logcpu)))) 106 107#define bytetok(bytes) ((bytes) >> 10) 108 109/* what we consider to be process size: */ 110#define PROCSIZE(up) bytetok(ctob((up)->u_tsize + (up)->u_dsize+(up)->u_ssize)) 111 112/* definitions for indices in the nlist array */ 113#define X_V 0 /* System configuration information */ 114#define X_PROC 1 /* process tables */ 115#define X_FREEMEM 2 /* current free memory */ 116#define X_AVAILRMEM 3 /* available resident (not swappable) mem in pages 117*/ 118#define X_AVAILSMEM 4 /* available swappable memory in pages */ 119#define X_MAXMEM 5 /* maximum available free memory in clicks */ 120#define X_PHYSMEM 6 /* physical memory in clicks */ 121#define X_NSWAP 7 /* size of swap space in blocks */ 122#define X_HZ 8 /* ticks/second of the clock */ 123#define X_MPID 9 /* last process id */ 124#define X_SYSINFO 10 /* system information (cpu states) */ 125#define X_CUR_CPU 11 126 127static struct nlist nlst[] = { 128 { "v" }, /* 0 */ 129 { "proc" }, /* 1 */ 130 { "freemem" }, /* 2 */ 131 { "availrmem" }, /* 3 */ 132 { "availsmem" }, /* 4 */ 133 { "maxmem" }, /* 5 */ 134 { "physmem" }, /* 6 */ 135 { "nswap" }, /* 7 */ 136 { "Hz" }, /* 8 */ 137 { "mpid" }, /* 9 */ 138 { "sysinfo" }, /* 10 */ 139 { "cur_cpu" }, /* 11 */ 140 { NULL } 141}; 142 143/* 144 * These definitions control the format of the per-process area 145 */ 146 147static char header[] = 148 " PID X PRI NICE SIZE RES STATE TIME COMMAND"; 149/* 0123456 -- field to fill in starts at header+6 */ 150#define UNAME_START 6 151 152#define Proc_format \ 153 "%5d %-8.8s %3d %4d %5s %5dK %-5s %6s %.28s" 154 155static int kmem, mem; 156 157static double logcpu; 158 159/* these are retrieved from the kernel in _init */ 160static int Hz; 161static struct var v; 162static ulong proca; 163static load_avg cur_cpu; 164 165/* these are for detailing the process states */ 166int process_states[8]; 167char *procstatenames[] = { 168 "", " sleeping, ", " running, ", " zombie, ", " stopped, ", 169 " created, ", " onproc, ", " xswapped, ", 170 NULL 171}; 172 173/* process state names for the "STATE" column of the display */ 174char *state_abbrev[] = { 175 "", "sleep", "run", "zomb", "stop", "create", "onpr", "swap" 176}; 177 178/* these are for calculating cpu state percentages */ 179#define CPUSTATES 5 /* definition from struct sysinfo */ 180static time_t cp_time[CPUSTATES]; 181static time_t cp_old[CPUSTATES]; 182static time_t cp_diff[CPUSTATES]; 183 184/* these are for detailing the cpu states */ 185int cpu_states[CPUSTATES]; 186char *cpustatenames[] = { 187 "idle", "user", "system", "wait", "sxbrk", 188 NULL 189}; 190 191/* these are for detailing the memory statistics */ 192unsigned long memory_stats[6]; 193char *memorynames[] = { 194 "K phys, ", "K max, ", "K free, ", "K lck, ", "K unlck, ", 195 "K swap,", NULL 196}; 197 198/* these are for keeping track of the proc array */ 199static int bytes; 200static int pref_len; 201static struct proc *pbase; 202static struct proc **pref; 203 204/* forward definitions for comparison functions */ 205int proc_compare(); 206int compare_cpu(); 207int compare_size(); 208int compare_time(); 209 210int (*proc_compares[])() = { 211 proc_compare, /* state, pri, time, size */ 212 compare_cpu, /* cpu, time, state, pri, size */ 213 compare_size, /* size, cpu, time, state pri */ 214 compare_time, /* time, cpu, state, pri, size */ 215/* compare_res, /* res, cpu, time, state pri */ 216 NULL }; 217 218/* these are names given to allowed sorting orders -- first is default */ 219char *ordernames[]={"state", "cpu", "size", "time", NULL}; /*hops*/ 220 221/* useful externals */ 222extern int errno; 223extern char *sys_errlist[]; 224 225long time(); 226long percentages(); 227 228int 229machine_init(struct statics *statics) 230 231{ 232ulong ptr; 233 234 if ((kmem = open(KMEM, O_RDONLY)) == -1) { 235 perror(KMEM); 236 return -1; 237 } 238 if ((mem = open(MEM, O_RDONLY)) == -1) { 239 perror(MEM); 240 return -1; 241 } 242 243 /* get the list of symbols we want to access in the kernel */ 244 if (nlist(VMUNIX, nlst) == -1) { 245 fprintf(stderr, "top: nlist failed\n"); 246 return -1; 247 } 248 /* make sure they were all found */ 249 /*ZZ 250 if (check_nlist(nlst) > 0) 251 return -1; 252 */ 253 254 proca = nlst[X_PROC].n_value; 255 256 /* get the symbol values out of kmem */ 257 (void) getkval(nlst[X_CUR_CPU].n_value, (int *)(&cur_cpu), sizeof(cur_cpu), 258 nlst[X_CUR_CPU].n_name); 259 (void) getkval(nlst[X_HZ].n_value, (int *)(&Hz), sizeof(Hz), 260 nlst[X_HZ].n_name); 261 (void) getkval(nlst[X_V].n_value, (int *)(&v), sizeof(v), 262 nlst[X_V].n_name); 263 264 /* this is used in calculating WCPU -- calculate it ahead of time */ 265 logcpu = log(fabs(loaddouble(cur_cpu))); 266 267 /* allocate space for proc structure array and array of pointers */ 268 bytes = v.v_proc * sizeof(struct proc); 269 pbase = (struct proc *)malloc(bytes); 270 pref = (struct proc **)malloc(v.v_proc * sizeof(struct proc *)); 271 if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL) { 272 fprintf(stderr, "top: cannot allocate sufficient memory\n"); 273 return -1; 274 } 275 276 /* fill in the statics information */ 277 statics->procstate_names = procstatenames; 278 statics->cpustate_names = cpustatenames; 279 statics->memory_names = memorynames; 280 statics->order_names = ordernames ; /* hops */ 281 282 return 0; 283} 284 285char * 286format_header(register char *uname_field) 287 288{ 289 register char *ptr; 290 291 ptr = header + UNAME_START; 292 while (*uname_field != '\0') 293 { 294 *ptr++ = *uname_field++; 295 } 296 297 return(header); 298} 299 300 301/* philiph - get run ave fm /dev/table info */ 302static int 303tab_avenrun(double runave[]) 304{ 305 FILE *fp = fopen("/dev/table/avenrun", "r"); 306 int i; 307 308 for (i=0; i<3; i++) 309 runave[i] = -1.0; 310 311 if (fp==NULL) 312 return -1; 313 else 314 { 315 short rawave[3]; 316 317 if (fread(rawave, sizeof(short), 3, fp) !=3 ) 318 { 319 fclose(fp); 320 return -1; 321 } 322 else 323 { 324 int i; 325 326 for (i=0; i<3; i++) 327 runave[i] = (double) (rawave[i] / 256.0); 328 329 fclose(fp); 330 return 0; 331 } 332 } 333} 334 335struct pregion * 336get_pregion(void *ptr) 337{ 338 static struct pregion preg; 339 long addr = (long)ptr; 340 341 (void) getkval(addr , (struct pregion *)(&preg), 342 sizeof(struct pregion), "pregion" ); 343 return &preg; 344} 345 346struct region * 347get_region(void *ptr) 348{ 349 static struct region reg; 350 long addr = (long)ptr; 351 352 (void) getkval( addr , (struct region *)(®), 353 sizeof(struct region), "region" ); 354 return ® 355} 356 357static unsigned char shareable[RT_VM86 + 1]; /* 1 if shareable */ 358 359/* 360 * sum private referenced pages, 361 * treat shared pages depending on value of TREAT_SHARABLE_PAGES macro 362 * undefined : ignore (don't account for - default) 363 * 1: divide among # of references 364 * 2: accumulate as if private 365 */ 366/* #define TREAT_SHAREABLE_PAGES 1 */ 367static long 368proc_residentsize(struct proc *pp) 369{ 370 struct pregion *prp; 371 struct region *rp; 372 long rtot = 0; 373 long stot = 0; 374 long s1tot = 0; 375 376 /* init shareable region array */ 377 if (shareable[RT_STEXT] == 0 ) 378 shareable[RT_STEXT] = shareable[RT_SHMEM] = shareable[RT_MAPFILE] = 1 379 ; 380 381 prp = pp->p_region; 382 383 if ( prp == 0) 384 return 0; 385 386 for( ; prp && (prp = get_pregion((void *)(prp))) && 387 prp->p_reg && (rp = get_region((void*)(prp->p_reg))); 388 prp = prp->p_next) 389 { 390 if (shareable[rp->r_type] ) /* account for shared pgs separately 391 */ 392 { 393 stot += (rp->r_nvalid / rp->r_refcnt); 394 s1tot += rp->r_nvalid; 395 } 396 else 397 rtot += rp->r_nvalid; 398 399 } 400#if defined(TREAT_SHAREABLE_PAGES) && TREAT_SHAREABLE_PAGES == 1 401 rtot += stot; /* accumulate and spread over users */ 402#endif 403 404#if defined(TREAT_SHAREABLE_PAGES) && TREAT_SHAREABLE_PAGES == 1 405 rtot += s1tot; /* accumulate as if private */ 406#endif 407 408 return rtot * NBPP/1024; ; 409} 410 411void 412get_system_info(struct system_info *si) 413 414{ 415long total; 416 417 /* get process id of the last process */ 418 (void) getkval(nlst[X_MPID].n_value, &(si->last_pid), 419 sizeof(si->last_pid), 420 nlst[X_MPID].n_name); 421 /* get the cp_time array */ 422 (void) getkval(nlst[X_SYSINFO].n_value, (int *)cp_time, sizeof(cp_time), 423 nlst[X_SYSINFO].n_name); 424 425 /* convert cp_time counts to persentages */ 426 total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff); 427 428 /* sum memory statistics */ 429 (void) getkval(nlst[X_PHYSMEM].n_value, &memory_stats[0], 430 sizeof(memory_stats[0]), nlst[X_PHYSMEM].n_name); 431 (void) getkval(nlst[X_MAXMEM].n_value, &memory_stats[1], 432 sizeof(memory_stats[1]), nlst[X_MAXMEM].n_name); 433 (void) getkval(nlst[X_FREEMEM].n_value, &memory_stats[2], 434 sizeof(memory_stats[2]), nlst[X_FREEMEM].n_name); 435 (void) getkval(nlst[X_AVAILRMEM].n_value, &memory_stats[3], 436 sizeof(memory_stats[3]), nlst[X_AVAILRMEM].n_name); 437 (void) getkval(nlst[X_AVAILSMEM].n_value, &memory_stats[4], 438 sizeof(memory_stats[4]), nlst[X_AVAILSMEM].n_name); 439 (void) getkval(nlst[X_NSWAP].n_value, &memory_stats[5], 440 sizeof(memory_stats[5]), nlst[X_NSWAP].n_name); 441 memory_stats[0] = bytetok(ctob(memory_stats[0])); /* clicks -> bytes 442 */ 443 memory_stats[1] = bytetok(ctob(memory_stats[1])); /* clicks -> bytes 444 */ 445 memory_stats[2] = bytetok(ctob(memory_stats[2])); /* clicks -> bytes 446 */ 447 memory_stats[3] = bytetok(memory_stats[3] * NBPP); /* # bytes per page 448 */ 449 memory_stats[4] = bytetok(memory_stats[4] * NBPP); /* # bytes per page 450 */ 451 memory_stats[5] = bytetok(memory_stats[5] * NBPSCTR);/* # bytes per sector 452 */ 453 454 /* set arrays and strings */ 455 /* Note: we keep memory_stats as an unsigned long to avoid sign 456 extension problems when shifting in bytetok. But the module 457 interface requires an array of signed longs. So we just cast 458 the pointer here and hope for the best. --wnl 459 */ 460 si->cpustates = cpu_states; 461 si->memory = (long *)memory_stats; 462 463 tab_avenrun(si->load_avg); /* philiph */ 464} 465 466static struct handle handle; 467 468caddr_t 469get_process_info(struct system_info *si, 470 struct process_select *sel, 471 int idx) 472 473{ 474register int i; 475register int total_procs; 476register int active_procs; 477register struct proc **prefp; 478register struct proc *pp; 479 480/* set up flags of what we are going to select */ 481/* these are copied out of sel for simplicity */ 482int show_idle = sel->idle; 483int show_system = sel->system; 484int show_uid = sel->uid != -1; 485int show_command = sel->command != NULL; 486 487 /* read all the proc structures in one fell swoop */ 488 (void) getkval(proca, (int *)pbase, bytes, "proc array"); 489 490 /* get a pointer to the states summary array */ 491 si->procstates = process_states; 492 493 /* count up process states and get pointers to interesting procs */ 494 total_procs = active_procs = 0; 495 memset((char *)process_states, 0, sizeof(process_states)); 496 prefp = pref; 497 for (pp = pbase, i = 0; i < v.v_proc; pp++, i++) { 498 /* 499 * Place pointers to each valid proc structure in pref[]. 500 * Process slots that are actually in use have a non-zero 501 * status field. Processes with SSYS set are system processes -- 502 * these are ignored unless show_system is set. 503 */ 504 if (pp->p_stat && (show_system || ((pp->p_flag & SSYS) == 0))) { 505 total_procs++; 506 process_states[pp->p_stat]++; 507 if ((pp->p_stat != SZOMB) && 508 (show_idle || (pp->p_stat == SRUN) || (pp->p_stat == SONPROC)) && 509 (!show_uid || pp->p_uid == (ushort)sel->uid)) { 510 *prefp++ = pp; 511 active_procs++; 512 } 513 } 514 } 515 516 /* if requested, sort the "interesting" processes */ 517 qsort((char *)pref, active_procs, sizeof(struct proc *), proc_compares[idx]); 518 519 /* remember active and total counts */ 520 SI_TOTAL(si) = total_procs; 521 SI_ACTIVE(si) = pref_len = active_procs; 522 523 /* pass back a handle */ 524 handle.next_proc = pref; 525 handle.remaining = active_procs; 526 return((caddr_t)&handle); 527} 528 529char fmt[128]; /* static area where result is built */ 530 531char * 532format_next_process(caddr_t handle, char *(*get_userid)()) 533 534{ 535register struct proc *pp; 536register time_t cputime; 537register double pct; 538int where; 539struct user u; 540struct handle *hp; 541char command[29]; 542char * process; 543char * process2; 544 545 /* find and remember the next proc structure */ 546 hp = (struct handle *)handle; 547 pp = *(hp->next_proc++); 548 hp->remaining--; 549 550 /* get the process's user struct and set cputime */ 551 if ((where = sysi86(RDUBLK, pp->p_pid, &u, sizeof(struct user))) != -1) 552 where = (pp->p_flag & SLOAD) ? 0 : 1; 553 if (where == -1) { 554 strcpy(command, "<swapped>"); 555 cputime = 0; 556 } else { 557 /* set u_comm for system processes */ 558 if (u.u_comm[0] == '\0') { 559 if (pp->p_pid == 0) 560 strcpy(command, "Swapper"); 561 else if (pp->p_pid == 2) 562 strcpy(command, "Pager"); 563 else if (pp->p_pid == 3) 564 strcpy(command, "Sync'er"); 565 } else if (where == 1) { 566 /* print swapped processes as <pname> */ 567 register char *s1; 568 569 u.u_psargs[28 - 3] = '\0'; 570 strcpy(command, "<"); 571 strcat(command, strtok(u.u_psargs, " ")); 572 strcat(command, ">"); 573 while (s1 = (char *)strtok(NULL, " ")) 574 strcat(command, s1); 575 } else { 576 sprintf(command, "%s", u.u_psargs); 577 } 578 cputime = u.u_utime + u.u_stime; 579/* cputime = pp->p_utime + pp->p_stime; */ 580 } 581 /* calculate the base for cpu percentages */ 582 pct = pctdouble(pp->p_cpu); 583 584 /* 585 * psargs gives the absolute path of the process... strip it to only the 586 * command - [Changes by D. Currie & M. Muldner Aitt NS Canada] 587 */ 588 process = printable(command); 589#if NO_COMMAND_ARGS 590 strtok(process," "); 591#endif 592 process2 = strrchr(process,'/'); 593 if(process2) 594 { 595 process = process2; 596 process++; 597 } 598 599 600 /* format this entry */ 601 sprintf(fmt, 602 Proc_format, 603 pp->p_pid, 604 (*get_userid)(pp->p_uid), 605 pp->p_pri - PZERO, 606 pp->p_nice - NZERO, 607 format_k(PROCSIZE(&u)), /* same as pp->p_size * 4 */ 608 proc_residentsize(pp), 609 state_abbrev[pp->p_stat], 610 format_time(cputime / Hz), 611 printable(process) ); 612 613 return(fmt); 614} 615 616/* 617 * Checks the nlist to see if any symbols were not found. 618 * For every symbol that was not found, a one-line message 619 * is printed to stderr. The routine returns the number of 620 * symbols NOT founded. 621 */ 622 623int check_nlist(register struct nlist *nlst) 624 625{ 626register int i = 0; 627 628 while (nlst->n_name) { 629 if (nlst->n_type == 0) { 630 fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name); 631 i++; 632 } 633 nlst++; 634 } 635 return i; 636} 637 638/* 639 * getkval(offset, ptr, size, refstr) - get a value out of the kernel. 640 * "offset" is the byte offset into the kernel for the desired value, 641 * "ptr" points to a buffer into which the value is retrieved, 642 * "size" is the size of the buffer (and the object to retrieve), 643 * "refstr" is a reference string used when printing error meessages, 644 * if "refstr" starts with a '!', then a failure on read will not 645 * be fatal (this may seem like a silly way to do things, but I 646 * really didn't want the overhead of another argument). 647 * 648 */ 649 650int 651getkval(unsigned long offset, int *ptr, int size, char *refstr) 652 653{ 654 if (lseek(kmem, (long)offset, SEEK_SET) == -1) { 655 if (*refstr == '!') 656 refstr++; 657 fprintf(stderr, "%s: lseek to %s: %s\n", KMEM, 658 refstr, errmsg(errno)); 659 quit(23); 660 } 661 if (read(kmem, (char *)ptr, size) == -1) { 662 if (*refstr == '!') 663 return 0; 664 fprintf(stderr, "%s: reading %s: %s\n", KMEM, 665 refstr, errmsg(errno)); 666 quit(23); 667 } 668 return(1); 669} 670 671/* comparison routine for qsort */ 672/* NOTE: this is specific to the BSD proc structure, but it should 673 give you a good place to start. */ 674 675/* 676 * proc_compare - comparison function for "qsort" 677 * Compares the resource consumption of two processes using five 678 * distinct keys. The keys (in descending order of importance) are: 679 * percent cpu, cpu ticks, state, resident set size, total virtual 680 * memory usage. The process states are ordered as follows (from least 681 * to most important): WAIT, zombie, sleep, stop, start, run. The 682 * array declaration below maps a process state index into a number 683 * that reflects this ordering. 684 */ 685 686static unsigned char sorted_state[] = 687{ 688 0, /* not used */ 689 5, /* sleep */ 690 6, /* run */ 691 2, /* zombie */ 692 4, /* stop */ 693 1, /* start */ 694 7, /* onpr */ 695 3, /* swap */ 696}; 697 698int 699proc_compare(struct proc **pp1, struct proc **pp2) 700 701{ 702register struct proc *p1; 703register struct proc *p2; 704register int result; 705register ulong lresult; 706 707 /* remove one level of indirection */ 708 p1 = *pp1; 709 p2 = *pp2; 710 711 /* use process state to break the tie */ 712 if ((result = sorted_state[p2->p_stat] - 713 sorted_state[p1->p_stat]) == 0) 714 { 715 /* use priority to break the tie */ 716 if ((result = p2->p_pri - p1->p_pri) == 0) 717 { 718 /* use time to break the tie */ 719 if ((result = (p2->p_utime + p2->p_stime) - 720 (p1->p_utime + p1->p_stime)) == 0) 721 { 722 /* use resident set size (rssize) to break the tie */ 723 if ((result = p2->p_size - p1->p_size) == 0) 724 { 725 result = 0; 726 } 727 } 728 } 729 } 730 731 return(result); 732} 733 734/* returns uid of owner of process pid */ 735int 736proc_owner(int pid) 737 738{ 739register int cnt; 740register struct proc **prefp; 741register struct proc *pp; 742 743 prefp = pref; 744 cnt = pref_len; 745 while (--cnt >= 0) { 746 if ((pp = *prefp++)->p_pid == (short)pid) 747 return ((int)pp->p_uid); 748 } 749 return(-1); 750} 751 752#if 0 753int setpriority(int dummy, int who, int nicewal) 754{ 755 errno = 1; 756 return -1; 757} 758#endif 759 760/* sigblock is not POSIX conformant */ 761sigset_t sigblock (sigset_t mask) 762{ 763sigset_t oset; 764 765 sigemptyset(&oset); 766 sigprocmask(SIG_BLOCK, &mask, &oset); 767 return oset; 768} 769 770/* sigsetmask is not POSIX conformant */ 771sigsetmask(sigset_t mask) 772{ 773sigset_t oset; 774 775 sigemptyset(&oset); 776 sigprocmask(SIG_SETMASK, &mask, &oset); 777 return oset; 778} 779 780 781/* ---------------- hops - comparison/ordering support ---------------- */ 782 783#define ORDERKEY_PCTCPU if (dresult = pctdouble(p2->p_cpu) - pctdouble(p1->p_cpu),\ 784 (result = dresult > 0.0 ? 1 : dresult < 0.0 ? -1 : 0) == 0) 785#define ORDERKEY_MEMSIZE if ((result = (p2->p_size - p1->p_size)) == 0) 786#define ORDERKEY_CPTIME if ((result = (long)(p2->p_utime + p2->p_stime) -\ 787 (long)(p1->p_utime + p1->p_stime)) == 0) 788 789#define ORDERKEY_STATE if ((result = (sorted_state[p2->p_stat] - \ 790 sorted_state[p1->p_stat])) == 0) 791#define ORDERKEY_PRIO if ((result = p2->p_pri - p1->p_pri) == 0) 792 793 794int 795compare_cpu ( struct proc **pp1, struct proc **pp2) 796{ 797 register struct proc *p1; 798 register struct proc *p2; 799 register int result; 800 double dresult; 801 802 /* remove one level of indirection */ 803 p1 = *pp1; 804 p2 = *pp2; 805 806 ORDERKEY_PCTCPU 807 ORDERKEY_CPTIME 808 ORDERKEY_STATE 809 ORDERKEY_PRIO 810 ORDERKEY_MEMSIZE 811 ; 812 813 return (result); 814} 815 816 817 818/* compare_size - the comparison function for sorting by process size */ 819int 820compare_size ( struct proc **pp1, struct proc **pp2) 821{ 822 register struct proc *p1; 823 register struct proc *p2; 824 register int result; 825 double dresult; 826 827 /* remove one level of indirection */ 828 p1 = *pp1; 829 p2 = *pp2; 830 831 832 ORDERKEY_MEMSIZE 833 ORDERKEY_PCTCPU 834 ORDERKEY_CPTIME 835 ORDERKEY_STATE 836 ORDERKEY_PRIO 837 ; 838 839 return (result); 840} 841 842/* compare_res - the comparison function for sorting by resident set size */ 843/* TODO: add shadow proc struct updating usr + sys times and RSS for use 844 * in comparison rtns, implement compare_res rtn as per compare_size() 845 */ 846 847/* compare_time - the comparison function for sorting by total cpu time */ 848/* This is giving wrong results since its using the proc structure vals not 849 * the u struct vals we display above 850 * TODO: add shadow proc struct updating usr + sys times and RSS for use 851 * in comparison rtns 852 */ 853int 854compare_time ( struct proc **pp1, struct proc **pp2) 855{ 856 register struct proc *p1; 857 register struct proc *p2; 858 register int result; 859 double dresult; 860 861 /* remove one level of indirection */ 862 p1 = *pp1; 863 p2 = *pp2; 864 865 ORDERKEY_CPTIME 866 ORDERKEY_PCTCPU 867 ORDERKEY_STATE 868 ORDERKEY_PRIO 869 ORDERKEY_MEMSIZE 870 ; 871 872 return (result); 873} 874 875