source: trunk/third/top/machine/m_sunos4.c @ 16185

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