📄 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 all revisions of SunOS 5 from 5.0 * through 5.9 (otherwise known as Solaris 9). It has not been * tested on SunOS 5.10. * * LIBS: -lelf -lkvm -lkstat * * CFLAGS: -DHAVE_GETOPT -DORDER -DHAVE_STRERROR -DUSE_SIZE_T * * * 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 == 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 <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>#include "utils.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#ifdef SC_AINFO#undef USE_ANONINFO /* Use swapctl() instead */#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))#if (OSREV >= 54) /* * 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 */#if OSREV >= 58static char header[] =" PID X LWP PRI NICE SIZE RES STATE TIME CPU COMMAND";/* 0123456 -- field to fill in starts at header+6 */#define UNAME_START 7#define Proc_format \ "%6d %-8.8s %3d %3d %4d %5s %5s %-6s %6s %5.2f%% %s"#elsestatic char header[] =" PID X LWP 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 %-6s %6s %5.2f%% %s"#endif/* process state names for the "STATE" column of the display */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; char *p;#ifndef USE_KSTAT int offset;#endif /* There's a buffer overflow bug in curses that can be exploited when we run as root. By making sure that TERMINFO is set to something this bug is avoided. This code thanks to Casper */ if ((p = getenv("TERMINFO")) == NULL || *p == '\0') { putenv("TERMINFO=/usr/share/lib/terminfo/"); } /* perform the kvm_open - suppress error here */ kd = kvm_open (NULL, NULL, NULL, O_RDONLY, NULL); /* * 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 - print error message and exit * when we need to read kernel memory (older releases) */ if (kd == NULL) {#ifndef USE_KSTAT /* Print the failure message here */ (void) kvm_open (NULL, NULL, NULL, O_RDONLY, "top"); perror("kvm_open"); 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)\ goto kcid_changed;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -