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