Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / top / dist / machine / m_sunos4.c
blob1202a764c9895c3e4df1b837363db2fb868bc136
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.
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.
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.
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.
34 * top - a top users display for Unix
36 * SYNOPSIS: any Sun running SunOS version 4.x
38 * DESCRIPTION:
39 * This is the machine-dependent module for SunOS 4.x.
40 * This makes top work on the following systems:
41 * SunOS 4.0
42 * SunOS 4.0.1
43 * SunOS 4.0.2 (including 386i architecture)
44 * SunOS 4.0.3
45 * SunOS 4.1
46 * SunOS 4.1.1
47 * SunOS 4.1.2 (including MP architectures)
48 * SunOS 4.1.3 (including MP architectures)
49 * SunOS 4.1.3_U1 (including MP architectures)
50 * SunOS 4.1.4 (including MP architectures)
51 * Solbourne OS/MP PRIOR to 4.1A
53 * LIBS: -lkvm
55 * CFLAGS: -DHAVE_GETOPT -DORDER
57 * AUTHOR: William LeFebvre <wnl@groupsys.com>
58 * Solbourne support by David MacKenzie <djm@eng.umd.edu>
62 * #ifdef MULTIPROCESSOR means Sun MP.
63 * #ifdef solbourne is for Solbourne.
66 #include "config.h"
67 #include <sys/types.h>
68 #include <sys/signal.h>
70 /* make sure param.h gets loaded with KERNEL defined to get PZERO & NZERO */
71 #define KERNEL
72 #include <sys/param.h>
73 #undef KERNEL
75 #include <stdio.h>
76 #include <kvm.h>
77 #include <nlist.h>
78 #include <math.h>
79 #include <sys/dir.h>
80 #include <sys/user.h>
81 #include <sys/proc.h>
82 #include <sys/dk.h>
83 #include <sys/vm.h>
84 #include <sys/file.h>
85 #include <sys/time.h>
86 #include <vm/page.h>
88 #ifdef solbourne
89 #include <sys/syscall.h>
90 #endif
92 /* Older versions of SunOS don't have a typedef for pid_t.
93 Hopefully this will catch all those cases without causing other problems.
95 #ifndef __sys_stdtypes_h
96 typedef int pid_t;
97 #endif
99 #include "top.h"
100 #include "machine.h"
101 #include "utils.h"
103 /* declarations for load_avg */
104 #include "loadavg.h"
106 /* get_process_info passes back a handle. This is what it looks like: */
108 struct handle
110 struct proc **next_proc; /* points to next valid proc pointer */
111 int remaining; /* number of pointers remaining */
114 /* define what weighted cpu is. */
115 #define weighted_cpu(pct, pp) ((pp)->p_time == 0 ? 0.0 : \
116 ((pct) / (1.0 - exp((pp)->p_time * logcpu))))
118 /* what we consider to be process size: */
119 #define PROCSIZE(pp) ((pp)->p_tsize + (pp)->p_dsize + (pp)->p_ssize)
121 /* definitions for indices in the nlist array */
122 #define X_AVENRUN 0
123 #define X_CCPU 1
124 #define X_MPID 2
125 #define X_NPROC 3
126 #define X_PROC 4
127 #define X_TOTAL 5
128 #define X_CP_TIME 6
129 #define X_PAGES 7
130 #define X_EPAGES 8
132 static struct nlist nlst[] = {
133 #ifdef i386
134 { "avenrun" }, /* 0 */
135 { "ccpu" }, /* 1 */
136 { "mpid" }, /* 2 */
137 { "nproc" }, /* 3 */
138 { "proc" }, /* 4 */
139 { "total" }, /* 5 */
140 { "cp_time" }, /* 6 */
141 { "pages" }, /* 7 */
142 { "epages" }, /* 8 */
143 #else
144 { "_avenrun" }, /* 0 */
145 { "_ccpu" }, /* 1 */
146 { "_mpid" }, /* 2 */
147 { "_nproc" }, /* 3 */
148 { "_proc" }, /* 4 */
149 { "_total" }, /* 5 */
150 { "_cp_time" }, /* 6 */
151 { "_pages" }, /* 7 */
152 { "_epages" }, /* 8 */
153 #ifdef MULTIPROCESSOR
154 { "_ncpu" },
155 #define X_NCPU 9
156 { "_xp_time" },
157 #define X_XP_TIME 10
158 #endif
159 #endif
160 { 0 }
164 * These definitions control the format of the per-process area
167 static char header[] =
168 " PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND";
169 /* 0123456 -- field to fill in starts at header+6 */
170 #define UNAME_START 6
172 #define Proc_format \
173 "%5d %-8.8s %3d %4d %5s %5s %-5s %-6s %5.2f%% %5.2f%% %s"
176 /* process state names for the "STATE" column of the display */
177 /* the extra nulls in the string "run" are for adding a slash and
178 the processor number when needed */
180 char *state_abbrev[] =
182 "", "sleep", "WAIT", "run\0\0\0", "start", "zomb", "stop"
185 /* values that we stash away in _init and use in later routines */
187 static double logcpu;
188 kvm_t *kd;
190 /* these are retrieved from the kernel in _init */
192 static unsigned long proc;
193 static int nproc;
194 static load_avg ccpu;
195 static unsigned long pages;
196 static unsigned long epages;
197 static int ncpu = 0;
199 /* these are offsets obtained via nlist and used in the get_ functions */
201 static unsigned long mpid_offset;
202 static unsigned long avenrun_offset;
203 static unsigned long total_offset;
204 static unsigned long cp_time_offset;
205 #ifdef MULTIPROCESSOR
206 static unsigned long xp_time_offset;
207 #endif
209 /* these are for calculating cpu state percentages */
211 static long cp_time[CPUSTATES];
212 static long cp_old[CPUSTATES];
213 static long cp_diff[CPUSTATES];
214 #ifdef MULTIPROCESSOR
215 static long xp_time[NCPU][XPSTATES];
216 /* for now we only accumulate spin time, but extending this to pick up
217 other stuff in xp_time is trivial. */
218 static long xp_old[NCPU];
219 #endif
221 /* these are for detailing the process states */
223 int process_states[7];
224 char *procstatenames[] = {
225 "", " sleeping, ", " ABANDONED, ", " running, ", " starting, ",
226 " zombie, ", " stopped, ",
227 NULL
230 /* these are for detailing the cpu states */
232 int cpu_states[5];
233 char *cpustatenames[] = {
234 "user", "nice", "system", "idle",
235 #ifdef MULTIPROCESSOR
236 "spin",
237 #define XCP_SPIN 4
238 #endif
239 NULL
242 /* these are for detailing the memory statistics */
244 long memory_stats[4];
245 char *memorynames[] = {
246 "K available, ", "K in use, ", "K free, ", "K locked", NULL
249 /* these are names given to allowed sorting orders -- first is default */
250 char *ordernames[] =
251 {"cpu", "size", "res", NULL};
253 /* forward definitions for comparison functions */
254 int compare_cpu();
255 int compare_size();
256 int compare_res();
258 int (*proc_compares[])() = {
259 compare_cpu,
260 compare_size,
261 compare_res,
262 NULL };
265 /* these are for keeping track of the proc array */
267 static int bytes;
268 static int pref_len;
269 static struct proc *pbase;
270 static struct proc **pref;
272 /* these are for getting the memory statistics */
274 static struct page *physpage;
275 static int bytesize;
276 static int count;
277 static int pageshift; /* log base 2 of the pagesize */
279 /* define pagetok in terms of pageshift */
281 #define pagetok(size) ((size) << pageshift)
283 /* useful externals */
284 extern int errno;
285 extern char *sys_errlist[];
287 long lseek();
288 long time();
290 machine_init(statics)
292 struct statics *statics;
295 register int i;
296 register int pagesize;
298 /* initialize the kernel interface */
299 if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "top")) == NULL)
301 perror("kvm_open");
302 return(-1);
305 /* get the list of symbols we want to access in the kernel */
306 if ((i = kvm_nlist(kd, nlst)) < 0)
308 fprintf(stderr, "top: nlist failed\n");
309 return(-1);
312 #ifdef MULTIPROCESSOR
313 /* were ncpu and xp_time not found in the nlist? */
314 if (i > 0 && nlst[X_NCPU].n_type == 0 && nlst[X_XP_TIME].n_type == 0)
316 /* we were compiled on an MP system but we are not running on one */
317 /* so we will pretend this didn't happen and set ncpu = 1 */
318 i -= 2;
319 ncpu = 1;
321 #endif
323 #ifdef solbourne
325 unsigned int status, type;
327 /* Get the number of CPUs on this system. */
328 syscall(SYS_getcpustatus, &status, &ncpu, &type);
330 #endif
332 /* make sure they were all found */
333 if (i > 0 && check_nlist(nlst) > 0)
335 return(-1);
338 /* get the symbol values out of kmem */
339 (void) getkval(nlst[X_PROC].n_value, (int *)(&proc), sizeof(proc),
340 nlst[X_PROC].n_name);
341 (void) getkval(nlst[X_NPROC].n_value, &nproc, sizeof(nproc),
342 nlst[X_NPROC].n_name);
343 (void) getkval(nlst[X_CCPU].n_value, (int *)(&ccpu), sizeof(ccpu),
344 nlst[X_CCPU].n_name);
345 (void) getkval(nlst[X_PAGES].n_value, (int *)(&pages), sizeof(pages),
346 nlst[X_PAGES].n_name);
347 (void) getkval(nlst[X_EPAGES].n_value, (int *)(&epages), sizeof(epages),
348 nlst[X_EPAGES].n_name);
349 #ifdef MULTIPROCESSOR
350 if (ncpu == 0)
352 /* if ncpu > 0 then we are not really on an MP system */
353 (void) getkval(nlst[X_NCPU].n_value, (int *)(&ncpu), sizeof(ncpu),
354 nlst[X_NCPU].n_name);
356 #endif
358 /* stash away certain offsets for later use */
359 mpid_offset = nlst[X_MPID].n_value;
360 avenrun_offset = nlst[X_AVENRUN].n_value;
361 total_offset = nlst[X_TOTAL].n_value;
362 cp_time_offset = nlst[X_CP_TIME].n_value;
363 #ifdef MULTIPROCESSOR
364 xp_time_offset = nlst[X_XP_TIME].n_value;
365 #endif
367 /* this is used in calculating WCPU -- calculate it ahead of time */
368 logcpu = log(loaddouble(ccpu));
370 /* allocate space for proc structure array and array of pointers */
371 bytes = nproc * sizeof(struct proc);
372 pbase = (struct proc *)malloc(bytes);
373 pref = (struct proc **)malloc(nproc * sizeof(struct proc *));
375 /* Just in case ... */
376 if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL)
378 fprintf(stderr, "top: can't allocate sufficient memory\n");
379 return(-1);
382 /* allocate a table to hold all the page structs */
383 bytesize = epages - pages;
384 count = bytesize / sizeof(struct page);
385 physpage = (struct page *)malloc(epages - pages);
386 if (physpage == NULL)
388 fprintf(stderr, "top: can't allocate sufficient memory\n");
389 return(-1);
392 /* get the page size with "getpagesize" and calculate pageshift from it */
393 pagesize = getpagesize();
394 pageshift = 0;
395 while (pagesize > 1)
397 pageshift++;
398 pagesize >>= 1;
401 /* we only need the amount of log(2)1024 for our conversion */
402 pageshift -= LOG1024;
404 #if defined(MULTIPROCESSOR) || defined(solbourne)
405 /* add a slash to the "run" state abbreviation */
406 if (ncpu > 1)
408 state_abbrev[SRUN][3] = '/';
410 #endif
412 /* fill in the statics information */
413 statics->procstate_names = procstatenames;
414 statics->cpustate_names = cpustatenames;
415 statics->memory_names = memorynames;
416 statics->order_names = ordernames;
418 /* all done! */
419 return(0);
422 char *format_header(uname_field)
424 register char *uname_field;
427 register char *ptr;
429 ptr = header + UNAME_START;
430 while (*uname_field != '\0')
432 *ptr++ = *uname_field++;
435 return(header);
438 void
439 get_system_info(si)
441 struct system_info *si;
444 load_avg avenrun[3];
445 long total;
446 #ifdef MULTIPROCESSOR
447 long half_total;
448 #endif
450 /* get the cp_time array */
451 (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),
452 "_cp_time");
454 #ifdef MULTIPROCESSOR
455 /* get the xp_time array as well */
456 if (ncpu > 1)
458 (void) getkval(xp_time_offset, (int *)xp_time, sizeof(xp_time),
459 "_xp_time");
461 #endif
463 /* get load average array */
464 (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
465 "_avenrun");
467 /* get mpid -- process id of last process */
468 (void) getkval(mpid_offset, &(si->last_pid), sizeof(si->last_pid),
469 "_mpid");
471 /* get the array of physpage descriptors */
472 (void) getkval(pages, (int *)physpage, bytesize, "array _page");
474 /* convert load averages to doubles */
476 register int i;
477 register double *infoloadp;
478 register load_avg *sysloadp;
480 infoloadp = si->load_avg;
481 sysloadp = avenrun;
482 for (i = 0; i < 3; i++)
484 *infoloadp++ = loaddouble(*sysloadp++);
488 /* convert cp_time counts to percentages */
489 total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
491 #ifdef MULTIPROCESSOR
492 /* calculate spin time from all processors */
493 if (ncpu > 1)
495 register int c;
496 register int i;
497 register long sum;
498 register long change;
500 /* collect differences for each processor and add them */
501 sum = 0;
502 for (i = 0; i < ncpu; i++)
504 c = xp_time[i][XP_SPIN];
505 change = c - xp_old[i];
506 if (change < 0)
508 /* counter wrapped */
509 change = (long)((unsigned long)c -
510 (unsigned long)xp_old[i]);
512 sum += change;
513 xp_old[i] = c;
517 * NOTE: I am assuming that the ticks found in xp_time are
518 * already included in the ticks accumulated in cp_time. To
519 * get an accurate reflection, therefore, we have to subtract
520 * the spin time from the system time and recompute those two
521 * percentages.
523 half_total = total / 2l;
524 cp_diff[CP_SYS] -= sum;
525 cpu_states[CP_SYS] = (int)((cp_diff[CP_SYS] * 1000 + half_total) /
526 total);
527 cpu_states[XCP_SPIN] = (int)((sum * 1000 + half_total) / total);
529 #endif
531 /* sum memory statistics */
533 register struct page *pp;
534 register int cnt;
535 register int inuse;
536 register int free;
537 register int locked;
539 /* bop thru the array counting page types */
540 pp = physpage;
541 inuse = free = locked = 0;
542 for (cnt = count; --cnt >= 0; pp++)
544 if (pp->p_free)
545 free++;
546 else if (pp->p_lock || pp->p_keepcnt > 0)
547 locked++;
548 else
549 inuse++;
552 /* convert memory stats to Kbytes */
553 memory_stats[0] = pagetok(inuse + free);
554 memory_stats[1] = pagetok(inuse);
555 memory_stats[2] = pagetok(free);
556 memory_stats[3] = pagetok(locked);
559 /* set arrays and strings */
560 si->cpustates = cpu_states;
561 si->memory = memory_stats;
564 static struct handle handle;
566 caddr_t get_process_info(si, sel, compare_index)
568 struct system_info *si;
569 struct process_select *sel;
570 int compare_index;
573 register int i;
574 register int total_procs;
575 register int active_procs;
576 register struct proc **prefp;
577 register struct proc *pp;
579 /* these are copied out of sel for speed */
580 int show_idle;
581 int show_system;
582 int show_uid;
583 int show_command;
585 /* read all the proc structures in one fell swoop */
586 (void) getkval(proc, (int *)pbase, bytes, "proc array");
588 /* get a pointer to the states summary array */
589 si->procstates = process_states;
591 /* set up flags which define what we are going to select */
592 show_idle = sel->idle;
593 show_system = sel->system;
594 show_uid = sel->uid != -1;
595 show_command = sel->command != NULL;
597 /* count up process states and get pointers to interesting procs */
598 total_procs = 0;
599 active_procs = 0;
600 bzero((char *)process_states, sizeof(process_states));
601 prefp = pref;
602 for (pp = pbase, i = 0; i < nproc; pp++, i++)
605 * Place pointers to each valid proc structure in pref[].
606 * Process slots that are actually in use have a non-zero
607 * status field. Processes with SSYS set are system
608 * processes---these get ignored unless show_sysprocs is set.
610 if (pp->p_stat != 0 &&
611 (show_system || ((pp->p_flag & SSYS) == 0)))
613 total_procs++;
614 process_states[pp->p_stat]++;
615 if ((pp->p_stat != SZOMB) &&
616 (show_idle || (pp->p_pctcpu != 0) || (pp->p_stat == SRUN)) &&
617 (!show_uid || pp->p_uid == (uid_t)sel->uid))
619 *prefp++ = pp;
620 active_procs++;
625 /* if requested, sort the "interesting" processes */
626 qsort((char *)pref, active_procs, sizeof(struct proc *),
627 proc_compares[compare_index]);
629 /* remember active and total counts */
630 si->p_total = total_procs;
631 si->p_active = pref_len = active_procs;
633 /* pass back a handle */
634 handle.next_proc = pref;
635 handle.remaining = active_procs;
636 return((caddr_t)&handle);
639 char fmt[MAX_COLS]; /* static area where result is built */
641 char *format_next_process(handle, get_userid)
643 caddr_t handle;
644 char *(*get_userid)();
647 register struct proc *pp;
648 register long cputime;
649 register double pct;
650 struct user u;
651 struct handle *hp;
653 /* find and remember the next proc structure */
654 hp = (struct handle *)handle;
655 pp = *(hp->next_proc++);
656 hp->remaining--;
658 /* get the process's user struct and set cputime */
659 if (getu(pp, &u) == -1)
661 (void) strcpy(u.u_comm, "<swapped>");
662 cputime = 0;
664 else
666 /* set u_comm for system processes */
667 if (u.u_comm[0] == '\0')
669 if (pp->p_pid == 0)
671 (void) strcpy(u.u_comm, "Swapper");
673 else if (pp->p_pid == 2)
675 (void) strcpy(u.u_comm, "Pager");
679 cputime = u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec;
682 /* calculate the base for cpu percentages */
683 pct = pctdouble(pp->p_pctcpu);
685 #ifdef MULTIPROCESSOR
687 * If there is more than one cpu then add the processor number to
688 * the "run/" string. Note that this will only show up if the
689 * process is in the run state. Also note: when they
690 * start making Suns with more than 9 processors this will break
691 * since the string will then be more than 5 characters.
693 if (ncpu > 1)
695 state_abbrev[SRUN][4] = (pp->p_cpuid & 0xf) + '0';
697 #endif
698 #ifdef solbourne
699 if (ncpu > 1)
701 state_abbrev[SRUN][4] = (pp->p_lastcpu) + '0';
703 #endif
705 /* format this entry */
706 sprintf(fmt,
707 Proc_format,
708 pp->p_pid,
709 (*get_userid)(pp->p_uid),
710 pp->p_pri - PZERO,
711 pp->p_nice - NZERO,
712 format_k(pagetok(PROCSIZE(pp))),
713 format_k(pagetok(pp->p_rssize)),
714 state_abbrev[pp->p_stat],
715 format_time(cputime),
716 100.0 * weighted_cpu(pct, pp),
717 100.0 * pct,
718 printable(u.u_comm));
720 /* return the result */
721 return(fmt);
725 * getu(p, u) - get the user structure for the process whose proc structure
726 * is pointed to by p. The user structure is put in the buffer pointed
727 * to by u. Return 0 if successful, -1 on failure (such as the process
728 * being swapped out).
731 getu(p, u)
733 register struct proc *p;
734 struct user *u;
737 register struct user *lu;
739 lu = kvm_getu(kd, p);
740 if (lu == NULL)
742 return(-1);
744 else
746 *u = *lu;
747 return(0);
752 * check_nlist(nlst) - checks the nlist to see if any symbols were not
753 * found. For every symbol that was not found, a one-line
754 * message is printed to stderr. The routine returns the
755 * number of symbols NOT found.
758 int check_nlist(nlst)
760 register struct nlist *nlst;
763 register int i;
765 /* check to see if we got ALL the symbols we requested */
766 /* this will write one line to stderr for every symbol not found */
768 i = 0;
769 while (nlst->n_name != NULL)
771 #ifdef i386
772 if (nlst->n_value == 0)
773 #else
774 if (nlst->n_type == 0)
775 #endif
777 /* this one wasn't found */
778 fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
779 i = 1;
781 nlst++;
784 return(i);
789 * getkval(offset, ptr, size, refstr) - get a value out of the kernel.
790 * "offset" is the byte offset into the kernel for the desired value,
791 * "ptr" points to a buffer into which the value is retrieved,
792 * "size" is the size of the buffer (and the object to retrieve),
793 * "refstr" is a reference string used when printing error meessages,
794 * if "refstr" starts with a '!', then a failure on read will not
795 * be fatal (this may seem like a silly way to do things, but I
796 * really didn't want the overhead of another argument).
800 getkval(offset, ptr, size, refstr)
802 unsigned long offset;
803 int *ptr;
804 int size;
805 char *refstr;
808 if (kvm_read(kd, offset, ptr, size) != size)
810 if (*refstr == '!')
812 return(0);
814 else
816 fprintf(stderr, "top: kvm_read for %s: %s\n",
817 refstr, sys_errlist[errno]);
818 quit(23);
819 /*NOTREACHED*/
822 return(1);
825 /* comparison routines for qsort */
828 * There are currently four possible comparison routines. main selects
829 * one of these by indexing in to the array proc_compares.
831 * Possible keys are defined as macros below. Currently these keys are
832 * defined: percent cpu, cpu ticks, process state, resident set size,
833 * total virtual memory usage. The process states are ordered as follows
834 * (from least to most important): WAIT, zombie, sleep, stop, start, run.
835 * The array declaration below maps a process state index into a number
836 * that reflects this ordering.
839 /* First, the possible comparison keys. These are defined in such a way
840 that they can be merely listed in the source code to define the actual
841 desired ordering.
844 #define ORDERKEY_PCTCPU if (lresult = p2->p_pctcpu - p1->p_pctcpu,\
845 (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
846 #define ORDERKEY_CPTICKS if ((result = p2->p_cpticks - p1->p_cpticks) == 0)
847 #define ORDERKEY_STATE if ((result = sorted_state[p2->p_stat] - \
848 sorted_state[p1->p_stat]) == 0)
849 #define ORDERKEY_PRIO if ((result = p2->p_pri - p1->p_pri) == 0)
850 #define ORDERKEY_RSSIZE if ((result = p2->p_rssize - p1->p_rssize) == 0)
851 #define ORDERKEY_MEM if ((result = PROCSIZE(p2) - PROCSIZE(p1)) == 0)
853 /* Now the array that maps process state to a weight */
855 static unsigned char sorted_state[] =
857 0, /* not used */
858 3, /* sleep */
859 1, /* ABANDONED (WAIT) */
860 6, /* run */
861 5, /* start */
862 2, /* zombie */
863 4 /* stop */
866 /* compare_cpu - the comparison function for sorting by cpu percentage */
868 compare_cpu(pp1, pp2)
870 struct proc **pp1;
871 struct proc **pp2;
874 register struct proc *p1;
875 register struct proc *p2;
876 register int result;
877 register pctcpu lresult;
879 /* remove one level of indirection */
880 p1 = *pp1;
881 p2 = *pp2;
883 ORDERKEY_PCTCPU
884 ORDERKEY_CPTICKS
885 ORDERKEY_STATE
886 ORDERKEY_PRIO
887 ORDERKEY_RSSIZE
888 ORDERKEY_MEM
891 return(result);
894 /* compare_size - the comparison function for sorting by total memory usage */
896 compare_size(pp1, pp2)
898 struct proc **pp1;
899 struct proc **pp2;
902 register struct proc *p1;
903 register struct proc *p2;
904 register int result;
905 register pctcpu lresult;
907 /* remove one level of indirection */
908 p1 = *pp1;
909 p2 = *pp2;
911 ORDERKEY_MEM
912 ORDERKEY_RSSIZE
913 ORDERKEY_PCTCPU
914 ORDERKEY_CPTICKS
915 ORDERKEY_STATE
916 ORDERKEY_PRIO
919 return(result);
922 /* compare_res - the comparison function for sorting by resident set size */
924 compare_res(pp1, pp2)
926 struct proc **pp1;
927 struct proc **pp2;
930 register struct proc *p1;
931 register struct proc *p2;
932 register int result;
933 register pctcpu lresult;
935 /* remove one level of indirection */
936 p1 = *pp1;
937 p2 = *pp2;
939 ORDERKEY_RSSIZE
940 ORDERKEY_MEM
941 ORDERKEY_PCTCPU
942 ORDERKEY_CPTICKS
943 ORDERKEY_STATE
944 ORDERKEY_PRIO
947 return(result);
951 * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
952 * the process does not exist.
953 * It is EXTREMLY IMPORTANT that this function work correctly.
954 * If top runs setuid root (as in SVR4), then this function
955 * is the only thing that stands in the way of a serious
956 * security problem. It validates requests for the "kill"
957 * and "renice" commands.
960 int proc_owner(pid)
962 int pid;
965 register int cnt;
966 register struct proc **prefp;
967 register struct proc *pp;
969 prefp = pref;
970 cnt = pref_len;
971 while (--cnt >= 0)
973 if ((pp = *prefp++)->p_pid == (pid_t)pid)
975 return((int)pp->p_uid);
978 return(-1);