source: trunk/third/top/machine/m_dgux.c @ 9084

Revision 9084, 12.0 KB checked in by ghudson, 28 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r9083, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * top - a top users display for Unix
3 *
4 * SYNOPSIS:  for DG AViiON with DG/UX 5.4+
5 *
6 * DESCRIPTION:
7 * A top module for DG/UX 5.4 systems.
8 * Uses DG/UX system calls to get info from the kernel.
9 * (NB. top DOES NOT need to be installed setuid root under DG/UX 5.4.2)
10 *
11 * AUTHOR:  Mike Williams <mike@inform.co.nz>
12 */
13
14/*
15 * NOTE: This module will only work with top versions 3.1 and later!
16 */
17
18#include <stdlib.h>
19#include <unistd.h>
20#include <stdio.h>
21
22#include <sys/dg_sys_info.h>
23#include <sys/dg_process_info.h>
24#include <sys/systeminfo.h>
25#include <sys/sysmacros.h>
26
27#include "top.h"
28#include "machine.h"
29#include "utils.h"
30
31/*--- process formatting --------------------------------------------------*/
32
33static char header[] =
34  "  PID X         PRI NICE C    SIZE STATE    TIME    CPU COMMAND";
35/* ddddd ssssssss dddd ddd dd ddddddK ssssssdddd:dd dd.dd% sssssssssssssssss...
36 * 0123456   -- field to fill in starts at header+6 */
37#define UNAME_START 6
38
39#define Proc_format \
40     "%5d %-8.8s %4d %3d %2d %7s %-6s %6s %5.2f%% %.20s"
41
42/*--- process states ------------------------------------------------------*/
43
44static char* procStateNames[] = {
45    "", " sleeping, ", " waiting, ", " running, ", " starting, ",
46    " zombie, ", " stopped, ",
47    NULL
48};
49
50static char* procStateAbbrevs[] = {
51    "", "sleep", "wait", "run", "start", "zombie", "stop",
52    NULL
53};
54
55#define N_PROCESS_STATES \
56(sizeof (procStateNames) / sizeof (procStateNames[0]) - 1)
57
58static int processStats[N_PROCESS_STATES];
59
60/*--- cpu states ----------------------------------------------------------*/
61
62enum {
63    CPU_user,
64    CPU_system,
65    CPU_idle,
66    CPU_io_wait,
67};
68
69static char* cpuStateNames[] = {
70    "user", "system", "idle", "io_wait",
71    NULL
72};
73
74#define N_CPU_STATES \
75(sizeof (cpuStateNames) / sizeof (cpuStateNames[0]) - 1)
76
77static int cpuStats[N_CPU_STATES];
78
79/*--- memory statistics ---------------------------------------------------*/
80
81enum {
82    MEM_available,
83    MEM_used,
84    MEM_free,
85    MEM_freeswap,
86};
87
88static char* memoryNames[] = {
89    "K physical, ", "K in use, ", "K free, ", "K free swap, ", NULL
90};
91
92#define N_MEMORY_STATS \
93(sizeof (memoryNames) / sizeof (memoryNames[0]) - 1)
94
95static int memoryStats[N_MEMORY_STATS];
96
97/*--- conversion macros ---------------------------------------------------*/
98
99/* Convert clicks (kernel pages) to kbytes ... */
100#define pagetok(size) ctob(size) >> LOG1024
101
102/* Convert timeval's to double */
103#define tvtod(tval) (1000000.0 * (tval).tv_sec + 1.0 * (tval).tv_usec)
104
105/* Scale timeval's onto longs */
106#define scaledtv(tval) (tvtod (tval) / 4096)
107
108/*--- process table -------------------------------------------------------*/
109
110typedef struct _ProcInfo {
111    struct dg_process_info    p_info;
112    double                    cpu_time;
113    double                    fraction_cpu;
114} ProcInfo;
115
116static ProcInfo*              processInfo;
117static ProcInfo**             activeProcessInfo;
118
119int                           activeIndex;
120
121typedef struct _ProcTime {
122    pid_t                     pid;
123    double                    cpu_time;
124} ProcTime;
125
126static ProcTime*              oldProcessTimes;
127static int                    n_oldProcessTimes;
128
129static double                 lastTime;
130static double                 thisTime;
131static double                 timeSlice;
132
133/*=========================================================================*/
134/*=== top "Callback" routines =============================================*/
135
136static int IntCmp (i1, i2)
137  int*                  i1;
138  int*                  i2;
139{
140    return (*i2 - *i1);
141}
142
143/*=== Data collection =====================================================*/
144
145int machine_init (statics)
146  /*~~~~~~~~~~~~
147   */
148  struct statics *statics;
149{
150    struct dg_sys_info_pm_info pm_info;
151    int                       table_size;
152
153    /* fill in the statics information */
154    statics->procstate_names = procStateNames;
155    statics->cpustate_names = cpuStateNames;
156    statics->memory_names = memoryNames;
157
158    dg_sys_info ((long *)&pm_info,
159                 DG_SYS_INFO_PM_INFO_TYPE,
160                 DG_SYS_INFO_PM_VERSION_0);
161    table_size = pm_info.process_table_size + 1;
162
163    processInfo = (ProcInfo *)
164        malloc (sizeof (processInfo[0]) * table_size);
165    activeProcessInfo = (ProcInfo **)
166        malloc (sizeof (activeProcessInfo[0]) * table_size);
167    oldProcessTimes = (ProcTime *)
168        malloc (sizeof (oldProcessTimes[0]) * table_size);
169
170    lastTime = 0;
171
172    return(0);
173}
174
175int get_system_info (si)
176  /*~~~~~~~~~~~~~~~
177   */
178  struct system_info *si;
179{
180    struct dg_sys_info_vm_info    vm_info;
181    struct dg_sys_info_pm_info    pm_info;
182    struct dg_sys_info_load_info  load_info;
183
184    static long cpu_time [N_CPU_STATES];
185    static long cpu_old [N_CPU_STATES];
186    static long cpu_diff [N_CPU_STATES];
187
188    /* memory info */
189   
190    dg_sys_info ((long *)&vm_info,
191                 DG_SYS_INFO_VM_INFO_TYPE,
192                 DG_SYS_INFO_VM_VERSION_0);
193
194    memoryStats[MEM_available] = sysconf (_SC_AVAILMEM);
195    memoryStats[MEM_free]      = pagetok (vm_info.freemem);
196    memoryStats[MEM_used]      = memoryStats[0] - memoryStats[2];
197    memoryStats[MEM_freeswap]  = pagetok (vm_info.freeswap);
198    si->memory                 = memoryStats;
199
200    /* process info */
201   
202    dg_sys_info ((long *)&pm_info,
203                 DG_SYS_INFO_PM_INFO_TYPE,
204                 DG_SYS_INFO_PM_VERSION_0);
205
206    si->last_pid              = 0;
207    si->p_total               = pm_info.process_count;
208    si->p_active              = pm_info.bound_runnable_process_count;
209
210    cpu_time[CPU_user]        = scaledtv (pm_info.user_time);
211    cpu_time[CPU_system]      = scaledtv (pm_info.system_time);
212    cpu_time[CPU_idle]        = scaledtv (pm_info.idle_time);
213    cpu_time[CPU_io_wait]     = scaledtv (pm_info.io_wait_time);
214    percentages (N_CPU_STATES, cpuStats, cpu_time, cpu_old, cpu_diff);
215    si->cpustates             = cpuStats;
216
217    /* calculate timescale */
218
219    thisTime = tvtod (pm_info.current_time);
220    timeSlice = thisTime - lastTime;
221    lastTime = thisTime;
222   
223    /* load info */
224   
225    dg_sys_info ((long *)&load_info,
226                 DG_SYS_INFO_LOAD_INFO_TYPE,
227                 DG_SYS_INFO_LOAD_VERSION_0);
228
229    si->load_avg[0]     = load_info.one_minute;
230    si->load_avg[1]     = load_info.five_minute;
231    si->load_avg[2]     = load_info.fifteen_minute;
232
233    return 1;
234}
235
236caddr_t get_process_info (si, sel, compare)
237  /*    ~~~~~~~~~~~~~~~~
238   */
239  struct system_info*   si;
240  struct process_select* sel;
241  int                   (*compare)();
242{
243    long                key = DG_PROCESS_INFO_INITIAL_KEY;
244                       
245    int                 n_total = 0;
246    int                 n_active = 0;
247
248    ProcInfo*           pp;
249    int                 i;
250
251    bzero((char *)processStats, sizeof(processStats));
252
253    while (dg_process_info (DG_PROCESS_INFO_SELECTOR_ALL_PROCESSES, 0,
254                            DG_PROCESS_INFO_CMD_NAME_ONLY,
255                            &key,
256                            &(processInfo[n_total].p_info),
257                            DG_PROCESS_INFO_CURRENT_VERSION) == 1) {
258
259        ProcInfo*       pp = &(processInfo[n_total++]);
260        int             pid = pp->p_info.process_id;
261        ProcTime*       old_time;
262
263        /* Increment count for this process state */
264        ++processStats[pp->p_info.state];
265
266        /* Calculate % CPU usage */
267        pp->cpu_time = (tvtod (pp->p_info.system_time) +
268                        tvtod (pp->p_info.user_time));
269        old_time = (ProcTime *)
270            bsearch (&pid, oldProcessTimes,
271                     n_oldProcessTimes, sizeof (ProcTime),
272                     IntCmp);
273        pp->fraction_cpu = (old_time
274                            ? ((pp->cpu_time - old_time->cpu_time)
275                               / timeSlice)
276                            : 0.0);
277
278        /* Skip if process not classed as "active" */
279        if ((pp->p_info.state == DG_PROCESS_INFO_STATUS_TERMINATED) ||
280            (!sel->idle
281             && (pp->p_info.state != DG_PROCESS_INFO_STATUS_RUNNING)
282             && (pp->p_info.state != DG_PROCESS_INFO_STATUS_WAITING)) ||
283            (sel->uid != -1 && pp->p_info.user_id != (uid_t)sel->uid) ||
284            (!sel->system && (pp->p_info.user_id == 0 &&
285                             pp->p_info.parent_process_id == 1)) ||
286            (sel->command && strcmp (pp->p_info.cmd, sel->command) != 0))
287            continue;
288
289        activeProcessInfo[n_active++] = pp;
290       
291    }
292
293    activeProcessInfo[n_active] = NULL;
294
295    si->p_total         = n_total;
296    si->p_active        = n_active;
297    si->procstates      = processStats;
298
299    /* If requested, sort the "interesting" processes */
300    if (compare != NULL) qsort((void *)activeProcessInfo,
301                               n_active,
302                               sizeof (ProcInfo *),
303                               compare);
304
305    /* Record scaled CPU totals, for calculating %CPU */
306    n_oldProcessTimes = n_total;
307    for (i = 0; i < n_oldProcessTimes; i++) {
308        oldProcessTimes[i].pid = processInfo[i].p_info.process_id;
309        oldProcessTimes[i].cpu_time = processInfo[i].cpu_time;
310    }
311    qsort (oldProcessTimes, n_oldProcessTimes, sizeof (ProcTime), IntCmp);
312
313    /* pass back a handle */
314    activeIndex = 0;
315    return ((caddr_t) &activeIndex);
316}
317
318/*=== Process comparison routine ==========================================*/
319
320/*
321 * Sort keys are (in descending order of importance):
322 *     - percent cpu
323 *     - cpu ticks
324 *     - state
325 *     - resident set size
326 *     
327 * The process states are ordered as follows:
328 *     - zombie
329 *     - wait
330 *     - sleep
331 *     - stop
332 *     - start
333 *     - run
334 */
335
336static unsigned char sortedState[] =
337{
338    0,                                  /* not used */
339    3,                                  /* sleep */
340    1,                                  /* wait */
341    6,                                  /* run */
342    5,                                  /* start */
343    2,                                  /* zombie */
344    4,                                  /* stop */
345};
346
347int proc_compare(pp1, pp2)
348  /*~~~~~~~~~~~~
349   */
350  ProcInfo**            pp1;
351  ProcInfo**            pp2;
352{
353    register ProcInfo*  p1;
354    register ProcInfo*  p2;
355    register int        result;
356    register float      lresult;
357
358    register long       p1_cpu;
359    register long       p2_cpu;
360
361    /* remove one level of indirection */
362    p1 = *pp1;
363    p2 = *pp2;
364
365    /* calculate cpu totals */
366    p1_cpu = p1->p_info.system_time.tv_sec + p1->p_info.user_time.tv_sec;
367    p2_cpu = p2->p_info.system_time.tv_sec + p2->p_info.user_time.tv_sec;
368
369    /* Compare %CPU usage */
370    if ((lresult = (p2->fraction_cpu - p1->fraction_cpu)) != 0)
371        return lresult < 0 ? -1 : 1;
372
373    /* Compare other fields until one differs */
374    ((result = (p2->p_info.cpu_usage - p1->p_info.cpu_usage)) ||
375     (result = (sortedState [p2->p_info.state] -
376                sortedState [p1->p_info.state])) ||
377     (result = (p2->p_info.priority - p1->p_info.priority)) ||
378     (result = (p2->p_info.resident_process_size -
379                p1->p_info.resident_process_size)) ||
380     (result = (p1->p_info.process_id - p2->p_info.process_id)));
381
382    return result;
383}
384
385/*=== Process owner validation ============================================*/
386
387/*
388 * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
389 *              the process does not exist.
390 *              It is EXTREMLY IMPORTANT that this function work correctly.
391 *              If top runs setuid root (as in SVR4), then this function
392 *              is the only thing that stands in the way of a serious
393 *              security problem.  It validates requests for the "kill"
394 *              and "renice" commands.
395 */
396
397int proc_owner (pid)
398  /*~~~~~~~~~~
399   */
400  int pid;
401{
402    register int      i;
403    ProcInfo*         pp;
404
405    for (i = 0; (pp = activeProcessInfo [i]); i++) {
406        if (pp->p_info.process_id == pid)
407            return (int)pp->p_info.user_id;
408    }
409    return(-1);
410}
411
412/*=== Output formatting ===================================================*/
413
414char* format_header (uname_field)
415  /*  ~~~~~~~~~~~~~
416   */
417  register char*        uname_field;
418{
419    register char*      ptr;
420
421    ptr = header + UNAME_START;
422    while (*uname_field != '\0')
423    {
424        *ptr++ = *uname_field++;
425    }
426
427    return(header);
428}
429
430char* format_next_process (index_ptr, get_userid)
431  /*  ~~~~~~~~~~~~~~~~~~~
432   */
433  int*                  index_ptr;
434  char*                 (*get_userid)();
435{
436    static char         fmt[MAX_COLS];
437
438    int                 proc_index;
439    ProcInfo*           pp;
440    long                proc_cpu;
441
442    proc_index = (*index_ptr)++;
443    pp = activeProcessInfo [proc_index];
444    proc_cpu = pp->p_info.system_time.tv_sec + pp->p_info.user_time.tv_sec;
445
446    /* format this entry */
447
448    sprintf (fmt,
449             Proc_format,
450             pp->p_info.process_id,
451             (*get_userid) (pp->p_info.user_id),
452             pp->p_info.priority,
453             pp->p_info.nice_value,
454             pp->p_info.cpu_usage,
455             format_k(pagetok (pp->p_info.resident_process_size)),
456             procStateAbbrevs[pp->p_info.state],
457             format_time(proc_cpu),
458             100.0 * pp->fraction_cpu,
459             pp->p_info.cmd);
460   
461    return(fmt);
462}
463
464/*=== END of m_dgux.c =====================================================*/
Note: See TracBrowser for help on using the repository browser.