📄 machine.c
字号:
/* * top - a top users display for Unix * * SYNOPSIS: Any Sun running SunOS 5.x (Solaris 2.x) * * DESCRIPTION: * This is the machine-dependent module for SunOS 5.x (Solaris 2). * There is some support for MP architectures. * This makes top work on the following systems: * SunOS 5.0 (not tested) * SunOS 5.1 * SunOS 5.2 * SunOS 5.3 * SunOS 5.4 * SunOS 5.5 * SunOS 5.6 * SunOS 5.7 (beta) * * Tested on a SPARCclassic with SunOS 5.1, using gcc-2.3.3, and * SPARCsystem 600 with SunOS 5.2, using Sun C * * LIBS: -lelf -lkvm -lkstat * * CFLAGS: -DHAVE_GETOPT -DORDER -DHAVE_STRERROR * * * AUTHORS: Torsten Kasch <torsten@techfak.uni-bielefeld.de> * Robert Boucher <boucher@sofkin.ca> * CONTRIBUTORS: Marc Cohen <marc@aai.com> * Charles Hedrick <hedrick@geneva.rutgers.edu> * William L. Jones <jones@chpc> * Petri Kutvonen <kutvonen@cs.helsinki.fi> * Casper Dik <casper.dik@sun.com> * Tim Pugh <tpugh@oce.orst.edu> */#define _KMEMUSER#if (OSREV >= 54)#define SOLARIS24#endif#if (OSREV == 551)#undef OSREV#define OSREV 55#endif#define USE_NEW_PROC#if defined(USE_NEW_PROC) && OSREV >= 56#define _STRUCTURED_PROC 1#define prpsinfo psinfo#include <sys/procfs.h>#define pr_fill pr_nlwp/* These require an ANSI C compiler "Reisser cpp" doesn't like this */#define pr_state pr_lwp.pr_state#define pr_oldpri pr_lwp.pr_oldpri#define pr_nice pr_lwp.pr_nice#define pr_pri pr_lwp.pr_pri#define pr_onpro pr_lwp.pr_onpro#define ZOMBIE(p) ((p)->pr_nlwp == 0)#define SIZE_K(p) ((p)->pr_size)#define RSS_K(p) ((p)->pr_rssize)#else#undef USE_NEW_PROC#define ZOMBIE(p) ((p)->pr_zomb)#define SIZE_K(p) ((p)->pr_bysize/1024)#define RSS_K(p) ((p)->pr_byrssize/1024)#define pr_onpro pr_filler[5]#endif#include "top.h"#include "machine.h"#include "utils.h"#include <stdio.h>#include <fcntl.h>#include <unistd.h>#include <stdlib.h>#include <errno.h>#include <dirent.h>#include <nlist.h>#include <string.h>#include <kvm.h>#include <sys/types.h>#include <sys/param.h>#include <sys/signal.h>#include <sys/fault.h>#include <sys/sysinfo.h>#include <sys/sysmacros.h>#include <sys/syscall.h>#include <sys/user.h>#include <sys/proc.h>#include <sys/procfs.h>#include <sys/vm.h>#include <sys/var.h>#include <sys/cpuvar.h>#include <sys/file.h>#include <sys/time.h>#include <sys/priocntl.h>#include <sys/tspriocntl.h>#include <sys/processor.h>#include <sys/swap.h>#include <vm/anon.h>#include <math.h>#if OSREV >= 53#define USE_KSTAT#endif#ifdef USE_KSTAT#include <kstat.h>/* * Some kstats are fixed at 32 bits, these will be specified as ui32; some * are "natural" size (32 bit on 32 bit Solaris, 64 on 64 bit Solaris * we'll make those unsigned long) * Older Solaris doesn't define KSTAT_DATA_UINT32, those are always 32 bit. */# ifndef KSTAT_DATA_UINT32# define ui32 ul# endif#endif#define UNIX "/dev/ksyms"#define KMEM "/dev/kmem"#define PROCFS "/proc"#define CPUSTATES 5#ifndef PRIO_MIN#define PRIO_MIN -20#endif#ifndef PRIO_MAX#define PRIO_MAX 20#endif#ifndef FSCALE#define FSHIFT 8 /* bits to right of fixed binary point */#define FSCALE (1<<FSHIFT)#endif /* FSCALE */#define loaddouble(la) ((double)(la) / FSCALE)#define dbl_align(x) (((unsigned long)(x)+(sizeof(double)-1)) & \ ~(sizeof(double)-1))#ifdef SOLARIS24 /* * snarfed from <sys/procfs.h>: * The following percent numbers are 16-bit binary * fractions [0 .. 1] with the binary point to the * right of the high-order bit (one == 0x8000) */#define percent_cpu(pp) (((double)pp->pr_pctcpu)/0x8000*100)#define weighted_cpu(pp) (*(double *)dbl_align(pp->pr_filler))#else#define percent_cpu(pp) (*(double *)dbl_align(&pp->pr_filler[0]))#define weighted_cpu(pp) (*(double *)dbl_align(&pp->pr_filler[2]))#endif/* definitions for indices in the nlist array */#define X_V 0#define X_MPID 1#define X_ANONINFO 2#define X_MAXMEM 3#define X_SWAPFS_MINFREE 4#define X_FREEMEM 5#define X_AVAILRMEM 6#define X_AVENRUN 7#define X_CPU 8#define X_NPROC 9#define X_NCPUS 10static struct nlist nlst[] ={ {"v"}, /* 0 */ /* replaced by dynamic allocation */ {"mpid"}, /* 1 */#if OSREV >= 56 /* this structure really has some extra fields, but the first three match */ {"k_anoninfo"}, /* 2 */#else {"anoninfo"}, /* 2 */#endif {"maxmem"}, /* 3 */ /* use sysconf */ {"swapfs_minfree"}, /* 4 */ /* used only w/ USE_ANONINFO */ {"freemem"}, /* 5 */ /* available from kstat >= 2.5 */ {"availrmem"}, /* 6 */ /* available from kstat >= 2.5 */ {"avenrun"}, /* 7 */ /* available from kstat */ {"cpu"}, /* 8 */ /* available from kstat */ {"nproc"}, /* 9 */ /* available from kstat */ {"ncpus"}, /* 10 */ /* available from kstat */ {0}};static unsigned long avenrun_offset;static unsigned long mpid_offset;#ifdef USE_KSTAT#define NO_NPROCstatic kstat_ctl_t *kc = NULL;static kstat_t **cpu_ks;static cpu_stat_t *cpu_stat;#elsestatic unsigned long *cpu_offset;#endifstatic unsigned long nproc_offset;static unsigned long freemem_offset;static unsigned long maxmem_offset;static unsigned long availrmem_offset;static unsigned long swapfs_minfree_offset;static unsigned long anoninfo_offset;static void reallocproc(int n);static int maxprocs;/* get_process_info passes back a handle. This is what it looks like: */struct handle { struct prpsinfo **next_proc;/* points to next valid proc pointer */ int remaining; /* number of pointers remaining */ };/* * Structure for keeping track of CPU times from last time around * the program. We keep these things in a hash table, which is * recreated at every cycle. */struct oldproc { pid_t oldpid; double oldtime; double oldpct; };int oldprocs; /* size of table */#define HASH(x) ((x << 1) % oldprocs)/* * GCC assumes that all doubles are aligned. Unfortunately it * doesn't round up the structure size to be a multiple of 8. * Thus we'll get a coredump when going through array. The * following is a size rounded up to 8. */#define PRPSINFOSIZE dbl_align(sizeof(struct prpsinfo))/* * These definitions control the format of the per-process area */static char header[] =" PID X THR PRI NICE SIZE RES STATE TIME CPU COMMAND";/* 0123456 -- field to fill in starts at header+6 */#define UNAME_START 6#define Proc_format \ "%5d %-8.8s %3d %3d %4d %5s %5s %-5s %6s %5.2f%% %s"/* process state names for the "STATE" column of the display *//* the extra nulls in the string "run" are for adding a slash and the processor number when needed */char *state_abbrev[] ={"", "sleep", "run", "zombie", "stop", "start", "cpu", "swap"};int process_states[8];char *procstatenames[] ={ "", " sleeping, ", " running, ", " zombie, ", " stopped, ", " starting, ", " on cpu, ", " swapped, ", NULL};int cpu_states[CPUSTATES];char *cpustatenames[] ={"idle", "user", "kernel", "iowait", "swap", NULL};#define CPUSTATE_IOWAIT 3#define CPUSTATE_SWAP 4/* these are for detailing the memory statistics */int memory_stats[5];char *memorynames[] ={"K real, ", "K active, ", "K free, ", "K swap in use, ", "K swap free", NULL};/* these are names given to allowed sorting orders -- first is default */char *ordernames[] = {"cpu", "size", "res", "time", NULL};/* forward definitions for comparison functions */int compare_cpu();int compare_size();int compare_res();int compare_time();int (*proc_compares[])() = { compare_cpu, compare_size, compare_res, compare_time, NULL };kvm_t *kd;static DIR *procdir;static int nproc;static int ncpus;/* these are for keeping track of the proc array */static int bytes;static struct prpsinfo *pbase;static struct prpsinfo **pref;static struct oldproc *oldbase;/* pagetok function is really a pointer to an appropriate function */static int pageshift;static int (*p_pagetok) ();#define pagetok(size) ((*p_pagetok)(size))/* useful externals */extern char *myname;extern int check_nlist ();extern int gettimeofday ();extern int getkval ();extern void perror ();extern void getptable ();extern void quit ();extern int nlist ();int pagetok_none(int size){ return(size);}int pagetok_left(int size){ return(size << pageshift);}int pagetok_right(int size){ return(size >> pageshift);}intmachine_init (struct statics *statics){ static struct var v; struct oldproc *op, *endbase; int i;#ifndef USE_KSTAT int offset;#endif /* perform the kvm_open */ kd = kvm_open (NULL, NULL, NULL, O_RDONLY, "top"); /* * turn off super group/user privs - but beware; we might * want the privs back later and we still have a fd to * /dev/kmem open so we can't use setgid()/setuid() as that * would allow a debugger to attach to this process. CD */ setegid(getgid()); seteuid(getuid()); /* super user not needed for NEW_PROC */ /* fill in the statics information */ statics->procstate_names = procstatenames; statics->cpustate_names = cpustatenames; statics->memory_names = memorynames; statics->order_names = ordernames; /* test kvm_open return value */ if (kd == NULL) { perror ("kvm_open");#ifndef USE_KSTAT return (-1);#endif } if (kd) { if (kvm_nlist (kd, nlst) < 0) { perror ("kvm_nlist"); return (-1); } if (check_nlist (nlst) != 0) return (-1); }#ifndef NO_NPROC /* NPROC Tuning parameter for max number of processes */ (void) getkval (nlst[X_V].n_value, &v, sizeof (struct var), nlst[X_V].n_name); nproc = v.v_proc; reallocproc(nproc);#endif /* stash away certain offsets for later use */ mpid_offset = nlst[X_MPID].n_value; nproc_offset = nlst[X_NPROC].n_value; avenrun_offset = nlst[X_AVENRUN].n_value; anoninfo_offset = nlst[X_ANONINFO].n_value; freemem_offset = nlst[X_FREEMEM].n_value; maxmem_offset = nlst[X_MAXMEM].n_value; availrmem_offset = nlst[X_AVAILRMEM].n_value; swapfs_minfree_offset = nlst[X_SWAPFS_MINFREE].n_value;#ifndef USE_KSTAT (void) getkval (nlst[X_NCPUS].n_value, (int *) (&ncpus), sizeof (ncpus), "ncpus"); cpu_offset = (unsigned long *) malloc (ncpus * sizeof (unsigned long)); for (i = offset = 0; i < ncpus; offset += sizeof(unsigned long)) { (void) getkval (nlst[X_CPU].n_value + offset, &cpu_offset[i], sizeof (unsigned long), nlst[X_CPU].n_name ); if (cpu_offset[i] != 0) i++; }#endif /* calculate pageshift value */ i = sysconf(_SC_PAGESIZE); pageshift = 0; while ((i >>= 1) > 0) { pageshift++; } /* calculate an amount to shift to K values */ /* remember that log base 2 of 1024 is 10 (i.e.: 2^10 = 1024) */ pageshift -= 10; /* now determine which pageshift function is appropriate for the result (have to because x << y is undefined for y < 0) */ if (pageshift > 0) { /* this is the most likely */ p_pagetok = pagetok_left; } else if (pageshift == 0) { p_pagetok = pagetok_none; } else { p_pagetok = pagetok_right; pageshift = -pageshift; } if (!(procdir = opendir (PROCFS))) { (void) fprintf (stderr, "Unable to open %s\n", PROCFS); return (-1); } if (chdir (PROCFS)) { /* handy for later on when we're reading it */ (void) fprintf (stderr, "Unable to chdir to %s\n", PROCFS); return (-1); } /* all done! */ return (0); }char *format_header (register char *uname_field){ register char *ptr; ptr = header + UNAME_START; while (*uname_field != '\0') *ptr++ = *uname_field++; return (header);}#ifdef USE_KSTAT#define UPDKCID(nk,ok) \if (nk == -1) { \ perror("kstat_read "); \ quit(1); \} \if (nk != ok)\
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -