"Fossies" - the Fresh Open Source Software Archive

Member "top-3.8beta1/machine/m_netbsd.c" (7 May 2008, 21722 Bytes) of package /linux/misc/old/top-3.8beta1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "m_netbsd.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.7_vs_3.8beta1.

    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 /*  $NetBSD: m_netbsd15.c,v 1.16 2002/03/23 01:28:11 thorpej Exp $  */
   34 
   35 /*
   36  * top - a top users display for Unix
   37  *
   38  * SYNOPSIS:  For a NetBSD-1.5 (or later) system
   39  *
   40  * DESCRIPTION:
   41  * Originally written for BSD4.4 system by Christos Zoulas.
   42  * Based on the FreeBSD 2.0 version by Steven Wallace and Wolfram Schneider.
   43  * NetBSD-1.0 port by Arne Helme. Process ordering by Luke Mewburn.
   44  * NetBSD-1.3 port by Luke Mewburn, based on code by Matthew Green.
   45  * NetBSD-1.4/UVM port by matthew green.
   46  * NetBSD-1.5 port by Simon Burge.
   47  * NetBSD-1.6/UBC port by Tomas Svensson.
   48  * NetBSD-3.0/kernel threads port Simon Burge.
   49  * -
   50  * This is the machine-dependent module for NetBSD-1.5 and later
   51  * works for:
   52  *  NetBSD-1.6
   53  *  NetBSD-2.0
   54  *  NetBSD-3.0  (when released)
   55  *  NetBSD-3.99.10  (current development version)
   56  * and should work for:
   57  *  NetBSD-1.5
   58  * -
   59  * Doesn't include separate CPU states line per cpu on multiprocessor
   60  * systems like the NetBSD version of top, but that requires some
   61  * recent kernel support.  This module forsakes that functionality as
   62  * a tradeoff for working on older versions of NetBSD.
   63  * -
   64  * top does not need to be installed setuid or setgid with this module.
   65  *
   66  * LIBS: -lkvm
   67  *
   68  * AUTHORS: Christos Zoulas <christos@ee.cornell.edu>
   69  *      Steven Wallace <swallace@freebsd.org>
   70  *      Wolfram Schneider <wosch@cs.tu-berlin.de>
   71  *      Arne Helme <arne@acm.org>
   72  *      Luke Mewburn <lukem@netbsd.org>
   73  *      matthew green <mrg@eterna.com.au>
   74  *      Simon Burge <simonb@netbsd.org>
   75  *      Tomas Svensson <ts@unix1.net>
   76  *
   77  *
   78  * $Id: m_netbsd15.c,v 1.16 2002/03/23 01:28:11 thorpej Exp $
   79  */
   80 
   81 #include <sys/param.h>
   82 #include <sys/sysctl.h>
   83 #include <sys/sched.h>
   84 #include <sys/swap.h>
   85 
   86 #include <uvm/uvm_extern.h>
   87 
   88 #include <err.h>
   89 #include <errno.h>
   90 #include <kvm.h>
   91 #include <math.h>
   92 #include <nlist.h>
   93 #include <stdio.h>
   94 #include <stdlib.h>
   95 #include <string.h>
   96 #include <unistd.h>
   97 
   98 #include "os.h"
   99 #include "top.h"
  100 #include "machine.h"
  101 #include "utils.h"
  102 #include "display.h"
  103 #include "loadavg.h"
  104 
  105 void percentages64 __P((int, int *, u_int64_t *, u_int64_t *, u_int64_t *));
  106 
  107 
  108 /* get_process_info passes back a handle.  This is what it looks like: */
  109 
  110 struct handle {
  111     struct kinfo_proc2 **next_proc; /* points to next valid proc pointer */
  112     int remaining;      /* number of pointers remaining */
  113 };
  114 
  115 /* define what weighted cpu is. */
  116 #define weighted_cpu(pct, pp) ((pp)->p_swtime == 0 ? 0.0 : \
  117              ((pct) / (1.0 - exp((pp)->p_swtime * logcpu))))
  118 
  119 /* what we consider to be process size: */
  120 #define PROCSIZE(pp) \
  121     ((pp)->p_vm_tsize + (pp)->p_vm_dsize + (pp)->p_vm_ssize)
  122 
  123 
  124 /*
  125  * These definitions control the format of the per-process area
  126  */
  127 
  128 static char header[] =
  129   "  PID X        PRI NICE   SIZE   RES STATE      TIME   WCPU    CPU COMMAND";
  130 /* 0123456   -- field to fill in starts at header+6 */
  131 #define UNAME_START 6
  132 
  133 #define Proc_format \
  134     "%5d %-8.8s %3d %4d%7s %5s %-8.8s%7s %5.2f%% %5.2f%% %.12s"
  135 
  136 
  137 /* 
  138  * Process state names for the "STATE" column of the display.
  139  */
  140 
  141 const char *state_abbrev[] = {
  142     "", "START", "RUN", "SLEEP", "STOP", "ZOMB", "DEAD", "CPU"
  143 };
  144 
  145 static kvm_t *kd;
  146 
  147 /* these are retrieved from the kernel in _init */
  148 
  149 static double logcpu;
  150 static int hz;
  151 static int ccpu;
  152 
  153 /* these are for calculating cpu state percentages */
  154 
  155 static u_int64_t cp_time[CPUSTATES];
  156 static u_int64_t cp_old[CPUSTATES];
  157 static u_int64_t cp_diff[CPUSTATES];
  158 
  159 /* these are for detailing the process states */
  160 
  161 int process_states[8];
  162 char *procstatenames[] = {
  163     "", " starting, ", " runnable, ", " sleeping, ", " stopped, ",
  164     " zombie, ", " dead, ", " on processor, ",
  165     NULL
  166 };
  167 
  168 /* these are for detailing the cpu states */
  169 
  170 int cpu_states[CPUSTATES];
  171 char *cpustatenames[] = {
  172     "user", "nice", "system", "interrupt", "idle", NULL
  173 };
  174 
  175 /* these are for detailing the memory statistics */
  176 
  177 long memory_stats[7];
  178 char *memorynames[] = {
  179     "K Act, ", "K Inact, ", "K Wired, ", "K Exec, ", "K File, ",
  180     "K Free, ",
  181     NULL
  182 };
  183 
  184 long swap_stats[4];
  185 char *swapnames[] = {
  186     "K Total, ", "K Used, ", "K Free, ",
  187     NULL
  188 };
  189 
  190 
  191 /* these are names given to allowed sorting orders -- first is default */
  192 char *ordernames[] = {
  193     "cpu",
  194     "pri",
  195     "res",
  196     "size",
  197     "state",
  198     "time",
  199     NULL
  200 };
  201 
  202 /* forward definitions for comparison functions */
  203 static int compare_cpu __P((struct proc **, struct proc **));
  204 static int compare_prio __P((struct proc **, struct proc **));
  205 static int compare_res __P((struct proc **, struct proc **));
  206 static int compare_size __P((struct proc **, struct proc **));
  207 static int compare_state __P((struct proc **, struct proc **));
  208 static int compare_time __P((struct proc **, struct proc **));
  209 
  210 int (*proc_compares[]) __P((struct proc **, struct proc **)) = {
  211     compare_cpu,
  212     compare_prio,
  213     compare_res,
  214     compare_size,
  215     compare_state,
  216     compare_time,
  217     NULL
  218 };
  219 
  220 
  221 /* these are for keeping track of the proc array */
  222 
  223 static int nproc;
  224 static int onproc = -1;
  225 static int pref_len;
  226 static struct kinfo_proc2 *pbase;
  227 static struct kinfo_proc2 **pref;
  228 
  229 /* these are for getting the memory statistics */
  230 
  231 static int pageshift;       /* log base 2 of the pagesize */
  232 
  233 /* define pagetok in terms of pageshift */
  234 
  235 #define pagetok(size) ((size) << pageshift)
  236 
  237 /* Pre/post lwp process states */
  238 #ifndef SDEAD
  239 #define SDEAD   LSDEAD
  240 #define SRUN    LSRUN
  241 #define SONPROC LSONPROC
  242 #define SSLEEP  LSSLEEP
  243 #define P_INMEM L_INMEM
  244 #endif
  245 
  246 int
  247 machine_init(statics)
  248     struct statics *statics;
  249 {
  250     int pagesize;
  251     int mib[2];
  252     size_t size;
  253     struct clockinfo clockinfo;
  254 
  255     if ((kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open")) == NULL)
  256         return -1;
  257 
  258     mib[0] = CTL_KERN;
  259     mib[1] = KERN_CCPU;
  260     size = sizeof(ccpu);
  261     if (sysctl(mib, 2, &ccpu, &size, NULL, 0) == -1) {
  262         fprintf(stderr, "top: sysctl kern.ccpu failed: %s\n",
  263             strerror(errno));
  264         return(-1);
  265     }
  266 
  267     mib[0] = CTL_KERN;
  268     mib[1] = KERN_CLOCKRATE;
  269     size = sizeof(clockinfo);
  270     if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) == -1) {
  271         fprintf(stderr, "top: sysctl kern.clockrate failed: %s\n",
  272             strerror(errno));
  273         return(-1);
  274     }
  275     hz = clockinfo.stathz;
  276 
  277     /* this is used in calculating WCPU -- calculate it ahead of time */
  278     logcpu = log(loaddouble(ccpu));
  279 
  280     pbase = NULL;
  281     pref = NULL;
  282     nproc = 0;
  283     onproc = -1;
  284     /* get the page size with "getpagesize" and calculate pageshift from it */
  285     pagesize = getpagesize();
  286     pageshift = 0;
  287     while (pagesize > 1) {
  288         pageshift++;
  289         pagesize >>= 1;
  290     }
  291 
  292     /* we only need the amount of log(2)1024 for our conversion */
  293     pageshift -= LOG1024;
  294 
  295     /* fill in the statics information */
  296     statics->procstate_names = procstatenames;
  297     statics->cpustate_names = cpustatenames;
  298     statics->memory_names = memorynames;
  299     statics->swap_names = swapnames;
  300     statics->order_names = ordernames;
  301 
  302     /* all done! */
  303     return(0);
  304 }
  305 
  306 char *
  307 format_header(uname_field)
  308     char *uname_field;
  309 {
  310     char *ptr;
  311 
  312     ptr = header + UNAME_START;
  313     while (*uname_field != '\0') {
  314         *ptr++ = *uname_field++;
  315     }
  316 
  317     return(header);
  318 }
  319 
  320 void
  321 get_system_info(si)
  322     struct system_info *si;
  323 {
  324     size_t ssize;
  325     int mib[2];
  326     struct uvmexp_sysctl uvmexp;
  327     struct swapent *sep, *seporig;
  328     u_int64_t totalsize, totalinuse;
  329     int size, inuse, ncounted;
  330     int rnswap, nswap;
  331 
  332     mib[0] = CTL_KERN;
  333     mib[1] = KERN_CP_TIME;
  334     ssize = sizeof(cp_time);
  335     if (sysctl(mib, 2, cp_time, &ssize, NULL, 0) < 0) {
  336         fprintf(stderr, "top: sysctl kern.cp_time failed: %s\n",
  337             strerror(errno));
  338         quit(23);
  339     }
  340 
  341     if (getloadavg(si->load_avg, NUM_AVERAGES) < 0) {
  342         int i;
  343 
  344         warn("can't getloadavg");
  345         for (i = 0; i < NUM_AVERAGES; i++)
  346             si->load_avg[i] = 0.0;
  347     }
  348 
  349     /* convert cp_time counts to percentages */
  350     percentages64(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
  351 
  352     mib[0] = CTL_VM;
  353     mib[1] = VM_UVMEXP2;
  354     ssize = sizeof(uvmexp);
  355     if (sysctl(mib, 2, &uvmexp, &ssize, NULL, 0) < 0) {
  356         fprintf(stderr, "top: sysctl vm.uvmexp2 failed: %s\n",
  357             strerror(errno));
  358         quit(23);
  359     }
  360 
  361     /* convert memory stats to Kbytes */
  362     memory_stats[0] = pagetok(uvmexp.active);
  363     memory_stats[1] = pagetok(uvmexp.inactive);
  364     memory_stats[2] = pagetok(uvmexp.wired);
  365     memory_stats[3] = pagetok(uvmexp.execpages);
  366     memory_stats[4] = pagetok(uvmexp.filepages);
  367     memory_stats[5] = pagetok(uvmexp.free);
  368 
  369     swap_stats[0] = swap_stats[1] = swap_stats[2] = 0;
  370 
  371     seporig = NULL;
  372     do {
  373         nswap = swapctl(SWAP_NSWAP, 0, 0);
  374         if (nswap < 1)
  375             break;
  376         /* Use seporig to keep track of the malloc'd memory
  377          * base, as sep will be incremented in the for loop
  378          * below.
  379          */
  380         seporig = sep = (struct swapent *)malloc(nswap * sizeof(*sep));
  381         if (sep == NULL)
  382             break;
  383         rnswap = swapctl(SWAP_STATS, (void *)sep, nswap);
  384         if (nswap != rnswap)
  385             break;
  386 
  387         totalsize = totalinuse = ncounted = 0;
  388         for (; rnswap-- > 0; sep++) {
  389             ncounted++;
  390             size = sep->se_nblks;
  391             inuse = sep->se_inuse;
  392             totalsize += size;
  393             totalinuse += inuse;
  394         }
  395         swap_stats[0] = dbtob(totalsize) / 1024;
  396         swap_stats[1] = dbtob(totalinuse) / 1024;
  397         swap_stats[2] = dbtob(totalsize) / 1024 - swap_stats[1];
  398         /* Free here, before we malloc again in the next
  399          * iteration of this loop.
  400          */
  401         if (seporig) {
  402             free(seporig);
  403             seporig = NULL;
  404         }
  405     } while (0);
  406     /* Catch the case where we malloc'd, but then exited the
  407      * loop due to nswap != rnswap.
  408      */
  409     if (seporig)
  410         free(seporig);
  411 
  412     memory_stats[6] = -1;
  413     swap_stats[3] = -1;
  414 
  415     /* set arrays and strings */
  416     si->cpustates = cpu_states;
  417     si->memory = memory_stats;
  418     si->swap = swap_stats;
  419     si->last_pid = -1;
  420 }
  421 
  422 
  423 caddr_t
  424 get_process_info(si, sel, compare_index)
  425     struct system_info *si;
  426     struct process_select *sel;
  427     int compare_index;
  428 {
  429     int i;
  430     int total_procs;
  431     int active_procs;
  432     struct kinfo_proc2 **prefp;
  433     struct kinfo_proc2 *pp;
  434 
  435     /* these are copied out of sel for speed */
  436     int show_idle;
  437     int show_system;
  438     int show_uid;
  439     int show_command;
  440 
  441     static struct handle handle;
  442 
  443 
  444     pbase = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2), &nproc);
  445     if (nproc > onproc)
  446         pref = (struct kinfo_proc2 **) realloc(pref,
  447             sizeof(struct kinfo_proc2 *) * (onproc = nproc));
  448     if (pref == NULL || pbase == NULL) {
  449         (void) fprintf(stderr, "top: Out of memory.\n");
  450         quit(23);
  451     }
  452     /* get a pointer to the states summary array */
  453     si->procstates = process_states;
  454 
  455     /* set up flags which define what we are going to select */
  456     show_idle = sel->idle;
  457     show_system = sel->system;
  458     show_uid = sel->uid != -1;
  459     show_command = sel->command != NULL;
  460 
  461     /* count up process states and get pointers to interesting procs */
  462     total_procs = 0;
  463     active_procs = 0;
  464     memset((char *)process_states, 0, sizeof(process_states));
  465     prefp = pref;
  466     for (pp = pbase, i = 0; i < nproc; pp++, i++) {
  467 
  468         /*
  469          * Place pointers to each valid proc structure in pref[].
  470          * Process slots that are actually in use have a non-zero
  471          * status field.  Processes with P_SYSTEM set are system
  472          * processes---these get ignored unless show_sysprocs is set.
  473          */
  474         if (pp->p_stat != 0 && (show_system || ((pp->p_flag & P_SYSTEM) == 0))) {
  475             total_procs++;
  476             process_states[(unsigned char) pp->p_stat]++;
  477             if (pp->p_stat != SZOMB && pp->p_stat != SDEAD &&
  478                 (show_idle || (pp->p_pctcpu != 0) || 
  479                 (pp->p_stat == SRUN || pp->p_stat == SONPROC)) &&
  480                 (!show_uid || pp->p_ruid == (uid_t)sel->uid)) {
  481                 *prefp++ = pp;
  482                 active_procs++;
  483             }
  484         }
  485     }
  486 
  487     /* if requested, sort the "interesting" processes */
  488     qsort((char *)pref, active_procs, sizeof(struct kinfo_proc2 *), 
  489         proc_compares[compare_index]);
  490 
  491     /* remember active and total counts */
  492     si->p_total = total_procs;
  493     si->p_active = pref_len = active_procs;
  494 
  495     /* pass back a handle */
  496     handle.next_proc = pref;
  497     handle.remaining = active_procs;
  498     return((caddr_t)&handle);
  499 }
  500 
  501 
  502 char *
  503 format_next_process(handle, get_userid)
  504     caddr_t handle;
  505     char *(*get_userid) __P((int));
  506 {
  507     struct kinfo_proc2 *pp;
  508     long cputime;
  509     double pct;
  510     struct handle *hp;
  511     const char *statep;
  512 #ifdef KI_NOCPU
  513     char state[10];
  514 #endif
  515     char wmesg[KI_WMESGLEN + 1];
  516     static char fmt[128];       /* static area where result is built */
  517     char *pretty = "";
  518 
  519     /* find and remember the next proc structure */
  520     hp = (struct handle *)handle;
  521     pp = *(hp->next_proc++);
  522     hp->remaining--;
  523 
  524     /* get the process's user struct and set cputime */
  525     if ((pp->p_flag & P_INMEM) == 0)
  526         pretty = "<>";
  527     else if ((pp->p_flag & P_SYSTEM) != 0)
  528         pretty = "[]";
  529 
  530     if (pretty[0] != '\0') {
  531         /*
  532          * Print swapped processes as <pname> and
  533          * system processes as [pname]
  534          */
  535         char *comm = pp->p_comm;
  536 #define COMSIZ sizeof(pp->p_comm)
  537         char buf[COMSIZ];
  538         (void) strncpy(buf, comm, COMSIZ);
  539         comm[0] = pretty[0];
  540         (void) strncpy(&comm[1], buf, COMSIZ - 2);
  541         comm[COMSIZ - 2] = '\0';
  542         (void) strncat(comm, &pretty[1], COMSIZ - 1);
  543         comm[COMSIZ - 1] = '\0';
  544     }
  545 
  546 #if 0
  547     /* This does not produce the correct results */
  548     cputime = pp->p_uticks + pp->p_sticks + pp->p_iticks;
  549 #else
  550     cputime = pp->p_rtime_sec;  /* This does not count interrupts */
  551 #endif
  552 
  553     /* calculate the base for cpu percentages */
  554     pct = pctdouble(pp->p_pctcpu);
  555 
  556     if (pp->p_stat == SSLEEP) {
  557         strlcpy(wmesg, pp->p_wmesg, sizeof(wmesg));
  558         statep = wmesg;
  559     } else
  560         statep = state_abbrev[(unsigned)pp->p_stat];
  561 
  562 #ifdef KI_NOCPU
  563     /* Post-1.5 change: add cpu number if appropriate */
  564     if (pp->p_cpuid != KI_NOCPU) {
  565         switch (pp->p_stat) {
  566         case SONPROC:
  567         case SRUN:
  568         case SSLEEP:            
  569             snprintf(state, sizeof(state), "%.6s/%lld", 
  570                  statep, (long long)pp->p_cpuid);
  571             statep = state;
  572             break;
  573         }
  574     }
  575 #endif
  576     /* format this entry */
  577     sprintf(fmt,
  578         Proc_format,
  579         pp->p_pid,
  580         (*get_userid)(pp->p_ruid),
  581         pp->p_priority - PZERO,
  582         pp->p_nice - NZERO,
  583         format_k(pagetok(PROCSIZE(pp))),
  584         format_k(pagetok(pp->p_vm_rssize)),
  585         statep,
  586         format_time(cputime),
  587         100.0 * weighted_cpu(pct, pp),
  588         100.0 * pct,
  589         printable(pp->p_comm));
  590 
  591     /* return the result */
  592     return(fmt);
  593 }
  594 
  595 /* comparison routines for qsort */
  596 
  597 /*
  598  * There are currently four possible comparison routines.  main selects
  599  * one of these by indexing in to the array proc_compares.
  600  *
  601  * Possible keys are defined as macros below.  Currently these keys are
  602  * defined:  percent cpu, cpu ticks, process state, resident set size,
  603  * total virtual memory usage.  The process states are ordered as follows
  604  * (from least to most important):  WAIT, zombie, sleep, stop, start, run.
  605  * The array declaration below maps a process state index into a number
  606  * that reflects this ordering.
  607  */
  608 
  609 /*
  610  * First, the possible comparison keys.  These are defined in such a way
  611  * that they can be merely listed in the source code to define the actual
  612  * desired ordering.
  613  */
  614 
  615 #define ORDERKEY_PCTCPU \
  616     if (lresult = (pctcpu)(p2)->p_pctcpu - (pctcpu)(p1)->p_pctcpu,\
  617         (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
  618 
  619 #define ORDERKEY_CPTICKS \
  620     if (lresult = (pctcpu)(p2)->p_rtime_sec \
  621             - (pctcpu)(p1)->p_rtime_sec,\
  622         (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
  623 
  624 #define ORDERKEY_STATE \
  625     if ((result = sorted_state[(int)(p2)->p_stat] - \
  626               sorted_state[(int)(p1)->p_stat] ) == 0)
  627 
  628 #define ORDERKEY_PRIO \
  629     if ((result = (p2)->p_priority - (p1)->p_priority) == 0)
  630 
  631 #define ORDERKEY_RSSIZE \
  632     if ((result = p2->p_vm_rssize - p1->p_vm_rssize) == 0)
  633 
  634 #define ORDERKEY_MEM    \
  635     if ((result = (PROCSIZE(p2) - PROCSIZE(p1))) == 0)
  636 
  637 /*
  638  * Now the array that maps process state to a weight.
  639  * The order of the elements should match those in state_abbrev[]
  640  */
  641 
  642 static int sorted_state[] = {
  643     0,  /*  (not used)    ? */
  644     6,  /* "start"  SIDL    */
  645     4,  /* "run"    SRUN    */
  646     3,  /* "sleep"  SSLEEP  */
  647     3,  /* "stop"   SSTOP   */
  648     2,  /* "dead"   SDEAD   */
  649     1,  /* "zomb"   SZOMB   */
  650     5,  /* "onproc" SONPROC */
  651 };
  652 
  653 /* compare_cpu - the comparison function for sorting by cpu percentage */
  654 
  655 static int
  656 compare_cpu(pp1, pp2)
  657     struct proc **pp1, **pp2;
  658 {
  659     struct kinfo_proc2 *p1;
  660     struct kinfo_proc2 *p2;
  661     int result;
  662     pctcpu lresult;
  663 
  664     /* remove one level of indirection */
  665     p1 = *(struct kinfo_proc2 **) pp1;
  666     p2 = *(struct kinfo_proc2 **) pp2;
  667 
  668     ORDERKEY_PCTCPU
  669     ORDERKEY_CPTICKS
  670     ORDERKEY_STATE
  671     ORDERKEY_PRIO
  672     ORDERKEY_RSSIZE
  673     ORDERKEY_MEM
  674     ;
  675 
  676     return (result);
  677 }
  678 
  679 /* compare_prio - the comparison function for sorting by process priority */
  680 
  681 static int
  682 compare_prio(pp1, pp2)
  683     struct proc **pp1, **pp2;
  684 {
  685     struct kinfo_proc2 *p1;
  686     struct kinfo_proc2 *p2;
  687     int result;
  688     pctcpu lresult;
  689 
  690     /* remove one level of indirection */
  691     p1 = *(struct kinfo_proc2 **) pp1;
  692     p2 = *(struct kinfo_proc2 **) pp2;
  693 
  694     ORDERKEY_PRIO
  695     ORDERKEY_PCTCPU
  696     ORDERKEY_CPTICKS
  697     ORDERKEY_STATE
  698     ORDERKEY_RSSIZE
  699     ORDERKEY_MEM
  700     ;
  701 
  702     return (result);
  703 }
  704 
  705 /* compare_res - the comparison function for sorting by resident set size */
  706 
  707 static int
  708 compare_res(pp1, pp2)
  709     struct proc **pp1, **pp2;
  710 {
  711     struct kinfo_proc2 *p1;
  712     struct kinfo_proc2 *p2;
  713     int result;
  714     pctcpu lresult;
  715 
  716     /* remove one level of indirection */
  717     p1 = *(struct kinfo_proc2 **) pp1;
  718     p2 = *(struct kinfo_proc2 **) pp2;
  719 
  720     ORDERKEY_RSSIZE
  721     ORDERKEY_MEM
  722     ORDERKEY_PCTCPU
  723     ORDERKEY_CPTICKS
  724     ORDERKEY_STATE
  725     ORDERKEY_PRIO
  726     ;
  727 
  728     return (result);
  729 }
  730 
  731 /* compare_size - the comparison function for sorting by total memory usage */
  732 
  733 static int
  734 compare_size(pp1, pp2)
  735     struct proc **pp1, **pp2;
  736 {
  737     struct kinfo_proc2 *p1;
  738     struct kinfo_proc2 *p2;
  739     int result;
  740     pctcpu lresult;
  741 
  742     /* remove one level of indirection */
  743     p1 = *(struct kinfo_proc2 **) pp1;
  744     p2 = *(struct kinfo_proc2 **) pp2;
  745 
  746     ORDERKEY_MEM
  747     ORDERKEY_RSSIZE
  748     ORDERKEY_PCTCPU
  749     ORDERKEY_CPTICKS
  750     ORDERKEY_STATE
  751     ORDERKEY_PRIO
  752     ;
  753 
  754     return (result);
  755 }
  756 
  757 /* compare_state - the comparison function for sorting by process state */
  758 
  759 static int
  760 compare_state(pp1, pp2)
  761     struct proc **pp1, **pp2;
  762 {
  763     struct kinfo_proc2 *p1;
  764     struct kinfo_proc2 *p2;
  765     int result;
  766     pctcpu lresult;
  767 
  768     /* remove one level of indirection */
  769     p1 = *(struct kinfo_proc2 **) pp1;
  770     p2 = *(struct kinfo_proc2 **) pp2;
  771 
  772     ORDERKEY_STATE
  773     ORDERKEY_PCTCPU
  774     ORDERKEY_CPTICKS
  775     ORDERKEY_PRIO
  776     ORDERKEY_RSSIZE
  777     ORDERKEY_MEM
  778     ;
  779 
  780     return (result);
  781 }
  782 
  783 /* compare_time - the comparison function for sorting by total cpu time */
  784 
  785 static int
  786 compare_time(pp1, pp2)
  787     struct proc **pp1, **pp2;
  788 {
  789     struct kinfo_proc2 *p1;
  790     struct kinfo_proc2 *p2;
  791     int result;
  792     pctcpu lresult;
  793 
  794     /* remove one level of indirection */
  795     p1 = *(struct kinfo_proc2 **) pp1;
  796     p2 = *(struct kinfo_proc2 **) pp2;
  797 
  798     ORDERKEY_CPTICKS
  799     ORDERKEY_PCTCPU
  800     ORDERKEY_STATE
  801     ORDERKEY_PRIO
  802     ORDERKEY_MEM
  803     ORDERKEY_RSSIZE
  804     ;
  805 
  806     return (result);
  807 }
  808 
  809 
  810 /*
  811  * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
  812  *      the process does not exist.
  813  *      It is EXTREMLY IMPORTANT that this function work correctly.
  814  *      If top runs setuid root (as in SVR4), then this function
  815  *      is the only thing that stands in the way of a serious
  816  *      security problem.  It validates requests for the "kill"
  817  *      and "renice" commands.
  818  */
  819 
  820 int
  821 proc_owner(pid)
  822     int pid;
  823 {
  824     int cnt;
  825     struct kinfo_proc2 **prefp;
  826     struct kinfo_proc2 *pp;
  827 
  828     prefp = pref;
  829     cnt = pref_len;
  830     while (--cnt >= 0) {
  831         pp = *prefp++;  
  832         if (pp->p_pid == (pid_t)pid)
  833             return(pp->p_ruid);
  834     }
  835     return(-1);
  836 }
  837 
  838 /*
  839  *  percentages(cnt, out, new, old, diffs) - calculate percentage change
  840  *  between array "old" and "new", putting the percentages i "out".
  841  *  "cnt" is size of each array and "diffs" is used for scratch space.
  842  *  The array "old" is updated on each call.
  843  *  The routine assumes modulo arithmetic.  This function is especially
  844  *  useful on BSD mchines for calculating cpu state percentages.
  845  */
  846 
  847 void
  848 percentages64(cnt, out, new, old, diffs)
  849     int cnt;
  850     int *out;
  851     u_int64_t *new;
  852     u_int64_t *old;
  853     u_int64_t *diffs;
  854 {
  855     int i;
  856     u_int64_t change;
  857     u_int64_t total_change;
  858     u_int64_t *dp;
  859     u_int64_t half_total;
  860 
  861     /* initialization */
  862     total_change = 0;
  863     dp = diffs;
  864 
  865     /* calculate changes for each state and the overall change */
  866     for (i = 0; i < cnt; i++) {
  867         /*
  868          * Don't worry about wrapping - even at hz=1GHz, a
  869          * u_int64_t will last at least 544 years.
  870          */
  871         change = *new - *old;
  872         total_change += (*dp++ = change);
  873         *old++ = *new++;
  874     }
  875 
  876     /* avoid divide by zero potential */
  877     if (total_change == 0)
  878         total_change = 1;
  879 
  880     /* calculate percentages based on overall change, rounding up */
  881     half_total = total_change / 2;
  882     for (i = 0; i < cnt; i++)
  883         *out++ = (int)((*diffs++ * 1000 + half_total) / total_change);
  884 }