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 101static int pagesize; 102#define pagetok(size) ((size)*pagesize) 103 104static int numcpus; 105 106/* 107 * These definitions control the format of the per-process area 108 */ 109 110static 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 */ 119char *state_abbrev[] = 120{"", "sleep", "run\0\0\0", "zombie", "stop", "idle", "", "swap"}; 121 122int process_states[8]; 123char *procstatenames[] = { 124 "", " sleeping, ", " running, ", " zombie, ", " stopped, ", 125 " idle, ", "", " swapped, ", 126 NULL 127}; 128 129/* these are for detailing the cpu states */ 130int cpu_states[CPUSTATES]; 131char *cpustatenames[] = { 132 "idle", "usr", "ker", "wait", "swp", "intr", 133 NULL 134}; 135 136/* these are for detailing the memory statistics */ 137 138long memory_stats[5]; 139char *memorynames[] = { 140 "K max, ", "K avail, ", "K free, ", "K swap, ", "K free swap", NULL 141}; 142 143/* useful externals */ 144extern int errno; 145extern char *myname; 146extern char *sys_errlist[]; 147extern char *format_k(); 148extern char *format_time(); 149extern long percentages(); 150 151/* forward references */ 152int 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 161static 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}; 172static unsigned long avenrun_offset; 173static unsigned long nproc_offset; 174static unsigned long freemem_offset; 175static unsigned long maxmem_offset; 176static unsigned long availrmem_offset; 177static unsigned long mpid_offset; 178double load[3]; 179char fmt[MAX_COLS]; 180static int kmem; 181static int nproc; 182static int bytes; 183static struct prpsinfo *pbase; 184static struct prpsinfo **pref; 185static DIR *procdir; 186 187/* get_process_info passes back a handle. This is what it looks like: */ 188struct handle { 189 struct prpsinfo **next_proc;/* points to next valid proc pointer */ 190 int remaining; /* number of pointers remaining */ 191}; 192 193static struct handle handle; 194void 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 */ 201struct oldproc 202 { 203 pid_t oldpid; 204 double oldtime; 205 double oldpct; 206 }; 207static int oldprocs; /* size of table */ 208static struct oldproc *oldbase; 209#define HASH(x) ((x << 1) % oldprocs) 210#define PRPSINFOSIZE (sizeof(struct prpsinfo)) 211 212int 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 286char *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 300void 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 365caddr_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 432char *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 489int 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 527unsigned 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 539int 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. */ 573int 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 593int 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 */ 616void 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