top(1): Silence gcc warnings.
[dragonfly.git] / usr.bin / top / machine.c
1 /*
2  * top - a top users display for Unix
3  *
4  * SYNOPSIS:  For FreeBSD-2.x and later
5  *
6  * DESCRIPTION:
7  * Originally written for BSD4.4 system by Christos Zoulas.
8  * Ported to FreeBSD 2.x by Steven Wallace && Wolfram Schneider
9  * Order support hacked in from top-3.5beta6/machine/m_aix41.c
10  *   by Monte Mitzelfelt (for latest top see http://www.groupsys.com/topinfo/)
11  *
12  * This is the machine-dependent module for FreeBSD 2.2
13  * Works for:
14  *      FreeBSD 2.2.x, 3.x, 4.x, and probably FreeBSD 2.1.x
15  *
16  * LIBS: -lkvm
17  *
18  * AUTHOR:  Christos Zoulas <christos@ee.cornell.edu>
19  *          Steven Wallace  <swallace@freebsd.org>
20  *          Wolfram Schneider <wosch@FreeBSD.org>
21  *          Hiten Pandya <hmp@backplane.com>
22  *
23  * $FreeBSD: src/usr.bin/top/machine.c,v 1.29.2.2 2001/07/31 20:27:05 tmm Exp $
24  * $DragonFly: src/usr.bin/top/machine.c,v 1.26 2008/10/16 01:52:33 swildner Exp $
25  */
26
27
28 #include <sys/time.h>
29 #include <sys/types.h>
30 #include <sys/signal.h>
31 #include <sys/param.h>
32
33 #include "os.h"
34 #include <err.h>
35 #include <kvm.h>
36 #include <stdio.h>
37 #include <unistd.h>
38 #include <math.h>
39 #include <pwd.h>
40 #include <sys/errno.h>
41 #include <sys/sysctl.h>
42 #include <sys/file.h>
43 #include <sys/time.h>
44 #include <sys/user.h>
45 #include <sys/vmmeter.h>
46 #include <sys/resource.h>
47 #include <sys/rtprio.h>
48
49 /* Swap */
50 #include <stdlib.h>
51 #include <stdio.h>
52 #include <sys/conf.h>
53
54 #include <osreldate.h> /* for changes in kernel structures */
55
56 #include <sys/kinfo.h>
57 #include <kinfo.h>
58 #include "top.h"
59 #include "machine.h"
60 #include "utils.h"
61
62 #if 0
63 static int check_nlist(struct nlist *);
64 static int getkval(unsigned long, int *, int, char *);
65 #endif
66 extern char* printable(char *);
67 int swapmode(int *retavail, int *retfree);
68 static int smpmode;
69 static int namelength;
70 static int cmdlength;
71
72 /* 
73  * needs to be a global symbol, so wrapper can be
74  * modified accordingly.
75  */
76 static int show_threads = 0;
77
78 /* get_process_info passes back a handle.  This is what it looks like: */
79
80 struct handle
81 {
82     struct kinfo_proc **next_proc;      /* points to next valid proc pointer */
83     int remaining;              /* number of pointers remaining */
84 };
85
86 /* declarations for load_avg */
87 #include "loadavg.h"
88
89 #define PP(pp, field) ((pp)->kp_ ## field)
90 #define LP(pp, field) ((pp)->kp_lwp.kl_ ## field)
91 #define VP(pp, field) ((pp)->kp_vm_ ## field)
92
93 /* define what weighted cpu is.  */
94 #define weighted_cpu(pct, pp) (PP((pp), swtime) == 0 ? 0.0 : \
95                          ((pct) / (1.0 - exp(PP((pp), swtime) * logcpu))))
96
97 /* what we consider to be process size: */
98 #define PROCSIZE(pp) (VP((pp), map_size) / 1024)
99
100 /*
101  *  These definitions control the format of the per-process area
102  */
103
104 static char smp_header[] =
105   "  PID %-*.*s PRI NICE  SIZE    RES STATE  C   TIME   WCPU    CPU COMMAND";
106
107 #define smp_Proc_format \
108         "%5d %-*.*s %3d %3d%7s %6s %-6.6s %1x%7s %5.2f%% %5.2f%% %.*s"
109
110 static char up_header[] =
111   "  PID %-*.*s PRI NICE  SIZE    RES STATE    TIME   WCPU    CPU COMMAND";
112
113 #define up_Proc_format \
114         "%5d %-*.*s %3d %3d%7s %6s %-6.6s%.0d%7s %5.2f%% %5.2f%% %.*s"
115
116
117
118 /* process state names for the "STATE" column of the display */
119 /* the extra nulls in the string "run" are for adding a slash and
120    the processor number when needed */
121
122 const char *state_abbrev[] =
123 {
124     "", "RUN\0\0\0", "STOP", "SLEEP",
125 };
126
127
128 static kvm_t *kd;
129
130 /* values that we stash away in _init and use in later routines */
131
132 static double logcpu;
133
134 static long lastpid;
135 static int ccpu;
136
137 /* these are for calculating cpu state percentages */
138
139 static struct kinfo_cputime *cp_time, *cp_old;
140
141 /* these are for detailing the process states */
142
143 int process_states[6];
144 const char *procstatenames[] = {
145     "", " starting, ", " running, ", " sleeping, ", " stopped, ",
146     " zombie, ",
147     NULL
148 };
149
150 /* these are for detailing the cpu states */
151 #define CPU_STATES 5
152 int *cpu_states;
153 const char *cpustatenames[CPU_STATES + 1] = {
154     "user", "nice", "system", "interrupt", "idle", NULL
155 };
156
157 /* these are for detailing the memory statistics */
158
159 int memory_stats[7];
160 const char *memorynames[] = {
161     "K Active, ", "K Inact, ", "K Wired, ", "K Cache, ", "K Buf, ", "K Free",
162     NULL
163 };
164
165 int swap_stats[7];
166 const char *swapnames[] = {
167 /*   0           1            2           3            4       5 */
168     "K Total, ", "K Used, ", "K Free, ", "% Inuse, ", "K In, ", "K Out",
169     NULL
170 };
171
172
173 /* these are for keeping track of the proc array */
174
175 static int nproc;
176 static int onproc = -1;
177 static int pref_len;
178 static struct kinfo_proc *pbase;
179 static struct kinfo_proc **pref;
180
181 /* these are for getting the memory statistics */
182
183 static int pageshift;           /* log base 2 of the pagesize */
184
185 /* define pagetok in terms of pageshift */
186
187 #define pagetok(size) ((size) << pageshift)
188
189 #ifdef ORDER
190 /* sorting orders. first is default */
191 const char *ordernames[] = {
192     "cpu", "size", "res", "time", "pri", "thr", NULL
193 };
194 #endif
195
196 static void
197 cputime_percentages(int out[CPU_STATES], struct kinfo_cputime *new,
198                     struct kinfo_cputime *old)
199 {
200         struct kinfo_cputime diffs;
201         uint64_t total_change, half_total;
202
203         /* initialization */
204         total_change = 0;
205
206         diffs.cp_user = new->cp_user - old->cp_user;
207         diffs.cp_nice = new->cp_nice - old->cp_nice;
208         diffs.cp_sys = new->cp_sys - old->cp_sys;
209         diffs.cp_intr = new->cp_intr - old->cp_intr;
210         diffs.cp_idle = new->cp_idle - old->cp_idle;
211         total_change = diffs.cp_user + diffs.cp_nice + diffs.cp_sys +
212             diffs.cp_intr + diffs.cp_idle;
213         old->cp_user = new->cp_user;
214         old->cp_nice = new->cp_nice;
215         old->cp_sys = new->cp_sys;
216         old->cp_intr = new->cp_intr;
217         old->cp_idle = new->cp_idle;
218
219         /* avoid divide by zero potential */
220         if (total_change == 0)
221                 total_change = 1;
222
223         /* calculate percentages based on overall change, rounding up */
224         half_total = total_change >> 1;
225
226         out[0] = ((diffs.cp_user * 1000LL + half_total) / total_change);
227         out[1] = ((diffs.cp_nice * 1000LL + half_total) / total_change);
228         out[2] = ((diffs.cp_sys * 1000LL + half_total) / total_change);
229         out[3] = ((diffs.cp_intr * 1000LL + half_total) / total_change);
230         out[4] = ((diffs.cp_idle * 1000LL + half_total) / total_change);
231 }
232
233 int
234 machine_init(struct statics *statics)
235 {
236     int pagesize;
237     size_t modelen;
238     struct passwd *pw;
239
240     if (n_cpus < 1) {
241         if (kinfo_get_cpus(&n_cpus))
242             err(1, "kinfo_get_cpus failed");
243     }
244     modelen = sizeof(smpmode);
245     if ((sysctlbyname("machdep.smp_active", &smpmode, &modelen, NULL, 0) < 0 &&
246          sysctlbyname("smp.smp_active", &smpmode, &modelen, NULL, 0) < 0) ||
247         modelen != sizeof(smpmode))
248             smpmode = 0;
249
250     while ((pw = getpwent()) != NULL) {
251         if ((int)strlen(pw->pw_name) > namelength)
252             namelength = strlen(pw->pw_name);
253     }
254     if (namelength < 8)
255         namelength = 8;
256     if (smpmode && namelength > 13)
257         namelength = 13;
258     else if (namelength > 15)
259         namelength = 15;
260
261     if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open")) == NULL)
262         return -1;
263
264     if (kinfo_get_sched_ccpu(&ccpu)) {
265         fprintf(stderr, "top: kinfo_get_sched_ccpu failed\n");
266         return(-1);
267     }
268
269     /* this is used in calculating WCPU -- calculate it ahead of time */
270     logcpu = log(loaddouble(ccpu));
271
272     pbase = NULL;
273     pref = NULL;
274     nproc = 0;
275     onproc = -1;
276     /* get the page size with "getpagesize" and calculate pageshift from it */
277     pagesize = getpagesize();
278     pageshift = 0;
279     while (pagesize > 1)
280     {
281         pageshift++;
282         pagesize >>= 1;
283     }
284
285     /* we only need the amount of log(2)1024 for our conversion */
286     pageshift -= LOG1024;
287
288     /* fill in the statics information */
289     statics->procstate_names = procstatenames;
290     statics->cpustate_names = cpustatenames;
291     statics->memory_names = memorynames;
292     statics->swap_names = swapnames;
293 #ifdef ORDER
294     statics->order_names = ordernames;
295 #endif
296
297     /* all done! */
298     return(0);
299 }
300
301 char *
302 format_header(const char *uname_field)
303 {
304     static char Header[128];
305
306     snprintf(Header, sizeof(Header), smpmode ? smp_header : up_header,
307              namelength, namelength, uname_field);
308
309     if (screen_width <= 79)
310         cmdlength = 80;
311     else
312         cmdlength = 89;
313
314     cmdlength = cmdlength - strlen(Header) + 6;
315
316     return Header;
317 }
318
319 static int swappgsin = -1;
320 static int swappgsout = -1;
321 extern struct timeval timeout;
322
323 void
324 get_system_info(struct system_info *si)
325 {
326     int mib[2];
327     struct timeval boottime;
328     size_t bt_size;
329     size_t len;
330     int cpu;
331
332     if (cpu_states == NULL) {
333         cpu_states = malloc(sizeof(*cpu_states) * CPU_STATES * n_cpus);
334         if (cpu_states == NULL)
335             err(1, "malloc");
336         bzero(cpu_states, sizeof(*cpu_states) * CPU_STATES * n_cpus);
337     }
338     if (cp_time == NULL) {
339         cp_time = malloc(2 * n_cpus * sizeof(cp_time[0]));
340         if (cp_time == NULL)
341             err(1, "cp_time");
342         cp_old = cp_time + n_cpus;
343
344         len = n_cpus * sizeof(cp_old[0]);
345         bzero(cp_time, len);
346         if (sysctlbyname("kern.cputime", cp_old, &len, NULL, 0))
347             err(1, "kern.cputime");
348     }
349
350     len = n_cpus * sizeof(cp_time[0]);
351     bzero(cp_time, len);
352     if (sysctlbyname("kern.cputime", cp_time, &len, NULL, 0))
353         err(1, "kern.cputime");
354
355     getloadavg(si->load_avg, 3);
356
357     lastpid = 0;
358
359     /* convert cp_time counts to percentages */
360     for (cpu = 0; cpu < n_cpus; ++cpu) {
361         cputime_percentages(cpu_states + cpu * CPU_STATES,
362                             &cp_time[cpu], &cp_old[cpu]);
363     }
364
365     /* sum memory & swap statistics */
366     {
367         struct vmmeter vmm;
368         struct vmstats vms;
369         size_t vms_size = sizeof(vms);
370         size_t vmm_size = sizeof(vmm);
371         static unsigned int swap_delay = 0;
372         static int swapavail = 0;
373         static int swapfree = 0;
374         static int bufspace = 0;
375
376         if (sysctlbyname("vm.vmstats", &vms, &vms_size, NULL, 0))
377                 err(1, "sysctlbyname: vm.vmstats");
378
379         if (sysctlbyname("vm.vmmeter", &vmm, &vmm_size, NULL, 0))
380                 err(1, "sysctlbyname: vm.vmmeter");
381
382         if (kinfo_get_vfs_bufspace(&bufspace))
383                 err(1, "kinfo_get_vfs_bufspace");
384
385         /* convert memory stats to Kbytes */
386         memory_stats[0] = pagetok(vms.v_active_count);
387         memory_stats[1] = pagetok(vms.v_inactive_count);
388         memory_stats[2] = pagetok(vms.v_wire_count);
389         memory_stats[3] = pagetok(vms.v_cache_count);
390         memory_stats[4] = bufspace / 1024;
391         memory_stats[5] = pagetok(vms.v_free_count);
392         memory_stats[6] = -1;
393
394         /* first interval */
395         if (swappgsin < 0) {
396             swap_stats[4] = 0;
397             swap_stats[5] = 0;
398         } 
399
400         /* compute differences between old and new swap statistic */
401         else {
402             swap_stats[4] = pagetok(((vmm.v_swappgsin - swappgsin)));
403             swap_stats[5] = pagetok(((vmm.v_swappgsout - swappgsout)));
404         }
405
406         swappgsin = vmm.v_swappgsin;
407         swappgsout = vmm.v_swappgsout;
408
409         /* call CPU heavy swapmode() only for changes */
410         if (swap_stats[4] > 0 || swap_stats[5] > 0 || swap_delay == 0) {
411             swap_stats[3] = swapmode(&swapavail, &swapfree);
412             swap_stats[0] = swapavail;
413             swap_stats[1] = swapavail - swapfree;
414             swap_stats[2] = swapfree;
415         }
416         swap_delay = 1;
417         swap_stats[6] = -1;
418     }
419
420     /* set arrays and strings */
421     si->cpustates = cpu_states;
422     si->memory = memory_stats;
423     si->swap = swap_stats;
424
425
426     if(lastpid > 0) {
427         si->last_pid = lastpid;
428     } else {
429         si->last_pid = -1;
430     }
431
432     /*
433      * Print how long system has been up.
434      * (Found by looking getting "boottime" from the kernel)
435      */
436     mib[0] = CTL_KERN;
437     mib[1] = KERN_BOOTTIME;
438     bt_size = sizeof(boottime);
439     if (sysctl(mib, 2, &boottime, &bt_size, NULL, 0) != -1 &&
440         boottime.tv_sec != 0) {
441         si->boottime = boottime;
442     } else {
443         si->boottime.tv_sec = -1;
444     }
445 }
446
447 static struct handle handle;
448
449 caddr_t get_process_info(struct system_info *si, struct process_select *sel,
450                          int (*compare)(const void *, const void *))
451 {
452     int i;
453     int total_procs;
454     int active_procs;
455     struct kinfo_proc **prefp;
456     struct kinfo_proc *pp;
457
458     /* these are copied out of sel for speed */
459     int show_idle;
460     int show_self;
461     int show_system;
462     int show_only_threads;
463     int show_uid;
464     int show_command;
465
466     
467     pbase = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc);
468     if (nproc > onproc)
469         pref = (struct kinfo_proc **) realloc(pref, sizeof(struct kinfo_proc *)
470                 * (onproc = nproc));
471     if (pref == NULL || pbase == NULL) {
472         (void) fprintf(stderr, "top: Out of memory.\n");
473         quit(23);
474     }
475     /* get a pointer to the states summary array */
476     si->procstates = process_states;
477
478     /* set up flags which define what we are going to select */
479     show_idle = sel->idle;
480     show_self = sel->self;
481     show_system = sel->system;
482     show_threads = sel->threads || sel->only_threads;
483     show_only_threads = sel->only_threads;
484     show_uid = sel->uid != -1;
485     show_command = sel->command != NULL;
486
487     /* count up process states and get pointers to interesting procs */
488     total_procs = 0;
489     active_procs = 0;
490     memset((char *)process_states, 0, sizeof(process_states));
491     prefp = pref;
492     for (pp = pbase, i = 0; i < nproc; pp++, i++)
493     {
494         /*
495          *  Place pointers to each valid proc structure in pref[].
496          *  Process slots that are actually in use have a non-zero
497          *  status field.  Processes with P_SYSTEM set are system
498          *  processes---these get ignored unless show_sysprocs is set.
499          */
500         if ((show_threads && (LP(pp, pid) == -1)) ||
501             (!show_only_threads && (PP(pp, stat) != 0 &&
502             (show_self != PP(pp, pid)) &&
503             (show_system || ((PP(pp, flags) & P_SYSTEM) == 0)))))
504         {
505             total_procs++;
506             process_states[(unsigned char) PP(pp, stat)]++;
507             if ((show_threads && (LP(pp, pid) == -1)) ||
508                 (!show_only_threads && PP(pp, stat) != SZOMB &&
509                 (show_idle || (LP(pp, pctcpu) != 0) ||
510                  (LP(pp, stat) == LSRUN)) &&
511                 (!show_uid || PP(pp, ruid) == (uid_t)sel->uid)))
512             {
513                 *prefp++ = pp;
514                 active_procs++;
515             }
516         }
517     }
518
519     /* if requested, sort the "interesting" processes */
520     if (compare != NULL)
521     {
522         qsort((char *)pref, active_procs, sizeof(struct kinfo_proc *), compare);
523     }
524
525     /* remember active and total counts */
526     si->p_total = total_procs;
527     si->p_active = pref_len = active_procs;
528
529     /* pass back a handle */
530     handle.next_proc = pref;
531     handle.remaining = active_procs;
532     return((caddr_t)&handle);
533 }
534
535 char fmt[128];          /* static area where result is built */
536
537 char *
538 format_next_process(caddr_t xhandle, char *(*get_userid)(long))
539 {
540     struct kinfo_proc *pp;
541     long cputime;
542     double pct;
543     struct handle *hp;
544     char status[16];
545     char const *wrapper;
546     int state;
547     int xnice;
548
549     /* find and remember the next proc structure */
550     hp = (struct handle *)xhandle;
551     pp = *(hp->next_proc++);
552     hp->remaining--;
553     
554     /* set the wrapper for the process/thread name */
555     if ((PP(pp, flags) & P_SWAPPEDOUT))
556          wrapper = "[]"; /* swapped process [pname] */
557     else if (((PP(pp, flags) & P_SYSTEM) != 0) && (LP(pp, pid) > 0))
558          wrapper = "()"; /* system process (pname) */
559     else if (show_threads && (LP(pp, pid) == -1))
560          wrapper = "<>"; /* pure kernel threads <thread> */
561     else
562          wrapper = NULL;
563   
564     /* get the process's command name */
565     if (wrapper != NULL) {
566         char *comm = PP(pp, comm);
567 #define COMSIZ sizeof(PP(pp, comm))
568         char buf[COMSIZ];
569         (void) strncpy(buf, comm, COMSIZ);
570         comm[0] = wrapper[0];
571         (void) strncpy(&comm[1], buf, COMSIZ - 2);
572         comm[COMSIZ - 2] = '\0';
573         (void) strncat(comm, &wrapper[1], COMSIZ - 1);
574         comm[COMSIZ - 1] = '\0';
575     }
576
577     /*
578      * Convert the process's runtime from microseconds to seconds.  This
579      * time includes the interrupt time although that is not wanted here.
580      * ps(1) is similarly sloppy.
581      */
582     cputime = (LP(pp, uticks) + LP(pp, sticks)) / 1000000;
583
584     /* calculate the base for cpu percentages */
585     pct = pctdouble(LP(pp, pctcpu));
586
587     /* generate "STATE" field */
588     switch (state = LP(pp, stat)) {
589         case LSRUN:
590             if (smpmode && LP(pp, tdflags) & TDF_RUNNING)
591                 sprintf(status, "CPU%d", LP(pp, cpuid));
592             else
593                 strcpy(status, "RUN");
594             break;
595         case LSSLEEP:
596             if (LP(pp, wmesg) != NULL) {
597                 sprintf(status, "%.6s", LP(pp, wmesg));
598                 break;
599             }
600             /* fall through */
601         default:
602
603             if (state >= 0 &&
604                 (unsigned)state < sizeof(state_abbrev) / sizeof(*state_abbrev))
605                     sprintf(status, "%.6s", state_abbrev[(unsigned char) state]);
606             else
607                     sprintf(status, "?%5d", state);
608             break;
609     }
610
611     if (PP(pp, stat) == SZOMB)
612             strcpy(status, "ZOMB");
613
614     /*
615      * idle time 0 - 31 -> nice value +21 - +52
616      * normal time      -> nice value -20 - +20 
617      * real time 0 - 31 -> nice value -52 - -21
618      * thread    0 - 31 -> nice value -53 -
619      */
620     switch(LP(pp, rtprio.type)) {
621     case RTP_PRIO_REALTIME:
622         xnice = PRIO_MIN - 1 - RTP_PRIO_MAX + LP(pp, rtprio.prio);
623         break;
624     case RTP_PRIO_IDLE:
625         xnice = PRIO_MAX + 1 + LP(pp, rtprio.prio);
626         break;
627     case RTP_PRIO_THREAD:
628         xnice = PRIO_MIN - 1 - RTP_PRIO_MAX - LP(pp, rtprio.prio);
629         break;
630     default:
631         xnice = PP(pp, nice);
632         break;
633     }
634
635     /* format this entry */
636     snprintf(fmt, sizeof(fmt),
637             smpmode ? smp_Proc_format : up_Proc_format,
638             (int)PP(pp, pid),
639             namelength, namelength,
640             get_userid(PP(pp, ruid)),
641             (int)((show_threads && (LP(pp, pid) == -1)) ?
642                     LP(pp, tdprio) : LP(pp, prio)),
643             (int)xnice,
644             format_k2(PROCSIZE(pp)),
645             format_k2(pagetok(VP(pp, rssize))),
646             status,
647             (int)(smpmode ? LP(pp, cpuid) : 0),
648             format_time(cputime),
649             100.0 * weighted_cpu(pct, pp),
650             100.0 * pct,
651             cmdlength,
652             printable(PP(pp, comm)));
653
654     /* return the result */
655     return(fmt);
656 }
657
658 #if 0
659 /*
660  * check_nlist(nlst) - checks the nlist to see if any symbols were not
661  *              found.  For every symbol that was not found, a one-line
662  *              message is printed to stderr.  The routine returns the
663  *              number of symbols NOT found.
664  */
665 static int
666 check_nlist(struct nlist *nlst)
667 {
668     int i;
669
670     /* check to see if we got ALL the symbols we requested */
671     /* this will write one line to stderr for every symbol not found */
672
673     i = 0;
674     while (nlst->n_name != NULL)
675     {
676         if (nlst->n_type == 0)
677         {
678             /* this one wasn't found */
679             (void) fprintf(stderr, "kernel: no symbol named `%s'\n",
680                            nlst->n_name);
681             i = 1;
682         }
683         nlst++;
684     }
685
686     return(i);
687 }
688 #endif
689
690 /* comparison routines for qsort */
691
692 /*
693  *  proc_compare - comparison function for "qsort"
694  *      Compares the resource consumption of two processes using five
695  *      distinct keys.  The keys (in descending order of importance) are:
696  *      percent cpu, cpu ticks, state, resident set size, total virtual
697  *      memory usage.  The process states are ordered as follows (from least
698  *      to most important):  WAIT, zombie, sleep, stop, start, run.  The
699  *      array declaration below maps a process state index into a number
700  *      that reflects this ordering.
701  */
702
703 static unsigned char sorted_state[] =
704 {
705     0,  /* not used             */
706     3,  /* sleep                */
707     1,  /* ABANDONED (WAIT)     */
708     6,  /* run                  */
709     5,  /* start                */
710     2,  /* zombie               */
711     4   /* stop                 */
712 };
713  
714
715 #define ORDERKEY_PCTCPU \
716   if (lresult = (long) LP(p2, pctcpu) - (long) LP(p1, pctcpu), \
717      (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
718
719 #define CPTICKS(p)      (LP(p, uticks) + LP(p, sticks))
720
721 #define ORDERKEY_CPTICKS \
722   if ((result = CPTICKS(p2) > CPTICKS(p1) ? 1 : \
723                 CPTICKS(p2) < CPTICKS(p1) ? -1 : 0) == 0)
724
725 #define ORDERKEY_STATE \
726   if ((result = sorted_state[(unsigned char) PP(p2, stat)] - \
727                 sorted_state[(unsigned char) PP(p1, stat)]) == 0)
728
729 #define ORDERKEY_PRIO \
730   if ((result = LP(p2, prio) - LP(p1, prio)) == 0)
731
732 #define ORDERKEY_KTHREADS \
733   if ((result = (LP(p1, pid) == 0) - (LP(p2, pid) == 0)) == 0)
734
735 #define ORDERKEY_KTHREADS_PRIO \
736   if ((result = LP(p2, tdprio) - LP(p1, tdprio)) == 0)
737
738 #define ORDERKEY_RSSIZE \
739   if ((result = VP(p2, rssize) - VP(p1, rssize)) == 0) 
740
741 #define ORDERKEY_MEM \
742   if ( (result = PROCSIZE(p2) - PROCSIZE(p1)) == 0 )
743
744 /* compare_cpu - the comparison function for sorting by cpu percentage */
745
746 int
747 #ifdef ORDER
748 compare_cpu(const void *arg1, const void *arg2)
749 #else
750 proc_compare(const void *arg1, const void *arg2)
751 #endif
752 {
753     const struct proc *const*pp1 = arg1;
754     const struct proc *const*pp2 = arg2;
755     const struct kinfo_proc *p1;
756     const struct kinfo_proc *p2;
757     int result;
758     pctcpu lresult;
759
760     /* remove one level of indirection */
761     p1 = *(const struct kinfo_proc *const *) pp1;
762     p2 = *(const struct kinfo_proc *const *) pp2;
763
764     ORDERKEY_PCTCPU
765     ORDERKEY_CPTICKS
766     ORDERKEY_STATE
767     ORDERKEY_PRIO
768     ORDERKEY_RSSIZE
769     ORDERKEY_MEM
770     {}
771
772     return(result);
773 }
774
775 #ifdef ORDER
776 /* compare routines */
777 int compare_size(const void *, const void *);
778 int compare_res(const void *, const void *);
779 int compare_time(const void *, const void *);
780 int compare_prio(const void *, const void *);
781 int compare_thr(const void *, const void *);
782
783 int (*proc_compares[])(const void *, const void *) = {
784     compare_cpu,
785     compare_size,
786     compare_res,
787     compare_time,
788     compare_prio,
789     compare_thr,
790     NULL
791 };
792
793 /* compare_size - the comparison function for sorting by total memory usage */
794
795 int
796 compare_size(const void *arg1, const void *arg2)
797 {
798     struct proc *const *pp1 = arg1;
799     struct proc *const *pp2 = arg2;
800     struct kinfo_proc *p1;
801     struct kinfo_proc *p2;
802     int result;
803     pctcpu lresult;
804
805     /* remove one level of indirection */
806     p1 = *(struct kinfo_proc *const*) pp1;
807     p2 = *(struct kinfo_proc *const*) pp2;
808
809     ORDERKEY_MEM
810     ORDERKEY_RSSIZE
811     ORDERKEY_PCTCPU
812     ORDERKEY_CPTICKS
813     ORDERKEY_STATE
814     ORDERKEY_PRIO
815     {}
816
817     return(result);
818 }
819
820 /* compare_res - the comparison function for sorting by resident set size */
821
822 int
823 compare_res(const void *arg1, const void *arg2)
824 {
825     struct proc *const *pp1 = arg1;
826     struct proc *const *pp2 = arg2;
827     struct kinfo_proc *p1;
828     struct kinfo_proc *p2;
829     int result;
830     pctcpu lresult;
831
832     /* remove one level of indirection */
833     p1 = *(struct kinfo_proc *const*) pp1;
834     p2 = *(struct kinfo_proc *const*) pp2;
835
836     ORDERKEY_RSSIZE
837     ORDERKEY_MEM
838     ORDERKEY_PCTCPU
839     ORDERKEY_CPTICKS
840     ORDERKEY_STATE
841     ORDERKEY_PRIO
842     {}
843
844     return(result);
845 }
846
847 /* compare_time - the comparison function for sorting by total cpu time */
848
849 int
850 compare_time(const void *arg1, const void *arg2)
851 {
852     struct proc *const *pp1 = arg1;
853     struct proc *const *pp2 = arg2;
854     const struct kinfo_proc *p1;
855     const struct kinfo_proc *p2;
856     int result;
857     pctcpu lresult;
858   
859     /* remove one level of indirection */
860     p1 = *(struct kinfo_proc *const*) pp1;
861     p2 = *(struct kinfo_proc *const*) pp2;
862
863     ORDERKEY_CPTICKS
864     ORDERKEY_PCTCPU
865     ORDERKEY_KTHREADS
866     ORDERKEY_KTHREADS_PRIO
867     ORDERKEY_STATE
868     ORDERKEY_PRIO
869     ORDERKEY_RSSIZE
870     ORDERKEY_MEM
871     {}
872
873       return(result);
874   }
875   
876 /* compare_prio - the comparison function for sorting by cpu percentage */
877
878 int
879 compare_prio(const void *arg1, const void *arg2)
880 {
881     struct proc *const *pp1 = arg1;
882     struct proc *const *pp2 = arg2;
883     const struct kinfo_proc *p1;
884     const struct kinfo_proc *p2;
885     int result;
886     pctcpu lresult;
887
888     /* remove one level of indirection */
889     p1 = *(struct kinfo_proc *const*) pp1;
890     p2 = *(struct kinfo_proc *const*) pp2;
891
892     ORDERKEY_KTHREADS
893     ORDERKEY_KTHREADS_PRIO
894     ORDERKEY_PRIO
895     ORDERKEY_CPTICKS
896     ORDERKEY_PCTCPU
897     ORDERKEY_STATE
898     ORDERKEY_RSSIZE
899     ORDERKEY_MEM
900     {}
901
902     return(result);
903 }
904
905 int
906 compare_thr(const void *arg1, const void *arg2)
907 {
908     struct proc *const *pp1 = arg1;
909     struct proc *const *pp2 = arg2;
910     const struct kinfo_proc *p1;
911     const struct kinfo_proc *p2;
912     int result;
913     pctcpu lresult;
914
915     /* remove one level of indirection */
916     p1 = *(struct kinfo_proc *const*) pp1;
917     p2 = *(struct kinfo_proc *const*) pp2;
918
919     ORDERKEY_KTHREADS
920     ORDERKEY_KTHREADS_PRIO
921     ORDERKEY_CPTICKS
922     ORDERKEY_PCTCPU
923     ORDERKEY_STATE
924     ORDERKEY_RSSIZE
925     ORDERKEY_MEM
926     {}
927
928     return(result);
929 }
930
931
932 #endif
933
934 /*
935  * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
936  *              the process does not exist.
937  *              It is EXTREMLY IMPORTANT that this function work correctly.
938  *              If top runs setuid root (as in SVR4), then this function
939  *              is the only thing that stands in the way of a serious
940  *              security problem.  It validates requests for the "kill"
941  *              and "renice" commands.
942  */
943
944 int
945 proc_owner(int pid)
946 {
947     int xcnt;
948     struct kinfo_proc **prefp;
949     struct kinfo_proc *pp;
950
951     prefp = pref;
952     xcnt = pref_len;
953     while (--xcnt >= 0)
954     {
955         pp = *prefp++;  
956         if (PP(pp, pid) == (pid_t)pid)
957         {
958             return((int)PP(pp, ruid));
959         }
960     }
961     return(-1);
962 }
963
964
965 /*
966  * swapmode is based on a program called swapinfo written
967  * by Kevin Lahey <kml@rokkaku.atl.ga.us>.
968  */
969 int
970 swapmode(int *retavail, int *retfree)
971 {
972         int n;
973         int pagesize = getpagesize();
974         struct kvm_swap swapary[1];
975
976         *retavail = 0;
977         *retfree = 0;
978
979 #define CONVERT(v)      ((quad_t)(v) * pagesize / 1024)
980
981         n = kvm_getswapinfo(kd, swapary, 1, 0);
982         if (n < 0 || swapary[0].ksw_total == 0)
983                 return(0);
984
985         *retavail = CONVERT(swapary[0].ksw_total);
986         *retfree = CONVERT(swapary[0].ksw_total - swapary[0].ksw_used);
987
988         n = (int)((double)swapary[0].ksw_used * 100.0 /
989             (double)swapary[0].ksw_total);
990         return(n);
991 }