📄 m_macosx.c
字号:
/* * m_macosx.c * * AUTHOR: Andrew S. Townley * based on m_bsd44.c and m_next32.c * by Christos Zoulas and Tim Pugh * CREATED: Tue Aug 11 01:51:35 CDT 1998 * SYNOPSIS: MacOS X Server (Rhapsody Developer Release 2) * DESCRIPTION: * MacOS X Server (Rhapsody Developer Release 2) * * CFLAGS: -DHAVE_STRERROR * TERMCAP: none * MATH: none *//* * normal stuff */#include <stdio.h>#include <stdarg.h>#include <errno.h>#include "top.h"#include "machine.h"#include "utils.h"/* * MacOS kernel stuff */#include <kvm.h>#include <fcntl.h>#include <sys/dkstat.h>#include <sys/sysctl.h>#include <mach/message.h>#include <mach/vm_statistics.h>#include <mach/mach.h>#define VMUNIX "/mach_kernel"#define MEM "/dev/mem"#define SWAP NULL#define NUM_AVERAGES 3#define LOG1024 10#define MAX_COLS 128#define PP(pp, field) ((pp)->kp_proc . field)#define EP(pp, field) ((pp)->kp_eproc . field)#define VP(pp, field) ((pp)->kp_eproc.e_vm . field)#define MPP(mp, field) (PP((mp)->kproc, field))#define MEP(mp, field) (EP((mp)->kproc, field))#define MVP(mp, field) (VP((mp)->kproc, field))#define TP(mp, field) ((mp)->task_info . field)#define RP(mp, field) ((mp)->thread_summary . field)/* define what weighted cpu is */#define weighted_cpu(pct, s) (s == 0 ? 0.0 : \ ((pct) / (1.0 - exp(s * logcpu)))) /* what we consider to be process size: */#define PROCSIZE(pp) (VP((pp), vm_tsize) + VP((pp), vm_dsize) + VP((pp), vm_ssize))#define TASKSIZE(t) (TP(t, virtual_size) + TP(t, resident_size))#define pctdouble(p) ((double)(p) / FSCALE)/* * globals */static kvm_t *kd = NULL;static int nproc;static int onproc = -1;static int pref_len;static long maxmem;static long hz;static char fmt[MAX_COLS];static double logcpu = 1.0;/* process array stuff */static struct kinfo_proc *kproc_list = NULL;static struct macos_proc *proc_list = NULL;static struct macos_proc **proc_ref = NULL;static int process_states[7];static struct handle handle;/* * The mach information hopefully will not be necessary * when the kvm_* interfaces are supported completely. * * Since we're only concerned with task and thread info * for 'interesting' processes, we're going to only allocate * as many task and thread structures as needed. */static struct task_basic_info *task_list = NULL;/* memory statistics */static int pageshift = 0;static int pagesize = 0;#define pagetok(size) ((size) << pageshift)static int swappgsin = -1;static int swappgsout = -1;static vm_statistics_data_t vm_stats;static int memory_stats[7];/* CPU state percentages */static long cp_time[CPUSTATES];static long cp_old[CPUSTATES];static long cp_diff[CPUSTATES];static int cpu_states[CPUSTATES];/* * types */typedef long pctcpu;//struct statics//{// char **procstate_names;// char **cpustate_names;// char **memory_names;// char **order_names;//};////struct system_info//{// int last_pid;// double load_avg[NUM_AVERAGES];// int p_total; /* total # of processes */// int p_active; /* number processes considered active */// int *procstates;// int *cpustates;// int *memory;//};////struct process_select//{// int idle; /* show idle processes */// int system; /* show system processes */// int uid; /* show only this uid (unless -1) */// char *command; /* only this command (unless NULL) *///};/* * We need to declare a hybrid structure which will store all * of the stuff we care about for each process. */struct macos_proc{ struct kinfo_proc *kproc; task_t the_task; struct task_basic_info task_info; int thread_count; struct thread_basic_info thread_summary;};struct handle{ struct macos_proc **next_proc; int remaining;};static char header[] = " PID X PRI THRD SIZE RES STATE TIME MEM 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%% %5.2f%% %.16s"/* * puke() * * This function is used to report errors to stderr. */static void puke(const char* fmt, ...){ va_list args; va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); fputc('\n', stderr); fflush(stderr);}/* * kread() * * This function is a wrapper for the kvm_read() function * with the addition of a message parameter per kvm_open(). * * All other behavior is per kvm_read except the error reporting. */static ssize_t kread(u_long addr, void *buf, size_t nbytes, const char *errstr){ ssize_t s = 0; s = kvm_read(kd, addr, buf, nbytes); if(s == -1) { puke("error: kvm_read() failed for '%s' (%s)\n", errstr, strerror(errno)); } return s;}/* * prototypes for functions which top needs */char *format_header(register char *uname_field);char *format_next_process(caddr_t handle, char *(*getuserid)());caddr_t get_process_info(struct system_info *si, struct process_select *sel, int (*compare)());int get_system_info(struct system_info *si);int machine_init(struct statics *stat);char *printable();/* * definitions for offsets */#define X_NPROC 0#define X_CP_TIME 1#define X_HZ 2#define X_MAXMEM 3#define NLIST_LAST 4static struct nlist nlst[] ={ { "_maxproc" }, /* 0 *** maximum processes */ { "_cp_time" }, /* 1 */ { "_hz" }, /* 2 */ { "_mem_size" }, /* 3 */ { 0 }};static char *procstates[] ={ "", " starting, ", " running, ", " sleeping, ", " stopped, ", " zombie, ", " swapped ", NULL};static char *cpustates[] ={ "user", "nice", "system", "intr", "idle", NULL};static char *state_abbrev[] ={ "", "start", "run\0\0\0", "sleep", "stop", "zomb"};static char *mach_state[] ={ "", "R", "T", "S", "U", "H"};static char *thread_state[] ={ "", "run\0\0\0", "stop", "wait", "uwait", "halted",};static char *flags_state[] ={ "", "W", "I"};static char *memnames[] ={ "K Tot, ", "K Free, ", "K Act, ", "K Inact, ", "K Wired, ", "K in, ", "K out ", NULL};/* * format_header() * * This function is used to add the username into the * header information. */char *format_header(register char *uname_field){ register char *ptr; ptr = header + UNAME_START; while(*uname_field != NULL) *ptr++ = *uname_field++; return(header);}/* * format_next_process() * * This function actuall is responsible for the formatting of * each row which is displayed. */char *format_next_process(caddr_t handle, char *(*getuserid)()){ register struct macos_proc *pp; register long cputime; register double pct; register int vsize; register int rsize; struct handle *hp; /* * we need to keep track of the next proc structure. */ hp = (struct handle*)handle; pp = *(hp->next_proc++); hp->remaining--; /* * get the process structure and take care of the cputime */ if((MPP(pp, p_flag) & P_INMEM) == 0) { /* we want to print swapped processes as <pname> */ char *comm = MPP(pp, p_comm);#define COMSIZ sizeof(MPP(pp, p_comm)) char buf[COMSIZ]; strncpy(buf, comm, COMSIZ); comm[0] = '<'; strncpy(&comm[1], buf, COMSIZ - 2); comm[COMSIZ - 2] = '\0'; strncat(comm, ">", COMSIZ - 1); comm[COMSIZ - 1] = '\0'; } /* * count the cpu time, but ignore the interrupts * * At the present time (DR2 8/1998), MacOS X doesn't * correctly report this information through the * kinfo_proc structure. We need to get it from the * task threads. * * cputime = PP(pp, p_rtime).tv_sec; */ cputime = RP(pp, user_time).seconds + RP(pp, system_time).seconds; /* * calculate the base cpu percentages * * Again, at the present time, MacOS X doesn't report * this information through the kinfo_proc. We need * to talk to the threads. */// pct = pctdouble(PP(pp, p_pctcpu)); pct = (double)(RP(pp, cpu_usage))/TH_USAGE_SCALE; /* * format the entry */ /* * In the final version, I would expect this to work correctly, * but it seems that not all of the fields in the proc * structure are being used. * * For now, we'll attempt to get some of the things we need * from the mach task info. */ sprintf(fmt, Proc_format, MPP(pp, p_pid), (*getuserid)(MEP(pp, e_pcred.p_ruid)), TP(pp, base_priority), pp->thread_count, format_k(TASKSIZE(pp) / 1024), format_k(pagetok((MVP(pp, vm_rssize)))), state_abbrev[(u_char)MPP(pp, p_stat)], format_time(cputime), 100.0 * TP(pp, resident_size) / maxmem,// 100.0 * weighted_cpu(pct, (RP(pp, user_time).seconds + RP(pp, system_time).seconds)), 100.0 * pct, printable(MPP(pp, p_comm))); return(fmt);}/* * get_process_info() * * This function returns information about the processes * on the system. */caddr_t get_process_info(struct system_info *si, struct process_select *sel, int (*compare)()){ register int i; register int total_procs; register int active_procs; register struct macos_proc **prefp; register struct macos_proc *pp; register struct kinfo_proc *pp2; register struct kinfo_proc **prefp2; register struct thread_basic_info *thread; /* * these are copied out of sel for speed */ int show_idle; int show_system; int show_uid; int show_command; kproc_list = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc); if(nproc > onproc) { proc_list = (struct macos_proc*)realloc(proc_list, sizeof(struct macos_proc) * nproc); proc_ref = (struct macos_proc **)realloc(proc_ref, sizeof(struct macos_proc *) * (onproc = nproc)); } if(proc_ref == NULL || proc_list == NULL || kproc_list == NULL) { puke("error: out of memory (%s)", strerror(errno)); return(NULL); } /* * now, our task is to build the array of information we * need to function correctly. This involves setting a pointer * to each real kinfo_proc structure returned by kvm_getprocs() * in addition to getting the mach information for each of * those processes. */ for(pp2 = kproc_list, i = 0; i < nproc; pp2++, i++) { kern_return_t rc; u_int info_count = TASK_BASIC_INFO_COUNT; /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -