home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / Utilities / top-0.5-MI / machine / m_bsd43.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-03  |  18.0 KB  |  775 lines

  1. /*
  2.  * top - a top users display for Unix
  3.  *
  4.  * SYNOPSIS:  any generic 4.3BSD system
  5.  *
  6.  * DESCRIPTION:
  7.  * This is the machine-dependent module for BSD4.3 
  8.  * Works for:
  9.  *      4.3 BSD
  10.  *    AOS4.3,    IBM rt/pc
  11.  *    mtXinu, vax
  12.  *
  13.  * LIBS: 
  14.  *
  15.  * AUTHOR:  Christos Zoulas <christos@ee.cornell.edu>
  16.  */
  17.  
  18. #include <sys/types.h>
  19. #include <sys/signal.h>
  20. #include <sys/param.h>
  21.  
  22. #include <stdio.h>
  23. #include <nlist.h>
  24. #include <math.h>
  25. #include <sys/dir.h>
  26. #include <sys/user.h>
  27. #include <sys/proc.h>
  28. #include <sys/dk.h>
  29. #include <sys/vm.h>
  30. #include <sys/file.h>
  31. #include <sys/time.h>
  32. #include <machine/pte.h>
  33.  
  34.  
  35. #define DOSWAP
  36.  
  37. #include "top.h"
  38. #include "machine.h"
  39. #include "utils.h"
  40.  
  41. extern int errno, sys_nerr;
  42. extern char *sys_errlist[];
  43. #define strerror(e) (((e) >= 0 && (e) < sys_nerr) ? sys_errlist[(e)] : "Unknown error")
  44.  
  45. #define VMUNIX    "/vmunix"
  46. #define KMEM    "/dev/kmem"
  47. #define MEM    "/dev/mem"
  48. #ifdef DOSWAP
  49. #define SWAP    "/dev/drum"
  50. #endif
  51.  
  52. /* get_process_info passes back a handle.  This is what it looks like: */
  53.  
  54. struct handle
  55. {
  56.     struct proc **next_proc;    /* points to next valid proc pointer */
  57.     int remaining;        /* number of pointers remaining */
  58. };
  59.  
  60. /* declarations for load_avg */
  61. #include "loadavg.h"
  62.  
  63. /* define what weighted cpu is.  */
  64. #define weighted_cpu(pct, pp) ((pp)->p_time == 0 ? 0.0 : \
  65.              ((pct) / (1.0 - exp((pp)->p_time * logcpu))))
  66.  
  67. /* what we consider to be process size: */
  68. #define PROCSIZE(pp) ((pp)->p_tsize + (pp)->p_dsize + (pp)->p_ssize)
  69.  
  70. /* definitions for indices in the nlist array */
  71. #define X_AVENRUN    0
  72. #define X_CCPU        1
  73. #define X_NPROC        2
  74. #define X_PROC        3
  75. #define X_TOTAL        4
  76. #define X_CP_TIME    5
  77. #define X_MPID        6
  78. #define X_HZ        7
  79.  
  80. static struct nlist nlst[] = {
  81.     { "_avenrun" },        /* 0 */
  82.     { "_ccpu" },        /* 1 */
  83.     { "_nproc" },        /* 2 */
  84.     { "_proc" },        /* 3 */
  85.     { "_total" },        /* 4 */
  86.     { "_cp_time" },        /* 5 */
  87.     { "_mpid" },        /* 6 */
  88.     { "_hz" },            /* 7 */
  89.     { 0 }
  90. };
  91.  
  92. /*
  93.  *  These definitions control the format of the per-process area
  94.  */
  95.  
  96. static char header[] =
  97.   "  PID X        PRI NICE  SIZE   RES STATE   TIME   WCPU    CPU COMMAND";
  98. /* 0123456   -- field to fill in starts at header+6 */
  99. #define UNAME_START 6
  100.  
  101. #define Proc_format \
  102.     "%5d %-8.8s %3d %4d %5s %5s %-5s %6s %5.2f%% %5.2f%% %.14s"
  103.  
  104.  
  105. /* process state names for the "STATE" column of the display */
  106. /* the extra nulls in the string "run" are for adding a slash and
  107.    the processor number when needed */
  108.  
  109. char *state_abbrev[] =
  110. {
  111.     "", "sleep", "WAIT", "run\0\0\0", "start", "zomb", "stop"
  112. };
  113.  
  114.  
  115. static int kmem, mem;
  116. #ifdef DOSWAP
  117. static int swap;
  118. #endif
  119.  
  120. /* values that we stash away in _init and use in later routines */
  121.  
  122. static double logcpu;
  123.  
  124. /* these are retrieved from the kernel in _init */
  125.  
  126. static unsigned long proc;
  127. static          int  nproc;
  128. static          long hz;
  129. static load_avg  ccpu;
  130. static          int  ncpu = 0;
  131.  
  132. /* these are offsets obtained via nlist and used in the get_ functions */
  133.  
  134. static unsigned long avenrun_offset;
  135. static unsigned long mpid_offset;
  136. static unsigned long total_offset;
  137. static unsigned long cp_time_offset;
  138.  
  139. /* these are for calculating cpu state percentages */
  140.  
  141. static long cp_time[CPUSTATES];
  142. static long cp_old[CPUSTATES];
  143. static long cp_diff[CPUSTATES];
  144.  
  145. /* these are for detailing the process states */
  146.  
  147. int process_states[7];
  148. char *procstatenames[] = {
  149.     "", " sleeping, ", " ABANDONED, ", " running, ", " starting, ",
  150.     " zombie, ", " stopped, ",
  151.     NULL
  152. };
  153.  
  154. /* these are for detailing the cpu states */
  155.  
  156. int cpu_states[4];
  157. char *cpustatenames[] = {
  158.     "user", "nice", "system", "idle", NULL
  159. };
  160.  
  161. /* these are for detailing the memory statistics */
  162.  
  163. int memory_stats[8];
  164. char *memorynames[] = {
  165.     "Real: ", "K/", "K act/tot  ", "Virtual: ", "K/",
  166.     "K act/tot  ", "Free: ", "K", NULL
  167. };
  168.  
  169. /* these are for keeping track of the proc array */
  170.  
  171. static int bytes;
  172. static int pref_len;
  173. static struct proc *pbase;
  174. static struct proc **pref;
  175.  
  176. /* these are for getting the memory statistics */
  177.  
  178. static int pageshift;        /* log base 2 of the pagesize */
  179.  
  180. /* define pagetok in terms of pageshift */
  181.  
  182. #define pagetok(size) ((size) << pageshift)
  183.  
  184. /* useful externals */
  185. extern int errno;
  186. extern char *sys_errlist[];
  187.  
  188. long lseek();
  189. long time();
  190.  
  191. machine_init(statics)
  192.  
  193. struct statics *statics;
  194.  
  195. {
  196.     register int i = 0;
  197.     register int pagesize;
  198.  
  199.     if ((kmem = open(KMEM, O_RDONLY)) == -1) {
  200.     perror(KMEM);
  201.     return(-1);
  202.     }
  203.     if ((mem = open(MEM, O_RDONLY)) == -1) {
  204.     perror(MEM);
  205.     return(-1);
  206.     }
  207.  
  208. #ifdef DOSWAP
  209.     if ((swap = open(SWAP, O_RDONLY)) == -1) {
  210.     perror(SWAP);
  211.     return(-1);
  212.     }
  213. #endif
  214.  
  215.     /* get the list of symbols we want to access in the kernel */
  216.     (void) nlist(VMUNIX, nlst);
  217.     if (nlst[0].n_type == 0)
  218.     {
  219.     fprintf(stderr, "top: nlist failed\n");
  220.     return(-1);
  221.     }
  222.  
  223.     /* make sure they were all found */
  224.     if (i > 0 && check_nlist(nlst) > 0)
  225.     {
  226.     return(-1);
  227.     }
  228.  
  229.     /* get the symbol values out of kmem */
  230.     (void) getkval(nlst[X_PROC].n_value,   (int *)(&proc),    sizeof(proc),
  231.         nlst[X_PROC].n_name);
  232.     (void) getkval(nlst[X_NPROC].n_value,  &nproc,        sizeof(nproc),
  233.         nlst[X_NPROC].n_name);
  234.     (void) getkval(nlst[X_HZ].n_value,     (int *)(&hz),    sizeof(hz),
  235.         nlst[X_HZ].n_name);
  236.     (void) getkval(nlst[X_CCPU].n_value,   (int *)(&ccpu),    sizeof(ccpu),
  237.         nlst[X_CCPU].n_name);
  238.  
  239.     /* stash away certain offsets for later use */
  240.     mpid_offset = nlst[X_MPID].n_value;
  241.     avenrun_offset = nlst[X_AVENRUN].n_value;
  242.     total_offset = nlst[X_TOTAL].n_value;
  243.     cp_time_offset = nlst[X_CP_TIME].n_value;
  244.  
  245.     /* this is used in calculating WCPU -- calculate it ahead of time */
  246.     logcpu = log(loaddouble(ccpu));
  247.  
  248.     /* allocate space for proc structure array and array of pointers */
  249.     bytes = nproc * sizeof(struct proc);
  250.     pbase = (struct proc *)malloc(bytes);
  251.     pref  = (struct proc **)malloc(nproc * sizeof(struct proc *));
  252.  
  253.     /* Just in case ... */
  254.     if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL)
  255.     {
  256.     fprintf(stderr, "top: can't allocate sufficient memory\n");
  257.     return(-1);
  258.     }
  259.  
  260.     /* get the page size with "getpagesize" and calculate pageshift from it */
  261.     pagesize = getpagesize();
  262.     pageshift = 0;
  263.     while (pagesize > 1)
  264.     {
  265.     pageshift++;
  266.     pagesize >>= 1;
  267.     }
  268.  
  269.     /* we only need the amount of log(2)1024 for our conversion */
  270.     pageshift -= LOG1024;
  271.  
  272.     /* fill in the statics information */
  273.     statics->procstate_names = procstatenames;
  274.     statics->cpustate_names = cpustatenames;
  275.     statics->memory_names = memorynames;
  276.  
  277.     /* all done! */
  278.     return(0);
  279. }
  280.  
  281. char *format_header(uname_field)
  282.  
  283. register char *uname_field;
  284.  
  285. {
  286.     register char *ptr;
  287.  
  288.     ptr = header + UNAME_START;
  289.     while (*uname_field != '\0')
  290.     {
  291.     *ptr++ = *uname_field++;
  292.     }
  293.  
  294.     return(header);
  295. }
  296.  
  297. get_system_info(si)
  298.  
  299. struct system_info *si;
  300.  
  301. {
  302.     load_avg avenrun[3];
  303.     long total;
  304.  
  305.     /* get the cp_time array */
  306.     (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),
  307.            "_cp_time");
  308.  
  309.     /* get load average array */
  310.     (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
  311.            "_avenrun");
  312.  
  313.     /* get mpid -- process id of last process */
  314.     (void) getkval(mpid_offset, &(si->last_pid), sizeof(si->last_pid),
  315.            "_mpid");
  316.  
  317.     /* convert load averages to doubles */
  318.     {
  319.     register int i;
  320.     register double *infoloadp;
  321.     register load_avg *sysloadp;
  322.  
  323.     infoloadp = si->load_avg;
  324.     sysloadp = avenrun;
  325.     for (i = 0; i < 3; i++)
  326.     {
  327.         *infoloadp++ = loaddouble(*sysloadp++);
  328.     }
  329.     }
  330.  
  331.     /* convert cp_time counts to percentages */
  332.     total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
  333.  
  334.     /* sum memory statistics */
  335.     {
  336.     struct vmtotal total;
  337.  
  338.     /* get total -- systemwide main memory usage structure */
  339.     (void) getkval(total_offset, (int *)(&total), sizeof(total),
  340.                "_total");
  341.     /* convert memory stats to Kbytes */
  342.     memory_stats[0] = -1;
  343.     memory_stats[1] = pagetok(total.t_arm);
  344.     memory_stats[2] = pagetok(total.t_rm);
  345.     memory_stats[3] = -1;
  346.     memory_stats[4] = pagetok(total.t_avm);
  347.     memory_stats[5] = pagetok(total.t_vm);
  348.     memory_stats[6] = -1;
  349.     memory_stats[7] = pagetok(total.t_free);
  350.     }
  351.  
  352.     /* set arrays and strings */
  353.     si->cpustates = cpu_states;
  354.     si->memory = memory_stats;
  355. }
  356.  
  357. static struct handle handle;
  358.  
  359. caddr_t get_process_info(si, sel, compare)
  360.  
  361. struct system_info *si;
  362. struct process_select *sel;
  363. int (*compare)();
  364.  
  365. {
  366.     register int i;
  367.     register int total_procs;
  368.     register int active_procs;
  369.     register struct proc **prefp;
  370.     register struct proc *pp;
  371.  
  372.     /* these are copied out of sel for speed */
  373.     int show_idle;
  374.     int show_system;
  375.     int show_uid;
  376.     int show_command;
  377.  
  378.     /* read all the proc structures in one fell swoop */
  379.     (void) getkval(proc, (int *)pbase, bytes, "proc array");
  380.  
  381.     /* get a pointer to the states summary array */
  382.     si->procstates = process_states;
  383.  
  384.     /* set up flags which define what we are going to select */
  385.     show_idle = sel->idle;
  386.     show_system = sel->system;
  387.     show_uid = sel->uid != -1;
  388.     show_command = sel->command != NULL;
  389.  
  390.     /* count up process states and get pointers to interesting procs */
  391.     total_procs = 0;
  392.     active_procs = 0;
  393.     memset((char *)process_states, 0, sizeof(process_states));
  394.     prefp = pref;
  395.     for (pp = pbase, i = 0; i < nproc; pp++, i++)
  396.     {
  397.     /*
  398.      *  Place pointers to each valid proc structure in pref[].
  399.      *  Process slots that are actually in use have a non-zero
  400.      *  status field.  Processes with SSYS set are system
  401.      *  processes---these get ignored unless show_sysprocs is set.
  402.      */
  403.     if (pp->p_stat != 0 &&
  404.         (show_system || ((pp->p_flag & SSYS) == 0)))
  405.     {
  406.         total_procs++;
  407.         process_states[pp->p_stat]++;
  408.         if ((pp->p_stat != SZOMB) &&
  409.         (show_idle || (pp->p_pctcpu != 0) || (pp->p_stat == SRUN)) &&
  410.         (!show_uid || pp->p_uid == (uid_t)sel->uid))
  411.         {
  412.         *prefp++ = pp;
  413.         active_procs++;
  414.         }
  415.     }
  416.     }
  417.  
  418.     /* if requested, sort the "interesting" processes */
  419.     if (compare != NULL)
  420.     {
  421.     qsort((char *)pref, active_procs, sizeof(struct proc *), compare);
  422.     }
  423.  
  424.     /* remember active and total counts */
  425.     si->p_total = total_procs;
  426.     si->p_active = pref_len = active_procs;
  427.  
  428.     /* pass back a handle */
  429.     handle.next_proc = pref;
  430.     handle.remaining = active_procs;
  431.     return((caddr_t)&handle);
  432. }
  433.  
  434. char fmt[MAX_COLS];        /* static area where result is built */
  435.  
  436. char *format_next_process(handle, get_userid)
  437.  
  438. caddr_t handle;
  439. char *(*get_userid)();
  440.  
  441. {
  442.     register struct proc *pp;
  443.     register long cputime;
  444.     register double pct;
  445.     int where;
  446.     struct user u;
  447.     struct handle *hp;
  448.  
  449.     /* find and remember the next proc structure */
  450.     hp = (struct handle *)handle;
  451.     pp = *(hp->next_proc++);
  452.     hp->remaining--;
  453.     
  454.  
  455.     /* get the process's user struct and set cputime */
  456.     where = getu(pp, &u);
  457.     if (where == -1)
  458.     {
  459.     (void) strcpy(u.u_comm, "<swapped>");
  460.     cputime = 0;
  461.     }
  462.     else
  463.     {
  464.  
  465.       
  466.     /* set u_comm for system processes */
  467.     if (u.u_comm[0] == '\0')
  468.     {
  469.         if (pp->p_pid == 0)
  470.         {
  471.         (void) strcpy(u.u_comm, "Swapper");
  472.         }
  473.         else if (pp->p_pid == 2)
  474.         {
  475.         (void) strcpy(u.u_comm, "Pager");
  476.         }
  477.     }
  478.     if (where == 1) {
  479.         /*
  480.          * Print swapped processes as <pname>
  481.          */
  482.         char buf[sizeof(u.u_comm)];
  483.         (void) strncpy(buf, u.u_comm, sizeof(u.u_comm));
  484.         u.u_comm[0] = '<';
  485.         (void) strncpy(&u.u_comm[1], buf, sizeof(u.u_comm) - 2);
  486.         u.u_comm[sizeof(u.u_comm) - 2] = '\0';
  487.         (void) strncat(u.u_comm, ">", sizeof(u.u_comm) - 1);
  488.         u.u_comm[sizeof(u.u_comm) - 1] = '\0';
  489.     }
  490.  
  491.     cputime = u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec;
  492.     }
  493.  
  494.     /* calculate the base for cpu percentages */
  495.     pct = pctdouble(pp->p_pctcpu);
  496.  
  497.     /* format this entry */
  498.     sprintf(fmt,
  499.         Proc_format,
  500.         pp->p_pid,
  501.         (*get_userid)(pp->p_uid),
  502.         pp->p_pri - PZERO,
  503.         pp->p_nice - NZERO,
  504.         format_k(pagetok(PROCSIZE(pp))),
  505.         format_k(pagetok(pp->p_rssize)),
  506.         state_abbrev[pp->p_stat],
  507.         format_time(cputime),
  508.         100.0 * weighted_cpu(pct, pp),
  509.         100.0 * pct,
  510.         printable(u.u_comm));
  511.  
  512.     /* return the result */
  513.     return(fmt);
  514. }
  515.  
  516. /*
  517.  *  getu(p, u) - get the user structure for the process whose proc structure
  518.  *    is pointed to by p.  The user structure is put in the buffer pointed
  519.  *    to by u.  Return 0 if successful, -1 on failure (such as the process
  520.  *    being swapped out).
  521.  */
  522.  
  523. #ifdef ibm032
  524. static struct alignuser {
  525.     char userfill[UPAGES*NBPG-sizeof (struct user)];
  526.     struct user user;
  527. } au;
  528. # define USERSIZE sizeof(struct alignuser)
  529. # define GETUSER(b)    (&au)
  530. # define SETUSER(b)    *(b) = au.user
  531. #else
  532. # define USERSIZE sizeof(struct user)
  533. # define GETUSER(b)    (b)
  534. # define SETUSER(b)    /* Nothing */
  535. #endif
  536.  
  537. getu(p, u)
  538.  
  539. register struct proc *p;
  540. struct user *u;
  541.  
  542. {
  543.     struct pte uptes[UPAGES];
  544.     register caddr_t upage;
  545.     register struct pte *pte;
  546.     register nbytes, n;
  547.  
  548.     /*
  549.      *  Check if the process is currently loaded or swapped out.  The way we
  550.      *  get the u area is totally different for the two cases.  For this
  551.      *  application, we just don't bother if the process is swapped out.
  552.      */
  553.     if ((p->p_flag & SLOAD) == 0) {
  554. #ifdef DOSWAP
  555.     if (lseek(swap, (long)dtob(p->p_swaddr), 0) == -1) {
  556.         perror("lseek(swap)");
  557.         return(-1);
  558.     }
  559.     if (read(swap, (char *) GETUSER(u), USERSIZE) != USERSIZE)  {
  560.         perror("read(swap)");
  561.         return(-1);
  562.     }
  563.     SETUSER(u);
  564.     return (1);
  565. #else
  566.     return(-1);
  567. #endif
  568.     }
  569.  
  570.     /*
  571.      *  Process is currently in memory, we hope!
  572.      */
  573.     if (!getkval((unsigned long)p->p_addr, (int *)uptes, sizeof(uptes),
  574.                 "!p->p_addr"))
  575.     {
  576. #ifdef DEBUG
  577.     perror("getkval(uptes)");
  578. #endif
  579.     /* we can't seem to get to it, so pretend it's swapped out */
  580.     return(-1);
  581.     } 
  582.     upage = (caddr_t) GETUSER(u);
  583.     pte = uptes;
  584.     for (nbytes = USERSIZE; nbytes > 0; nbytes -= NBPG) {
  585.         (void) lseek(mem, (long)(pte++->pg_pfnum * NBPG), 0);
  586. #ifdef DEBUG
  587.     perror("lseek(mem)");
  588. #endif
  589.     n = MIN(nbytes, NBPG);
  590.     if (read(mem, upage, n) != n) {
  591. #ifdef DEBUG
  592.     perror("read(mem)");
  593. #endif
  594.         /* we can't seem to get to it, so pretend it's swapped out */
  595.         return(-1);
  596.     }
  597.     upage += n;
  598.     }
  599.     SETUSER(u);
  600.     return(0);
  601. }
  602.  
  603. /*
  604.  * check_nlist(nlst) - checks the nlist to see if any symbols were not
  605.  *        found.  For every symbol that was not found, a one-line
  606.  *        message is printed to stderr.  The routine returns the
  607.  *        number of symbols NOT found.
  608.  */
  609.  
  610. int check_nlist(nlst)
  611.  
  612. register struct nlist *nlst;
  613.  
  614. {
  615.     register int i;
  616.  
  617.     /* check to see if we got ALL the symbols we requested */
  618.     /* this will write one line to stderr for every symbol not found */
  619.  
  620.     i = 0;
  621.     while (nlst->n_name != NULL)
  622.     {
  623.     if (nlst->n_type == 0)
  624.     {
  625.         /* this one wasn't found */
  626.         fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
  627.         i = 1;
  628.     }
  629.     nlst++;
  630.     }
  631.  
  632.     return(i);
  633. }
  634.  
  635.  
  636. /*
  637.  *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
  638.  *    "offset" is the byte offset into the kernel for the desired value,
  639.  *      "ptr" points to a buffer into which the value is retrieved,
  640.  *      "size" is the size of the buffer (and the object to retrieve),
  641.  *      "refstr" is a reference string used when printing error meessages,
  642.  *        if "refstr" starts with a '!', then a failure on read will not
  643.  *          be fatal (this may seem like a silly way to do things, but I
  644.  *          really didn't want the overhead of another argument).
  645.  *      
  646.  */
  647.  
  648. getkval(offset, ptr, size, refstr)
  649.  
  650. unsigned long offset;
  651. int *ptr;
  652. int size;
  653. char *refstr;
  654.  
  655. {
  656.     if (lseek(kmem, (long)offset, L_SET) == -1) {
  657.         if (*refstr == '!')
  658.             refstr++;
  659.         (void) fprintf(stderr, "%s: lseek to %s: %s\n", KMEM, 
  660.                refstr, strerror(errno));
  661.         quit(23);
  662.     }
  663.     if (read(kmem, (char *) ptr, size) == -1) {
  664.         if (*refstr == '!') 
  665.             return(0);
  666.         else {
  667.             (void) fprintf(stderr, "%s: reading %s: %s\n", KMEM, 
  668.                refstr, strerror(errno));
  669.             quit(23);
  670.         }
  671.     }
  672.     return(1);
  673. }
  674.     
  675. /* comparison routine for qsort */
  676.  
  677. /*
  678.  *  proc_compare - comparison function for "qsort"
  679.  *    Compares the resource consumption of two processes using five
  680.  *      distinct keys.  The keys (in descending order of importance) are:
  681.  *      percent cpu, cpu ticks, state, resident set size, total virtual
  682.  *      memory usage.  The process states are ordered as follows (from least
  683.  *      to most important):  WAIT, zombie, sleep, stop, start, run.  The
  684.  *      array declaration below maps a process state index into a number
  685.  *      that reflects this ordering.
  686.  */
  687.  
  688. static unsigned char sorted_state[] =
  689. {
  690.     0,    /* not used        */
  691.     3,    /* sleep        */
  692.     1,    /* ABANDONED (WAIT)    */
  693.     6,    /* run            */
  694.     5,    /* start        */
  695.     2,    /* zombie        */
  696.     4    /* stop            */
  697. };
  698.  
  699. proc_compare(pp1, pp2)
  700.  
  701. struct proc **pp1;
  702. struct proc **pp2;
  703.  
  704. {
  705.     register struct proc *p1;
  706.     register struct proc *p2;
  707.     register int result;
  708.     register pctcpu lresult;
  709.  
  710.     /* remove one level of indirection */
  711.     p1 = *pp1;
  712.     p2 = *pp2;
  713.  
  714.     /* compare percent cpu (pctcpu) */
  715.     if ((lresult = p2->p_pctcpu - p1->p_pctcpu) == 0)
  716.     {
  717.     /* use cpticks to break the tie */
  718.     if ((result = p2->p_cpticks - p1->p_cpticks) == 0)
  719.     {
  720.         /* use process state to break the tie */
  721.         if ((result = sorted_state[p2->p_stat] -
  722.               sorted_state[p1->p_stat])  == 0)
  723.         {
  724.         /* use priority to break the tie */
  725.         if ((result = p2->p_pri - p1->p_pri) == 0)
  726.         {
  727.             /* use resident set size (rssize) to break the tie */
  728.             if ((result = p2->p_rssize - p1->p_rssize) == 0)
  729.             {
  730.             /* use total memory to break the tie */
  731.             result = PROCSIZE(p2) - PROCSIZE(p1);
  732.             }
  733.         }
  734.         }
  735.     }
  736.     }
  737.     else
  738.     {
  739.     result = lresult < 0 ? -1 : 1;
  740.     }
  741.  
  742.     return(result);
  743. }
  744.  
  745. /*
  746.  * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
  747.  *        the process does not exist.
  748.  *        It is EXTREMLY IMPORTANT that this function work correctly.
  749.  *        If top runs setuid root (as in SVR4), then this function
  750.  *        is the only thing that stands in the way of a serious
  751.  *        security problem.  It validates requests for the "kill"
  752.  *        and "renice" commands.
  753.  */
  754.  
  755. int proc_owner(pid)
  756.  
  757. int pid;
  758.  
  759. {
  760.     register int cnt;
  761.     register struct proc **prefp;
  762.     register struct proc *pp;
  763.  
  764.     prefp = pref;
  765.     cnt = pref_len;
  766.     while (--cnt >= 0)
  767.     {
  768.     if ((pp = *prefp++)->p_pid == (pid_t)pid)
  769.     {
  770.         return((int)pp->p_uid);
  771.     }
  772.     }
  773.     return(-1);
  774. }
  775.