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

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