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.