📄 m_decosf1.c
字号:
/* * top - a top users display for Unix * * SYNOPSIS: OSF/1, Digital Unix 4.0, Compaq Tru64 5.0 * * DESCRIPTION: * This is the machine-dependent module for DEC OSF/1 and its descendents * It is known to work on OSF/1 1.2, 1.3, 2.0-T3, 3.0, Digital Unix V4.0, * Digital Unix 5.0, and Tru64 5.0. * WARNING: if you use optimization with the standard "cc" compiler that * . comes with V3.0 the resulting executable may core dump. If * . this happens, recompile without optimization. * * LIBS: -lmld -lmach * * CFLAGS: -DHAVE_GETOPT -DORDER * * AUTHOR: Anthony Baxter, <anthony@aaii.oz.au> * Derived originally from m_ultrix, by David S. Comay <dsc@seismo.css.gov>, * although by now there is hardly any of the code from m_ultrix left. * Helped a lot by having the source for syd(1), by Claus Kalle, and * from several people at DEC who helped with providing information on * some of the less-documented bits of the kernel interface. * * Modified: 31-Oct-94, Pat Welch, tpw@physics.orst.edu * changed _mpid to pidtab for compatibility with OSF/1 version 3.0 * * Modified: 13-Dec-94, William LeFebvre, lefebvre@dis.anl.gov * removed used of pidtab (that was bogus) and changed things to * automatically detect the absence of _mpid in the nlist and * recover gracefully---this appears to be the only difference * with 3.0. * * Modified: 3-Mar-00, Rainer Orth <ro@TechFak.Uni-Bielefeld.DE> * added support for sort ordering. *//* * Theory of operation: * * Use Mach calls to build up a structure that contains all the sorts * of stuff normally found in a struct proc in a BSD system. Then * everything else uses this structure. This has major performance wins, * and also should work for future versions of the O/S. */#include <sys/types.h>#include <sys/signal.h>#include <sys/param.h>#include <string.h>#include <sys/user.h>#include <stdio.h>#include <nlist.h>#include <math.h>#include <sys/dir.h>#include <sys/user.h>#include <sys/proc.h>#include <sys/dk.h>#include <sys/vm.h>#include <sys/file.h>#include <sys/time.h>/* #include <machine/pte.h> *//* forward declarations, needed by <net/if.h> included from <sys/table.h> */struct rtentry;struct mbuf;#include <sys/table.h>#include <mach.h>#include <mach/mach_types.h>#include <mach/vm_statistics.h>#include <sys/syscall.h> /* for SYS_setpriority, in setpriority(), below */#include "top.h"#include "machine.h"#include "utils.h"extern int errno, sys_nerr;extern char *sys_errlist[];#define strerror(e) (((e) >= 0 && (e) < sys_nerr) ? sys_errlist[(e)] : "Unknown error")#define VMUNIX "/vmunix"#define KMEM "/dev/kmem"#define MEM "/dev/mem"/* get_process_info passes back a handle. This is what it looks like: */struct handle{ struct osf1_top_proc **next_proc; /* points to next valid proc pointer */ int remaining; /* number of pointers remaining */};/* declarations for load_avg */#include "loadavg.h"/* definitions for indices in the nlist array */#define X_MPID 0static struct nlist nlst[] = { { "_mpid" }, /* 0 */ { 0 }};/* Some versions of OSF/1 don't support reporting of the last PID. This flag indicates whether or not we are reporting the last PID. */static int do_last_pid = 1;/* * These definitions control the format of the per-process area */static char header[] = " PID X 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 %4d %5s %5s %-5s %-6s %5.2f%% %.14s"/* 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. Although OSF/1 doesnt support * multiple processors yet, (and this module _certainly_ doesnt * support it, either, we may as well plan for the future. :-) */char *state_abbrev[] ={ "", "run\0\0\0", "WAIT", "sleep", "sleep", "stop", "halt", "???", "zomb"};static int kmem, mem;/* values that we stash away in _init and use in later routines */static double logcpu;/* these are retrieved from the kernel in _init */static unsigned long proc;static int nproc;static load_avg ccpu;typedef long mtime_t;/* these are offsets obtained via nlist and used in the get_ functions */static unsigned long mpid_offset;/* these are for detailing the process states */int process_states[9];char *procstatenames[] = { "", " running, ", " waiting, ", " sleeping, ", " idle, ", " stopped, ", " halted, ", "", " zombie", NULL};/* these are for detailing the cpu states */int cpu_states[4];char *cpustatenames[] = { "user", "nice", "system", "idle", NULL};long old_cpu_ticks[4];/* these are for detailing the memory statistics */int memory_stats[8];char *memorynames[] = { "Real: ", "K/", "K act/tot ", "Virtual: ", "M/", "M use/tot ", "Free: ", "K", 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};/* these are for getting the memory statistics */static int pageshift; /* log base 2 of the pagesize *//* define pagetok in terms of pageshift */#define pagetok(size) ((size) << pageshift)/* take a process, make it a mach task, and grab all the info out */void do_threads_calculations();/* * Because I dont feel like repeatedly grunging through the kernel with * Mach calls, and I also dont want the horrid performance hit this * would give, I read the stuff I need out, and put in into my own * structure, for later use. */struct osf1_top_proc { size_t p_mach_virt_size; char p_mach_state; int p_flag; fixpt_t p_mach_pct_cpu; /* aka p_pctcpu */ int used_ticks; size_t process_size; pid_t p_pid; uid_t p_ruid; char p_pri; char p_nice; size_t p_rssize; char u_comm[PI_COMLEN + 1];} ;/* these are for keeping track of the proc array */static int bytes;static int pref_len;static struct osf1_top_proc *pbase;static struct osf1_top_proc **pref;/* useful externals */extern int errno;extern char *sys_errlist[];long percentages();machine_init(statics)struct statics *statics;{ register int i = 0; register int pagesize; struct tbl_sysinfo sibuf; if ((kmem = open(KMEM, O_RDONLY)) == -1) { perror(KMEM); return(-1); } if ((mem = open(MEM, O_RDONLY)) == -1) { perror(MEM); return(-1); } /* get the list of symbols we want to access in the kernel */ if (nlist(VMUNIX, nlst) == -1) { perror("TOP(nlist)"); return (-1); } if (nlst[X_MPID].n_type == 0) { /* this kernel has no _mpid, so go without */ do_last_pid = 0; } else { /* stash away mpid pointer for later use */ mpid_offset = nlst[X_MPID].n_value; } /* get the symbol values out of kmem */ nproc = table(TBL_PROCINFO, 0, (struct tbl_procinfo *)NULL, INT_MAX, 0); /* allocate space for proc structure array and array of pointers */ bytes = nproc * sizeof(struct osf1_top_proc); pbase = (struct osf1_top_proc *)malloc(bytes); pref = (struct osf1_top_proc **)malloc(nproc * sizeof(struct osf1_top_proc *)); /* Just in case ... */ if (pbase == (struct osf1_top_proc *)NULL || pref == (struct osf1_top_proc **)NULL) { fprintf(stderr, "top: cannot allocate sufficient memory\n"); return(-1); } /* get the page size with "getpagesize" and calculate pageshift from it */ pagesize = getpagesize(); pageshift = 0; while (pagesize > 1) { pageshift++; pagesize >>= 1; } /* we only need the amount of log(2)1024 for our conversion */ pageshift -= LOG1024; /* fill in the statics information */ statics->procstate_names = procstatenames; statics->cpustate_names = cpustatenames; statics->memory_names = memorynames; statics->order_names = ordernames; /* initialise this, for calculating cpu time */ if (table(TBL_SYSINFO,0,&sibuf,1,sizeof(struct tbl_sysinfo))<0) { perror("TBL_SYSINFO"); return(-1); } old_cpu_ticks[0] = sibuf.si_user; old_cpu_ticks[1] = sibuf.si_nice; old_cpu_ticks[2] = sibuf.si_sys; old_cpu_ticks[3] = sibuf.si_idle; /* all done! */ return(0);}char *format_header(uname_field)register char *uname_field;{ register char *ptr; ptr = header + UNAME_START; while (*uname_field != '\0') { *ptr++ = *uname_field++; } return(header);}void get_system_info(si)struct system_info *si;{ struct tbl_loadavg labuf; struct tbl_sysinfo sibuf; struct tbl_swapinfo swbuf; vm_statistics_data_t vmstats; int swap_pages=0,swap_free=0,i; long new_ticks[4],diff_ticks[4]; long delta_ticks; if (do_last_pid) { /* last pid assigned */ (void) getkval(mpid_offset, &(si->last_pid), sizeof(si->last_pid), "_mpid"); } else { si->last_pid = -1; } /* get load averages */ if (table(TBL_LOADAVG,0,&labuf,1,sizeof(struct tbl_loadavg))<0) { perror("TBL_LOADAVG"); return; } if (labuf.tl_lscale) /* scaled */ for(i=0;i<3;i++) si->load_avg[i] = ((double)labuf.tl_avenrun.l[i] / (double)labuf.tl_lscale ); else /* not scaled */ for(i=0;i<3;i++) si->load_avg[i] = labuf.tl_avenrun.d[i]; /* array of cpu state counters */ if (table(TBL_SYSINFO,0,&sibuf,1,sizeof(struct tbl_sysinfo))<0) { perror("TBL_SYSINFO"); return; } new_ticks[0] = sibuf.si_user ; new_ticks[1] = sibuf.si_nice; new_ticks[2] = sibuf.si_sys ; new_ticks[3] = sibuf.si_idle; delta_ticks=0; for(i=0;i<4;i++) { diff_ticks[i] = new_ticks[i] - old_cpu_ticks[i]; delta_ticks += diff_ticks[i]; old_cpu_ticks[i] = new_ticks[i]; } si->cpustates = cpu_states; if(delta_ticks) for(i=0;i<4;i++) si->cpustates[i] = (int)( ( (double)diff_ticks[i] / (double)delta_ticks ) * 1000 ); /* memory information */ /* this is possibly bogus - we work out total # pages by */ /* adding up the free, active, inactive, wired down, and */ /* zero filled. Anyone who knows a better way, TELL ME! */ /* Change: dont use zero filled. */ (void) vm_statistics(task_self(),&vmstats); /* thanks DEC for the table() command. No thanks at all for */ /* omitting the man page for it from OSF/1 1.2, and failing */ /* to document SWAPINFO in the 1.3 man page. Lets hear it for */ /* include files. */ i=0; while(table(TBL_SWAPINFO,i,&swbuf,1,sizeof(struct tbl_swapinfo))>0) { swap_pages += swbuf.size; swap_free += swbuf.free; i++; } memory_stats[0] = -1; memory_stats[1] = pagetok(vmstats.active_count); memory_stats[2] = pagetok((vmstats.free_count + vmstats.active_count + vmstats.inactive_count + vmstats.wire_count)); memory_stats[3] = -1; memory_stats[4] = pagetok((swap_pages - swap_free))/1024; memory_stats[5] = pagetok(swap_pages)/1024; memory_stats[6] = -1; memory_stats[7] = pagetok(vmstats.free_count); si->memory = memory_stats;}static struct handle handle;caddr_t get_process_info(si, sel, compare)struct system_info *si;struct process_select *sel;int (*compare)();{ register int i; register int total_procs; register int active_procs; register struct osf1_top_proc **prefp; register struct osf1_top_proc *pp; struct tbl_procinfo p_i[8]; int j,k,r; /* these are copied out of sel for speed */ int show_idle; int show_uid; int show_command; /* get a pointer to the states summary array */ si->procstates = process_states; /* set up flags which define what we are going to select */ show_idle = sel->idle; show_uid = sel->uid != -1; show_command = sel->command != NULL; /* count up process states and get pointers to interesting procs */ total_procs = 0; active_procs = 0; memset((char *)process_states, 0, sizeof(process_states)); prefp = pref; pp=pbase; for (j=0; j<nproc; j += 8) { r = table(TBL_PROCINFO, j, (struct tbl_procinfo *)p_i, 8, sizeof(struct tbl_procinfo)); for (k=0; k < r; k++ , pp++) { if(p_i[k].pi_pid == 0) { pp->p_pid = 0; } else { pp->p_pid = p_i[k].pi_pid; pp->p_ruid = p_i[k].pi_ruid; pp->p_flag = p_i[k].pi_flag; pp->p_nice = getpriority(PRIO_PROCESS,p_i[k].pi_pid); /* Load useful values into the proc structure */ do_threads_calculations(pp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -