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

Revision 16185, 34.5 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:  For Intel based System V Release 5 (Unixware7)
5 *
6 * DESCRIPTION:
7 * System V release 5 for i[3456]86
8 * Works for:
9 * i586-sco-sysv5uw7  i386 SCO UNIX_SVR5 (UnixWare 7)
10 *
11 * LIBS:  -lelf -lmas
12 *
13 * CFLAGS: -DHAVE_GETOPT -DORDER
14 *
15 * AUTHORS: Mike Hopkirk       <hops@sco.com>
16 *          David Cutter       <dpc@grail.com>
17 *          Andrew Herbert     <andrew@werple.apana.org.au>
18 *          Robert Boucher     <boucher@sofkin.ca>
19 */
20
21/* build config
22 *  SHOW_NICE - process nice fields don't seem to be being updated so changed
23 *     default to display # of threads in use instead.
24 *     define this to display nice fields (values always 0)
25 * #define SHOW_NICE 1
26 */
27
28#define _KMEMUSER
29#define prpsinfo psinfo
30#include <sys/procfs.h>
31
32#define pr_state pr_lwp.pr_state
33#define pr_nice pr_lwp.pr_nice
34#define pr_pri pr_lwp.pr_pri
35#define pr_onpro pr_lwp.pr_onpro
36#define ZOMBIE(p)       ((p)->pr_nlwp == 0)
37#define SIZE_K(p)       pagetok((p)->pr_size)
38#define RSS_K(p)        pagetok((p)->pr_rssize)
39
40
41#include <stdio.h>
42#include <fcntl.h>
43#include <unistd.h>
44#include <stdlib.h>
45#include <errno.h>
46#include <dirent.h>
47#include <nlist.h>
48#include <string.h>
49#include <sys/types.h>
50#include <sys/param.h>
51#include <sys/proc.h>
52#include <sys/sysmacros.h>
53#include <vm/anon.h>
54#include <sys/priocntl.h>
55#include <sys/tspriocntl.h>
56#include <sys/var.h>
57
58#include "top.h"
59#include "machine.h"
60#include "utils.h"
61
62#define UNIX "/stand/unix"
63#define KMEM "/dev/kmem"
64#define PROCFS "/proc"
65#define CPUSTATES       5
66
67#ifndef PRIO_MAX
68#define PRIO_MAX        20
69#endif
70#ifndef PRIO_MIN
71#define PRIO_MIN        -20
72#endif
73
74#ifndef FSCALE
75#define FSHIFT  8               /* bits to right of fixed binary point */
76#define FSCALE  (1<<FSHIFT)
77#endif
78
79#define loaddouble(x) ((double)x/FSCALE)
80#define pagetok(size) ((size) * pagesz) >> LOG1024
81
82/* definitions for the index in the nlist array */
83#define X_AVENRUN       0
84#define X_V             1
85#define X_MPID          2
86
87static struct nlist nlst[] =
88{
89   {"avenrun"},                 /* 0 */
90   {"v"},                       /* 1 */
91   {"nextpid"},                 /* 2 */
92  {NULL}
93};
94
95static unsigned long avenrun_offset;
96static unsigned long mpid_offset;
97
98static unsigned int pagesz;
99
100static void reallocproc(int n);
101static int maxprocs;
102
103/* get_process_info passes back a handle.  This is what it looks like: */
104
105struct handle
106{
107    struct prpsinfo **next_proc;/* points to next valid proc pointer */
108    int remaining;              /* number of pointers remaining */
109};
110
111/*
112 *  These definitions control the format of the per-process area
113 */
114
115static char header[] =
116#ifdef SHOW_NICE
117"  PID X        PRI NICE  SIZE   RES STATE   TIME      CPU  COMMAND";
118#else
119"  PID X        PRI  THR  SIZE   RES STATE   TIME      CPU  COMMAND";
120#endif
121/* 0123456   -- field to fill in starts at header+6 */
122#define UNAME_START 6
123#define Proc_format \
124        "%5d %-8.8s %3d %4d %5s %5s %-5s %6s %8.4f%% %.16s"
125
126char *state_abbrev[] =
127{"oncpu", "run", "sleep",  "stop", "idle", "zombie"};
128
129#define sZOMB 5
130int process_states[8];
131char *procstatenames[] =
132{
133  " on cpu, ", " running, ", " sleeping, ", " stopped, ",
134  " idling ",  " zombie, ",
135  NULL
136};
137
138int cpu_states[CPUSTATES];
139char *cpustatenames[] =
140{"idle", "user", "kernel", "wait", NULL};
141
142
143/* these are for detailing the memory statistics */
144int memory_stats[5];
145char *memorynames[] =
146{"K phys, ", "K used, ", "K free, ", "K swapUsed, ", "K swapFree", NULL};
147
148/* these are names given to allowed sorting orders -- first is default */
149char *ordernames[] =
150{"state", "cpu", "size", "res", "time", "pid", "uid", "rpid", "ruid", NULL};
151
152/* forward definitions for comparison functions */
153int proc_compare();
154int compare_cpu();
155int compare_size();
156int compare_res();
157int compare_time();
158int compare_pid();
159int compare_uid();
160int compare_rpid();
161int compare_ruid();
162
163int (*proc_compares[])() = {
164    proc_compare,
165    compare_cpu,
166    compare_size,
167    compare_res,
168    compare_time,
169    compare_pid,
170    compare_uid,
171    compare_rpid,
172    compare_ruid,
173    NULL };
174
175
176static int kmem = -1;
177static int nproc;
178static int bytes;
179static struct prpsinfo *pbase;
180static struct prpsinfo **pref;
181static DIR *procdir;
182
183/* useful externals */
184extern int errno;
185extern char *sys_errlist[];
186extern char *myname;
187extern long percentages ();
188extern int check_nlist ();
189extern int getkval ();
190extern void perror ();
191extern void getptable ();
192extern void quit ();
193extern int nlist ();
194
195/* fwd dcls */
196static int kmet_init(void );
197static int get_cpustates(int *new);
198
199
200int
201machine_init (struct statics *statics)
202  {
203    static struct var v;
204    int i;
205
206    /* fill in the statics information */
207    statics->procstate_names = procstatenames;
208    statics->cpustate_names = cpustatenames;
209    statics->memory_names = memorynames;
210    statics->order_names = ordernames;
211
212    /* get the list of symbols we want to access in the kernel */
213    if (nlist (UNIX, nlst))
214      {
215        (void) fprintf (stderr, "Unable to nlist %s\n", UNIX);
216        return (-1);
217      }
218
219    /* make sure they were all found */
220    if (check_nlist (nlst) > 0)
221      return (-1);
222
223    /* open kernel memory */
224    if ((kmem = open (KMEM, O_RDONLY)) == -1)
225      {
226        perror (KMEM);
227        return (-1);
228      }
229
230    v.v_proc=200;   /* arbitrary default */
231    /* get the symbol values out of kmem */
232    /* NPROC Tuning parameter for max number of processes */
233    (void) getkval (nlst[X_V].n_value, &v, sizeof (struct var), nlst[X_V].n_name);
234    nproc = v.v_proc;
235    maxprocs = nproc;
236
237    /* stash away certain offsets for later use */
238    mpid_offset = nlst[X_MPID].n_value;
239    avenrun_offset = nlst[X_AVENRUN].n_value;
240
241    /* allocate space for proc structure array and array of pointers */
242    bytes = nproc * sizeof (struct prpsinfo);
243    pbase = (struct prpsinfo *) malloc (bytes);
244    pref = (struct prpsinfo **) malloc (nproc * sizeof (struct prpsinfo *));
245
246    pagesz = sysconf(_SC_PAGESIZE);
247
248
249    /* Just in case ... */
250    if (pbase == (struct prpsinfo *) NULL || pref == (struct prpsinfo **) NULL)
251      {
252        (void) fprintf (stderr, "%s: can't allocate sufficient memory\n", myname);
253        return (-1);
254      }
255
256    if (!(procdir = opendir (PROCFS)))
257      {
258        (void) fprintf (stderr, "Unable to open %s\n", PROCFS);
259        return (-1);
260      }
261
262    if (chdir (PROCFS))
263    {                           /* handy for later on when we're reading it */
264        (void) fprintf (stderr, "Unable to chdir to %s\n", PROCFS);
265        return (-1);
266    }
267
268
269    kmet_init();
270
271    /* all done! */
272    return (0);
273  }
274
275char *
276format_header (char *uname_field)
277{
278  register char *ptr;
279
280  ptr = header + UNAME_START;
281  while (*uname_field != '\0')
282    *ptr++ = *uname_field++;
283
284  return (header);
285}
286
287void
288get_system_info (struct system_info *si)
289{
290  long avenrun[3];
291  long mem;
292  static time_t cp_old[CPUSTATES];
293  static time_t cp_diff[CPUSTATES];     /* for cpu state percentages */
294  register int i;
295  static long swap_total;
296  static long swap_free;
297  int new_states[CPUSTATES];
298
299  get_cpustates(new_states);
300
301  /* convert cp_time counts to percentages */
302  (void) percentages (CPUSTATES, cpu_states, new_states, cp_old, cp_diff);
303
304
305  si->last_pid = -1;
306  /* get mpid -- process id of last process
307   * svr5 is nextpid - next pid to be assigned (already incremented)
308   */
309   (void) getkval (mpid_offset, &(si->last_pid), sizeof (si->last_pid),
310                  "nextpid");
311   (si->last_pid)--;    /* so we shld decrement for display */
312
313
314  /* get load average array */
315  (void) getkval (avenrun_offset, (int *) avenrun, sizeof (avenrun), "avenrun");
316  /* convert load averages to doubles */
317  for (i = 0; i < 3; i++)
318    si->load_avg[i] = loaddouble(avenrun[i]);
319
320  mem = sysconf(_SC_TOTAL_MEMORY);      /* physical mem */
321  memory_stats[0] = pagetok (mem);
322
323  mem = kmet_get_freemem();             /* free mem */
324  memory_stats[2] = pagetok (mem);
325
326  /* mem = sysconf(_SC_GENERAL_MEMORY);    */
327  memory_stats[1] = memory_stats[0] - memory_stats[2]; /* active */
328
329  get_swapinfo(&swap_total, &swap_free);
330  memory_stats[3] = pagetok(swap_total - swap_free);
331  memory_stats[4] = pagetok(swap_free);
332 
333
334  /* set arrays and strings */
335  si->cpustates = cpu_states;
336  si->memory = memory_stats;
337}
338
339static struct handle handle;
340
341caddr_t
342get_process_info (
343                   struct system_info *si,
344                   struct process_select *sel,
345                   int (*compare) ())
346{
347  register int i;
348  register int total_procs;
349  register int active_procs;
350  register struct prpsinfo **prefp;
351  register struct prpsinfo *pp;
352
353  /* these are copied out of sel for speed */
354  int show_idle;
355  int show_system;
356  int show_uid;
357
358  /* Get current number of processes */
359
360  /* read all the proc structures */
361  getptable (pbase);
362
363  /* get a pointer to the states summary array */
364  si->procstates = process_states;
365
366  /* set up flags which define what we are going to select */
367  show_idle   = sel->idle;
368  show_system = sel->system;
369  show_uid    = sel->uid != -1;
370
371  nproc = kmet_get_nproc();
372
373  /* count up process states and get pointers to interesting procs */
374  total_procs = 0;
375  active_procs = 0;
376  (void) memset (process_states, 0, sizeof (process_states));
377  prefp = pref;
378
379  for (pp = pbase, i = 0; i < nproc; pp++, i++)
380  {
381      /*
382         *  Place pointers to each valid proc structure in pref[].
383         *  Process slots that are actually in use have a non-zero
384         *  status field.  Processes with PR_ISSYS set are system
385         *  processes---these get ignored unless show_sysprocs is set.
386         */
387      if ((pp->pr_state >= SONPROC && pp->pr_state <= SIDL)  &&
388          (show_system || ((pp->pr_flag & PR_ISSYS) == 0)))
389      {
390          total_procs++;
391          process_states[pp->pr_state]++;
392          if ((!ZOMBIE(pp)) &&
393              (show_idle || (pp->pr_state == SRUN) || (pp->pr_state == SONPROC)) &&
394              (!show_uid || pp->pr_uid == (uid_t) sel->uid))
395          {
396              *prefp++ = pp;
397              active_procs++;
398          }
399          if (ZOMBIE(pp))
400            process_states[sZOMB]++;    /* invented */
401
402      }
403  }
404
405  /* if requested, sort the "interesting" processes */
406  if (compare != NULL)
407      qsort ((char *) pref, active_procs, sizeof (struct prpsinfo *), compare);
408
409  /* remember active and total counts */
410  si->p_total = total_procs;
411  si->P_ACTIVE = active_procs;
412
413  /* pass back a handle */
414  handle.next_proc = pref;
415  handle.remaining = active_procs;
416  return ((caddr_t) & handle);
417}
418
419/*
420 * cpu percentage calculation is as fm ps.c
421 * seems to be ratio of (sys+user time used)/(elapsed time)
422 * i.e percent of cpu utilised when on cpu
423 */
424static double percent_cpu( struct prpsinfo *pp)
425{
426    static time_t tim = 0L;   
427    time_t starttime;
428    time_t ctime;
429    time_t etime;
430
431    /* if (tim == 0L) */
432        tim = time((time_t *) 0);
433    starttime = pp->pr_start.tv_sec;
434    if (pp->pr_start.tv_nsec > 500000000)
435            starttime++;
436    etime = (tim - starttime);
437    ctime = pp->pr_time.tv_sec;
438    if (pp->pr_time.tv_nsec > 500000000)
439    ctime++;
440    if (etime)
441    {
442        /* return  (float)(ctime * 100) / (unsigned)etime; */
443        /* this was ocasionally giving vals >100 for some
444         * unknown reason so the below normalises it
445         */
446       
447        double pct;
448        pct = (float)(ctime * 100) / (unsigned)etime;
449        return (pct < 100.0) ? pct : 100.00;
450    }
451    return 0.00;
452}
453
454
455char fmt[MAX_COLS];                     /* static area where result is built */
456
457char *
458format_next_process (
459                      caddr_t handle,
460                      char *(*get_userid) ())
461{
462  register struct prpsinfo *pp;
463  struct handle *hp;
464  register long cputime;
465  register double pctcpu;
466
467  /* find and remember the next proc structure */
468  hp = (struct handle *) handle;
469  pp = *(hp->next_proc++);
470  hp->remaining--;
471
472  /* get the cpu usage and calculate the cpu percentages */
473  cputime = pp->pr_time.tv_sec;
474  pctcpu = percent_cpu(pp);
475
476
477  /* format this entry */
478  (void) sprintf (fmt,
479                  Proc_format,
480                  pp->pr_pid,
481                  (*get_userid) (pp->pr_uid),
482                  pp->pr_pri,
483#ifdef SHOW_NICE
484                  pp->pr_nice,
485#else
486                  (u_short)pp->pr_nlwp < 999 ? (u_short)pp->pr_nlwp : 999,
487#endif
488                  format_k(SIZE_K(pp)),
489                  format_k(RSS_K(pp)), 
490                  (ZOMBIE(pp))  ? state_abbrev[sZOMB]
491                                : state_abbrev[pp->pr_state],
492                  format_time(cputime),
493                  /* 100.0 * */ pctcpu,
494                  pp->pr_fname);
495
496  /* return the result */
497  return (fmt);
498}
499
500/*
501 * check_nlist(nlst) - checks the nlist to see if any symbols were not
502 *              found.  For every symbol that was not found, a one-line
503 *              message is printed to stderr.  The routine returns the
504 *              number of symbols NOT found.
505 */
506int
507check_nlist (register struct nlist *nlst)
508{
509  register int i;
510
511  /* check to see if we got ALL the symbols we requested */
512  /* this will write one line to stderr for every symbol not found */
513
514  i = 0;
515  while (nlst->n_name != NULL)
516    {
517      if (nlst->n_value == 0)
518        {
519          /* this one wasn't found */
520          (void) fprintf (stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
521          i = 1;
522        }
523      nlst++;
524    }
525  return (i);
526}
527
528
529/*
530 *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
531 *      "offset" is the byte offset into the kernel for the desired value,
532 *      "ptr" points to a buffer into which the value is retrieved,
533 *      "size" is the size of the buffer (and the object to retrieve),
534 *      "refstr" is a reference string used when printing error meessages,
535 *          if "refstr" starts with a '!', then a failure on read will not
536 *          be fatal (this may seem like a silly way to do things, but I
537 *          really didn't want the overhead of another argument).
538 *
539 */
540int
541getkval (
542          unsigned long offset,
543          int *ptr,
544          int size,
545          char *refstr)
546{
547  if (lseek (kmem, (long) offset, 0) == -1)
548    {
549      if (*refstr == '!')
550        refstr++;
551      (void) fprintf (stderr, "%s: lseek to %s: %s\n",
552                      myname, refstr, sys_errlist[errno]);
553      quit (22);
554    }
555  if (read (kmem, (char *) ptr, size) == -1)
556    if (*refstr == '!')
557      /* we lost the race with the kernel, process isn't in memory */
558      return (0);
559    else
560      {
561        (void) fprintf (stderr, "%s: reading %s: %s\n",
562                        myname, refstr, sys_errlist[errno]);
563        quit (23);
564      }
565  return (1);
566}
567
568/* ----------------- comparison routines for qsort ---------------- */
569
570/* First, the possible comparison keys.  These are defined in such a way
571   that they can be merely listed in the source code to define the actual
572   desired ordering.
573 */
574
575#define ORDERKEY_PCTCPU  if (dresult = percent_cpu (p2) - percent_cpu (p1),\
576                             (result = dresult > 0.0 ? 1 : \
577                             dresult < 0.0 ? -1 : 0) == 0)
578
579#define ORDERKEY_CPTICKS if ((result = p2->pr_time.tv_sec - p1->pr_time.tv_sec) == 0)
580#define ORDERKEY_STATE   if ((result = (long) (sorted_state[p2->pr_state] - \
581                               sorted_state[p1->pr_state])) == 0)
582
583#define ORDERKEY_PRIO    if ((result = p2->pr_pri    - p1->pr_pri)    == 0)
584#define ORDERKEY_RSSIZE  if ((result = p2->pr_rssize - p1->pr_rssize) == 0)
585#define ORDERKEY_MEM     if ((result = (p2->pr_size  - p1->pr_size))  == 0)
586
587#define ORDERKEY_PID     if ((result = (p2->pr_pid  - p1->pr_pid))  == 0)
588#define ORDERKEY_UID     if ((result = (p2->pr_uid  - p1->pr_uid))  == 0)
589#define ORDERKEY_RPID    if ((result = (p1->pr_pid  - p2->pr_pid))  == 0)
590#define ORDERKEY_RUID    if ((result = (p1->pr_uid  - p2->pr_uid))  == 0)
591
592/* states enum {SONPROC, SRUN, SSLEEP, SSTOP, SIDL}  */
593unsigned char sorted_state[] =
594{
595  7,                            /* onproc               */
596  6,                            /* run                  */
597  5,                            /* sleep                */
598  4,                            /* stop                 */
599  3,                            /* idle                 */
600  2,                            /* zombie               */
601  0,                            /* unused               */
602  0                             /* unused               */
603};
604
605#if 0
606/*
607 *  proc_compare - original singleton comparison function for "qsort"
608 *      Compares the resource consumption of two processes using five
609 *      distinct keys.  The keys (in descending order of importance) are:
610 *      percent cpu, cpu ticks, state, resident set size, total virtual
611 *      memory usage.  The process states are ordered as follows (from least
612 *      to most important):  WAIT, zombie, sleep, stop, start, run.  The
613 *      array declaration below maps a process state index into a number
614 *      that reflects this ordering.
615 */
616 /* default comparison rtn */
617int
618original_proc_compare (
619               struct prpsinfo **pp1,
620               struct prpsinfo **pp2)
621  {
622    register struct prpsinfo *p1;
623    register struct prpsinfo *p2;
624    register long result;
625    double dresult;
626
627    /* remove one level of indirection */
628    p1 = *pp1;
629    p2 = *pp2;
630
631    /* compare percent cpu (pctcpu) */
632    dresult = percent_cpu(p2) - percent_cpu (p1);
633    result = dresult > 0.0 ?  1 :
634             dresult < 0.0 ? -1 : 0;
635    if (result)
636    {
637        /* use cpticks to break the tie */
638        if ((result = p2->pr_time.tv_sec - p1->pr_time.tv_sec) == 0)
639          {
640            /* use process state to break the tie */
641            if ((result = (long) (sorted_state[p2->pr_state] -
642                                  sorted_state[p1->pr_state])) == 0)
643              {
644                /* use priority to break the tie */
645                if ((result = p2->pr_pri - p1->pr_pri) == 0)
646                  {
647                    /* use resident set size (rssize) to break the tie */
648                    if ((result = p2->pr_rssize - p1->pr_rssize) == 0)
649                      {
650                        /* use total memory to break the tie */
651                        result = (p2->pr_size - p1->pr_size);
652                      }
653                  }
654              }
655          }
656    }
657    return (result);
658  }
659#endif  /* original comparison rtn */
660
661/* compare_state - comparison function for sorting by state,pri,time,size */
662int
663proc_compare (
664               struct prpsinfo **pp1,
665               struct prpsinfo **pp2)
666  {
667    register struct prpsinfo *p1;
668    register struct prpsinfo *p2;
669    register long result;
670    double dresult;
671
672    /* remove one level of indirection */
673    p1 = *pp1;
674    p2 = *pp2;
675
676    ORDERKEY_STATE
677    ORDERKEY_PRIO
678    ORDERKEY_CPTICKS
679    ORDERKEY_RSSIZE
680    ORDERKEY_MEM
681    ORDERKEY_PCTCPU
682    ;
683
684    return (result);
685  }
686
687
688/* compare_cpu - the comparison function for sorting by cpu % (deflt) */
689int
690compare_cpu (
691               struct prpsinfo **pp1,
692               struct prpsinfo **pp2)
693  {
694    register struct prpsinfo *p1;
695    register struct prpsinfo *p2;
696    register long result;
697    double dresult;
698
699    /* remove one level of indirection */
700    p1 = *pp1;
701    p2 = *pp2;
702
703    ORDERKEY_PCTCPU
704    ORDERKEY_CPTICKS
705    ORDERKEY_STATE
706    ORDERKEY_PRIO
707    ORDERKEY_RSSIZE
708    ORDERKEY_MEM
709    ;
710
711    return (result);
712  }
713
714/* compare_size - the comparison function for sorting by total memory usage */
715int
716compare_size (
717               struct prpsinfo **pp1,
718               struct prpsinfo **pp2)
719  {
720    register struct prpsinfo *p1;
721    register struct prpsinfo *p2;
722    register long result;
723    double dresult;
724
725    /* remove one level of indirection */
726    p1 = *pp1;
727    p2 = *pp2;
728
729    ORDERKEY_MEM
730    ORDERKEY_RSSIZE
731    ORDERKEY_PCTCPU
732    ORDERKEY_CPTICKS
733    ORDERKEY_STATE
734    ORDERKEY_PRIO
735    ;
736
737    return (result);
738  }
739
740/* compare_res - the comparison function for sorting by resident set size */
741int
742compare_res (
743               struct prpsinfo **pp1,
744               struct prpsinfo **pp2)
745  {
746    register struct prpsinfo *p1;
747    register struct prpsinfo *p2;
748    register long result;
749    double dresult;
750
751    /* remove one level of indirection */
752    p1 = *pp1;
753    p2 = *pp2;
754
755    ORDERKEY_RSSIZE
756    ORDERKEY_MEM
757    ORDERKEY_PCTCPU
758    ORDERKEY_CPTICKS
759    ORDERKEY_STATE
760    ORDERKEY_PRIO
761    ;
762
763    return (result);
764  }
765
766/* compare_time - the comparison function for sorting by total cpu time */
767int
768compare_time (
769               struct prpsinfo **pp1,
770               struct prpsinfo **pp2)
771  {
772    register struct prpsinfo *p1;
773    register struct prpsinfo *p2;
774    register long result;
775    double dresult;
776
777    /* remove one level of indirection */
778    p1 = *pp1;
779    p2 = *pp2;
780
781    ORDERKEY_CPTICKS
782    ORDERKEY_PCTCPU
783    ORDERKEY_STATE
784    ORDERKEY_PRIO
785    ORDERKEY_MEM
786    ORDERKEY_RSSIZE
787    ;
788
789    return (result);
790  }
791
792/* compare_pid - the comparison function for sorting by pid */
793int
794compare_pid (
795               struct prpsinfo **pp1,
796               struct prpsinfo **pp2)
797  {
798    register struct prpsinfo *p1;
799    register struct prpsinfo *p2;
800    register long result;
801    double dresult;
802
803    /* remove one level of indirection */
804    p1 = *pp1;
805    p2 = *pp2;
806
807    ORDERKEY_PID
808    ORDERKEY_CPTICKS
809    ORDERKEY_PCTCPU
810    ORDERKEY_STATE
811    ORDERKEY_PRIO
812    ORDERKEY_MEM
813    ORDERKEY_RSSIZE
814    ;
815
816    return (result);
817  }
818
819/* compare_uid - the comparison function for sorting by user ID */
820int
821compare_uid (
822               struct prpsinfo **pp1,
823               struct prpsinfo **pp2)
824  {
825    register struct prpsinfo *p1;
826    register struct prpsinfo *p2;
827    register long result;
828    double dresult;
829
830    /* remove one level of indirection */
831    p1 = *pp1;
832    p2 = *pp2;
833
834    ORDERKEY_UID
835    ORDERKEY_CPTICKS
836    ORDERKEY_PCTCPU
837    ORDERKEY_STATE
838    ORDERKEY_PRIO
839    ORDERKEY_MEM
840    ORDERKEY_RSSIZE
841    ;
842
843    return (result);
844  }
845
846/* compare_rpid - the comparison function for sorting by pid ascending */
847int
848compare_rpid (
849               struct prpsinfo **pp1,
850               struct prpsinfo **pp2)
851  {
852    register struct prpsinfo *p1;
853    register struct prpsinfo *p2;
854    register long result;
855    double dresult;
856
857    /* remove one level of indirection */
858    p1 = *pp1;
859    p2 = *pp2;
860
861    ORDERKEY_RPID
862    ORDERKEY_CPTICKS
863    ORDERKEY_PCTCPU
864    ORDERKEY_STATE
865    ORDERKEY_PRIO
866    ORDERKEY_MEM
867    ORDERKEY_RSSIZE
868    ;
869
870    return (result);
871  }
872
873/* compare_uid - the comparison function for sorting by user ID ascending */
874int
875compare_ruid (
876               struct prpsinfo **pp1,
877               struct prpsinfo **pp2)
878  {
879    register struct prpsinfo *p1;
880    register struct prpsinfo *p2;
881    register long result;
882    double dresult;
883
884    /* remove one level of indirection */
885    p1 = *pp1;
886    p2 = *pp2;
887
888    ORDERKEY_RUID
889    ORDERKEY_CPTICKS
890    ORDERKEY_PCTCPU
891    ORDERKEY_STATE
892    ORDERKEY_PRIO
893    ORDERKEY_MEM
894    ORDERKEY_RSSIZE
895    ;
896
897    return (result);
898  }
899
900
901/* ---------------- helper rtns ---------------- */
902
903/*
904 * get process table
905 */
906void
907getptable (struct prpsinfo *baseptr)
908{
909  struct prpsinfo *currproc;    /* pointer to current proc structure    */
910  int numprocs = 0;
911  struct dirent *direntp;
912
913  currproc = baseptr;
914  for (rewinddir (procdir); direntp = readdir (procdir);)
915    {
916      int fd;
917      char buf[30];
918
919      sprintf(buf,"%s/psinfo", direntp->d_name);
920
921      if ((fd = open (buf, O_RDONLY)) < 0)
922        continue;
923
924      if (read(fd, currproc, sizeof(psinfo_t)) != sizeof(psinfo_t))
925      {
926          (void) close (fd);
927          continue;
928      }
929       
930      numprocs++;
931      currproc++;
932     
933      (void) close (fd);
934
935      /* Atypical place for growth */
936      if (numprocs >= maxprocs)
937      {
938            reallocproc(2 * numprocs);
939            currproc = (struct prpsinfo *)
940                    ((char *)baseptr + sizeof(psinfo_t) * numprocs);
941      }
942
943    }
944
945  if (nproc != numprocs)
946    nproc = numprocs;
947}
948
949/* return the owner of the specified process, for use in commands.c as we're
950   running setuid root */
951uid_t
952proc_owner (pid_t pid)
953{
954  register struct prpsinfo *p;
955  int i;
956  for (i = 0, p = pbase; i < nproc; i++, p++)
957    if (p->pr_pid == pid)
958      return (p->pr_uid);
959
960  return (-1);
961}
962
963int
964setpriority (int dummy, int who, int niceval)
965{
966  int scale;
967  int prio;
968  pcinfo_t pcinfo;
969  pcparms_t pcparms;
970  tsparms_t *tsparms;
971
972  strcpy (pcinfo.pc_clname, "TS");
973  if (priocntl (0, 0, PC_GETCID, (caddr_t) & pcinfo) == -1)
974    return (-1);
975
976  prio = niceval;
977  if (prio > PRIO_MAX)
978    prio = PRIO_MAX;
979  else if (prio < PRIO_MIN)
980    prio = PRIO_MIN;
981
982  tsparms = (tsparms_t *) pcparms.pc_clparms;
983  scale = ((tsinfo_t *) pcinfo.pc_clinfo)->ts_maxupri;
984  tsparms->ts_uprilim = tsparms->ts_upri = -(scale * prio) / 20;
985  pcparms.pc_cid = pcinfo.pc_cid;
986
987  if (priocntl (P_PID, who, PC_SETPARMS, (caddr_t) & pcparms) == -1)
988    return (-1);
989
990  return (0);
991}
992
993
994get_swapinfo(long *total, long *fr)
995{
996    register int cnt, i;
997    register long t, f;
998    struct swaptable *swt;
999    struct swapent *ste;
1000    static char path[256];
1001
1002    /* get total number of swap entries */
1003    cnt = swapctl(SC_GETNSWP, 0);
1004
1005    /* allocate enough space to hold count + n swapents */
1006    swt = (struct swaptable *)malloc(sizeof(int) +
1007                                     cnt * sizeof(struct swapent));
1008    if (swt == NULL)
1009    {
1010        *total = 0;
1011        *fr = 0;
1012        return;
1013    }
1014    swt->swt_n = cnt;
1015
1016    /* fill in ste_path pointers: we don't care about the paths, so we point
1017       them all to the same buffer */
1018    ste = &(swt->swt_ent[0]);
1019    i = cnt;
1020    while (--i >= 0)
1021    {
1022        ste++->ste_path = path;
1023    }
1024
1025    /* grab all swap info */
1026    swapctl(SC_LIST, swt);
1027
1028    /* walk thru the structs and sum up the fields */
1029    t = f = 0;
1030    ste = &(swt->swt_ent[0]);
1031    i = cnt;
1032    while (--i >= 0)
1033    {
1034        /* dont count slots being deleted */
1035        if (!(ste->ste_flags & ST_INDEL) )
1036        {
1037            t += ste->ste_pages;
1038            f += ste->ste_free;
1039        }
1040        ste++;
1041    }
1042
1043    /* fill in the results */
1044    *total = t;
1045    *fr = f;
1046    free(swt);
1047}
1048
1049
1050/*
1051 * When we reach a proc limit, we need to realloc the stuff.
1052 */
1053static void reallocproc(int n)
1054{
1055    int bytes;
1056    struct oldproc *op, *endbase;
1057
1058    if (n < maxprocs)
1059        return;
1060
1061    maxprocs = n;
1062
1063    /* allocate space for proc structure array and array of pointers */
1064    bytes = maxprocs * sizeof(psinfo_t) ;
1065    pbase = (struct prpsinfo *) realloc(pbase, bytes);
1066    pref = (struct prpsinfo **) realloc(pref,
1067                        maxprocs * sizeof(struct prpsinfo *));
1068
1069    /* Just in case ... */
1070    if (pbase == (struct prpsinfo *) NULL || pref == (struct prpsinfo **) NULL)
1071    {
1072        fprintf (stderr, "%s: can't allocate sufficient memory\n", myname);
1073        quit(1);
1074    }
1075}
1076
1077/* ---------------------------------------------------------------- */
1078/* Access kernel Metrics
1079 * SVR5 uses metreg inteface to Kernel statistics (metrics)
1080 *  see /usr/include/mas.h, /usr/include/metreg.h
1081 */
1082
1083#include <sys/mman.h>
1084#include <sys/dl.h>
1085#include <mas.h>
1086#include <metreg.h>
1087 
1088static int md;         /* metric descriptor handle */   
1089static  uint32 ncpu;   /* number of processors in system */
1090
1091/* fwd dcls */
1092static uint32 kmet_get_cpu( int type, char *desc);
1093static void kmet_verify(
1094    uint32 md,    metid_t id,  units_t units, type_t mettype,
1095    uint32 metsz, uint32 nobj, uint32 nlocs,  resource_t res_id,
1096    uint32 ressz ) ;
1097
1098
1099static int get_cpustates(int *new)
1100{
1101    new[0] = (int)kmet_get_cpu( MPC_CPU_IDLE, "idle");
1102    new[1] = (int)kmet_get_cpu( MPC_CPU_USR,  "usr");
1103    new[2] = (int)kmet_get_cpu( MPC_CPU_SYS,  "sys");
1104    new[3] = (int)kmet_get_cpu( MPC_CPU_WIO,  "wio");
1105}
1106
1107
1108/* initialises kernel metrics access and gets #cpus */
1109static int kmet_init()
1110{
1111    uint32 *ncpu_p;
1112
1113    /*  open (and map in) the metric access file and assoc data structures */
1114    if( ( md = mas_open( MAS_FILE, MAS_MMAP_ACCESS ) ) < 0 )
1115    {
1116        (void)fprintf(stderr,"mas_open failed\n");
1117        mas_perror();
1118        quit(10);
1119    }
1120
1121    /* verify the NCPU metric is everything we expect */
1122    kmet_verify(md, NCPU, CPUS, CONFIGURABLE, sizeof(short),
1123                   1, 1, MAS_SYSTEM, sizeof(uint32) );
1124
1125    /* get the number of cpu's on the system */
1126    if( (ncpu_p = (uint32 *)mas_get_met( md, NCPU, 0 )) == NULL )
1127    {
1128        (void)fprintf(stderr,"mas_get_met of ncpu failed\n"); 
1129        mas_perror();
1130        quit(12);
1131    }
1132    ncpu = (uint32)(*(short *)ncpu_p);
1133
1134    /* check that MPC_CPU_IDLE is of the form we expect
1135     *      ( paranoically we should check the rest as well but ... )
1136     */
1137    kmet_verify( md, MPC_CPU_IDLE, TIX, PROFILE, sizeof(uint32),
1138                    1,  ncpu, NCPU, sizeof(short) );
1139
1140    kmet_verify( md, PROCUSE, PROCESSES, COUNT, sizeof(uint32),
1141                    1,  1, MAS_SYSTEM, sizeof(uint32) );
1142    nproc = kmet_get_nproc();
1143
1144    return 0;
1145}
1146
1147/* done with kernel metrics access */
1148static int
1149kmet_done()
1150{
1151    if ( mas_close( md ) < 0 )
1152    {
1153        (void)fprintf(stderr,"mas_close failed\n");
1154        mas_perror();
1155        quit(14);
1156    }
1157}
1158
1159
1160static uint32
1161kmet_get_cpu( int type, char *desc)
1162{
1163    int i;
1164    uint32 r=0, rtot=0 ;
1165
1166    for (i=0; i <ncpu; i++)
1167    {
1168        r=*(uint32 *)mas_get_met( md, (metid_t)type, 0 );
1169        if ( !r)
1170        {
1171            (void)fprintf(stderr,"mas_get_met of %s failed\n", desc);
1172            mas_perror();
1173            quit(12);
1174        }
1175        rtot += r;      /* sum them for multi cpus */
1176    }
1177    return rtot /* /ncpu */ ;
1178}
1179
1180static int
1181kmet_get_freemem()
1182{
1183    dl_t            *fm_p, fm, fmc, denom;
1184    time_t          td1;
1185    static time_t   td0;
1186    static dl_t     fm_old;
1187   
1188
1189    td1 = time(NULL);
1190    if ((fm_p = (dl_t *)mas_get_met( md, FREEMEM, 0 )) == NULL )
1191    {
1192        (void)fprintf(stderr,"mas_get_met of freemem failed\n");
1193        mas_perror();
1194        quit(12);
1195    }
1196    fm = *fm_p;
1197   
1198    denom.dl_hop = 0;
1199    denom.dl_lop = (long) (td1 - td0);
1200    td0 = td1;
1201
1202    /* calculate the freemem difference divided by the time diff
1203     * giving the freemem in that time sample
1204     *  (new - old) / (time_between_samples)
1205     */
1206    fmc = lsub(fm, fm_old);
1207    fm_old = fm;
1208
1209    fmc = ldivide(fmc, denom);
1210    return  fmc.dl_lop;
1211}
1212
1213/*
1214 * return # of processes currently executing on system
1215 */
1216static int
1217kmet_get_nproc()
1218{
1219    uint32 *p;
1220    if ((p = (uint32 *)mas_get_met( md, PROCUSE, 0 )) == NULL )
1221    {
1222        (void)fprintf(stderr,"mas_get_met of procuse failed\n");
1223        mas_perror();
1224        quit(11);
1225    }
1226    nproc = (int)*p;
1227}
1228
1229
1230/*
1231 * Function:    kmet_verify
1232 * renamed from mas_usrtime example verify_met() fm Doug Souders
1233 *
1234 * Description: Verify the registration data associated with this metric
1235 *              match what are expected.  Cautious consumer applications
1236 *              should do this sort of verification before using metrics.
1237 */
1238static void
1239kmet_verify(
1240     uint32     md,         /* metric descriptor                */
1241     metid_t    id,         /* metric id number                 */
1242     units_t    units,      /* expected units of metric         */
1243     type_t     mettype,    /* expected type of metric          */
1244     uint32     metsz,      /* expected object size of metric   */
1245     uint32     nobj,       /* expected number of array elements */
1246     uint32     nlocs,      /* expected number of instances     */
1247     resource_t res_id,     /* expected resource id number      */
1248     uint32     ressz       /* expected resource object size    */
1249     )
1250{
1251
1252    char                *name;          /* the name of the metric       */
1253    units_t             *units_p;       /* the units of the metric      */
1254    type_t              *mettype_p;     /* type field of the metric     */
1255    uint32              *objsz_p;       /* size of each element in met  */
1256    uint32              *nobj_p;        /* num of elements >1 then array*/
1257    uint32              *nlocs_p;       /* total number of instances    */
1258    uint32              *status_p;      /* status word (update|avail)   */
1259    resource_t          *resource_p;    /* the resource list of the met */
1260    uint32              *resval_p;      /* pointer to resource          */
1261    uint32              *ressz_p;       /* size of the resource met     */
1262
1263    if (!(name = mas_get_met_name( md, id )))
1264    {
1265            (void)fprintf(stderr,"mas_get_met_name failed\n");
1266            mas_perror();
1267            quit(11);
1268    }
1269   
1270    if (!(status_p = mas_get_met_status( md, id )))
1271    {
1272            (void)fprintf(stderr,"mas_get_met_status of %s failed\n",
1273                name );
1274            mas_perror();
1275            quit(11);
1276    }
1277    if ( *status_p != MAS_AVAILABLE )
1278    {
1279        (void)fprintf(stderr,"unexpected status word for %s\n"
1280                                "- expected %u got %u\n",
1281                name, MAS_AVAILABLE, *status_p );
1282        quit(11);
1283    }
1284    if (!(units_p = mas_get_met_units( md, id )))
1285    {
1286            (void)fprintf(stderr,"mas_get_met_units of %s failed\n",
1287                name );
1288            mas_perror();
1289            quit(11);
1290    }
1291    if (units != *units_p )
1292    {
1293            (void)fprintf(stderr,"unexpected units for %s\n"
1294                                    "- expected %u got %u\n",
1295                name, units, *units_p );
1296            quit(11);
1297    }
1298
1299    if (!(mettype_p = mas_get_met_type( md, id )))
1300    {
1301            (void)fprintf(stderr,"mas_get_met_type of %s failed\n",
1302                name );
1303            mas_perror();
1304            quit(11);
1305    }
1306    if (mettype != *mettype_p )
1307    {
1308            (void)fprintf(stderr,"unexpected metric type for %s\n"
1309                                    "- expected %u got %u\n",
1310                name, mettype , *mettype_p );
1311            quit(11);
1312    }
1313
1314    if (!(objsz_p = mas_get_met_objsz( md, id )))
1315    {
1316            (void)fprintf(stderr,"mas_get_met_objsz of %s failed\n", name );
1317            mas_perror();
1318            quit(11);
1319    }
1320    if (*objsz_p != metsz )
1321    {
1322            (void)fprintf(stderr,"unexpected object size for %s\n"
1323                                    "- expected %u got %u\n",
1324                name, metsz, *objsz_p );
1325            quit(11);
1326    }
1327
1328    if (!(nobj_p = mas_get_met_nobj( md, id )))
1329    {
1330            (void)fprintf(stderr,"mas_get_met_nobj of %s failed\n", name );
1331            mas_perror();
1332            quit(11);
1333    }
1334    if (nobj != *nobj_p )
1335    {
1336        (void)fprintf(stderr,"unexpected number of objects for %s\n"
1337                                    "- expected %u got %u\n",
1338                name, nobj, *nobj_p );
1339         quit(11);
1340    }
1341
1342    /* get the number of instances that libmas thinks it knows about  */
1343    if (!(nlocs_p = mas_get_met_nlocs( md, id )))
1344    {
1345        (void)fprintf(stderr,"mas_get_met_nlocs of %s failed\n",  name );
1346        mas_perror();
1347        quit(11);
1348    }
1349    if (nlocs != *nlocs_p )
1350    {
1351        (void)fprintf(stderr,"unexpected number of instances for %s"
1352                        " - expected %u got %u\n",
1353                name, nlocs, *nlocs_p );
1354        quit(11);
1355
1356    }
1357    /*  get the resource list for the metric */
1358    if (!(resource_p = mas_get_met_resources( md, id )))
1359    {
1360        (void)fprintf(stderr,"mas_get_met_resources of %s failed\n", name );
1361        mas_perror();
1362        quit(11);
1363    }
1364    if (*resource_p != res_id )
1365    {
1366        (void)fprintf(stderr,"unexpected resource id for %s\n"
1367                                    "- expected %u got %u\n",
1368                name, res_id, *resource_p);
1369        quit(11);
1370    }
1371    /*  get the size of the resource  */
1372    if (!(ressz_p = mas_get_met_objsz( md, (metid_t)(*resource_p) )))
1373    {
1374        (void)fprintf(stderr,"mas_get_met_objsz of resource failed\n");
1375        mas_perror();
1376        quit(11);
1377    }
1378    if (*ressz_p != ressz )
1379    {
1380        (void)fprintf(stderr,"unexpected resource size for %s\n"
1381                                    "- expected %u got %u\n",
1382                name, ressz, *ressz_p );
1383        quit(11);
1384    }
1385/*
1386 *      get the address of the resource
1387 */
1388    if (!(resval_p = (uint32 *)mas_get_met( md, *resource_p, 0 )))
1389    {
1390            (void)fprintf(stderr,"mas_get_met of resource failed\n");
1391            mas_perror();
1392            quit(11);
1393    }
1394    if (ressz == sizeof( short ) )
1395    {
1396        if( (uint32)(*(short *)resval_p) != nlocs )
1397        {
1398            (void)fprintf(stderr,"unexpected resource value for %s\n"
1399                                    "- expected %u got %u\n",
1400                        name, nlocs, (uint32)(*(short *)resval_p) );
1401            quit(11);
1402        }
1403    }
1404    else
1405    { /* assume size of uint32 */
1406        if (*resval_p != nlocs )
1407        {
1408            (void)fprintf(stderr,"unexpected resource value for %s\n"
1409                                    "- expected %u got %u\n",
1410                        name, nlocs, *resval_p );
1411            quit(11);
1412        }
1413    }
1414    return;
1415}
1416
Note: See TracBrowser for help on using the repository browser.