Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / top / dist / machine / m_decosf1.c
blob4fd0dabef7811cd08c5c01dc5e72c0c1c0e9770a
1 /*
2 * Copyright (c) 1984 through 2008, William LeFebvre
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
16 * * Neither the name of William LeFebvre nor the names of other
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * top - a top users display for Unix
36 * SYNOPSIS: OSF/1, Digital Unix 4.0, Compaq Tru64 5.0
38 * DESCRIPTION:
39 * This is the machine-dependent module for DEC OSF/1 and its descendents
40 * It is known to work on OSF/1 1.2, 1.3, 2.0-T3, 3.0, Digital Unix V4.0,
41 * Digital Unix 5.0, and Tru64 5.0.
42 * WARNING: if you use optimization with the standard "cc" compiler that
43 * . comes with V3.0 the resulting executable may core dump. If
44 * . this happens, recompile without optimization.
46 * LIBS: -lmld -lmach
48 * CFLAGS: -DHAVE_GETOPT -DORDER
50 * AUTHOR: Anthony Baxter, <anthony@aaii.oz.au>
51 * Derived originally from m_ultrix, by David S. Comay <dsc@seismo.css.gov>,
52 * although by now there is hardly any of the code from m_ultrix left.
53 * Helped a lot by having the source for syd(1), by Claus Kalle, and
54 * from several people at DEC who helped with providing information on
55 * some of the less-documented bits of the kernel interface.
57 * Modified: 31-Oct-94, Pat Welch, tpw@physics.orst.edu
58 * changed _mpid to pidtab for compatibility with OSF/1 version 3.0
60 * Modified: 13-Dec-94, William LeFebvre, lefebvre@dis.anl.gov
61 * removed used of pidtab (that was bogus) and changed things to
62 * automatically detect the absence of _mpid in the nlist and
63 * recover gracefully---this appears to be the only difference
64 * with 3.0.
66 * Modified: 3-Mar-00, Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>
67 * added support for sort ordering.
69 /*
70 * Theory of operation:
72 * Use Mach calls to build up a structure that contains all the sorts
73 * of stuff normally found in a struct proc in a BSD system. Then
74 * everything else uses this structure. This has major performance wins,
75 * and also should work for future versions of the O/S.
78 #include "config.h"
80 #include <sys/types.h>
81 #include <sys/signal.h>
82 #include <sys/param.h>
84 #include <string.h>
85 #include <sys/user.h>
86 #include <stdio.h>
87 #include <nlist.h>
88 #include <math.h>
89 #include <sys/dir.h>
90 #include <sys/user.h>
91 #include <sys/proc.h>
92 #include <sys/dk.h>
93 #include <sys/vm.h>
94 #include <sys/file.h>
95 #include <sys/time.h>
96 /* #include <machine/pte.h> */
97 /* forward declarations, needed by <net/if.h> included from <sys/table.h> */
98 struct rtentry;
99 struct mbuf;
100 #include <sys/table.h>
101 #include <mach.h>
102 #include <mach/mach_types.h>
103 #include <mach/vm_statistics.h>
104 #include <sys/syscall.h> /* for SYS_setpriority, in setpriority(), below */
107 #include "top.h"
108 #include "machine.h"
109 #include "utils.h"
111 extern int errno, sys_nerr;
112 extern char *sys_errlist[];
113 #define strerror(e) (((e) >= 0 && (e) < sys_nerr) ? sys_errlist[(e)] : "Unknown error")
115 #define VMUNIX "/vmunix"
116 #define KMEM "/dev/kmem"
117 #define MEM "/dev/mem"
119 /* get_process_info passes back a handle. This is what it looks like: */
121 struct handle
123 struct osf1_top_proc **next_proc; /* points to next valid proc pointer */
124 int remaining; /* number of pointers remaining */
127 /* declarations for load_avg */
128 #include "loadavg.h"
130 /* definitions for indices in the nlist array */
131 #define X_MPID 0
133 static struct nlist nlst[] = {
134 { "_mpid" }, /* 0 */
135 { 0 }
138 /* Some versions of OSF/1 don't support reporting of the last PID.
139 This flag indicates whether or not we are reporting the last PID. */
140 static int do_last_pid = 1;
143 * These definitions control the format of the per-process area
146 static char header[] =
147 " PID X PRI NICE SIZE RES STATE TIME CPU COMMAND";
148 /* 01234567 -- field to fill in starts at header+7 */
149 #define UNAME_START 7
151 #define Proc_format \
152 "%6d %-8.8s %3d %4d %5s %5s %-5s %-6s %5.2f%% %s"
155 /* process state names for the "STATE" column of the display */
156 /* the extra nulls in the string "run" are for adding a slash and
157 * the processor number when needed. Although OSF/1 doesnt support
158 * multiple processors yet, (and this module _certainly_ doesnt
159 * support it, either, we may as well plan for the future. :-)
162 char *state_abbrev[] =
164 "", "run\0\0\0", "WAIT", "sleep", "sleep", "stop", "halt", "???", "zomb"
168 static int kmem, mem;
170 /* values that we stash away in _init and use in later routines */
172 static double logcpu;
174 /* these are retrieved from the kernel in _init */
176 static unsigned long proc;
177 static int nproc;
178 static load_avg ccpu;
180 typedef long mtime_t;
182 /* these are offsets obtained via nlist and used in the get_ functions */
184 static unsigned long mpid_offset;
186 /* these are for detailing the process states */
188 int process_states[9];
189 char *procstatenames[] = {
190 "", " running, ", " waiting, ", " sleeping, ", " idle, ",
191 " stopped, ", " halted, ", "", " zombie",
192 NULL
195 /* these are for detailing the cpu states */
197 int cpu_states[5];
198 char *cpustatenames[] = {
199 "user", "nice", "system", "wio", "idle", NULL
202 long old_cpu_ticks[5];
204 /* these are for detailing the memory statistics */
206 long memory_stats[5];
207 char *memorynames[] = {
208 "K active, ", "K inactive, ", "K total, ", "K free", NULL
211 long swap_stats[3];
212 char *swapnames[] = {
213 "K in use, ", "K total", NULL
216 /* these are names given to allowed sorting orders -- first is default */
217 char *ordernames[] = {
218 "cpu", "size", "res", "time", NULL
221 /* forward definitions for comparison functions */
222 int compare_cpu();
223 int compare_size();
224 int compare_res();
225 int compare_time();
227 int (*proc_compares[])() = {
228 compare_cpu,
229 compare_size,
230 compare_res,
231 compare_time,
232 NULL
235 /* these are for getting the memory statistics */
237 static int pageshift; /* log base 2 of the pagesize */
239 /* define pagetok in terms of pageshift */
241 #define pagetok(size) ((size) << pageshift)
243 /* take a process, make it a mach task, and grab all the info out */
244 void do_threads_calculations();
247 * Because I dont feel like repeatedly grunging through the kernel with
248 * Mach calls, and I also dont want the horrid performance hit this
249 * would give, I read the stuff I need out, and put in into my own
250 * structure, for later use.
253 struct osf1_top_proc {
254 size_t p_mach_virt_size;
255 char p_mach_state;
256 int p_flag;
257 fixpt_t p_mach_pct_cpu; /* aka p_pctcpu */
258 int used_ticks;
259 size_t process_size;
260 pid_t p_pid;
261 uid_t p_ruid;
262 char p_pri;
263 char p_nice;
264 size_t p_rssize;
265 char u_comm[PI_COMLEN + 1];
268 /* these are for keeping track of the proc array */
270 static int bytes;
271 static int pref_len;
272 static struct osf1_top_proc *pbase;
273 static struct osf1_top_proc **pref;
275 /* useful externals */
276 extern int errno;
277 extern char *sys_errlist[];
279 long percentages();
281 machine_init(statics)
282 struct statics *statics;
284 register int i = 0;
285 register int pagesize;
286 struct tbl_sysinfo sibuf;
288 if ((kmem = open(KMEM, O_RDONLY)) == -1) {
289 perror(KMEM);
290 return(-1);
292 if ((mem = open(MEM, O_RDONLY)) == -1) {
293 perror(MEM);
294 return(-1);
297 /* get the list of symbols we want to access in the kernel */
298 if (nlist(VMUNIX, nlst) == -1)
300 perror("TOP(nlist)");
301 return (-1);
304 if (nlst[X_MPID].n_type == 0)
306 /* this kernel has no _mpid, so go without */
307 do_last_pid = 0;
309 else
311 /* stash away mpid pointer for later use */
312 mpid_offset = nlst[X_MPID].n_value;
315 /* get the symbol values out of kmem */
316 nproc = table(TBL_PROCINFO, 0, (struct tbl_procinfo *)NULL, INT_MAX, 0);
318 /* allocate space for proc structure array and array of pointers */
319 bytes = nproc * sizeof(struct osf1_top_proc);
320 pbase = (struct osf1_top_proc *)malloc(bytes);
321 pref = (struct osf1_top_proc **)malloc(nproc *
322 sizeof(struct osf1_top_proc *));
324 /* Just in case ... */
325 if (pbase == (struct osf1_top_proc *)NULL ||
326 pref == (struct osf1_top_proc **)NULL)
328 fprintf(stderr, "top: cannot allocate sufficient memory\n");
329 return(-1);
332 /* get the page size with "getpagesize" and calculate pageshift from it */
333 pagesize = getpagesize();
334 pageshift = 0;
335 while (pagesize > 1)
337 pageshift++;
338 pagesize >>= 1;
341 /* we only need the amount of log(2)1024 for our conversion */
342 pageshift -= LOG1024;
344 /* fill in the statics information */
345 statics->procstate_names = procstatenames;
346 statics->cpustate_names = cpustatenames;
347 statics->memory_names = memorynames;
348 statics->order_names = ordernames;
349 statics->swap_names = swapnames;
351 /* initialise this, for calculating cpu time */
352 if (table(TBL_SYSINFO,0,&sibuf,1,sizeof(struct tbl_sysinfo))<0) {
353 perror("TBL_SYSINFO");
354 return(-1);
356 old_cpu_ticks[0] = sibuf.si_user;
357 old_cpu_ticks[1] = sibuf.si_nice;
358 old_cpu_ticks[2] = sibuf.si_sys;
359 old_cpu_ticks[3] = sibuf.wait;
360 old_cpu_ticks[4] = sibuf.si_idle;
362 /* all done! */
363 return(0);
366 char *format_header(uname_field)
367 register char *uname_field;
369 register char *ptr;
371 ptr = header + UNAME_START;
372 while (*uname_field != '\0')
374 *ptr++ = *uname_field++;
377 return(header);
380 void get_system_info(si)
381 struct system_info *si;
383 struct tbl_loadavg labuf;
384 struct tbl_sysinfo sibuf;
385 struct tbl_swapinfo swbuf;
386 vm_statistics_data_t vmstats;
387 int swap_pages=0,swap_free=0,i;
388 long new_ticks[5],diff_ticks[5];
389 long delta_ticks;
391 if (do_last_pid)
393 /* last pid assigned */
394 (void) getkval(mpid_offset, &(si->last_pid), sizeof(si->last_pid),
395 "_mpid");
397 else
399 si->last_pid = -1;
402 /* get load averages */
403 if (table(TBL_LOADAVG,0,&labuf,1,sizeof(struct tbl_loadavg))<0) {
404 perror("TBL_LOADAVG");
405 return;
407 if (labuf.tl_lscale) /* scaled */
408 for(i=0;i<3;i++)
409 si->load_avg[i] = ((double)labuf.tl_avenrun.l[i] /
410 (double)labuf.tl_lscale );
411 else /* not scaled */
412 for(i=0;i<3;i++)
413 si->load_avg[i] = labuf.tl_avenrun.d[i];
415 /* array of cpu state counters */
416 if (table(TBL_SYSINFO,0,&sibuf,1,sizeof(struct tbl_sysinfo))<0) {
417 perror("TBL_SYSINFO");
418 return;
420 new_ticks[0] = sibuf.si_user ; new_ticks[1] = sibuf.si_nice;
421 new_ticks[2] = sibuf.si_sys ; new_ticks[3] = sibuf.wait;
422 new_ticks[4] = sibuf.si_idle;
423 delta_ticks=0;
424 for(i=0;i<5;i++) {
425 diff_ticks[i] = new_ticks[i] - old_cpu_ticks[i];
426 delta_ticks += diff_ticks[i];
427 old_cpu_ticks[i] = new_ticks[i];
429 si->cpustates = cpu_states;
430 if(delta_ticks)
431 for(i=0;i<5;i++)
432 si->cpustates[i] = (int)( ( (double)diff_ticks[i] /
433 (double)delta_ticks ) * 1000 );
435 /* memory information */
436 /* this is possibly bogus - we work out total # pages by */
437 /* adding up the free, active, inactive, wired down, and */
438 /* zero filled. Anyone who knows a better way, TELL ME! */
439 /* Change: dont use zero filled. */
440 (void) vm_statistics(task_self(),&vmstats);
442 /* thanks DEC for the table() command. No thanks at all for */
443 /* omitting the man page for it from OSF/1 1.2, and failing */
444 /* to document SWAPINFO in the 1.3 man page. Lets hear it for */
445 /* include files. */
446 i=0;
447 while(table(TBL_SWAPINFO,i,&swbuf,1,sizeof(struct tbl_swapinfo))>0) {
448 swap_pages += swbuf.size;
449 swap_free += swbuf.free;
450 i++;
452 memory_stats[0] = pagetok(vmstats.active_count);
453 memory_stats[1] = pagetok(vmstats.inactive_count);
454 memory_stats[2] = pagetok((vmstats.free_count + vmstats.active_count +
455 vmstats.inactive_count + vmstats.wire_count));
456 memory_stats[3] = pagetok(vmstats.free_count);
457 swap_stats[0] = pagetok(swap_pages - swap_free);
458 swap_stats[1] = pagetok(swap_pages);
459 si->memory = memory_stats;
460 si->swap = swap_stats;
463 static struct handle handle;
465 caddr_t get_process_info(si, sel, compare_index)
466 struct system_info *si;
467 struct process_select *sel;
468 int compare_index;
470 register int i;
471 register int total_procs;
472 register int active_procs;
473 register struct osf1_top_proc **prefp;
474 register struct osf1_top_proc *pp;
475 struct tbl_procinfo p_i[8];
476 int j,k,r;
478 /* these are copied out of sel for speed */
479 int show_idle;
480 int show_uid;
481 int show_command;
483 /* get a pointer to the states summary array */
484 si->procstates = process_states;
486 /* set up flags which define what we are going to select */
487 show_idle = sel->idle;
488 show_uid = sel->uid != -1;
489 show_command = sel->command != NULL;
491 /* count up process states and get pointers to interesting procs */
492 total_procs = 0;
493 active_procs = 0;
494 memset((char *)process_states, 0, sizeof(process_states));
495 prefp = pref;
496 pp=pbase;
497 for (j=0; j<nproc; j += 8)
499 r = table(TBL_PROCINFO, j, (struct tbl_procinfo *)p_i, 8,
500 sizeof(struct tbl_procinfo));
501 for (k=0; k < r; k++ , pp++)
503 if(p_i[k].pi_pid == 0)
505 pp->p_pid = 0;
507 else
509 pp->p_pid = p_i[k].pi_pid;
510 pp->p_ruid = p_i[k].pi_ruid;
511 pp->p_flag = p_i[k].pi_flag;
512 pp->p_nice = getpriority(PRIO_PROCESS,p_i[k].pi_pid);
513 /* Load useful values into the proc structure */
514 do_threads_calculations(pp);
516 * Place pointers to each valid proc structure in pref[].
517 * Process slots that are actually in use have a non-zero
518 * status field.
520 #ifdef DEBUG
522 * Emit debug info about all processes before selection.
524 fprintf(stderr, "pid = %d ruid = %d comm = %s p_mach_state = %d p_stat = %d p_flag = 0x%x\n",
525 pp->p_pid, pp->p_ruid, p_i[k].pi_comm,
526 pp->p_mach_state, p_i[k].pi_status, pp->p_flag);
527 #endif
528 if (pp->p_mach_state != 0)
530 total_procs++;
531 process_states[pp->p_mach_state]++;
532 if ((pp->p_mach_state != 8) &&
533 (show_idle || (pp->p_mach_pct_cpu != 0) ||
534 (pp->p_mach_state == 1)) &&
535 (!show_uid || pp->p_ruid == (uid_t)sel->uid)) {
536 *prefp++ = pp;
537 active_procs++;
544 /* if requested, sort the "interesting" processes */
545 if (proc_compares[compare_index] != NULL)
547 qsort((char *)pref, active_procs, sizeof(struct osf1_top_proc *),
548 proc_compares[compare_index]);
551 /* remember active and total counts */
552 si->p_total = total_procs;
553 si->p_active = pref_len = active_procs;
555 /* pass back a handle */
556 handle.next_proc = pref;
557 handle.remaining = active_procs;
558 return((caddr_t)&handle);
561 char fmt[MAX_COLS]; /* static area where result is built */
563 char *format_next_process(handle, get_userid)
564 caddr_t handle;
565 char *(*get_userid)();
567 register struct osf1_top_proc *pp;
568 register long cputime;
569 register double pct;
570 struct user u;
571 struct handle *hp;
573 /* find and remember the next proc structure */
574 hp = (struct handle *)handle;
575 pp = *(hp->next_proc++);
576 hp->remaining--;
578 /* get the process's user struct and set cputime */
580 if (table(TBL_UAREA,pp->p_pid,&u,1,sizeof(struct user))<0) {
581 /* whoops, it must have died between the read of the proc area
582 * and now. Oh well, lets just dump some meaningless thing out
583 * to keep the rest of the program happy
585 sprintf(fmt,
586 Proc_format,
587 pp->p_pid,
588 (*get_userid)(pp->p_ruid),
593 "dead",
595 0.0,
596 "<dead>");
597 return(fmt);
600 /* set u_comm for system processes */
601 if (u.u_comm[0] == '\0')
603 if (pp->p_pid == 0)
605 (void) strcpy(u.u_comm, "[idle]");
607 else if (pp->p_pid == 2)
609 (void) strcpy(u.u_comm, "[execpt.hndlr]");
613 /* Check if process is in core */
614 if (!(pp->p_flag & SLOAD)) {
616 * Print swapped processes as <pname>
618 char buf[sizeof(u.u_comm)];
619 (void) strncpy(buf, u.u_comm, sizeof(u.u_comm));
620 u.u_comm[0] = '<';
621 (void) strncpy(&u.u_comm[1], buf, sizeof(u.u_comm) - 2);
622 u.u_comm[sizeof(u.u_comm) - 2] = '\0';
623 (void) strncat(u.u_comm, ">", sizeof(u.u_comm) - 1);
624 u.u_comm[sizeof(u.u_comm) - 1] = '\0';
627 cputime = u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec;
629 /* calculate the base for cpu percentages */
630 pct = pctdouble(pp->p_mach_pct_cpu);
632 /* format this entry */
633 sprintf(fmt,
634 Proc_format,
635 pp->p_pid,
636 (*get_userid)(pp->p_ruid),
637 pp->p_pri,
638 pp->p_nice,
639 format_k(pp->p_mach_virt_size/1024),
640 format_k(pp->p_rssize/1000),
641 state_abbrev[pp->p_mach_state],
642 format_time(cputime),
643 100.0 * ((double)pp->p_mach_pct_cpu / 10000.0),
644 printable(u.u_comm));
646 /* return the result */
647 return(fmt);
651 * getkval(offset, ptr, size, refstr) - get a value out of the kernel.
652 * "offset" is the byte offset into the kernel for the desired value,
653 * "ptr" points to a buffer into which the value is retrieved,
654 * "size" is the size of the buffer (and the object to retrieve),
655 * "refstr" is a reference string used when printing error meessages,
656 * if "refstr" starts with a '!', then a failure on read will not
657 * be fatal (this may seem like a silly way to do things, but I
658 * really didn't want the overhead of another argument).
662 getkval(offset, ptr, size, refstr)
664 unsigned long offset;
665 int *ptr;
666 int size;
667 char *refstr;
670 if (lseek(kmem, (long)offset, L_SET) == -1) {
671 if (*refstr == '!')
672 refstr++;
673 (void) fprintf(stderr, "%s: lseek to %s: %s\n", KMEM,
674 refstr, strerror(errno));
675 quit(23);
677 if (read(kmem, (char *) ptr, size) == -1) {
678 if (*refstr == '!')
679 return(0);
680 else {
681 (void) fprintf(stderr, "%s: reading %s: %s\n", KMEM,
682 refstr, strerror(errno));
683 quit(23);
686 return(1);
689 /* comparison routines for qsort */
692 * There are currently four possible comparison routines. main selects
693 * one of these by indexing in to the array proc_compares.
695 * Possible keys are defined as macros below. Currently these keys are
696 * defined: percent cpu, cpu ticks, process state, resident set size,
697 * total virtual memory usage. The process states are ordered as follows
698 * (from least to most important): WAIT, zomb, ???, halt, idle, sleep,
699 * stop, run. The array declaration below maps a process state index into
700 * a number that reflects this ordering.
703 /* First, the possible comparison keys. These are defined in such a way
704 that they can be merely listed in the source code to define the actual
705 desired ordering.
708 #define ORDERKEY_PCTCPU if (lresult = p2->p_mach_pct_cpu - p1->p_mach_pct_cpu,\
709 (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
710 #define ORDERKEY_CPTICKS if ((result = p2->used_ticks - p1->used_ticks) == 0)
711 #define ORDERKEY_STATE if ((result = sorted_state[p2->p_mach_state] - \
712 sorted_state[p1->p_mach_state]) == 0)
713 #define ORDERKEY_PRIO if ((result = p2->p_pri - p1->p_pri) == 0)
714 #define ORDERKEY_RSSIZE if ((result = p2->p_rssize - p1->p_rssize) == 0)
715 #define ORDERKEY_MEM if ((result = p2->p_mach_virt_size - p1->p_mach_virt_size) == 0)
717 /* Now the array that maps process state to a weight */
719 static unsigned char sorted_state[] =
721 0, /*""*/
722 8, /*"run"*/
723 1, /*"WAIT"*/
724 6, /*"sleep"*/
725 5, /*"idle"*/
726 7, /*"stop"*/
727 4, /*"halt"*/
728 3, /*"???"*/
729 2, /*"zomb"*/
732 /* compare_cpu - the comparison function for sorting by cpu percentage */
734 compare_cpu(pp1, pp2)
736 struct osf1_top_proc **pp1;
737 struct osf1_top_proc **pp2;
740 register struct osf1_top_proc *p1;
741 register struct osf1_top_proc *p2;
742 register long result;
743 register pctcpu lresult;
745 /* remove one level of indirection */
746 p1 = *pp1;
747 p2 = *pp2;
749 ORDERKEY_PCTCPU
750 ORDERKEY_CPTICKS
751 ORDERKEY_STATE
752 ORDERKEY_PRIO
753 ORDERKEY_RSSIZE
754 ORDERKEY_MEM
757 return(result);
760 /* compare_size - the comparison function for sorting by total memory usage */
762 compare_size(pp1, pp2)
764 struct osf1_top_proc **pp1;
765 struct osf1_top_proc **pp2;
768 register struct osf1_top_proc *p1;
769 register struct osf1_top_proc *p2;
770 register long result;
771 register pctcpu lresult;
773 /* remove one level of indirection */
774 p1 = *pp1;
775 p2 = *pp2;
777 ORDERKEY_MEM
778 ORDERKEY_RSSIZE
779 ORDERKEY_PCTCPU
780 ORDERKEY_CPTICKS
781 ORDERKEY_STATE
782 ORDERKEY_PRIO
785 return(result);
788 /* compare_res - the comparison function for sorting by resident set size */
790 compare_res(pp1, pp2)
792 struct osf1_top_proc **pp1;
793 struct osf1_top_proc **pp2;
796 register struct osf1_top_proc *p1;
797 register struct osf1_top_proc *p2;
798 register long result;
799 register pctcpu lresult;
801 /* remove one level of indirection */
802 p1 = *pp1;
803 p2 = *pp2;
805 ORDERKEY_RSSIZE
806 ORDERKEY_MEM
807 ORDERKEY_PCTCPU
808 ORDERKEY_CPTICKS
809 ORDERKEY_STATE
810 ORDERKEY_PRIO
813 return(result);
816 /* compare_time - the comparison function for sorting by total cpu time */
818 compare_time(pp1, pp2)
820 struct osf1_top_proc **pp1;
821 struct osf1_top_proc **pp2;
824 register struct osf1_top_proc *p1;
825 register struct osf1_top_proc *p2;
826 register long result;
827 register pctcpu lresult;
829 /* remove one level of indirection */
830 p1 = *pp1;
831 p2 = *pp2;
833 ORDERKEY_CPTICKS
834 ORDERKEY_PCTCPU
835 ORDERKEY_STATE
836 ORDERKEY_PRIO
837 ORDERKEY_RSSIZE
838 ORDERKEY_MEM
841 return(result);
845 * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
846 * the process does not exist.
847 * It is EXTREMLY IMPORTANT that this function work correctly.
848 * If top runs setuid root (as in SVR4), then this function
849 * is the only thing that stands in the way of a serious
850 * security problem. It validates requests for the "kill"
851 * and "renice" commands.
854 int proc_owner(pid)
856 int pid;
859 register int cnt;
860 register struct osf1_top_proc **prefp;
861 register struct osf1_top_proc *pp;
863 prefp = pref;
864 cnt = pref_len;
865 while (--cnt >= 0)
867 if ((pp = *prefp++)->p_pid == (pid_t)pid)
869 return((int)pp->p_ruid);
872 return(-1);
877 * We use the Mach interface, as well as the table(UAREA,,,) call to
878 * get some more information, then put it into unused fields in our
879 * copy of the proc structure, to make it faster and easier to get at
880 * later.
882 void do_threads_calculations(thisproc)
883 struct osf1_top_proc *thisproc;
885 int j;
886 task_t thistask;
887 task_basic_info_data_t taskinfo;
888 unsigned int taskinfo_l;
889 thread_array_t threadarr;
890 unsigned int threadarr_l;
891 thread_basic_info_t threadinfo;
892 thread_basic_info_data_t threadinfodata;
893 unsigned int threadinfo_l;
894 int task_tot_cpu=0; /* total cpu usage of threads in a task */
895 struct user u;
897 thisproc->p_pri=0;
898 thisproc->p_rssize=0;
899 thisproc->p_mach_virt_size=0;
900 thisproc->p_mach_state=0;
901 thisproc->p_mach_pct_cpu=0;
903 if(task_by_unix_pid(task_self(), thisproc->p_pid, &thistask)
904 != KERN_SUCCESS){
905 thisproc->p_mach_state=8; /* (zombie) */
906 } else {
907 taskinfo_l=TASK_BASIC_INFO_COUNT;
908 if(task_info(thistask, TASK_BASIC_INFO, (task_info_t) &taskinfo,
909 &taskinfo_l)
910 != KERN_SUCCESS) {
911 thisproc->p_mach_state=8; /* (zombie) */
912 } else {
913 int minim_state=99,mcurp=1000,mbasp=1000,mslpt=999;
915 thisproc->p_rssize=taskinfo.resident_size;
916 thisproc->p_mach_virt_size=taskinfo.virtual_size;
918 if (task_threads(thistask, &threadarr, &threadarr_l) != KERN_SUCCESS)
919 return;
920 threadinfo= &threadinfodata;
921 for(j=0; j < threadarr_l; j++) {
922 threadinfo_l=THREAD_BASIC_INFO_COUNT;
923 if(thread_info(threadarr[j],THREAD_BASIC_INFO,
924 (thread_info_t) threadinfo, &threadinfo_l) == KERN_SUCCESS) {
926 task_tot_cpu += threadinfo->cpu_usage;
927 if(minim_state>threadinfo->run_state)
928 minim_state=threadinfo->run_state;
929 if(mcurp>threadinfo->cur_priority)
930 mcurp=threadinfo->cur_priority;
931 if(mbasp>threadinfo->base_priority)
932 mbasp=threadinfo->base_priority;
933 if(mslpt>threadinfo->sleep_time)
934 mslpt=threadinfo->sleep_time;
937 switch (minim_state) {
938 case TH_STATE_RUNNING:
939 thisproc->p_mach_state=1; break;
940 case TH_STATE_UNINTERRUPTIBLE:
941 thisproc->p_mach_state=2; break;
942 case TH_STATE_WAITING:
943 thisproc->p_mach_state=(threadinfo->sleep_time > 20) ? 4 : 3; break;
944 case TH_STATE_STOPPED:
945 thisproc->p_mach_state=5; break;
946 case TH_STATE_HALTED:
947 thisproc->p_mach_state=6; break;
948 default:
949 thisproc->p_mach_state=7; break;
952 thisproc->p_pri=mcurp;
953 thisproc->p_mach_pct_cpu=(fixpt_t)(task_tot_cpu*10);
954 vm_deallocate(task_self(),(vm_address_t)threadarr,threadarr_l);
957 if (table(TBL_UAREA,thisproc->p_pid,&u,1,sizeof(struct user))>=0) {
958 thisproc->used_ticks=(u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec);
959 thisproc->process_size=u.u_tsize + u.u_dsize + u.u_ssize;
963 /* The reason for this function is that the system call will let
964 * someone lower their own processes priority (because top is setuid :-(
965 * Yes, using syscall() is a hack, if you can come up with something
966 * better, then I'd be thrilled to hear it. I'm not holding my breath,
967 * though.
968 * Anthony.
970 int setpriority(int dummy, int procnum, int niceval)
973 int uid, curprio;
975 uid=getuid();
976 if ( (curprio=getpriority(PRIO_PROCESS,procnum) ) == -1)
978 return(-1); /* errno goes back to renice_process() */
980 /* check for not-root - if so, dont allow users to decrease priority */
981 else if ( uid && (niceval<curprio) )
983 errno=EACCES;
984 return(-1);
986 return(syscall(SYS_setpriority,PRIO_PROCESS,procnum,niceval));