home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / Utilities / top-0.5-MI / machine / m_sunos4mp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-02  |  19.5 KB  |  824 lines

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