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

Revision 16185, 25.0 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:  OSF/1, Digital Unix 4.0, Compaq Tru64 5.0
5 *
6 * DESCRIPTION:
7 * This is the machine-dependent module for DEC OSF/1 and its descendents
8 * It is known to work on OSF/1 1.2, 1.3, 2.0-T3, 3.0, Digital Unix V4.0,
9 * Digital Unix 5.0, and Tru64 5.0.
10 * WARNING: if you use optimization with the standard "cc" compiler that
11 * .        comes with V3.0 the resulting executable may core dump.  If
12 * .        this happens, recompile without optimization.
13 *
14 * LIBS: -lmld -lmach
15 *
16 * CFLAGS: -DHAVE_GETOPT -DORDER
17 *
18 * AUTHOR:  Anthony Baxter, <anthony@aaii.oz.au>
19 * Derived originally from m_ultrix, by David S. Comay <dsc@seismo.css.gov>,
20 * although by now there is hardly any of the code from m_ultrix left.
21 * Helped a lot by having the source for syd(1), by Claus Kalle, and
22 * from several people at DEC who helped with providing information on
23 * some of the less-documented bits of the kernel interface.
24 *
25 * Modified: 31-Oct-94, Pat Welch, tpw@physics.orst.edu
26 *      changed _mpid to pidtab for compatibility with OSF/1 version 3.0
27 *
28 * Modified: 13-Dec-94, William LeFebvre, lefebvre@dis.anl.gov
29 *      removed used of pidtab (that was bogus) and changed things to
30 *      automatically detect the absence of _mpid in the nlist and
31 *      recover gracefully---this appears to be the only difference
32 *      with 3.0.
33 *
34 * Modified: 3-Mar-00, Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>
35 *      added support for sort ordering.
36 */
37/*
38 * Theory of operation:
39 *
40 * Use Mach calls to build up a structure that contains all the sorts
41 * of stuff normally found in a struct proc in a BSD system. Then
42 * everything else uses this structure. This has major performance wins,
43 * and also should work for future versions of the O/S.
44 */
45
46#include <sys/types.h>
47#include <sys/signal.h>
48#include <sys/param.h>
49
50#include <string.h>
51#include <sys/user.h>
52#include <stdio.h>
53#include <nlist.h>
54#include <math.h>
55#include <sys/dir.h>
56#include <sys/user.h>
57#include <sys/proc.h>
58#include <sys/dk.h>
59#include <sys/vm.h>
60#include <sys/file.h>
61#include <sys/time.h>
62/* #include <machine/pte.h> */
63/* forward declarations, needed by <net/if.h> included from <sys/table.h> */
64struct rtentry;
65struct mbuf;
66#include <sys/table.h>
67#include <mach.h>
68#include <mach/mach_types.h>
69#include <mach/vm_statistics.h>
70#include <sys/syscall.h> /* for SYS_setpriority, in setpriority(), below */
71
72
73#include "top.h"
74#include "machine.h"
75#include "utils.h"
76
77extern int errno, sys_nerr;
78extern char *sys_errlist[];
79#define strerror(e) (((e) >= 0 && (e) < sys_nerr) ? sys_errlist[(e)] : "Unknown error")
80
81#define VMUNIX  "/vmunix"
82#define KMEM    "/dev/kmem"
83#define MEM     "/dev/mem"
84
85/* get_process_info passes back a handle.  This is what it looks like: */
86
87struct handle
88{
89    struct osf1_top_proc **next_proc;   /* points to next valid proc pointer */
90    int remaining;              /* number of pointers remaining */
91};
92
93/* declarations for load_avg */
94#include "loadavg.h"
95
96/* definitions for indices in the nlist array */
97#define X_MPID          0
98
99static struct nlist nlst[] = {
100    { "_mpid" },                /* 0 */
101    { 0 }
102};
103
104/* Some versions of OSF/1 don't support reporting of the last PID.
105   This flag indicates whether or not we are reporting the last PID. */
106static int do_last_pid = 1;
107
108/*
109 *  These definitions control the format of the per-process area
110 */
111
112static char header[] =
113  "  PID X        PRI NICE  SIZE   RES STATE   TIME    CPU COMMAND";
114/* 0123456   -- field to fill in starts at header+6 */
115#define UNAME_START 6
116
117#define Proc_format \
118        "%5d %-8.8s %3d %4d %5s %5s %-5s %-6s %5.2f%% %.14s"
119
120
121/* process state names for the "STATE" column of the display */
122/* the extra nulls in the string "run" are for adding a slash and
123 * the processor number when needed. Although OSF/1 doesnt support
124 * multiple processors yet, (and this module _certainly_ doesnt
125 * support it, either, we may as well plan for the future. :-)
126 */
127
128char *state_abbrev[] =
129{
130    "", "run\0\0\0", "WAIT", "sleep", "sleep", "stop", "halt", "???", "zomb"
131};
132
133
134static int kmem, mem;
135
136/* values that we stash away in _init and use in later routines */
137
138static double logcpu;
139
140/* these are retrieved from the kernel in _init */
141
142static unsigned long proc;
143static          int  nproc;
144static load_avg  ccpu;
145
146typedef long mtime_t;
147
148/* these are offsets obtained via nlist and used in the get_ functions */
149
150static unsigned long mpid_offset;
151
152/* these are for detailing the process states */
153
154int process_states[9];
155char *procstatenames[] = {
156    "", " running, ", " waiting, ", " sleeping, ", " idle, ",
157    " stopped, ", " halted, ", "", " zombie",
158    NULL
159};
160
161/* these are for detailing the cpu states */
162
163int cpu_states[4];
164char *cpustatenames[] = {
165    "user", "nice", "system", "idle", NULL
166};
167
168long old_cpu_ticks[4];
169
170/* these are for detailing the memory statistics */
171
172int memory_stats[8];
173char *memorynames[] = {
174    "Real: ", "K/", "K act/tot  ", "Virtual: ", "M/",
175    "M use/tot  ", "Free: ", "K", NULL
176};
177
178/* these are names given to allowed sorting orders -- first is default */
179char *ordernames[] = {
180    "cpu", "size", "res", "time", NULL
181};
182
183/* forward definitions for comparison functions */
184int compare_cpu();
185int compare_size();
186int compare_res();
187int compare_time();
188
189int (*proc_compares[])() = {
190    compare_cpu,
191    compare_size,
192    compare_res,
193    compare_time,
194    NULL
195};
196
197/* these are for getting the memory statistics */
198
199static int pageshift;           /* log base 2 of the pagesize */
200
201/* define pagetok in terms of pageshift */
202
203#define pagetok(size) ((size) << pageshift)
204
205/* take a process, make it a mach task, and grab all the info out */
206void do_threads_calculations();
207
208/*
209 * Because I dont feel like repeatedly grunging through the kernel with
210 * Mach calls, and I also dont want the horrid performance hit this
211 * would give, I read the stuff I need out, and put in into my own
212 * structure, for later use.
213 */
214
215struct osf1_top_proc {
216    size_t p_mach_virt_size;
217    char p_mach_state;
218    int p_flag;
219    fixpt_t p_mach_pct_cpu; /* aka p_pctcpu */
220    int used_ticks;
221    size_t process_size;
222    pid_t p_pid;
223    uid_t p_ruid;
224    char p_pri;
225    char p_nice;
226    size_t p_rssize;
227    char u_comm[PI_COMLEN + 1];
228} ;
229
230/* these are for keeping track of the proc array */
231
232static int bytes;
233static int pref_len;
234static struct osf1_top_proc *pbase;
235static struct osf1_top_proc **pref;
236
237/* useful externals */
238extern int errno;
239extern char *sys_errlist[];
240
241long percentages();
242
243machine_init(statics)
244struct statics *statics;
245{
246    register int i = 0;
247    register int pagesize;
248    struct tbl_sysinfo sibuf;
249
250    if ((kmem = open(KMEM, O_RDONLY)) == -1) {
251        perror(KMEM);
252        return(-1);
253    }
254    if ((mem = open(MEM, O_RDONLY)) == -1) {
255        perror(MEM);
256        return(-1);
257    }
258
259    /* get the list of symbols we want to access in the kernel */
260    if (nlist(VMUNIX, nlst) == -1)
261    {
262        perror("TOP(nlist)");
263        return (-1);
264    }
265
266    if (nlst[X_MPID].n_type == 0)
267    {
268        /* this kernel has no _mpid, so go without */
269        do_last_pid = 0;
270    }
271    else
272    {
273        /* stash away mpid pointer for later use */
274        mpid_offset = nlst[X_MPID].n_value;
275    }
276
277    /* get the symbol values out of kmem */
278    nproc  = table(TBL_PROCINFO, 0, (struct tbl_procinfo *)NULL, INT_MAX, 0);
279
280    /* allocate space for proc structure array and array of pointers */
281    bytes = nproc * sizeof(struct osf1_top_proc);
282    pbase = (struct osf1_top_proc *)malloc(bytes);
283    pref  = (struct osf1_top_proc **)malloc(nproc *
284                                              sizeof(struct osf1_top_proc *));
285
286    /* Just in case ... */
287    if (pbase == (struct osf1_top_proc *)NULL ||
288                                  pref == (struct osf1_top_proc **)NULL)
289    {
290        fprintf(stderr, "top: cannot allocate sufficient memory\n");
291        return(-1);
292    }
293
294    /* get the page size with "getpagesize" and calculate pageshift from it */
295    pagesize = getpagesize();
296    pageshift = 0;
297    while (pagesize > 1)
298    {
299        pageshift++;
300        pagesize >>= 1;
301    }
302
303    /* we only need the amount of log(2)1024 for our conversion */
304    pageshift -= LOG1024;
305
306    /* fill in the statics information */
307    statics->procstate_names = procstatenames;
308    statics->cpustate_names = cpustatenames;
309    statics->memory_names = memorynames;
310    statics->order_names = ordernames;
311
312    /* initialise this, for calculating cpu time */
313    if (table(TBL_SYSINFO,0,&sibuf,1,sizeof(struct tbl_sysinfo))<0) {
314        perror("TBL_SYSINFO");
315        return(-1);
316    }
317    old_cpu_ticks[0] = sibuf.si_user;
318    old_cpu_ticks[1] = sibuf.si_nice;
319    old_cpu_ticks[2] = sibuf.si_sys;
320    old_cpu_ticks[3] = sibuf.si_idle;
321
322    /* all done! */
323    return(0);
324}
325
326char *format_header(uname_field)
327register char *uname_field;
328{
329    register char *ptr;
330
331    ptr = header + UNAME_START;
332    while (*uname_field != '\0')
333    {
334        *ptr++ = *uname_field++;
335    }
336
337    return(header);
338}
339
340void get_system_info(si)
341struct system_info *si;
342{
343    struct tbl_loadavg labuf;
344    struct tbl_sysinfo sibuf;
345    struct tbl_swapinfo swbuf;
346    vm_statistics_data_t vmstats;
347    int swap_pages=0,swap_free=0,i;
348    long new_ticks[4],diff_ticks[4];
349    long delta_ticks;
350
351    if (do_last_pid)
352    {
353        /* last pid assigned */
354        (void) getkval(mpid_offset, &(si->last_pid), sizeof(si->last_pid),
355                       "_mpid");
356    }
357    else
358    {
359        si->last_pid = -1;
360    }
361
362    /* get load averages */
363    if (table(TBL_LOADAVG,0,&labuf,1,sizeof(struct tbl_loadavg))<0) {
364        perror("TBL_LOADAVG");
365        return;
366    }
367    if (labuf.tl_lscale)   /* scaled */
368        for(i=0;i<3;i++)
369            si->load_avg[i] = ((double)labuf.tl_avenrun.l[i] /
370                                            (double)labuf.tl_lscale );
371    else                   /* not scaled */
372        for(i=0;i<3;i++)
373            si->load_avg[i] = labuf.tl_avenrun.d[i];
374
375    /* array of cpu state counters */
376    if (table(TBL_SYSINFO,0,&sibuf,1,sizeof(struct tbl_sysinfo))<0) {
377        perror("TBL_SYSINFO");
378        return;
379    }
380    new_ticks[0] = sibuf.si_user ; new_ticks[1] = sibuf.si_nice;
381    new_ticks[2] = sibuf.si_sys  ; new_ticks[3] = sibuf.si_idle;
382    delta_ticks=0;
383    for(i=0;i<4;i++) {
384        diff_ticks[i] = new_ticks[i] - old_cpu_ticks[i];
385        delta_ticks += diff_ticks[i];
386        old_cpu_ticks[i] = new_ticks[i];
387    }
388    si->cpustates = cpu_states;
389    if(delta_ticks)
390        for(i=0;i<4;i++)
391            si->cpustates[i] = (int)( ( (double)diff_ticks[i] /
392                                           (double)delta_ticks ) * 1000 );
393   
394    /* memory information */
395    /* this is possibly bogus - we work out total # pages by */
396    /* adding up the free, active, inactive, wired down, and */
397    /* zero filled. Anyone who knows a better way, TELL ME!  */
398    /* Change: dont use zero filled. */
399    (void) vm_statistics(task_self(),&vmstats);
400
401    /* thanks DEC for the table() command. No thanks at all for   */
402    /* omitting the man page for it from OSF/1 1.2, and failing   */
403    /* to document SWAPINFO in the 1.3 man page. Lets hear it for */
404    /* include files. */
405    i=0;
406    while(table(TBL_SWAPINFO,i,&swbuf,1,sizeof(struct tbl_swapinfo))>0) {
407        swap_pages += swbuf.size;
408        swap_free  += swbuf.free;
409        i++;
410    }
411    memory_stats[0] = -1;
412    memory_stats[1] = pagetok(vmstats.active_count);
413    memory_stats[2] = pagetok((vmstats.free_count + vmstats.active_count +
414        vmstats.inactive_count + vmstats.wire_count));
415    memory_stats[3] = -1;
416    memory_stats[4] = pagetok((swap_pages - swap_free))/1024;
417    memory_stats[5] = pagetok(swap_pages)/1024;
418    memory_stats[6] = -1;
419    memory_stats[7] = pagetok(vmstats.free_count);
420    si->memory = memory_stats;
421}
422
423static struct handle handle;
424
425caddr_t get_process_info(si, sel, compare)
426struct system_info *si;
427struct process_select *sel;
428int (*compare)();
429{
430    register int i;
431    register int total_procs;
432    register int active_procs;
433    register struct osf1_top_proc **prefp;
434    register struct osf1_top_proc *pp;
435    struct tbl_procinfo p_i[8];
436    int j,k,r;
437
438    /* these are copied out of sel for speed */
439    int show_idle;
440    int show_uid;
441    int show_command;
442
443    /* get a pointer to the states summary array */
444    si->procstates = process_states;
445
446    /* set up flags which define what we are going to select */
447    show_idle = sel->idle;
448    show_uid = sel->uid != -1;
449    show_command = sel->command != NULL;
450
451    /* count up process states and get pointers to interesting procs */
452    total_procs = 0;
453    active_procs = 0;
454    memset((char *)process_states, 0, sizeof(process_states));
455    prefp = pref;
456    pp=pbase;
457    for (j=0; j<nproc; j += 8)
458    {
459        r = table(TBL_PROCINFO, j, (struct tbl_procinfo *)p_i, 8,
460                                               sizeof(struct tbl_procinfo));
461        for (k=0; k < r; k++ , pp++)
462        {
463            if(p_i[k].pi_pid == 0)
464            {
465                pp->p_pid = 0;
466            }
467            else
468            {
469                pp->p_pid = p_i[k].pi_pid;
470                pp->p_ruid = p_i[k].pi_ruid;
471                pp->p_flag = p_i[k].pi_flag;
472                pp->p_nice = getpriority(PRIO_PROCESS,p_i[k].pi_pid);
473                /* Load useful values into the proc structure */
474                do_threads_calculations(pp);
475                /*
476                 *  Place pointers to each valid proc structure in pref[].
477                 *  Process slots that are actually in use have a non-zero
478                 *  status field. 
479                 */
480#ifdef DEBUG
481                /*
482                 *  Emit debug info about all processes before selection.
483                 */
484                fprintf(stderr, "pid = %d ruid = %d comm = %s p_mach_state = %d p_stat = %d p_flag = 0x%x\n",
485                        pp->p_pid, pp->p_ruid, p_i[k].pi_comm,
486                        pp->p_mach_state, p_i[k].pi_status, pp->p_flag);
487#endif
488                if (pp->p_mach_state != 0)
489                {
490                    total_procs++;
491                    process_states[pp->p_mach_state]++;
492                    if ((pp->p_mach_state != 8) &&
493                        (show_idle || (pp->p_mach_pct_cpu != 0) ||
494                         (pp->p_mach_state == 1)) &&
495                        (!show_uid || pp->p_ruid == (uid_t)sel->uid)) {
496                        *prefp++ = pp;
497                        active_procs++;
498                    }
499                }
500            }
501        }
502    }
503
504    /* if requested, sort the "interesting" processes */
505    if (compare != NULL)
506    {
507        qsort((char *)pref, active_procs, sizeof(struct osf1_top_proc *),
508                                                                    compare);
509    }
510
511    /* remember active and total counts */
512    si->p_total = total_procs;
513    si->p_active = pref_len = active_procs;
514
515    /* pass back a handle */
516    handle.next_proc = pref;
517    handle.remaining = active_procs;
518    return((caddr_t)&handle);
519}
520
521char fmt[128];          /* static area where result is built */
522
523char *format_next_process(handle, get_userid)
524caddr_t handle;
525char *(*get_userid)();
526{
527    register struct osf1_top_proc *pp;
528    register long cputime;
529    register double pct;
530    struct user u;
531    struct handle *hp;
532
533    /* find and remember the next proc structure */
534    hp = (struct handle *)handle;
535    pp = *(hp->next_proc++);
536    hp->remaining--;
537
538    /* get the process's user struct and set cputime */
539   
540    if (table(TBL_UAREA,pp->p_pid,&u,1,sizeof(struct user))<0) {
541    /* whoops, it must have died between the read of the proc area
542     * and now. Oh well, lets just dump some meaningless thing out
543     * to keep the rest of the program happy
544     */
545        sprintf(fmt,
546                Proc_format,
547                pp->p_pid,
548                (*get_userid)(pp->p_ruid),
549                0,
550                0,
551                "",
552                "",
553                "dead",
554                "",
555                0.0,
556                "<dead>");
557            return(fmt);
558    }
559
560    /* set u_comm for system processes */
561    if (u.u_comm[0] == '\0')
562    {
563        if (pp->p_pid == 0)
564        {
565            (void) strcpy(u.u_comm, "[idle]");
566        }
567        else if (pp->p_pid == 2)
568        {
569            (void) strcpy(u.u_comm, "[execpt.hndlr]");
570        }
571    }
572
573    /* Check if process is in core */
574    if (!(pp->p_flag & SLOAD)) {
575        /*
576         * Print swapped processes as <pname>
577         */
578        char buf[sizeof(u.u_comm)];
579        (void) strncpy(buf, u.u_comm, sizeof(u.u_comm));
580        u.u_comm[0] = '<';
581        (void) strncpy(&u.u_comm[1], buf, sizeof(u.u_comm) - 2);
582        u.u_comm[sizeof(u.u_comm) - 2] = '\0';
583        (void) strncat(u.u_comm, ">", sizeof(u.u_comm) - 1);
584        u.u_comm[sizeof(u.u_comm) - 1] = '\0';
585    }
586
587    cputime = u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec;
588
589    /* calculate the base for cpu percentages */
590    pct = pctdouble(pp->p_mach_pct_cpu);
591
592    /* format this entry */
593    sprintf(fmt,
594            Proc_format,
595            pp->p_pid,
596            (*get_userid)(pp->p_ruid),
597            pp->p_pri,
598            pp->p_nice,
599            format_k(pp->p_mach_virt_size/1024),
600            format_k(pp->p_rssize/1000),
601            state_abbrev[pp->p_mach_state],
602            format_time(cputime),
603            100.0 * ((double)pp->p_mach_pct_cpu / 10000.0),
604            printable(u.u_comm));
605
606    /* return the result */
607    return(fmt);
608}
609
610/*
611 *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
612 *      "offset" is the byte offset into the kernel for the desired value,
613 *      "ptr" points to a buffer into which the value is retrieved,
614 *      "size" is the size of the buffer (and the object to retrieve),
615 *      "refstr" is a reference string used when printing error meessages,
616 *          if "refstr" starts with a '!', then a failure on read will not
617 *          be fatal (this may seem like a silly way to do things, but I
618 *          really didn't want the overhead of another argument).
619 *     
620 */
621
622getkval(offset, ptr, size, refstr)
623
624unsigned long offset;
625int *ptr;
626int size;
627char *refstr;
628
629{
630    if (lseek(kmem, (long)offset, L_SET) == -1) {
631        if (*refstr == '!')
632            refstr++;
633        (void) fprintf(stderr, "%s: lseek to %s: %s\n", KMEM,
634                       refstr, strerror(errno));
635        quit(23);
636    }
637    if (read(kmem, (char *) ptr, size) == -1) {
638        if (*refstr == '!')
639            return(0);
640        else {
641            (void) fprintf(stderr, "%s: reading %s: %s\n", KMEM,
642                           refstr, strerror(errno));
643            quit(23);
644        }
645    }
646    return(1);
647}
648   
649/* comparison routines for qsort */
650
651/*
652 * There are currently four possible comparison routines.  main selects
653 * one of these by indexing in to the array proc_compares.
654 *
655 * Possible keys are defined as macros below.  Currently these keys are
656 * defined:  percent cpu, cpu ticks, process state, resident set size,
657 * total virtual memory usage.  The process states are ordered as follows
658 * (from least to most important):  WAIT, zomb, ???, halt, idle, sleep,
659 * stop, run.  The array declaration below maps a process state index into
660 * a number that reflects this ordering.
661 */
662
663/* First, the possible comparison keys.  These are defined in such a way
664   that they can be merely listed in the source code to define the actual
665   desired ordering.
666 */
667
668#define ORDERKEY_PCTCPU  if (lresult = p2->p_mach_pct_cpu - p1->p_mach_pct_cpu,\
669                           (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
670#define ORDERKEY_CPTICKS if ((result = p2->used_ticks - p1->used_ticks) == 0)
671#define ORDERKEY_STATE   if ((result = sorted_state[p2->p_mach_state] - \
672                            sorted_state[p1->p_mach_state])  == 0)
673#define ORDERKEY_PRIO    if ((result = p2->p_pri - p1->p_pri) == 0)
674#define ORDERKEY_RSSIZE  if ((result = p2->p_rssize - p1->p_rssize) == 0)
675#define ORDERKEY_MEM     if ((result = p2->p_mach_virt_size - p1->p_mach_virt_size) == 0)
676
677/* Now the array that maps process state to a weight */
678
679static unsigned char sorted_state[] =
680{
681   0, /*""*/
682   8, /*"run"*/
683   1, /*"WAIT"*/
684   6, /*"sleep"*/
685   5, /*"idle"*/
686   7, /*"stop"*/
687   4, /*"halt"*/
688   3, /*"???"*/
689   2, /*"zomb"*/
690};
691 
692/* compare_cpu - the comparison function for sorting by cpu percentage */
693
694compare_cpu(pp1, pp2)
695
696struct osf1_top_proc **pp1;
697struct osf1_top_proc **pp2;
698
699{
700    register struct osf1_top_proc *p1;
701    register struct osf1_top_proc *p2;
702    register long result;
703    register pctcpu lresult;
704
705    /* remove one level of indirection */
706    p1 = *pp1;
707    p2 = *pp2;
708
709    ORDERKEY_PCTCPU
710    ORDERKEY_CPTICKS
711    ORDERKEY_STATE
712    ORDERKEY_PRIO
713    ORDERKEY_RSSIZE
714    ORDERKEY_MEM
715    ;
716
717    return(result);
718}
719
720/* compare_size - the comparison function for sorting by total memory usage */
721
722compare_size(pp1, pp2)
723
724struct osf1_top_proc **pp1;
725struct osf1_top_proc **pp2;
726
727{
728    register struct osf1_top_proc *p1;
729    register struct osf1_top_proc *p2;
730    register long result;
731    register pctcpu lresult;
732
733    /* remove one level of indirection */
734    p1 = *pp1;
735    p2 = *pp2;
736
737    ORDERKEY_MEM
738    ORDERKEY_RSSIZE
739    ORDERKEY_PCTCPU
740    ORDERKEY_CPTICKS
741    ORDERKEY_STATE
742    ORDERKEY_PRIO
743    ;
744
745    return(result);
746}
747
748/* compare_res - the comparison function for sorting by resident set size */
749
750compare_res(pp1, pp2)
751
752struct osf1_top_proc **pp1;
753struct osf1_top_proc **pp2;
754
755{
756    register struct osf1_top_proc *p1;
757    register struct osf1_top_proc *p2;
758    register long result;
759    register pctcpu lresult;
760
761    /* remove one level of indirection */
762    p1 = *pp1;
763    p2 = *pp2;
764
765    ORDERKEY_RSSIZE
766    ORDERKEY_MEM
767    ORDERKEY_PCTCPU
768    ORDERKEY_CPTICKS
769    ORDERKEY_STATE
770    ORDERKEY_PRIO
771    ;
772
773    return(result);
774}
775
776/* compare_time - the comparison function for sorting by total cpu time */
777
778compare_time(pp1, pp2)
779
780struct osf1_top_proc **pp1;
781struct osf1_top_proc **pp2;
782
783{
784    register struct osf1_top_proc *p1;
785    register struct osf1_top_proc *p2;
786    register long result;
787    register pctcpu lresult;
788
789    /* remove one level of indirection */
790    p1 = *pp1;
791    p2 = *pp2;
792
793    ORDERKEY_CPTICKS
794    ORDERKEY_PCTCPU
795    ORDERKEY_STATE
796    ORDERKEY_PRIO
797    ORDERKEY_RSSIZE
798    ORDERKEY_MEM
799    ;
800 
801    return(result);
802}
803
804/*
805 * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
806 *              the process does not exist.
807 *              It is EXTREMLY IMPORTANT that this function work correctly.
808 *              If top runs setuid root (as in SVR4), then this function
809 *              is the only thing that stands in the way of a serious
810 *              security problem.  It validates requests for the "kill"
811 *              and "renice" commands.
812 */
813
814int proc_owner(pid)
815
816int pid;
817
818{
819    register int cnt;
820    register struct osf1_top_proc **prefp;
821    register struct osf1_top_proc *pp;
822
823    prefp = pref;
824    cnt = pref_len;
825    while (--cnt >= 0)
826    {
827        if ((pp = *prefp++)->p_pid == (pid_t)pid)
828        {
829            return((int)pp->p_ruid);
830        }
831    }
832    return(-1);
833}
834
835
836/*
837 * We use the Mach interface, as well as the table(UAREA,,,) call to
838 * get some more information, then put it into unused fields in our
839 * copy of the proc structure, to make it faster and easier to get at
840 * later.
841 */
842void do_threads_calculations(thisproc)
843struct osf1_top_proc *thisproc;
844{
845  int j;
846  task_t  thistask;
847  task_basic_info_data_t   taskinfo;
848  unsigned int taskinfo_l;
849  thread_array_t    threadarr;
850  unsigned int threadarr_l;
851  thread_basic_info_t     threadinfo;
852  thread_basic_info_data_t threadinfodata;
853  unsigned int threadinfo_l;
854  int task_tot_cpu=0;  /* total cpu usage of threads in a task */
855  struct user u;
856
857  thisproc->p_pri=0;
858  thisproc->p_rssize=0;
859  thisproc->p_mach_virt_size=0;
860  thisproc->p_mach_state=0;
861  thisproc->p_mach_pct_cpu=0;
862
863  if(task_by_unix_pid(task_self(), thisproc->p_pid, &thistask)
864                                                != KERN_SUCCESS){
865      thisproc->p_mach_state=8; /* (zombie) */
866  } else {
867    taskinfo_l=TASK_BASIC_INFO_COUNT;
868    if(task_info(thistask, TASK_BASIC_INFO, (task_info_t) &taskinfo,
869                                      &taskinfo_l)
870       != KERN_SUCCESS) {
871      thisproc->p_mach_state=8; /* (zombie) */
872    } else {
873      int minim_state=99,mcurp=1000,mbasp=1000,mslpt=999;
874
875      thisproc->p_rssize=taskinfo.resident_size;
876      thisproc->p_mach_virt_size=taskinfo.virtual_size;
877
878      (void) task_threads(thistask, &threadarr, &threadarr_l);
879      threadinfo= &threadinfodata;
880      for(j=0; j < threadarr_l; j++) {
881        threadinfo_l=THREAD_BASIC_INFO_COUNT;
882        if(thread_info(threadarr[j],THREAD_BASIC_INFO,
883               (thread_info_t) threadinfo, &threadinfo_l) == KERN_SUCCESS) {
884           
885          task_tot_cpu += threadinfo->cpu_usage;
886          if(minim_state>threadinfo->run_state)
887              minim_state=threadinfo->run_state;
888          if(mcurp>threadinfo->cur_priority)
889              mcurp=threadinfo->cur_priority;
890          if(mbasp>threadinfo->base_priority)
891              mbasp=threadinfo->base_priority;
892          if(mslpt>threadinfo->sleep_time)
893              mslpt=threadinfo->sleep_time;
894        }
895      }
896      switch (minim_state) {
897      case TH_STATE_RUNNING:     
898            thisproc->p_mach_state=1;  break;
899      case TH_STATE_UNINTERRUPTIBLE:
900            thisproc->p_mach_state=2; break;
901      case TH_STATE_WAITING:     
902            thisproc->p_mach_state=(threadinfo->sleep_time > 20) ? 4 : 3; break;
903      case TH_STATE_STOPPED:     
904            thisproc->p_mach_state=5; break;
905      case TH_STATE_HALTED:       
906            thisproc->p_mach_state=6; break;
907      default:                   
908            thisproc->p_mach_state=7; break;
909      }
910
911      thisproc->p_pri=mcurp;
912      thisproc->p_mach_pct_cpu=(fixpt_t)(task_tot_cpu*10);
913      vm_deallocate(task_self(),(vm_address_t)threadarr,threadarr_l);
914    }
915  }
916  if (table(TBL_UAREA,thisproc->p_pid,&u,1,sizeof(struct user))>=0) {
917    thisproc->used_ticks=(u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec);
918    thisproc->process_size=u.u_tsize + u.u_dsize + u.u_ssize;
919  }
920}
921
922/* The reason for this function is that the system call will let
923 * someone lower their own processes priority (because top is setuid :-(
924 * Yes, using syscall() is a hack, if you can come up with something
925 * better, then I'd be thrilled to hear it. I'm not holding my breath,
926 * though. 
927 *             Anthony.
928 */
929int setpriority(int dummy, int procnum, int niceval)
930{
931
932    int uid, curprio;
933
934    uid=getuid();
935    if ( (curprio=getpriority(PRIO_PROCESS,procnum) ) == -1)
936    {
937        return(-1); /* errno goes back to renice_process() */
938    }
939    /* check for not-root - if so, dont allow users to decrease priority */
940    else if ( uid && (niceval<curprio) )
941    {
942        errno=EACCES;
943        return(-1);
944    }
945    return(syscall(SYS_setpriority,PRIO_PROCESS,procnum,niceval));
946}
947
Note: See TracBrowser for help on using the repository browser.