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.
10 *
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.
15 *
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.
19 *
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.
31 */
32
33 /*
34 * top - a top users display for Unix
35 *
36 * SYNOPSIS: SCO UNIX OpenServer5
37 *
38 * DESCRIPTION:
39 * This is the machine-dependent module for SCO OpenServer5.
40 * Originally written for BSD4.3 system by Christos Zoulas.
41 * Modified to m_sco.c (3.2v4.2) by Gregory Shilin <shilin@onyx.co.il>
42 * Modified to m_sco5.c (3.2v5.*) by Mike Hopkirk <hops@sco.com>
43 * Works for:
44 * SCO UNIX 3.2v5.*
45 *
46 * CFLAGS: -DHAVE_GETOPT -DORDER
47 *
48 * AUTHOR: Mike Hopkirk (hops@sco.com)
49 * hops 10-Jul-98 - added sort fields
50 * 17-Jul-98 - add philiph's chopped cmd string support
51 * (define NO_COMMAND_ARGS to enable )
52 * 09-Dec-98 - provide RSS calculation
53 * 15-Mar-2000 - Fix broken lines and cleanup sysinfo access w macros
54 */
55
56 #include <sys/types.h>
57 #include <sys/param.h>
58
59 #include <stdio.h>
60 #include <unistd.h>
61 #include <fcntl.h>
62 #include <nlist.h>
63 #include <math.h>
64 #include <signal.h>
65 #include <string.h>
66
67 #include <sys/dir.h>
68 #include <sys/immu.h>
69 #include <sys/region.h>
70 #include <sys/proc.h>
71 #include <sys/user.h>
72 #include <sys/sysinfo.h>
73 #include <sys/systm.h>
74 #include <sys/sysmacros.h>
75 #include <sys/var.h>
76 #include <sys/sysi86.h>
77
78 #include "top.h"
79 #include "machine.h"
80 #include "utils.h"
81 #include "loadavg.h"
82
83 /*
84 typedef unsigned long ulong;
85 typedef unsigned int uint;
86 typedef unsigned short ushort;
87 */
88 typedef unsigned char uchar;
89
90 #define VMUNIX "/unix"
91 #define KMEM "/dev/kmem"
92 #define MEM "/dev/mem"
93
94 #define SI_ACTIVE(p) p->p_active
95 #define SI_TOTAL(p) p->p_total
96
97 /* get_process_info passes back a handle. This is what it looks like: */
98 struct handle {
99 struct proc **next_proc; /* points to next valid proc pointer */
100 int remaining; /* number of pointers remaining */
101 };
102
103 /* define what weighted cpu is */
104 #define weighted_cpu(pct, pp) ((pp)->p_time == 0 ? 0.0 : \
105 ((pct) / (1.0 - exp((pp)->p_time * logcpu))))
106
107 #define bytetok(bytes) ((bytes) >> 10)
108
109 /* what we consider to be process size: */
110 #define PROCSIZE(up) bytetok(ctob((up)->u_tsize + (up)->u_dsize+(up)->u_ssize))
111
112 /* definitions for indices in the nlist array */
113 #define X_V 0 /* System configuration information */
114 #define X_PROC 1 /* process tables */
115 #define X_FREEMEM 2 /* current free memory */
116 #define X_AVAILRMEM 3 /* available resident (not swappable) mem in pages
117 */
118 #define X_AVAILSMEM 4 /* available swappable memory in pages */
119 #define X_MAXMEM 5 /* maximum available free memory in clicks */
120 #define X_PHYSMEM 6 /* physical memory in clicks */
121 #define X_NSWAP 7 /* size of swap space in blocks */
122 #define X_HZ 8 /* ticks/second of the clock */
123 #define X_MPID 9 /* last process id */
124 #define X_SYSINFO 10 /* system information (cpu states) */
125 #define X_CUR_CPU 11
126
127 static struct nlist nlst[] = {
128 { "v" }, /* 0 */
129 { "proc" }, /* 1 */
130 { "freemem" }, /* 2 */
131 { "availrmem" }, /* 3 */
132 { "availsmem" }, /* 4 */
133 { "maxmem" }, /* 5 */
134 { "physmem" }, /* 6 */
135 { "nswap" }, /* 7 */
136 { "Hz" }, /* 8 */
137 { "mpid" }, /* 9 */
138 { "sysinfo" }, /* 10 */
139 { "cur_cpu" }, /* 11 */
140 { NULL }
141 };
142
143 /*
144 * These definitions control the format of the per-process area
145 */
146
147 static char header[] =
148 " PID X PRI NICE SIZE RES STATE TIME COMMAND";
149 /* 0123456 -- field to fill in starts at header+6 */
150 #define UNAME_START 6
151
152 #define Proc_format \
153 "%5d %-8.8s %3d %4d %5s %5dK %-5s %6s %.28s"
154
155 static int kmem, mem;
156
157 static double logcpu;
158
159 /* these are retrieved from the kernel in _init */
160 static int Hz;
161 static struct var v;
162 static ulong proca;
163 static load_avg cur_cpu;
164
165 /* these are for detailing the process states */
166 int process_states[8];
167 char *procstatenames[] = {
168 "", " sleeping, ", " running, ", " zombie, ", " stopped, ",
169 " created, ", " onproc, ", " xswapped, ",
170 NULL
171 };
172
173 /* process state names for the "STATE" column of the display */
174 char *state_abbrev[] = {
175 "", "sleep", "run", "zomb", "stop", "create", "onpr", "swap"
176 };
177
178 /* these are for calculating cpu state percentages */
179 #define CPUSTATES 5 /* definition from struct sysinfo */
180 static time_t cp_time[CPUSTATES];
181 static time_t cp_old[CPUSTATES];
182 static time_t cp_diff[CPUSTATES];
183
184 /* these are for detailing the cpu states */
185 int cpu_states[CPUSTATES];
186 char *cpustatenames[] = {
187 "idle", "user", "system", "wait", "sxbrk",
188 NULL
189 };
190
191 /* these are for detailing the memory statistics */
192 unsigned long memory_stats[6];
193 char *memorynames[] = {
194 "K phys, ", "K max, ", "K free, ", "K lck, ", "K unlck, ",
195 "K swap,", NULL
196 };
197
198 /* these are for keeping track of the proc array */
199 static int bytes;
200 static int pref_len;
201 static struct proc *pbase;
202 static struct proc **pref;
203
204 /* forward definitions for comparison functions */
205 int proc_compare();
206 int compare_cpu();
207 int compare_size();
208 int compare_time();
209
210 int (*proc_compares[])() = {
211 proc_compare, /* state, pri, time, size */
212 compare_cpu, /* cpu, time, state, pri, size */
213 compare_size, /* size, cpu, time, state pri */
214 compare_time, /* time, cpu, state, pri, size */
215 /* compare_res, /* res, cpu, time, state pri */
216 NULL };
217
218 /* these are names given to allowed sorting orders -- first is default */
219 char *ordernames[]={"state", "cpu", "size", "time", NULL}; /*hops*/
220
221 /* useful externals */
222 extern int errno;
223 extern char *sys_errlist[];
224
225 long time();
226 long percentages();
227
228 int
machine_init(struct statics * statics)229 machine_init(struct statics *statics)
230
231 {
232 ulong ptr;
233
234 if ((kmem = open(KMEM, O_RDONLY)) == -1) {
235 perror(KMEM);
236 return -1;
237 }
238 if ((mem = open(MEM, O_RDONLY)) == -1) {
239 perror(MEM);
240 return -1;
241 }
242
243 /* get the list of symbols we want to access in the kernel */
244 if (nlist(VMUNIX, nlst) == -1) {
245 fprintf(stderr, "top: nlist failed\n");
246 return -1;
247 }
248 /* make sure they were all found */
249 /*ZZ
250 if (check_nlist(nlst) > 0)
251 return -1;
252 */
253
254 proca = nlst[X_PROC].n_value;
255
256 /* get the symbol values out of kmem */
257 (void) getkval(nlst[X_CUR_CPU].n_value, (int *)(&cur_cpu), sizeof(cur_cpu),
258 nlst[X_CUR_CPU].n_name);
259 (void) getkval(nlst[X_HZ].n_value, (int *)(&Hz), sizeof(Hz),
260 nlst[X_HZ].n_name);
261 (void) getkval(nlst[X_V].n_value, (int *)(&v), sizeof(v),
262 nlst[X_V].n_name);
263
264 /* this is used in calculating WCPU -- calculate it ahead of time */
265 logcpu = log(fabs(loaddouble(cur_cpu)));
266
267 /* allocate space for proc structure array and array of pointers */
268 bytes = v.v_proc * sizeof(struct proc);
269 pbase = (struct proc *)malloc(bytes);
270 pref = (struct proc **)malloc(v.v_proc * sizeof(struct proc *));
271 if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL) {
272 fprintf(stderr, "top: cannot allocate sufficient memory\n");
273 return -1;
274 }
275
276 /* fill in the statics information */
277 statics->procstate_names = procstatenames;
278 statics->cpustate_names = cpustatenames;
279 statics->memory_names = memorynames;
280 statics->order_names = ordernames ; /* hops */
281
282 return 0;
283 }
284
285 char *
format_header(register char * uname_field)286 format_header(register char *uname_field)
287
288 {
289 register char *ptr;
290
291 ptr = header + UNAME_START;
292 while (*uname_field != '\0')
293 {
294 *ptr++ = *uname_field++;
295 }
296
297 return(header);
298 }
299
300
301 /* philiph - get run ave fm /dev/table info */
302 static int
tab_avenrun(double runave[])303 tab_avenrun(double runave[])
304 {
305 FILE *fp = fopen("/dev/table/avenrun", "r");
306 int i;
307
308 for (i=0; i<3; i++)
309 runave[i] = -1.0;
310
311 if (fp==NULL)
312 return -1;
313 else
314 {
315 short rawave[3];
316
317 if (fread(rawave, sizeof(short), 3, fp) !=3 )
318 {
319 fclose(fp);
320 return -1;
321 }
322 else
323 {
324 int i;
325
326 for (i=0; i<3; i++)
327 runave[i] = (double) (rawave[i] / 256.0);
328
329 fclose(fp);
330 return 0;
331 }
332 }
333 }
334
335 struct pregion *
get_pregion(void * ptr)336 get_pregion(void *ptr)
337 {
338 static struct pregion preg;
339 long addr = (long)ptr;
340
341 (void) getkval(addr , (struct pregion *)(&preg),
342 sizeof(struct pregion), "pregion" );
343 return &preg;
344 }
345
346 struct region *
get_region(void * ptr)347 get_region(void *ptr)
348 {
349 static struct region reg;
350 long addr = (long)ptr;
351
352 (void) getkval( addr , (struct region *)(®),
353 sizeof(struct region), "region" );
354 return ®
355 }
356
357 static unsigned char shareable[RT_VM86 + 1]; /* 1 if shareable */
358
359 /*
360 * sum private referenced pages,
361 * treat shared pages depending on value of TREAT_SHARABLE_PAGES macro
362 * undefined : ignore (don't account for - default)
363 * 1: divide among # of references
364 * 2: accumulate as if private
365 */
366 /* #define TREAT_SHAREABLE_PAGES 1 */
367 static long
proc_residentsize(struct proc * pp)368 proc_residentsize(struct proc *pp)
369 {
370 struct pregion *prp;
371 struct region *rp;
372 long rtot = 0;
373 long stot = 0;
374 long s1tot = 0;
375
376 /* init shareable region array */
377 if (shareable[RT_STEXT] == 0 )
378 shareable[RT_STEXT] = shareable[RT_SHMEM] = shareable[RT_MAPFILE] = 1
379 ;
380
381 prp = pp->p_region;
382
383 if ( prp == 0)
384 return 0;
385
386 for( ; prp && (prp = get_pregion((void *)(prp))) &&
387 prp->p_reg && (rp = get_region((void*)(prp->p_reg)));
388 prp = prp->p_next)
389 {
390 if (shareable[rp->r_type] ) /* account for shared pgs separately
391 */
392 {
393 stot += (rp->r_nvalid / rp->r_refcnt);
394 s1tot += rp->r_nvalid;
395 }
396 else
397 rtot += rp->r_nvalid;
398
399 }
400 #if defined(TREAT_SHAREABLE_PAGES) && TREAT_SHAREABLE_PAGES == 1
401 rtot += stot; /* accumulate and spread over users */
402 #endif
403
404 #if defined(TREAT_SHAREABLE_PAGES) && TREAT_SHAREABLE_PAGES == 1
405 rtot += s1tot; /* accumulate as if private */
406 #endif
407
408 return rtot * NBPP/1024; ;
409 }
410
411 void
get_system_info(struct system_info * si)412 get_system_info(struct system_info *si)
413
414 {
415 long total;
416
417 /* get process id of the last process */
418 (void) getkval(nlst[X_MPID].n_value, &(si->last_pid),
419 sizeof(si->last_pid),
420 nlst[X_MPID].n_name);
421 /* get the cp_time array */
422 (void) getkval(nlst[X_SYSINFO].n_value, (int *)cp_time, sizeof(cp_time),
423 nlst[X_SYSINFO].n_name);
424
425 /* convert cp_time counts to persentages */
426 total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
427
428 /* sum memory statistics */
429 (void) getkval(nlst[X_PHYSMEM].n_value, &memory_stats[0],
430 sizeof(memory_stats[0]), nlst[X_PHYSMEM].n_name);
431 (void) getkval(nlst[X_MAXMEM].n_value, &memory_stats[1],
432 sizeof(memory_stats[1]), nlst[X_MAXMEM].n_name);
433 (void) getkval(nlst[X_FREEMEM].n_value, &memory_stats[2],
434 sizeof(memory_stats[2]), nlst[X_FREEMEM].n_name);
435 (void) getkval(nlst[X_AVAILRMEM].n_value, &memory_stats[3],
436 sizeof(memory_stats[3]), nlst[X_AVAILRMEM].n_name);
437 (void) getkval(nlst[X_AVAILSMEM].n_value, &memory_stats[4],
438 sizeof(memory_stats[4]), nlst[X_AVAILSMEM].n_name);
439 (void) getkval(nlst[X_NSWAP].n_value, &memory_stats[5],
440 sizeof(memory_stats[5]), nlst[X_NSWAP].n_name);
441 memory_stats[0] = bytetok(ctob(memory_stats[0])); /* clicks -> bytes
442 */
443 memory_stats[1] = bytetok(ctob(memory_stats[1])); /* clicks -> bytes
444 */
445 memory_stats[2] = bytetok(ctob(memory_stats[2])); /* clicks -> bytes
446 */
447 memory_stats[3] = bytetok(memory_stats[3] * NBPP); /* # bytes per page
448 */
449 memory_stats[4] = bytetok(memory_stats[4] * NBPP); /* # bytes per page
450 */
451 memory_stats[5] = bytetok(memory_stats[5] * NBPSCTR);/* # bytes per sector
452 */
453
454 /* set arrays and strings */
455 /* Note: we keep memory_stats as an unsigned long to avoid sign
456 extension problems when shifting in bytetok. But the module
457 interface requires an array of signed longs. So we just cast
458 the pointer here and hope for the best. --wnl
459 */
460 si->cpustates = cpu_states;
461 si->memory = (long *)memory_stats;
462
463 tab_avenrun(si->load_avg); /* philiph */
464 }
465
466 static struct handle handle;
467
468 caddr_t
get_process_info(struct system_info * si,struct process_select * sel,int idx)469 get_process_info(struct system_info *si,
470 struct process_select *sel,
471 int idx)
472
473 {
474 register int i;
475 register int total_procs;
476 register int active_procs;
477 register struct proc **prefp;
478 register struct proc *pp;
479
480 /* set up flags of what we are going to select */
481 /* these are copied out of sel for simplicity */
482 int show_idle = sel->idle;
483 int show_system = sel->system;
484 int show_uid = sel->uid != -1;
485 int show_command = sel->command != NULL;
486
487 /* read all the proc structures in one fell swoop */
488 (void) getkval(proca, (int *)pbase, bytes, "proc array");
489
490 /* get a pointer to the states summary array */
491 si->procstates = process_states;
492
493 /* count up process states and get pointers to interesting procs */
494 total_procs = active_procs = 0;
495 memset((char *)process_states, 0, sizeof(process_states));
496 prefp = pref;
497 for (pp = pbase, i = 0; i < v.v_proc; pp++, i++) {
498 /*
499 * Place pointers to each valid proc structure in pref[].
500 * Process slots that are actually in use have a non-zero
501 * status field. Processes with SSYS set are system processes --
502 * these are ignored unless show_system is set.
503 */
504 if (pp->p_stat && (show_system || ((pp->p_flag & SSYS) == 0))) {
505 total_procs++;
506 process_states[pp->p_stat]++;
507 if ((pp->p_stat != SZOMB) &&
508 (show_idle || (pp->p_stat == SRUN) || (pp->p_stat == SONPROC)) &&
509 (!show_uid || pp->p_uid == (ushort)sel->uid)) {
510 *prefp++ = pp;
511 active_procs++;
512 }
513 }
514 }
515
516 /* if requested, sort the "interesting" processes */
517 qsort((char *)pref, active_procs, sizeof(struct proc *), proc_compares[idx]);
518
519 /* remember active and total counts */
520 SI_TOTAL(si) = total_procs;
521 SI_ACTIVE(si) = pref_len = active_procs;
522
523 /* pass back a handle */
524 handle.next_proc = pref;
525 handle.remaining = active_procs;
526 return((caddr_t)&handle);
527 }
528
529 char fmt[128]; /* static area where result is built */
530
531 char *
format_next_process(caddr_t handle,char * (* get_userid)())532 format_next_process(caddr_t handle, char *(*get_userid)())
533
534 {
535 register struct proc *pp;
536 register time_t cputime;
537 register double pct;
538 int where;
539 struct user u;
540 struct handle *hp;
541 char command[29];
542 char * process;
543 char * process2;
544
545 /* find and remember the next proc structure */
546 hp = (struct handle *)handle;
547 pp = *(hp->next_proc++);
548 hp->remaining--;
549
550 /* get the process's user struct and set cputime */
551 if ((where = sysi86(RDUBLK, pp->p_pid, &u, sizeof(struct user))) != -1)
552 where = (pp->p_flag & SLOAD) ? 0 : 1;
553 if (where == -1) {
554 strcpy(command, "<swapped>");
555 cputime = 0;
556 } else {
557 /* set u_comm for system processes */
558 if (u.u_comm[0] == '\0') {
559 if (pp->p_pid == 0)
560 strcpy(command, "Swapper");
561 else if (pp->p_pid == 2)
562 strcpy(command, "Pager");
563 else if (pp->p_pid == 3)
564 strcpy(command, "Sync'er");
565 } else if (where == 1) {
566 /* print swapped processes as <pname> */
567 register char *s1;
568
569 u.u_psargs[28 - 3] = '\0';
570 strcpy(command, "<");
571 strcat(command, strtok(u.u_psargs, " "));
572 strcat(command, ">");
573 while (s1 = (char *)strtok(NULL, " "))
574 strcat(command, s1);
575 } else {
576 sprintf(command, "%s", u.u_psargs);
577 }
578 cputime = u.u_utime + u.u_stime;
579 /* cputime = pp->p_utime + pp->p_stime; */
580 }
581 /* calculate the base for cpu percentages */
582 pct = pctdouble(pp->p_cpu);
583
584 /*
585 * psargs gives the absolute path of the process... strip it to only the
586 * command - [Changes by D. Currie & M. Muldner Aitt NS Canada]
587 */
588 process = printable(command);
589 #if NO_COMMAND_ARGS
590 strtok(process," ");
591 #endif
592 process2 = strrchr(process,'/');
593 if(process2)
594 {
595 process = process2;
596 process++;
597 }
598
599
600 /* format this entry */
601 sprintf(fmt,
602 Proc_format,
603 pp->p_pid,
604 (*get_userid)(pp->p_uid),
605 pp->p_pri - PZERO,
606 pp->p_nice - NZERO,
607 format_k(PROCSIZE(&u)), /* same as pp->p_size * 4 */
608 proc_residentsize(pp),
609 state_abbrev[pp->p_stat],
610 format_time(cputime / Hz),
611 printable(process) );
612
613 return(fmt);
614 }
615
616 /*
617 * Checks the nlist to see if any symbols were not found.
618 * For every symbol that was not found, a one-line message
619 * is printed to stderr. The routine returns the number of
620 * symbols NOT founded.
621 */
622
check_nlist(register struct nlist * nlst)623 int check_nlist(register struct nlist *nlst)
624
625 {
626 register int i = 0;
627
628 while (nlst->n_name) {
629 if (nlst->n_type == 0) {
630 fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
631 i++;
632 }
633 nlst++;
634 }
635 return i;
636 }
637
638 /*
639 * getkval(offset, ptr, size, refstr) - get a value out of the kernel.
640 * "offset" is the byte offset into the kernel for the desired value,
641 * "ptr" points to a buffer into which the value is retrieved,
642 * "size" is the size of the buffer (and the object to retrieve),
643 * "refstr" is a reference string used when printing error meessages,
644 * if "refstr" starts with a '!', then a failure on read will not
645 * be fatal (this may seem like a silly way to do things, but I
646 * really didn't want the overhead of another argument).
647 *
648 */
649
650 int
getkval(unsigned long offset,int * ptr,int size,char * refstr)651 getkval(unsigned long offset, int *ptr, int size, char *refstr)
652
653 {
654 if (lseek(kmem, (long)offset, SEEK_SET) == -1) {
655 if (*refstr == '!')
656 refstr++;
657 fprintf(stderr, "%s: lseek to %s: %s\n", KMEM,
658 refstr, errmsg(errno));
659 quit(23);
660 }
661 if (read(kmem, (char *)ptr, size) == -1) {
662 if (*refstr == '!')
663 return 0;
664 fprintf(stderr, "%s: reading %s: %s\n", KMEM,
665 refstr, errmsg(errno));
666 quit(23);
667 }
668 return(1);
669 }
670
671 /* comparison routine for qsort */
672 /* NOTE: this is specific to the BSD proc structure, but it should
673 give you a good place to start. */
674
675 /*
676 * proc_compare - comparison function for "qsort"
677 * Compares the resource consumption of two processes using five
678 * distinct keys. The keys (in descending order of importance) are:
679 * percent cpu, cpu ticks, state, resident set size, total virtual
680 * memory usage. The process states are ordered as follows (from least
681 * to most important): WAIT, zombie, sleep, stop, start, run. The
682 * array declaration below maps a process state index into a number
683 * that reflects this ordering.
684 */
685
686 static unsigned char sorted_state[] =
687 {
688 0, /* not used */
689 5, /* sleep */
690 6, /* run */
691 2, /* zombie */
692 4, /* stop */
693 1, /* start */
694 7, /* onpr */
695 3, /* swap */
696 };
697
698 int
proc_compare(struct proc ** pp1,struct proc ** pp2)699 proc_compare(struct proc **pp1, struct proc **pp2)
700
701 {
702 register struct proc *p1;
703 register struct proc *p2;
704 register int result;
705 register ulong lresult;
706
707 /* remove one level of indirection */
708 p1 = *pp1;
709 p2 = *pp2;
710
711 /* use process state to break the tie */
712 if ((result = sorted_state[p2->p_stat] -
713 sorted_state[p1->p_stat]) == 0)
714 {
715 /* use priority to break the tie */
716 if ((result = p2->p_pri - p1->p_pri) == 0)
717 {
718 /* use time to break the tie */
719 if ((result = (p2->p_utime + p2->p_stime) -
720 (p1->p_utime + p1->p_stime)) == 0)
721 {
722 /* use resident set size (rssize) to break the tie */
723 if ((result = p2->p_size - p1->p_size) == 0)
724 {
725 result = 0;
726 }
727 }
728 }
729 }
730
731 return(result);
732 }
733
734 /* returns uid of owner of process pid */
735 int
proc_owner(int pid)736 proc_owner(int pid)
737
738 {
739 register int cnt;
740 register struct proc **prefp;
741 register struct proc *pp;
742
743 prefp = pref;
744 cnt = pref_len;
745 while (--cnt >= 0) {
746 if ((pp = *prefp++)->p_pid == (short)pid)
747 return ((int)pp->p_uid);
748 }
749 return(-1);
750 }
751
752 #if 0
753 int setpriority(int dummy, int who, int nicewal)
754 {
755 errno = 1;
756 return -1;
757 }
758 #endif
759
760 /* sigblock is not POSIX conformant */
sigblock(sigset_t mask)761 sigset_t sigblock (sigset_t mask)
762 {
763 sigset_t oset;
764
765 sigemptyset(&oset);
766 sigprocmask(SIG_BLOCK, &mask, &oset);
767 return oset;
768 }
769
770 /* sigsetmask is not POSIX conformant */
sigsetmask(sigset_t mask)771 sigsetmask(sigset_t mask)
772 {
773 sigset_t oset;
774
775 sigemptyset(&oset);
776 sigprocmask(SIG_SETMASK, &mask, &oset);
777 return oset;
778 }
779
780
781 /* ---------------- hops - comparison/ordering support ---------------- */
782
783 #define ORDERKEY_PCTCPU if (dresult = pctdouble(p2->p_cpu) - pctdouble(p1->p_cpu),\
784 (result = dresult > 0.0 ? 1 : dresult < 0.0 ? -1 : 0) == 0)
785 #define ORDERKEY_MEMSIZE if ((result = (p2->p_size - p1->p_size)) == 0)
786 #define ORDERKEY_CPTIME if ((result = (long)(p2->p_utime + p2->p_stime) -\
787 (long)(p1->p_utime + p1->p_stime)) == 0)
788
789 #define ORDERKEY_STATE if ((result = (sorted_state[p2->p_stat] - \
790 sorted_state[p1->p_stat])) == 0)
791 #define ORDERKEY_PRIO if ((result = p2->p_pri - p1->p_pri) == 0)
792
793
794 int
compare_cpu(struct proc ** pp1,struct proc ** pp2)795 compare_cpu ( struct proc **pp1, struct proc **pp2)
796 {
797 register struct proc *p1;
798 register struct proc *p2;
799 register int result;
800 double dresult;
801
802 /* remove one level of indirection */
803 p1 = *pp1;
804 p2 = *pp2;
805
806 ORDERKEY_PCTCPU
807 ORDERKEY_CPTIME
808 ORDERKEY_STATE
809 ORDERKEY_PRIO
810 ORDERKEY_MEMSIZE
811 ;
812
813 return (result);
814 }
815
816
817
818 /* compare_size - the comparison function for sorting by process size */
819 int
compare_size(struct proc ** pp1,struct proc ** pp2)820 compare_size ( struct proc **pp1, struct proc **pp2)
821 {
822 register struct proc *p1;
823 register struct proc *p2;
824 register int result;
825 double dresult;
826
827 /* remove one level of indirection */
828 p1 = *pp1;
829 p2 = *pp2;
830
831
832 ORDERKEY_MEMSIZE
833 ORDERKEY_PCTCPU
834 ORDERKEY_CPTIME
835 ORDERKEY_STATE
836 ORDERKEY_PRIO
837 ;
838
839 return (result);
840 }
841
842 /* compare_res - the comparison function for sorting by resident set size */
843 /* TODO: add shadow proc struct updating usr + sys times and RSS for use
844 * in comparison rtns, implement compare_res rtn as per compare_size()
845 */
846
847 /* compare_time - the comparison function for sorting by total cpu time */
848 /* This is giving wrong results since its using the proc structure vals not
849 * the u struct vals we display above
850 * TODO: add shadow proc struct updating usr + sys times and RSS for use
851 * in comparison rtns
852 */
853 int
compare_time(struct proc ** pp1,struct proc ** pp2)854 compare_time ( struct proc **pp1, struct proc **pp2)
855 {
856 register struct proc *p1;
857 register struct proc *p2;
858 register int result;
859 double dresult;
860
861 /* remove one level of indirection */
862 p1 = *pp1;
863 p2 = *pp2;
864
865 ORDERKEY_CPTIME
866 ORDERKEY_PCTCPU
867 ORDERKEY_STATE
868 ORDERKEY_PRIO
869 ORDERKEY_MEMSIZE
870 ;
871
872 return (result);
873 }
874
875