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: PowerPC running AIX 4.2 or higher 37 * 38 * DESCRIPTION: 39 * This is the machine-dependent module for AIX 4.2 and higher 40 * It is currenlty only tested on PowerPC architectures. 41 * 42 * TERMCAP: -lcurses 43 * 44 * CFLAGS: -DORDER -DHAVE_GETOPT 45 * 46 * LIBS: -bD:0x18000000 47 * 48 * AUTHOR: Joep Vesseur <joep@fwi.uva.nl> 49 * 50 * PATCHES: Antoine Tabary <tabary@bruyeres.cea.fr> 51 */ 52 53 #include "config.h" 54 55 #include <stdlib.h> 56 #include <stdio.h> 57 #include <fcntl.h> 58 #include <nlist.h> 59 #include <sys/sysinfo.h> 60 #include <procinfo.h> 61 #include <sys/proc.h> 62 #include <sys/times.h> 63 #include <sys/param.h> 64 #include <pwd.h> 65 #include "top.h" 66 #include "machine.h" 67 #include "utils.h" 68 69 70 #define PROCRESS(p) (((p)->pi_trss + (p)->pi_drss)*4) 71 #define PROCSIZE(p) (((p)->pi_tsize/1024+(p)->pi_dvm)*4) 72 #define PROCTIME(pi) (pi->pi_ru.ru_utime.tv_sec + pi->pi_ru.ru_stime.tv_sec) 73 74 75 /* 76 * structure definition taken from 'monitor' by Jussi Maki (jmaki@hut.fi) 77 */ 78 struct vmker { 79 uint n0,n1,n2,n3,n4,n5,n6,n7,n8; 80 uint totalmem; 81 uint badmem; /* this is used in RS/6000 model 220 */ 82 uint freemem; 83 uint n12; 84 uint numperm; /* this seems to keep other than text and data segment 85 usage; name taken from /usr/lpp/bos/samples/vmtune.c */ 86 uint totalvmem,freevmem; 87 uint n15, n16, n17, n18, n19; 88 }; 89 90 91 #define KMEM "/dev/kmem" 92 93 /* Indices in the nlist array */ 94 #define X_AVENRUN 0 95 #define X_SYSINFO 1 96 #define X_VMKER 2 97 #define X_PROC 3 98 #define X_V 4 99 100 static struct nlist nlst[] = { 101 { "avenrun", 0, 0, 0, 0, 0 }, /* 0 */ 102 { "sysinfo", 0, 0, 0, 0, 0 }, /* 1 */ 103 { "vmker", 0, 0, 0, 0, 0 }, /* 2 */ 104 { "proc", 0, 0, 0, 0, 0 }, /* 3 */ 105 { "v", 0, 0, 0, 0, 0 }, /* 4 */ 106 { NULL, 0, 0, 0, 0, 0 } 107 }; 108 109 110 /* get_process_info returns handle. definition is here */ 111 struct handle 112 { 113 struct procsinfo **next_proc; 114 int remaining; 115 }; 116 117 /* 118 * These definitions control the format of the per-process area 119 */ 120 static char header[] = 121 " PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND"; 122 /* 0123456 -- field to fill in starts at header+6 */ 123 #define UNAME_START 7 124 125 #define Proc_format \ 126 "%6d %-8.8s %3d %4d %5d%c %4d%c %-5s %6s %5.2f%% %5.2f%% %.14s%s" 127 128 129 /* these are for detailing the process states */ 130 int process_states[9]; 131 char *procstatenames[] = { 132 " none, ", " sleeping, ", " state2, ", " runnable, ", 133 " idle, ", " zombie, ", " stopped, ", " running, ", " swapped, ", 134 NULL 135 }; 136 137 138 /* these are for detailing the cpu states */ 139 int cpu_states[4]; 140 char *cpustatenames[] = { 141 "idle", "user", "kernel", "wait", 142 NULL 143 }; 144 145 /* these are for detailing the memory statistics */ 146 long memory_stats[4]; 147 char *memorynames[] = { 148 "K Total, ", "K Free, ", "K Buffers", NULL 149 }; 150 #define M_REAL 0 151 #define M_REALFREE 1 152 #define M_BUFFERS 2 153 154 long swap_stats[3]; 155 char *swapnames[] = { 156 "K Total, ", "K Free", NULL 157 }; 158 159 #define M_VIRTUAL 0 160 #define M_VIRTFREE 1 161 162 char *state_abbrev[] = { 163 "", "sleep", "", "", "sleep", "zomb", "stop", "run", "swap" 164 }; 165 166 /* sorting orders. first is default */ 167 char *ordernames[] = { 168 "cpu", "size", "res", "time", "pri", NULL 169 }; 170 171 /* compare routines */ 172 int compare_cpu(), compare_size(), compare_res(), compare_time(), 173 compare_prio(); 174 175 int (*proc_compares[])() = { 176 compare_cpu, 177 compare_size, 178 compare_res, 179 compare_time, 180 compare_prio, 181 NULL 182 }; 183 184 /* useful externals */ 185 extern int errno; 186 extern char *sys_errlist[]; 187 long lseek(); 188 long time(); 189 long percentages(); 190 191 192 /* useful globals */ 193 int kmem; /* file descriptor */ 194 195 /* offsets in kernel */ 196 static unsigned long avenrun_offset; 197 static unsigned long sysinfo_offset; 198 static unsigned long vmker_offset; 199 static unsigned long proc_offset; 200 static unsigned long v_offset; 201 202 /* used for calculating cpu state percentages */ 203 static long cp_time[CPU_NTIMES]; 204 static long cp_old[CPU_NTIMES]; 205 static long cp_diff[CPU_NTIMES]; 206 207 /* the runqueue length is a cumulative value. keep old value */ 208 long old_runque; 209 210 /* process info */ 211 struct var v_info; /* to determine nprocs */ 212 int nprocs; /* maximum nr of procs in proctab */ 213 int ncpus; /* nr of cpus installed */ 214 215 int ptsize; /* size of process table in bytes */ 216 struct proc *p_proc; /* a copy of the process table */ 217 struct procsinfo *p_info; /* needed for vm and ru info */ 218 struct procsinfo **pref; /* processes selected for display */ 219 int pref_len; /* number of processes selected */ 220 221 /* needed to calculate WCPU */ 222 unsigned long curtime; 223 224 225 /* 226 * Initialize globals, get kernel offsets and stuff... 227 */ 228 machine_init(struct statics *statics) 229 230 { 231 time_t uptime, now; 232 struct tms tbuf; 233 234 if ((kmem = open(KMEM, O_RDONLY)) == -1) { 235 perror(KMEM); 236 return -1; 237 } 238 239 /* get kernel symbol offsets */ 240 if (knlist(nlst, 5, sizeof(struct nlist)) != 0) { 241 perror("knlist"); 242 return -1; 243 } 244 avenrun_offset = nlst[X_AVENRUN].n_value; 245 sysinfo_offset = nlst[X_SYSINFO].n_value; 246 vmker_offset = nlst[X_VMKER].n_value; 247 proc_offset = nlst[X_PROC].n_value; 248 v_offset = nlst[X_V].n_value; 249 250 getkval(v_offset, (caddr_t)&v_info, sizeof v_info, "v"); 251 252 ncpus = v_info.v_ncpus; /* number of cpus */ 253 nprocs = PROCMASK(PIDMAX); 254 if (nprocs > 1024) nprocs = 1024; 255 256 ptsize = nprocs * sizeof (struct proc); 257 p_proc = (struct proc *)malloc(ptsize); 258 p_info = (struct procsinfo *)malloc(nprocs * sizeof (struct procsinfo)); 259 pref = (struct procsinfo **)malloc(nprocs * sizeof (struct procsinfo *)); 260 261 if (!p_proc || !p_info || !pref) { 262 fprintf(stderr, "top: not enough memory\n"); 263 return -1; 264 } 265 266 /* set boot time */ 267 now = time(NULL); 268 uptime = times(&tbuf) / HZ; 269 statics->boottime = now - uptime; 270 271 statics->procstate_names = procstatenames; 272 statics->cpustate_names = cpustatenames; 273 statics->memory_names = memorynames; 274 statics->order_names = ordernames; 275 statics->swap_names = swapnames; 276 277 return(0); 278 } 279 280 281 282 char *format_header(char *uname_field) 283 284 { 285 register char *ptr; 286 287 ptr = header + UNAME_START; 288 while (*uname_field != '\0') 289 { 290 *ptr++ = *uname_field++; 291 } 292 293 return(header); 294 } 295 296 297 298 void 299 get_system_info(struct system_info *si) 300 301 { 302 int load_avg[3]; 303 struct sysinfo s_info; 304 struct vmker m_info; 305 int i; 306 double total = 0; 307 308 /* get the load avarage array */ 309 getkval(avenrun_offset, (caddr_t)load_avg, sizeof load_avg, "avenrun"); 310 311 /* get the sysinfo structure */ 312 getkval(sysinfo_offset, (caddr_t)&s_info, sizeof s_info, "sysinfo"); 313 314 /* get vmker structure */ 315 getkval(vmker_offset, (caddr_t)&m_info, sizeof m_info, "vmker"); 316 317 /* convert load avarages to doubles */ 318 for (i = 0; i < 3; i++) 319 si->load_avg[i] = (double)load_avg[i]/65536.0; 320 321 /* calculate cpu state in percentages */ 322 for (i = 0; i < CPU_NTIMES; i++) { 323 cp_old[i] = cp_time[i]; 324 cp_time[i] = s_info.cpu[i]; 325 cp_diff[i] = cp_time[i] - cp_old[i]; 326 total += cp_diff[i]; 327 } 328 329 total = total/1000.0; /* top itself will correct this */ 330 for (i = 0; i < CPU_NTIMES; i++) { 331 cpu_states[i] = cp_diff[i] / total; 332 } 333 334 /* calculate memory statistics, scale 4K pages to megabytes */ 335 #define PAGE_TO_MB(a) ((a)*4/1024) 336 memory_stats[M_REAL] = PAGE_TO_MB(m_info.totalmem); 337 memory_stats[M_REALFREE] = PAGE_TO_MB(m_info.freemem); 338 memory_stats[M_BUFFERS] = PAGE_TO_MB(m_info.numperm); 339 swap_stats[M_VIRTUAL] = PAGE_TO_MB(m_info.totalvmem); 340 swap_stats[M_VIRTFREE] = PAGE_TO_MB(m_info.freevmem); 341 342 /* runnable processes */ 343 process_states[0] = s_info.runque - old_runque; 344 old_runque = s_info.runque; 345 346 si->cpustates = cpu_states; 347 si->memory = memory_stats; 348 si->swap = swap_stats; 349 } 350 351 static struct handle handle; 352 353 caddr_t 354 get_process_info(struct system_info *si, struct process_select *sel, int compare_index) 355 356 { 357 int i, nproc; 358 int ptsize_util; 359 int active_procs = 0, total_procs = 0; 360 struct procsinfo *pp, **p_pref = pref; 361 unsigned long pctcpu; 362 pid_t procsindex = 0; 363 struct proc *p; 364 365 si->procstates = process_states; 366 367 curtime = time(0); 368 369 /* get the procsinfo structures of all running processes */ 370 nproc = getprocs(p_info, sizeof (struct procsinfo), NULL, 0, 371 &procsindex, nprocs); 372 if (nproc < 0) { 373 perror("getprocs"); 374 quit(1); 375 } 376 377 /* the swapper has no cmd-line attached */ 378 strcpy(p_info[0].pi_comm, "swapper"); 379 380 /* get proc table */ 381 ptsize_util = (PROCMASK(p_info[nproc-1].pi_pid)+1) * sizeof(struct proc); 382 getkval(proc_offset, (caddr_t)p_proc, ptsize_util, "proc"); 383 384 memset(process_states, 0, sizeof process_states); 385 386 /* build a list of pointers to processes to show. walk through the 387 * list of procsinfo structures instead of the proc table since the 388 * mapping of procsinfo -> proctable is easy, the other way around 389 * is cumbersome 390 */ 391 for (pp = p_info, i = 0; i < nproc; pp++, i++) { 392 393 p = &p_proc[PROCMASK(pp->pi_pid)]; 394 395 /* AIX marks all runnable processes as ACTIVE. We want to know 396 which processes are sleeping, so check used cpu ticks and adjust 397 status field accordingly 398 */ 399 if (p->p_stat == SACTIVE && p->p_cpticks == 0) 400 p->p_stat = SIDL; 401 402 if (pp->pi_state && (sel->system || ((pp->pi_flags & SKPROC) == 0))) { 403 total_procs++; 404 process_states[p->p_stat]++; 405 if ( (pp->pi_state != SZOMB) && 406 (sel->idle || p->p_cpticks != 0 || (p->p_stat == SACTIVE)) 407 && (sel->uid == -1 || pp->pi_uid == (uid_t)sel->uid)) { 408 *p_pref++ = pp; 409 active_procs++; 410 } 411 } 412 } 413 414 /* the pref array now holds pointers to the procsinfo structures in 415 * the p_info array that were selected for display 416 */ 417 418 /* sort if requested */ 419 if (si->p_active) 420 qsort((char *)pref, active_procs, sizeof (struct procsinfo *), 421 proc_compares[compare_index]); 422 423 si->last_pid = -1; /* no way to figure out last used pid */ 424 si->p_total = total_procs; 425 si->p_active = pref_len = active_procs; 426 427 handle.next_proc = pref; 428 handle.remaining = active_procs; 429 430 return((caddr_t)&handle); 431 } 432 433 char fmt[MAX_COLS]; /* static area where result is built */ 434 435 /* define what weighted cpu is. use definition of %CPU from 'man ps(1)' */ 436 #define weighted_cpu(pp) (PROCTIME(pp) == 0 ? 0.0 : \ 437 (((PROCTIME(pp)*100.0)/(curtime-pi->pi_start)/ncpus))) 438 #define double_pctcpu(p) ((double)p->p_pctcpu/(double)FLT_MODULO) 439 440 char * 441 format_next_process(caddr_t handle, char *(*get_userid)()) 442 443 { 444 register struct handle *hp; 445 register struct procsinfo *pi; 446 register struct proc *p; 447 char *uname; 448 long cpu_time; 449 int proc_size, proc_ress; 450 char size_unit = 'K'; 451 char ress_unit = 'K'; 452 453 hp = (struct handle *)handle; 454 if (hp->remaining == 0) { /* safe guard */ 455 fmt[0] = '\0'; 456 return fmt; 457 } 458 pi = *(hp->next_proc++); 459 hp->remaining--; 460 p = &p_proc[PROCMASK(pi->pi_pid)]; 461 462 cpu_time = PROCTIME(pi); 463 464 /* we disply sizes up to 10M in KiloBytes, beyond 10M in MegaBytes */ 465 if ((proc_size = (pi->pi_tsize/1024+pi->pi_dvm)*4) > 10240) { 466 proc_size /= 1024; 467 size_unit = 'M'; 468 } 469 if ((proc_ress = (pi->pi_trss + pi->pi_drss)*4) > 10240) { 470 proc_ress /= 1024; 471 ress_unit = 'M'; 472 } 473 474 sprintf(fmt, Proc_format , 475 pi->pi_pid, /* PID */ 476 (*get_userid)(pi->pi_uid), /* login name */ 477 getpriority(PRIO_PROCESS, pi->pi_pid), 478 EXTRACT_NICE(p), /* fixed or vari */ 479 proc_size, /* size */ 480 size_unit, /* K or M */ 481 proc_ress, /* resident */ 482 ress_unit, /* K or M */ 483 state_abbrev[p->p_stat], /* process state */ 484 format_time(cpu_time), /* time used */ 485 weighted_cpu(pi), /* WCPU */ 486 100.0 * double_pctcpu(p), /* CPU */ 487 printable(pi->pi_comm), /* COMM */ 488 (pi->pi_flags & SKPROC) == 0 ? "" : " (sys)" /* kernel process? */ 489 ); 490 return(fmt); 491 } 492 493 494 /* 495 * getkval(offset, ptr, size, refstr) - get a value out of the kernel. 496 * "offset" is the byte offset into the kernel for the desired value, 497 * "ptr" points to a buffer into which the value is retrieved, 498 * "size" is the size of the buffer (and the object to retrieve), 499 * "refstr" is a reference string used when printing error meessages, 500 * if "refstr" starts with a '!', then a failure on read will not 501 * be fatal (this may seem like a silly way to do things, but I 502 * really didn't want the overhead of another argument). 503 * 504 */ 505 506 int 507 getkval(unsigned long offset, caddr_t ptr, int size, char *refstr) 508 509 { 510 int upper_2gb = 0; 511 512 /* reads above 2Gb are done by seeking to offset%2Gb, and supplying 513 * 1 (opposed to 0) as fourth parameter to readx (see 'man kmem') 514 */ 515 if (offset > 1<<31) { 516 upper_2gb = 1; 517 offset &= 0x7fffffff; 518 } 519 520 if (lseek(kmem, offset, SEEK_SET) != offset) { 521 fprintf(stderr, "top: lseek failed\n"); 522 quit(2); 523 } 524 525 if (readx(kmem, ptr, size, upper_2gb) != size) { 526 if (*refstr == '!') 527 return 0; 528 else { 529 fprintf(stderr, "top: kvm_read for %s: %s\n", refstr, 530 sys_errlist[errno]); 531 quit(2); 532 } 533 } 534 535 return 1 ; 536 } 537 538 /* comparison routine for qsort */ 539 /* 540 * The following code is taken from the solaris module and adjusted 541 * for AIX -- JV . 542 */ 543 544 #define ORDERKEY_PCTCPU \ 545 if (lresult = p2->p_pctcpu - p1->p_pctcpu, \ 546 (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0) 547 548 #define ORDERKEY_CPTICKS \ 549 if ((result = PROCTIME(pi2) - PROCTIME(pi1)) == 0) 550 551 552 #define ORDERKEY_STATE \ 553 if ((result = sorted_state[p2->p_stat] \ 554 - sorted_state[p1->p_stat]) == 0) 555 556 /* Nice values directly reflect the process' priority, and are always >0 ;-) */ 557 #define ORDERKEY_PRIO \ 558 if ((result = EXTRACT_NICE(p1) - EXTRACT_NICE(p2)) == 0) 559 560 #define ORDERKEY_RSSIZE \ 561 if ((result = PROCRESS(pi2) - PROCRESS(pi1)) == 0) 562 #define ORDERKEY_MEM \ 563 if ((result = PROCSIZE(pi2) - PROCSIZE(pi1)) == 0) 564 565 static unsigned char sorted_state[] = 566 { 567 0, /* not used */ 568 0, 569 0, 570 0, 571 3, /* sleep */ 572 1, /* zombie */ 573 4, /* stop */ 574 6, /* run */ 575 2, /* swap */ 576 }; 577 578 /* compare_cpu - the comparison function for sorting by cpu percentage */ 579 580 int 581 compare_cpu(struct procsinfo **ppi1, struct procsinfo **ppi2) 582 583 { 584 register struct procsinfo *pi1 = *ppi1, *pi2 = *ppi2; 585 register struct proc *p1; 586 register struct proc *p2; 587 register int result; 588 register long lresult; 589 590 p1 = &p_proc[PROCMASK(pi1->pi_pid)]; 591 p2 = &p_proc[PROCMASK(pi2->pi_pid)]; 592 593 ORDERKEY_PCTCPU 594 ORDERKEY_CPTICKS 595 ORDERKEY_STATE 596 ORDERKEY_PRIO 597 ORDERKEY_RSSIZE 598 ORDERKEY_MEM 599 ; 600 601 return result; 602 } 603 604 605 /* compare_size - the comparison function for sorting by total memory usage */ 606 607 int 608 compare_size(struct procsinfo **ppi1, struct procsinfo **ppi2) 609 610 { 611 register struct procsinfo *pi1 = *ppi1, *pi2 = *ppi2; 612 register struct proc *p1; 613 register struct proc *p2; 614 register int result; 615 register long lresult; 616 617 p1 = &p_proc[PROCMASK(pi1->pi_pid)]; 618 p2 = &p_proc[PROCMASK(pi2->pi_pid)]; 619 620 ORDERKEY_MEM 621 ORDERKEY_RSSIZE 622 ORDERKEY_PCTCPU 623 ORDERKEY_CPTICKS 624 ORDERKEY_STATE 625 ORDERKEY_PRIO 626 ; 627 628 return result; 629 } 630 631 632 /* compare_res - the comparison function for sorting by resident set size */ 633 634 int 635 compare_res(struct procsinfo **ppi1, struct procsinfo **ppi2) 636 637 { 638 register struct procsinfo *pi1 = *ppi1, *pi2 = *ppi2; 639 register struct proc *p1; 640 register struct proc *p2; 641 register int result; 642 register long lresult; 643 644 p1 = &p_proc[PROCMASK(pi1->pi_pid)]; 645 p2 = &p_proc[PROCMASK(pi2->pi_pid)]; 646 647 ORDERKEY_RSSIZE 648 ORDERKEY_MEM 649 ORDERKEY_PCTCPU 650 ORDERKEY_CPTICKS 651 ORDERKEY_STATE 652 ORDERKEY_PRIO 653 ; 654 655 return result; 656 } 657 658 659 /* compare_time - the comparison function for sorting by total cpu time */ 660 661 int 662 compare_time(struct procsinfo **ppi1, struct procsinfo **ppi2) 663 664 { 665 register struct procsinfo *pi1 = *ppi1, *pi2 = *ppi2; 666 register struct proc *p1; 667 register struct proc *p2; 668 register int result; 669 register long lresult; 670 671 p1 = &p_proc[PROCMASK(pi1->pi_pid)]; 672 p2 = &p_proc[PROCMASK(pi2->pi_pid)]; 673 674 ORDERKEY_CPTICKS 675 ORDERKEY_PCTCPU 676 ORDERKEY_STATE 677 ORDERKEY_PRIO 678 ORDERKEY_MEM 679 ORDERKEY_RSSIZE 680 ; 681 682 return result; 683 } 684 685 686 /* compare_prio - the comparison function for sorting by cpu percentage */ 687 688 int 689 compare_prio(struct procsinfo **ppi1, struct procsinfo **ppi2) 690 691 { 692 register struct procsinfo *pi1 = *ppi1, *pi2 = *ppi2; 693 register struct proc *p1; 694 register struct proc *p2; 695 register int result; 696 register long lresult; 697 698 p1 = &p_proc[PROCMASK(pi1->pi_pid)]; 699 p2 = &p_proc[PROCMASK(pi2->pi_pid)]; 700 701 ORDERKEY_PRIO 702 ORDERKEY_PCTCPU 703 ORDERKEY_CPTICKS 704 ORDERKEY_STATE 705 ORDERKEY_RSSIZE 706 ORDERKEY_MEM 707 ; 708 709 return result; 710 } 711 712 int 713 proc_owner(int pid) 714 715 { 716 int uid; 717 register struct procsinfo **prefp = pref; 718 register int cnt = pref_len; 719 720 while (--cnt >= 0) { 721 if ((*prefp)->pi_pid == pid) 722 return (*prefp)->pi_uid; 723 prefp++; 724 } 725 726 return(-1); 727 } 728 729 730