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: any uniprocessor, 32 bit SGI machine running IRIX 5.3
37 *
38 * DESCRIPTION:
39 * This is the machine-dependent module for IRIX 5.3.
40 * It has been tested on Indys running 5.3 and Indigos running 5.3XFS
41 *
42 * LIBS: -lmld
43 * CFLAGS: -DHAVE_GETOPT
44 *
45 * AUTHOR: Sandeep Cariapa <cariapa@sgi.com>
46 * This is not a supported product of Silicon Graphics, Inc.
47 * Please do not call SGI for support.
48 *
49 */
50
51 #define _KMEMUSER
52
53 #include "config.h"
54
55 #include <sys/types.h>
56 #include <sys/time.h>
57 #include <sys/stat.h>
58 #include <sys/swap.h>
59 #include <sys/proc.h>
60 #include <sys/procfs.h>
61 #include <sys/sysinfo.h>
62 #include <sys/sysmp.h>
63 #include <paths.h>
64 #include <dirent.h>
65 #include <stdio.h>
66 #include <nlist.h>
67 #include <unistd.h>
68 #include <errno.h>
69 #include <fcntl.h>
70 #include "top.h"
71 #include "machine.h"
72
73 #ifdef IRIX64
74 #define nlist nlist64
75 #define lseek lseek64
76 #define off_t off64_t
77 #endif
78
79 #define UNIX "/unix"
80 #define KMEM "/dev/kmem"
81 #define CPUSTATES 6
82
83 #ifndef FSCALE
84 #define FSHIFT 8 /* bits to right of fixed binary point */
85 #define FSCALE (1<<FSHIFT)
86 #endif /* FSCALE */
87
88 #ifdef FIXED_LOADAVG
89 typedef long load_avg;
90 # define loaddouble(la) ((double)(la) / FIXED_LOADAVG)
91 # define intload(i) ((int)((i) * FIXED_LOADAVG))
92 #else
93 typedef double load_avg;
94 # define loaddouble(la) (la)
95 # define intload(i) ((double)(i))
96 #endif
97
98 #define percent_cpu(pp) (*(double *)pp->pr_fill)
99 #define weighted_cpu(pp) (*(double *)&pp->pr_fill[2])
100
101 static int pagesize;
102 #define pagetok(size) ((size)*pagesize)
103
104 static int numcpus;
105
106 /*
107 * These definitions control the format of the per-process area
108 */
109
110 static char header[] =
111 " PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND";
112 /* 0123456 -- field to fill in starts at header+6 */
113 #define UNAME_START 6
114
115 #define Proc_format \
116 "%5d %-8.8s %3d %4d %5s %5s %-5s %6s %5.2f%% %5.2f%% %.16s"
117
118 /* these are for detailing the process states */
119 char *state_abbrev[] =
120 {"", "sleep", "run\0\0\0", "zombie", "stop", "idle", "", "swap"};
121
122 int process_states[8];
123 char *procstatenames[] = {
124 "", " sleeping, ", " running, ", " zombie, ", " stopped, ",
125 " idle, ", "", " swapped, ",
126 NULL
127 };
128
129 /* these are for detailing the cpu states */
130 int cpu_states[CPUSTATES];
131 char *cpustatenames[] = {
132 "idle", "usr", "ker", "wait", "swp", "intr",
133 NULL
134 };
135
136 /* these are for detailing the memory statistics */
137
138 long memory_stats[5];
139 char *memorynames[] = {
140 "K max, ", "K avail, ", "K free, ", "K swap, ", "K free swap", NULL
141 };
142
143 /* useful externals */
144 extern int errno;
145 extern char *myname;
146 extern char *sys_errlist[];
147 extern char *format_k();
148 extern char *format_time();
149 extern long percentages();
150
151 /* forward references */
152 int proc_compare (void *pp1, void *pp2);
153
154 #define X_AVENRUN 0
155 #define X_NPROC 1
156 #define X_FREEMEM 2
157 #define X_MAXMEM 3
158 #define X_AVAILRMEM 4
159 #define X_MPID 5
160
161 static struct nlist nlst[] = {
162 { "avenrun" }, /* 0. Array containing the 3 load averages. */
163 { "nproc" }, /* 1. Kernel parameter: Max number of processes. */
164 { "freemem" }, /* 2. Amount of free memory in system. */
165 { "maxmem" }, /* 3. Maximum amount of memory usable by system. */
166 { "availrmem" }, /* 4. Available real memory. */
167 #ifndef IRIX64
168 { "mpid" }, /* 5. PID of last process. */
169 #endif
170 { 0 }
171 };
172 static unsigned long avenrun_offset;
173 static unsigned long nproc_offset;
174 static unsigned long freemem_offset;
175 static unsigned long maxmem_offset;
176 static unsigned long availrmem_offset;
177 static unsigned long mpid_offset;
178 double load[3];
179 char fmt[MAX_COLS];
180 static int kmem;
181 static int nproc;
182 static int bytes;
183 static struct prpsinfo *pbase;
184 static struct prpsinfo **pref;
185 static DIR *procdir;
186
187 /* get_process_info passes back a handle. This is what it looks like: */
188 struct handle {
189 struct prpsinfo **next_proc;/* points to next valid proc pointer */
190 int remaining; /* number of pointers remaining */
191 };
192
193 static struct handle handle;
194 void getptable();
195
196 /*
197 * Structure for keeping track of CPU times from last time around
198 * the program. We keep these things in a hash table, which is
199 * recreated at every cycle.
200 */
201 struct oldproc
202 {
203 pid_t oldpid;
204 double oldtime;
205 double oldpct;
206 };
207 static int oldprocs; /* size of table */
208 static struct oldproc *oldbase;
209 #define HASH(x) ((x << 1) % oldprocs)
210 #define PRPSINFOSIZE (sizeof(struct prpsinfo))
211
machine_init(statics)212 int machine_init(statics)
213 struct statics *statics;
214 {
215 struct oldproc *op, *endbase;
216
217 if ((kmem = open(KMEM, O_RDONLY)) == -1) {
218 perror(KMEM);
219 return(-1);
220 }
221
222 /* get the list of symbols we want to access in the kernel */
223 (void) nlist(UNIX, nlst);
224 if (nlst[0].n_type == 0) {
225 fprintf(stderr, "%s: nlist failed\n", myname);
226 return(-1);
227 }
228
229 /* Check if we got all of 'em. */
230 if (check_nlist(nlst) > 0) {
231 return(-1);
232 }
233 avenrun_offset = nlst[X_AVENRUN].n_value;
234 nproc_offset = nlst[X_NPROC].n_value;
235 freemem_offset = nlst[X_FREEMEM].n_value;
236 maxmem_offset = nlst[X_MAXMEM].n_value;
237 availrmem_offset = nlst[X_AVAILRMEM].n_value;
238 #ifndef IRIX64
239 mpid_offset = nlst[X_MPID].n_value;
240 #endif
241
242 /* Got to do this first so that we can map real estate for the
243 process array. */
244 (void) getkval(nproc_offset, (int *) (&nproc), sizeof(nproc), "nproc");
245
246 /* allocate space for proc structure array and array of pointers */
247 bytes = nproc * sizeof (struct prpsinfo);
248 pbase = (struct prpsinfo *) malloc (bytes);
249 pref = (struct prpsinfo **) malloc (nproc * sizeof (struct prpsinfo *));
250 oldbase = (struct oldproc *) malloc (2 * nproc * sizeof (struct oldproc));
251
252 /* Just in case ... */
253 if (pbase == (struct prpsinfo *) NULL || pref == (struct prpsinfo **) NULL ||
254 oldbase == (struct oldproc *)NULL) {
255 (void) fprintf (stderr, "%s: can't allocate sufficient memory\n", myname);
256 return (-1);
257 }
258
259 oldprocs = 2 * nproc;
260 endbase = oldbase + oldprocs;
261 for (op = oldbase; op < endbase; op++) {
262 op->oldpid = -1;
263 }
264
265 if (!(procdir = opendir (_PATH_PROCFSPI))) {
266 (void) fprintf (stderr, "Unable to open %s\n", _PATH_PROCFSPI);
267 return (-1);
268 }
269
270 if (chdir (_PATH_PROCFSPI)) {
271 /* handy for later on when we're reading it */
272 (void) fprintf (stderr, "Unable to chdir to %s\n", _PATH_PROCFSPI);
273 return (-1);
274 }
275
276 statics->procstate_names = procstatenames;
277 statics->cpustate_names = cpustatenames;
278 statics->memory_names = memorynames;
279
280 pagesize = getpagesize()/1024;
281
282 /* all done! */
283 return(0);
284 }
285
format_header(uname_field)286 char *format_header(uname_field)
287 register char *uname_field;
288
289 {
290 register char *ptr;
291
292 ptr = header + UNAME_START;
293 while (*uname_field != '\0') {
294 *ptr++ = *uname_field++;
295 }
296
297 return(header);
298 }
299
get_system_info(si)300 void get_system_info(si)
301 struct system_info *si;
302
303 {
304 register int i;
305 int avenrun[3];
306 static int freemem;
307 static int maxmem;
308 static int availrmem;
309 struct sysinfo sysinfo;
310 static long cp_new[CPUSTATES];
311 static long cp_old[CPUSTATES];
312 static long cp_diff[CPUSTATES]; /* for cpu state percentages */
313 off_t fswap; /* current free swap in blocks */
314 off_t tswap; /* total swap in blocks */
315
316 (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun), "avenrun");
317 for (i = 0; i < 3; i++) {
318 si->load_avg[i] = loaddouble (avenrun[i]);
319 si->load_avg[i] = si->load_avg[i]/1024.0;
320 }
321
322 (void) getkval(freemem_offset, (int *) (&freemem), sizeof(freemem),
323 "freemem");
324 (void) getkval(maxmem_offset, (int *) (&maxmem), sizeof(maxmem), "maxmem");
325 (void) getkval(availrmem_offset, (int *) (&availrmem), sizeof(availrmem),
326 "availrmem");
327 #ifdef IRIX64
328 si->last_pid = 0;
329 #else
330 (void) getkval(mpid_offset, &(si->last_pid), sizeof (si->last_pid), "mpid");
331 #endif
332 swapctl(SC_GETFREESWAP, &fswap);
333 swapctl(SC_GETSWAPTOT, &tswap);
334 memory_stats[0] = pagetok(maxmem);
335 memory_stats[1] = pagetok(availrmem);
336 memory_stats[2] = pagetok(freemem);
337 memory_stats[3] = tswap / 2;
338 memory_stats[4] = fswap / 2;
339
340 /* use sysmp() to get current sysinfo usage. Can run into all kinds of
341 problems if you try to nlist this kernel variable. */
342 if (sysmp(MP_SAGET, MPSA_SINFO, &sysinfo, sizeof(struct sysinfo)) == -1) {
343 perror("sysmp");
344 return;
345 }
346 /* copy sysinfo.cpu to an array of longs, as expected by percentages() */
347 for (i = 0; i < CPUSTATES; i++) {
348 cp_new[i] = sysinfo.cpu[i];
349 }
350 (void) percentages (CPUSTATES, cpu_states, cp_new, cp_old, cp_diff);
351
352 si->cpustates = cpu_states;
353 si->memory = memory_stats;
354
355 numcpus = sysmp(MP_NPROCS);
356
357 /* add a slash to the "run" state abbreviation */
358 if (numcpus > 1) {
359 state_abbrev[SRUN][3] = '/';
360 }
361
362 return;
363 }
364
get_process_info(si,sel,x)365 caddr_t get_process_info(si, sel, x)
366 struct system_info *si;
367 struct process_select *sel;
368 int x;
369 {
370 register int i;
371 register int total_procs;
372 register int active_procs;
373 register struct prpsinfo **prefp;
374 register struct prpsinfo *pp;
375
376 /* these are copied out of sel for speed */
377 int show_idle;
378 int show_system;
379 int show_uid;
380
381 /* read all the proc structures */
382 getptable (pbase);
383
384 /* get a pointer to the states summary array */
385 si->procstates = process_states;
386
387 /* set up flags which define what we are going to select */
388 show_idle = sel->idle;
389 show_system = sel->system;
390 show_uid = sel->uid != -1;
391
392 /* count up process states and get pointers to interesting procs */
393 total_procs = 0;
394 active_procs = 0;
395 (void) memset (process_states, 0, sizeof (process_states));
396 prefp = pref;
397
398 for (pp = pbase, i = 0; i < nproc; pp++, i++) {
399 /*
400 * Place pointers to each valid proc structure in pref[].
401 * Process slots that are actually in use have a non-zero
402 * status field. Processes with SSYS set are system
403 * processes---these get ignored unless show_system is set.
404 */
405 if (pp->pr_state != 0 &&
406 (show_system || ((pp->pr_flag & SSYS) == 0))) {
407 total_procs++;
408 process_states[pp->pr_state]++;
409 if ((!pp->pr_zomb) &&
410 (show_idle || (pp->pr_state == SRUN)) &&
411 (!show_uid || pp->pr_uid == (uid_t) sel->uid)) {
412 *prefp++ = pp;
413 active_procs++;
414 }
415 }
416 }
417
418 /* if requested, sort the "interesting" processes */
419 if (compare != NULL)
420 qsort ((char *) pref, active_procs, sizeof (struct prpsinfo *), proc_compare);
421
422 /* remember active and total counts */
423 si->p_total = total_procs;
424 si->p_active = active_procs;
425
426 /* pass back a handle */
427 handle.next_proc = pref;
428 handle.remaining = active_procs;
429 return((caddr_t)&handle);
430 }
431
format_next_process(handle,get_userid)432 char *format_next_process(handle, get_userid)
433 caddr_t handle;
434 char *(*get_userid)();
435
436 {
437 register struct prpsinfo *pp;
438 struct handle *hp;
439 register long cputime;
440 register double pctcpu;
441
442 /* find and remember the next proc structure */
443 hp = (struct handle *) handle;
444 pp = *(hp->next_proc++);
445 hp->remaining--;
446
447 /* get the cpu usage and calculate the cpu percentages */
448 cputime = pp->pr_time.tv_sec;
449 pctcpu = percent_cpu (pp);
450
451 if (numcpus > 1) {
452 if (pp->pr_sonproc < 0)
453 state_abbrev[SRUN][4] = '*';
454 else
455 state_abbrev[SRUN][4] = pp->pr_sonproc + '0';
456 }
457
458 /* format this entry */
459 sprintf (fmt,
460 Proc_format,
461 pp->pr_pid,
462 (*get_userid) (pp->pr_uid),
463 pp->pr_pri - PZERO,
464 pp->pr_nice - NZERO,
465 format_k(pagetok(pp->pr_size)),
466 format_k(pagetok(pp->pr_rssize)),
467 state_abbrev[pp->pr_state],
468 format_time(cputime),
469 weighted_cpu (pp),
470 pctcpu,
471 pp->pr_fname);
472
473 /* return the result */
474 return(fmt);
475 }
476
477 /*
478 * getkval(offset, ptr, size, refstr) - get a value out of the kernel.
479 * "offset" is the byte offset into the kernel for the desired value,
480 * "ptr" points to a buffer into which the value is retrieved,
481 * "size" is the size of the buffer (and the object to retrieve),
482 * "refstr" is a reference string used when printing error meessages,
483 * if "refstr" starts with a '!', then a failure on read will not
484 * be fatal (this may seem like a silly way to do things, but I
485 * really didn't want the overhead of another argument).
486 *
487 */
488
getkval(offset,ptr,size,refstr)489 int getkval(offset, ptr, size, refstr)
490 off_t offset;
491 int *ptr;
492 int size;
493 char *refstr;
494
495 {
496 if (lseek(kmem, offset, SEEK_SET) == -1) {
497 if (*refstr == '!')
498 refstr++;
499 (void) fprintf(stderr, "%s: lseek to %s: %s\n", KMEM,
500 refstr, strerror(errno));
501 quit(0);
502 }
503 if (read(kmem, (char *) ptr, size) == -1) {
504 if (*refstr == '!')
505 return(0);
506 else {
507 (void) fprintf(stderr, "%s: reading %s: %s\n", KMEM,
508 refstr, strerror(errno));
509 quit(0);
510 }
511 }
512 return(1);
513 }
514
515 /*
516 * proc_compare - comparison function for "qsort"
517 * Compares the resource consumption of two processes using five
518 * distinct keys. The keys (in descending order of importance) are:
519 * percent cpu, cpu ticks, state, resident set size, total virtual
520 * memory usage. The process states are ordered as follows (from least
521 * to most important): WAIT, zombie, sleep, stop, idle, run. The
522 * array declaration below maps a process state index into a number
523 * that reflects this ordering.
524 */
525
526
527 unsigned char sorted_state[] =
528 {
529 0, /* not used */
530 3, /* sleep */
531 6, /* run */
532 2, /* zombie */
533 4, /* stop */
534 5, /* idle */
535 0, /* not used */
536 1 /* being swapped (WAIT) */
537 };
538
proc_compare(pp1,pp2)539 int proc_compare (pp1, pp2)
540 void *pp1;
541 void *pp2;
542 {
543 register struct prpsinfo *p1;
544 register struct prpsinfo *p2;
545 register long result;
546
547 /* remove one level of indirection */
548 p1 = *(struct prpsinfo **)pp1;
549 p2 = *(struct prpsinfo **)pp2;
550
551 /* compare percent cpu (pctcpu) */
552 if ((result = (long) (p2->pr_cpu - p1->pr_cpu)) == 0) {
553 /* use cpticks to break the tie */
554 if ((result = p2->pr_time.tv_sec - p1->pr_time.tv_sec) == 0) {
555 /* use process state to break the tie */
556 if ((result = (long) (sorted_state[p2->pr_state] -
557 sorted_state[p1->pr_state])) == 0) {
558 /* use priority to break the tie */
559 if ((result = p2->pr_oldpri - p1->pr_oldpri) == 0) {
560 /* use resident set size (rssize) to break the tie */
561 if ((result = p2->pr_rssize - p1->pr_rssize) == 0) {
562 /* use total memory to break the tie */
563 result = (p2->pr_size - p1->pr_size);
564 }
565 }
566 }
567 }
568 }
569 return (result);
570 }
571
572 /* return the owner of the specified process. */
proc_owner(pid)573 int proc_owner (pid)
574 int pid;
575 {
576 register struct prpsinfo *p;
577 int i;
578
579 for (i = 0, p = pbase; i < nproc; i++, p++)
580 if (p->pr_pid == (oid_t)pid)
581 return ((int)p->pr_uid);
582
583 return (-1);
584 }
585
586 /*
587 * check_nlist(nlst) - checks the nlist to see if any symbols were not
588 * found. For every symbol that was not found, a one-line
589 * message is printed to stderr. The routine returns the
590 * number of symbols NOT found.
591 */
592
check_nlist(nlst)593 int check_nlist(nlst)
594 register struct nlist *nlst;
595
596 {
597 register int i;
598
599 /* check to see if we got ALL the symbols we requested */
600 /* this will write one line to stderr for every symbol not found */
601
602 i = 0;
603 while (nlst->n_name != NULL) {
604 if (nlst->n_type == 0) {
605 /* this one wasn't found */
606 fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
607 i = 1;
608 }
609 nlst++;
610 }
611
612 return(i);
613 }
614
615 /* get process table */
getptable(baseptr)616 void getptable (baseptr)
617 struct prpsinfo *baseptr;
618 {
619 struct prpsinfo *currproc; /* pointer to current proc structure */
620 int numprocs = 0;
621 int i;
622 struct dirent *directp;
623 struct oldproc *op;
624 static struct timeval lasttime =
625 {0L, 0L};
626 struct timeval thistime;
627 struct timezone thiszone;
628 double timediff;
629 double alpha, beta;
630 struct oldproc *endbase;
631
632 gettimeofday (&thistime, &thiszone);
633
634 /*
635 * To avoid divides, we keep times in nanoseconds. This is
636 * scaled by 1e7 rather than 1e9 so that when we divide we
637 * get percent.
638 */
639 if (lasttime.tv_sec)
640 timediff = ((double) thistime.tv_sec * 1.0e7 +
641 ((double) thistime.tv_usec * 10.0)) -
642 ((double) lasttime.tv_sec * 1.0e7 +
643 ((double) lasttime.tv_usec * 10.0));
644 else
645 timediff = 1.0e7;
646
647 /*
648 * constants for exponential average. avg = alpha * new + beta * avg
649 * The goal is 50% decay in 30 sec. However if the sample period
650 * is greater than 30 sec, there's not a lot we can do.
651 */
652 if (timediff < 30.0e7)
653 {
654 alpha = 0.5 * (timediff / 30.0e7);
655 beta = 1.0 - alpha;
656 }
657 else
658 {
659 alpha = 0.5;
660 beta = 0.5;
661 }
662
663 endbase = oldbase + oldprocs;
664 currproc = baseptr;
665
666
667 for (rewinddir (procdir); directp = readdir (procdir);)
668 {
669 int fd;
670
671 if ((fd = open (directp->d_name, O_RDONLY)) < 0)
672 continue;
673
674 currproc = &baseptr[numprocs];
675 if (ioctl (fd, PIOCPSINFO, currproc) < 0)
676 {
677 (void) close (fd);
678 continue;
679 }
680
681 /*
682 * SVr4 doesn't keep track of CPU% in the kernel, so we have
683 * to do our own. See if we've heard of this process before.
684 * If so, compute % based on CPU since last time.
685 */
686 op = oldbase + HASH (currproc->pr_pid);
687 while (1)
688 {
689 if (op->oldpid == -1) /* not there */
690 break;
691 if (op->oldpid == currproc->pr_pid)
692 { /* found old data */
693 percent_cpu (currproc) =
694 ((currproc->pr_time.tv_sec * 1.0e9 +
695 currproc->pr_time.tv_nsec)
696 - op->oldtime) / timediff;
697 weighted_cpu (currproc) =
698 op->oldpct * beta + percent_cpu (currproc) * alpha;
699
700 break;
701 }
702 op++; /* try next entry in hash table */
703 if (op == endbase) /* table wrapped around */
704 op = oldbase;
705 }
706
707 /* Otherwise, it's new, so use all of its CPU time */
708 if (op->oldpid == -1)
709 {
710 if (lasttime.tv_sec)
711 {
712 percent_cpu (currproc) =
713 (currproc->pr_time.tv_sec * 1.0e9 +
714 currproc->pr_time.tv_nsec) / timediff;
715 weighted_cpu (currproc) =
716 percent_cpu (currproc);
717 }
718 else
719 { /* first screen -- no difference is possible */
720 percent_cpu (currproc) = 0.0;
721 weighted_cpu (currproc) = 0.0;
722 }
723 }
724
725 numprocs++;
726 (void) close (fd);
727 }
728
729 if (nproc != numprocs)
730 nproc = numprocs;
731
732 /*
733 * Save current CPU time for next time around
734 * For the moment recreate the hash table each time, as the code
735 * is easier that way.
736 */
737 oldprocs = 2 * nproc;
738 endbase = oldbase + oldprocs;
739 for (op = oldbase; op < endbase; op++)
740 op->oldpid = -1;
741 for (i = 0, currproc = baseptr;
742 i < nproc;
743 i++, currproc = (struct prpsinfo *) ((char *) currproc + PRPSINFOSIZE))
744 {
745 /* find an empty spot */
746 op = oldbase + HASH (currproc->pr_pid);
747 while (1)
748 {
749 if (op->oldpid == -1)
750 break;
751 op++;
752 if (op == endbase)
753 op = oldbase;
754 }
755 op->oldpid = currproc->pr_pid;
756 op->oldtime = (currproc->pr_time.tv_sec * 1.0e9 +
757 currproc->pr_time.tv_nsec);
758 op->oldpct = weighted_cpu (currproc);
759 }
760 lasttime = thistime;
761
762 }
763
764