This is m_dgux.c in view mode; [Download] [Up]
/* * top - a top users display for Unix * * SYNOPSIS: for DG AViiON with DG/UX 5.4+ * * DESCRIPTION: * A top module for DG/UX 5.4 systems. * Uses DG/UX system calls to get info from the kernel. * (NB. top DOES NOT need to be installed setuid root under DG/UX 5.4.2) * * AUTHOR: Mike Williams <mike@inform.co.nz> */ /* * NOTE: This module will only work with top versions 3.1 and later! */ #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <sys/dg_sys_info.h> #include <sys/dg_process_info.h> #include <sys/systeminfo.h> #include <sys/sysmacros.h> #include "top.h" #include "machine.h" #include "utils.h" /*--- process formatting --------------------------------------------------*/ static char header[] = " PID X PRI NICE C SIZE STATE TIME CPU COMMAND"; /* ddddd ssssssss dddd ddd dd ddddddK ssssssdddd:dd dd.dd% sssssssssssssssss... * 0123456 -- field to fill in starts at header+6 */ #define UNAME_START 6 #define Proc_format \ "%5d %-8.8s %4d %3d %2d %7s %-6s %6s %5.2f%% %.20s" /*--- process states ------------------------------------------------------*/ static char* procStateNames[] = { "", " sleeping, ", " waiting, ", " running, ", " starting, ", " zombie, ", " stopped, ", NULL }; static char* procStateAbbrevs[] = { "", "sleep", "wait", "run", "start", "zombie", "stop", NULL }; #define N_PROCESS_STATES \ (sizeof (procStateNames) / sizeof (procStateNames[0]) - 1) static int processStats[N_PROCESS_STATES]; /*--- cpu states ----------------------------------------------------------*/ enum { CPU_user, CPU_system, CPU_idle, CPU_io_wait, }; static char* cpuStateNames[] = { "user", "system", "idle", "io_wait", NULL }; #define N_CPU_STATES \ (sizeof (cpuStateNames) / sizeof (cpuStateNames[0]) - 1) static int cpuStats[N_CPU_STATES]; /*--- memory statistics ---------------------------------------------------*/ enum { MEM_available, MEM_used, MEM_free, MEM_freeswap, }; static char* memoryNames[] = { "K physical, ", "K in use, ", "K free, ", "K free swap, ", NULL }; #define N_MEMORY_STATS \ (sizeof (memoryNames) / sizeof (memoryNames[0]) - 1) static int memoryStats[N_MEMORY_STATS]; /*--- conversion macros ---------------------------------------------------*/ /* Convert clicks (kernel pages) to kbytes ... */ #define pagetok(size) ctob(size) >> LOG1024 /* Convert timeval's to double */ #define tvtod(tval) (1000000.0 * (tval).tv_sec + 1.0 * (tval).tv_usec) /* Scale timeval's onto longs */ #define scaledtv(tval) (tvtod (tval) / 4096) /*--- process table -------------------------------------------------------*/ typedef struct _ProcInfo { struct dg_process_info p_info; double cpu_time; double fraction_cpu; } ProcInfo; static ProcInfo* processInfo; static ProcInfo** activeProcessInfo; int activeIndex; typedef struct _ProcTime { pid_t pid; double cpu_time; } ProcTime; static ProcTime* oldProcessTimes; static int n_oldProcessTimes; static double lastTime; static double thisTime; static double timeSlice; /*=========================================================================*/ /*=== top "Callback" routines =============================================*/ static int IntCmp (i1, i2) int* i1; int* i2; { return (*i2 - *i1); } /*=== Data collection =====================================================*/ int machine_init (statics) /*~~~~~~~~~~~~ */ struct statics *statics; { struct dg_sys_info_pm_info pm_info; int table_size; /* fill in the statics information */ statics->procstate_names = procStateNames; statics->cpustate_names = cpuStateNames; statics->memory_names = memoryNames; dg_sys_info ((long *)&pm_info, DG_SYS_INFO_PM_INFO_TYPE, DG_SYS_INFO_PM_VERSION_0); table_size = pm_info.process_table_size + 1; processInfo = (ProcInfo *) malloc (sizeof (processInfo[0]) * table_size); activeProcessInfo = (ProcInfo **) malloc (sizeof (activeProcessInfo[0]) * table_size); oldProcessTimes = (ProcTime *) malloc (sizeof (oldProcessTimes[0]) * table_size); lastTime = 0; return(0); } int get_system_info (si) /*~~~~~~~~~~~~~~~ */ struct system_info *si; { struct dg_sys_info_vm_info vm_info; struct dg_sys_info_pm_info pm_info; struct dg_sys_info_load_info load_info; static long cpu_time [N_CPU_STATES]; static long cpu_old [N_CPU_STATES]; static long cpu_diff [N_CPU_STATES]; /* memory info */ dg_sys_info ((long *)&vm_info, DG_SYS_INFO_VM_INFO_TYPE, DG_SYS_INFO_VM_VERSION_0); memoryStats[MEM_available] = sysconf (_SC_AVAILMEM); memoryStats[MEM_free] = pagetok (vm_info.freemem); memoryStats[MEM_used] = memoryStats[0] - memoryStats[2]; memoryStats[MEM_freeswap] = pagetok (vm_info.freeswap); si->memory = memoryStats; /* process info */ dg_sys_info ((long *)&pm_info, DG_SYS_INFO_PM_INFO_TYPE, DG_SYS_INFO_PM_VERSION_0); si->last_pid = 0; si->p_total = pm_info.process_count; si->p_active = pm_info.bound_runnable_process_count; cpu_time[CPU_user] = scaledtv (pm_info.user_time); cpu_time[CPU_system] = scaledtv (pm_info.system_time); cpu_time[CPU_idle] = scaledtv (pm_info.idle_time); cpu_time[CPU_io_wait] = scaledtv (pm_info.io_wait_time); percentages (N_CPU_STATES, cpuStats, cpu_time, cpu_old, cpu_diff); si->cpustates = cpuStats; /* calculate timescale */ thisTime = tvtod (pm_info.current_time); timeSlice = thisTime - lastTime; lastTime = thisTime; /* load info */ dg_sys_info ((long *)&load_info, DG_SYS_INFO_LOAD_INFO_TYPE, DG_SYS_INFO_LOAD_VERSION_0); si->load_avg[0] = load_info.one_minute; si->load_avg[1] = load_info.five_minute; si->load_avg[2] = load_info.fifteen_minute; return 1; } caddr_t get_process_info (si, sel, compare) /* ~~~~~~~~~~~~~~~~ */ struct system_info* si; struct process_select* sel; int (*compare)(); { long key = DG_PROCESS_INFO_INITIAL_KEY; int n_total = 0; int n_active = 0; ProcInfo* pp; int i; bzero((char *)processStats, sizeof(processStats)); while (dg_process_info (DG_PROCESS_INFO_SELECTOR_ALL_PROCESSES, 0, DG_PROCESS_INFO_CMD_NAME_ONLY, &key, &(processInfo[n_total].p_info), DG_PROCESS_INFO_CURRENT_VERSION) == 1) { ProcInfo* pp = &(processInfo[n_total++]); int pid = pp->p_info.process_id; ProcTime* old_time; /* Increment count for this process state */ ++processStats[pp->p_info.state]; /* Calculate % CPU usage */ pp->cpu_time = (tvtod (pp->p_info.system_time) + tvtod (pp->p_info.user_time)); old_time = (ProcTime *) bsearch (&pid, oldProcessTimes, n_oldProcessTimes, sizeof (ProcTime), IntCmp); pp->fraction_cpu = (old_time ? ((pp->cpu_time - old_time->cpu_time) / timeSlice) : 0.0); /* Skip if process not classed as "active" */ if ((pp->p_info.state == DG_PROCESS_INFO_STATUS_TERMINATED) || (!sel->idle && (pp->p_info.state != DG_PROCESS_INFO_STATUS_RUNNING) && (pp->p_info.state != DG_PROCESS_INFO_STATUS_WAITING)) || (sel->uid != -1 && pp->p_info.user_id != (uid_t)sel->uid) || (!sel->system && (pp->p_info.user_id == 0 && pp->p_info.parent_process_id == 1)) || (sel->command && strcmp (pp->p_info.cmd, sel->command) != 0)) continue; activeProcessInfo[n_active++] = pp; } activeProcessInfo[n_active] = NULL; si->p_total = n_total; si->p_active = n_active; si->procstates = processStats; /* If requested, sort the "interesting" processes */ if (compare != NULL) qsort((void *)activeProcessInfo, n_active, sizeof (ProcInfo *), compare); /* Record scaled CPU totals, for calculating %CPU */ n_oldProcessTimes = n_total; for (i = 0; i < n_oldProcessTimes; i++) { oldProcessTimes[i].pid = processInfo[i].p_info.process_id; oldProcessTimes[i].cpu_time = processInfo[i].cpu_time; } qsort (oldProcessTimes, n_oldProcessTimes, sizeof (ProcTime), IntCmp); /* pass back a handle */ activeIndex = 0; return ((caddr_t) &activeIndex); } /*=== Process comparison routine ==========================================*/ /* * Sort keys are (in descending order of importance): * - percent cpu * - cpu ticks * - state * - resident set size * * The process states are ordered as follows: * - zombie * - wait * - sleep * - stop * - start * - run */ static unsigned char sortedState[] = { 0, /* not used */ 3, /* sleep */ 1, /* wait */ 6, /* run */ 5, /* start */ 2, /* zombie */ 4, /* stop */ }; int proc_compare(pp1, pp2) /*~~~~~~~~~~~~ */ ProcInfo** pp1; ProcInfo** pp2; { register ProcInfo* p1; register ProcInfo* p2; register int result; register float lresult; register long p1_cpu; register long p2_cpu; /* remove one level of indirection */ p1 = *pp1; p2 = *pp2; /* calculate cpu totals */ p1_cpu = p1->p_info.system_time.tv_sec + p1->p_info.user_time.tv_sec; p2_cpu = p2->p_info.system_time.tv_sec + p2->p_info.user_time.tv_sec; /* Compare %CPU usage */ if ((lresult = (p2->fraction_cpu - p1->fraction_cpu)) != 0) return lresult < 0 ? -1 : 1; /* Compare other fields until one differs */ ((result = (p2->p_info.cpu_usage - p1->p_info.cpu_usage)) || (result = (sortedState [p2->p_info.state] - sortedState [p1->p_info.state])) || (result = (p2->p_info.priority - p1->p_info.priority)) || (result = (p2->p_info.resident_process_size - p1->p_info.resident_process_size)) || (result = (p1->p_info.process_id - p2->p_info.process_id))); return result; } /*=== Process owner validation ============================================*/ /* * proc_owner(pid) - returns the uid that owns process "pid", or -1 if * the process does not exist. * It is EXTREMLY IMPORTANT that this function work correctly. * If top runs setuid root (as in SVR4), then this function * is the only thing that stands in the way of a serious * security problem. It validates requests for the "kill" * and "renice" commands. */ int proc_owner (pid) /*~~~~~~~~~~ */ int pid; { register int i; ProcInfo* pp; for (i = 0; (pp = activeProcessInfo [i]); i++) { if (pp->p_info.process_id == pid) return (int)pp->p_info.user_id; } return(-1); } /*=== Output formatting ===================================================*/ 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); } char* format_next_process (index_ptr, get_userid) /* ~~~~~~~~~~~~~~~~~~~ */ int* index_ptr; char* (*get_userid)(); { static char fmt[MAX_COLS]; int proc_index; ProcInfo* pp; long proc_cpu; proc_index = (*index_ptr)++; pp = activeProcessInfo [proc_index]; proc_cpu = pp->p_info.system_time.tv_sec + pp->p_info.user_time.tv_sec; /* format this entry */ sprintf (fmt, Proc_format, pp->p_info.process_id, (*get_userid) (pp->p_info.user_id), pp->p_info.priority, pp->p_info.nice_value, pp->p_info.cpu_usage, format_k(pagetok (pp->p_info.resident_process_size)), procStateAbbrevs[pp->p_info.state], format_time(proc_cpu), 100.0 * pp->fraction_cpu, pp->p_info.cmd); return(fmt); } /*=== END of m_dgux.c =====================================================*/
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.