home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume27 / top-3.2 / part12 < prev    next >
Encoding:
Text File  |  1993-08-08  |  43.3 KB  |  1,749 lines

  1. Newsgroups: comp.sources.unix
  2. From: phil@eecs.nwu.edu (William LeFebvre)
  3. Subject: v27i012: top - a top process display, version 3.2, Part12/13
  4. References: <1.744843136.4744@gw.home.vix.com>
  5. Sender: unix-sources-moderator@gw.home.vix.com
  6. Approved: vixie@gw.home.vix.com
  7.  
  8. Submitted-By: phil@eecs.nwu.edu (William LeFebvre)
  9. Posting-Number: Volume 27, Issue 12
  10. Archive-Name: top-3.2/part12
  11.  
  12. #! /bin/sh
  13. # This is a shell archive.  Remove anything before this line, then unpack
  14. # it by saving it into a file and typing "sh file".  To overwrite existing
  15. # files, type "sh file -c".  You can also feed this as standard input via
  16. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  17. # will see the following message at the end:
  18. #        "End of archive 12 (of 13)."
  19. # Contents:  machine/m_sunos4.c machine/m_sunos4mp.c
  20. # Wrapped by phil@pex on Wed Aug  4 14:22:46 1993
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. if test -f 'machine/m_sunos4.c' -a "${1}" != "-c" ; then 
  23.   echo shar: Will not clobber existing file \"'machine/m_sunos4.c'\"
  24. else
  25. echo shar: Extracting \"'machine/m_sunos4.c'\" \(20456 characters\)
  26. sed "s/^X//" >'machine/m_sunos4.c' <<'END_OF_FILE'
  27. X/*
  28. X * top - a top users display for Unix
  29. X *
  30. X * SYNOPSIS:  any Sun running SunOS version 4.x
  31. X *
  32. X * DESCRIPTION:
  33. X * This is the machine-dependent module for SunOS 4.x.
  34. X * This makes top work on the following systems:
  35. X *    SunOS 4.0
  36. X *    SunOS 4.0.1
  37. X *    SunOS 4.0.2 (including 386i architecture)
  38. X *    SunOS 4.0.3
  39. X *    SunOS 4.1
  40. X *    SunOS 4.1.1
  41. X *    SunOS 4.1.2 (including MP architectures)
  42. X *    SunOS 4.1.3 (including MP architectures)
  43. X *    Solbourne OS/MP PRIOR to 4.1A
  44. X *
  45. X * LIBS:  -lkvm
  46. X *
  47. X * AUTHOR:  William LeFebvre <phil@eecs.nwu.edu>
  48. X * Solbourne support by David MacKenzie <djm@eng.umd.edu>
  49. X */
  50. X
  51. X/*
  52. X * #ifdef MULTIPROCESSOR means Sun MP.
  53. X * #ifdef solbourne is for Solbourne.
  54. X */
  55. X
  56. X#include <sys/types.h>
  57. X#include <sys/signal.h>
  58. X
  59. X/* make sure param.h gets loaded with KERNEL defined to get PZERO & NZERO */
  60. X#define KERNEL
  61. X#include <sys/param.h>
  62. X#undef KERNEL
  63. X
  64. X#include <stdio.h>
  65. X#include <kvm.h>
  66. X#include <nlist.h>
  67. X#include <math.h>
  68. X#include <sys/dir.h>
  69. X#include <sys/user.h>
  70. X#include <sys/proc.h>
  71. X#include <sys/dk.h>
  72. X#include <sys/vm.h>
  73. X#include <sys/file.h>
  74. X#include <sys/time.h>
  75. X#include <vm/page.h>
  76. X
  77. X#ifdef solbourne
  78. X#include <sys/syscall.h>
  79. X#endif
  80. X
  81. X#include "top.h"
  82. X#include "machine.h"
  83. X
  84. X/* declarations for load_avg */
  85. X#include "loadavg.h"
  86. X
  87. X/* get_process_info passes back a handle.  This is what it looks like: */
  88. X
  89. Xstruct handle
  90. X{
  91. X    struct proc **next_proc;    /* points to next valid proc pointer */
  92. X    int remaining;        /* number of pointers remaining */
  93. X};
  94. X
  95. X/* define what weighted cpu is.  */
  96. X#define weighted_cpu(pct, pp) ((pp)->p_time == 0 ? 0.0 : \
  97. X             ((pct) / (1.0 - exp((pp)->p_time * logcpu))))
  98. X
  99. X/* what we consider to be process size: */
  100. X#define PROCSIZE(pp) ((pp)->p_tsize + (pp)->p_dsize + (pp)->p_ssize)
  101. X
  102. X/* definitions for indices in the nlist array */
  103. X#define X_AVENRUN    0
  104. X#define X_CCPU        1
  105. X#define X_MPID        2
  106. X#define X_NPROC        3
  107. X#define X_PROC        4
  108. X#define X_TOTAL        5
  109. X#define X_CP_TIME    6
  110. X#define X_PAGES        7
  111. X#define X_EPAGES    8
  112. X
  113. Xstatic struct nlist nlst[] = {
  114. X#ifdef i386
  115. X    { "avenrun" },        /* 0 */
  116. X    { "ccpu" },            /* 1 */
  117. X    { "mpid" },            /* 2 */
  118. X    { "nproc" },        /* 3 */
  119. X    { "proc" },            /* 4 */
  120. X    { "total" },        /* 5 */
  121. X    { "cp_time" },        /* 6 */
  122. X    { "pages" },        /* 7 */
  123. X    { "epages" },        /* 8 */
  124. X#else
  125. X    { "_avenrun" },        /* 0 */
  126. X    { "_ccpu" },        /* 1 */
  127. X    { "_mpid" },        /* 2 */
  128. X    { "_nproc" },        /* 3 */
  129. X    { "_proc" },        /* 4 */
  130. X    { "_total" },        /* 5 */
  131. X    { "_cp_time" },        /* 6 */
  132. X    { "_pages" },        /* 7 */
  133. X    { "_epages" },        /* 8 */
  134. X#ifdef MULTIPROCESSOR
  135. X    { "_ncpu" },
  136. X#define X_NCPU        9
  137. X    { "_xp_time" },
  138. X#define X_XP_TIME    10
  139. X#endif
  140. X#endif
  141. X    { 0 }
  142. X};
  143. X
  144. X/*
  145. X *  These definitions control the format of the per-process area
  146. X */
  147. X
  148. Xstatic char header[] =
  149. X  "  PID X        PRI NICE   SIZE   RES STATE   TIME   WCPU    CPU COMMAND";
  150. X/* 0123456   -- field to fill in starts at header+6 */
  151. X#define UNAME_START 6
  152. X
  153. X#define Proc_format \
  154. X    "%5d %-8.8s %3d %4d%6dK %4dK %-5s%4d:%02d %5.2f%% %5.2f%% %.14s"
  155. X
  156. X
  157. X/* process state names for the "STATE" column of the display */
  158. X/* the extra nulls in the string "run" are for adding a slash and
  159. X   the processor number when needed */
  160. X
  161. Xchar *state_abbrev[] =
  162. X{
  163. X    "", "sleep", "WAIT", "run\0\0\0", "start", "zomb", "stop"
  164. X};
  165. X
  166. X/* values that we stash away in _init and use in later routines */
  167. X
  168. Xstatic double logcpu;
  169. Xkvm_t *kd;
  170. X
  171. X/* these are retrieved from the kernel in _init */
  172. X
  173. Xstatic unsigned long proc;
  174. Xstatic          int  nproc;
  175. Xstatic load_avg ccpu;
  176. Xstatic unsigned long pages;
  177. Xstatic unsigned long epages;
  178. Xstatic          int  ncpu = 0;
  179. X
  180. X/* these are offsets obtained via nlist and used in the get_ functions */
  181. X
  182. Xstatic unsigned long mpid_offset;
  183. Xstatic unsigned long avenrun_offset;
  184. Xstatic unsigned long total_offset;
  185. Xstatic unsigned long cp_time_offset;
  186. X#ifdef MULTIPROCESSOR
  187. Xstatic unsigned long xp_time_offset;
  188. X#endif
  189. X
  190. X/* these are for calculating cpu state percentages */
  191. X
  192. Xstatic long cp_time[CPUSTATES];
  193. Xstatic long cp_old[CPUSTATES];
  194. Xstatic long cp_diff[CPUSTATES];
  195. X#ifdef MULTIPROCESSOR
  196. Xstatic long xp_time[NCPU][XPSTATES];
  197. X/* for now we only accumulate spin time, but extending this to pick up
  198. X   other stuff in xp_time is trivial.  */
  199. Xstatic long xp_old[NCPU];
  200. X#endif
  201. X
  202. X/* these are for detailing the process states */
  203. X
  204. Xint process_states[7];
  205. Xchar *procstatenames[] = {
  206. X    "", " sleeping, ", " ABANDONED, ", " running, ", " starting, ",
  207. X    " zombie, ", " stopped, ",
  208. X    NULL
  209. X};
  210. X
  211. X/* these are for detailing the cpu states */
  212. X
  213. Xint cpu_states[5];
  214. Xchar *cpustatenames[] = {
  215. X    "user", "nice", "system", "idle",
  216. X#ifdef MULTIPROCESSOR
  217. X    "spin",
  218. X#define XCP_SPIN 4
  219. X#endif
  220. X    NULL
  221. X};
  222. X
  223. X/* these are for detailing the memory statistics */
  224. X
  225. Xint memory_stats[4];
  226. Xchar *memorynames[] = {
  227. X    "K available, ", "K in use, ", "K free, ", "K locked", NULL
  228. X};
  229. X
  230. X/* these are for keeping track of the proc array */
  231. X
  232. Xstatic int bytes;
  233. Xstatic int pref_len;
  234. Xstatic struct proc *pbase;
  235. Xstatic struct proc **pref;
  236. X
  237. X/* these are for getting the memory statistics */
  238. X
  239. Xstatic struct page *physpage;
  240. Xstatic int bytesize;
  241. Xstatic int count;
  242. Xstatic int pageshift;        /* log base 2 of the pagesize */
  243. X
  244. X/* define pagetok in terms of pageshift */
  245. X
  246. X#define pagetok(size) ((size) << pageshift)
  247. X
  248. X/* useful externals */
  249. Xextern int errno;
  250. Xextern char *sys_errlist[];
  251. X
  252. Xlong lseek();
  253. Xlong time();
  254. Xlong percentages();
  255. X
  256. Xmachine_init(statics)
  257. X
  258. Xstruct statics *statics;
  259. X
  260. X{
  261. X    register int i;
  262. X    register int pagesize;
  263. X
  264. X    /* initialize the kernel interface */
  265. X    if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "top")) == NULL)
  266. X    {
  267. X    perror("kvm_open");
  268. X    return(-1);
  269. X    }
  270. X
  271. X    /* get the list of symbols we want to access in the kernel */
  272. X    if ((i = kvm_nlist(kd, nlst)) < 0)
  273. X    {
  274. X    fprintf(stderr, "top: nlist failed\n");
  275. X    return(-1);
  276. X    }
  277. X
  278. X#ifdef MULTIPROCESSOR
  279. X    /* were ncpu and xp_time not found in the nlist? */
  280. X    if (i > 0 && nlst[X_NCPU].n_type == 0 && nlst[X_XP_TIME].n_type == 0)
  281. X    {
  282. X    /* we were compiled on an MP system but we are not running on one */
  283. X    /* so we will pretend this didn't happen and set ncpu = 1 */
  284. X    i -= 2;
  285. X    ncpu = 1;
  286. X    }
  287. X#endif
  288. X
  289. X#ifdef solbourne
  290. X    {
  291. X    unsigned int status, type;
  292. X
  293. X    /* Get the number of CPUs on this system.  */
  294. X    syscall(SYS_getcpustatus, &status, &ncpu, &type);
  295. X    }
  296. X#endif
  297. X
  298. X    /* make sure they were all found */
  299. X    if (i > 0 && check_nlist(nlst) > 0)
  300. X    {
  301. X    return(-1);
  302. X    }
  303. X
  304. X    /* get the symbol values out of kmem */
  305. X    (void) getkval(nlst[X_PROC].n_value,   (int *)(&proc),    sizeof(proc),
  306. X        nlst[X_PROC].n_name);
  307. X    (void) getkval(nlst[X_NPROC].n_value,  &nproc,        sizeof(nproc),
  308. X        nlst[X_NPROC].n_name);
  309. X    (void) getkval(nlst[X_CCPU].n_value,   (int *)(&ccpu),    sizeof(ccpu),
  310. X        nlst[X_CCPU].n_name);
  311. X    (void) getkval(nlst[X_PAGES].n_value,  (int *)(&pages),    sizeof(pages),
  312. X        nlst[X_PAGES].n_name);
  313. X    (void) getkval(nlst[X_EPAGES].n_value, (int *)(&epages),    sizeof(epages),
  314. X        nlst[X_EPAGES].n_name);
  315. X#ifdef MULTIPROCESSOR
  316. X    if (ncpu == 0)
  317. X    {
  318. X    /* if ncpu > 0 then we are not really on an MP system */
  319. X    (void) getkval(nlst[X_NCPU].n_value,   (int *)(&ncpu),    sizeof(ncpu),
  320. X               nlst[X_NCPU].n_name);
  321. X    }
  322. X#endif
  323. X
  324. X    /* stash away certain offsets for later use */
  325. X    mpid_offset = nlst[X_MPID].n_value;
  326. X    avenrun_offset = nlst[X_AVENRUN].n_value;
  327. X    total_offset = nlst[X_TOTAL].n_value;
  328. X    cp_time_offset = nlst[X_CP_TIME].n_value;
  329. X#ifdef MULTIPROCESSOR
  330. X    xp_time_offset = nlst[X_XP_TIME].n_value;
  331. X#endif
  332. X
  333. X    /* this is used in calculating WCPU -- calculate it ahead of time */
  334. X    logcpu = log(loaddouble(ccpu));
  335. X
  336. X    /* allocate space for proc structure array and array of pointers */
  337. X    bytes = nproc * sizeof(struct proc);
  338. X    pbase = (struct proc *)malloc(bytes);
  339. X    pref  = (struct proc **)malloc(nproc * sizeof(struct proc *));
  340. X
  341. X    /* Just in case ... */
  342. X    if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL)
  343. X    {
  344. X    fprintf(stderr, "top: can't allocate sufficient memory\n");
  345. X    return(-1);
  346. X    }
  347. X
  348. X    /* allocate a table to hold all the page structs */
  349. X    bytesize = epages - pages;
  350. X    count = bytesize / sizeof(struct page);
  351. X    physpage = (struct page *)malloc(epages - pages);
  352. X    if (physpage == NULL)
  353. X    {
  354. X    fprintf(stderr, "top: can't allocate sufficient memory\n");
  355. X    return(-1);
  356. X    }
  357. X   
  358. X    /* get the page size with "getpagesize" and calculate pageshift from it */
  359. X    pagesize = getpagesize();
  360. X    pageshift = 0;
  361. X    while (pagesize > 1)
  362. X    {
  363. X    pageshift++;
  364. X    pagesize >>= 1;
  365. X    }
  366. X
  367. X    /* we only need the amount of log(2)1024 for our conversion */
  368. X    pageshift -= LOG1024;
  369. X
  370. X#if defined(MULTIPROCESSOR) || defined(solbourne)
  371. X    /* add a slash to the "run" state abbreviation */
  372. X    if (ncpu > 1)
  373. X    {
  374. X    state_abbrev[SRUN][3] = '/';
  375. X    }
  376. X#endif
  377. X
  378. X    /* fill in the statics information */
  379. X    statics->procstate_names = procstatenames;
  380. X    statics->cpustate_names = cpustatenames;
  381. X    statics->memory_names = memorynames;
  382. X
  383. X    /* all done! */
  384. X    return(0);
  385. X}
  386. X
  387. Xchar *format_header(uname_field)
  388. X
  389. Xregister char *uname_field;
  390. X
  391. X{
  392. X    register char *ptr;
  393. X
  394. X    ptr = header + UNAME_START;
  395. X    while (*uname_field != '\0')
  396. X    {
  397. X    *ptr++ = *uname_field++;
  398. X    }
  399. X
  400. X    return(header);
  401. X}
  402. X
  403. Xget_system_info(si)
  404. X
  405. Xstruct system_info *si;
  406. X
  407. X{
  408. X    load_avg avenrun[3];
  409. X    long total;
  410. X#ifdef MULTIPROCESSOR
  411. X    long half_total;
  412. X#endif
  413. X
  414. X    /* get the cp_time array */
  415. X    (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),
  416. X           "_cp_time");
  417. X
  418. X#ifdef MULTIPROCESSOR
  419. X    /* get the xp_time array as well */
  420. X    if (ncpu > 1)
  421. X    {
  422. X    (void) getkval(xp_time_offset, (int *)xp_time, sizeof(xp_time),
  423. X               "_xp_time");
  424. X    }
  425. X#endif
  426. X
  427. X    /* get load average array */
  428. X    (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
  429. X           "_avenrun");
  430. X
  431. X    /* get mpid -- process id of last process */
  432. X    (void) getkval(mpid_offset, &(si->last_pid), sizeof(si->last_pid),
  433. X           "_mpid");
  434. X
  435. X    /* get the array of physpage descriptors */
  436. X    (void) getkval(pages, (int *)physpage, bytesize, "array _page");
  437. X
  438. X    /* convert load averages to doubles */
  439. X    {
  440. X    register int i;
  441. X    register double *infoloadp;
  442. X    register load_avg *sysloadp;
  443. X
  444. X    infoloadp = si->load_avg;
  445. X    sysloadp = avenrun;
  446. X    for (i = 0; i < 3; i++)
  447. X    {
  448. X        *infoloadp++ = loaddouble(*sysloadp++);
  449. X    }
  450. X    }
  451. X
  452. X    /* convert cp_time counts to percentages */
  453. X    total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
  454. X
  455. X#ifdef MULTIPROCESSOR
  456. X    /* calculate spin time from all processors */
  457. X    if (ncpu > 1)
  458. X    {
  459. X    register int c;
  460. X    register int i;
  461. X    register long sum;
  462. X    register long change;
  463. X
  464. X    /* collect differences for each processor and add them */
  465. X    sum = 0;
  466. X    for (i = 0; i < ncpu; i++)
  467. X    {
  468. X        c = xp_time[i][XP_SPIN];
  469. X        change = c - xp_old[i];
  470. X        if (change < 0)
  471. X        {
  472. X        /* counter wrapped */
  473. X        change = (long)((unsigned long)c -
  474. X                (unsigned long)xp_old[i]);
  475. X        }
  476. X        sum += change;
  477. X        xp_old[i] = c;
  478. X    }
  479. X
  480. X    /*
  481. X     *  NOTE:  I am assuming that the ticks found in xp_time are
  482. X     *  already included in the ticks accumulated in cp_time.  To
  483. X     *  get an accurate reflection, therefore, we have to subtract
  484. X     *  the spin time from the system time and recompute those two
  485. X     *  percentages.
  486. X     */
  487. X    half_total = total / 2l;
  488. X    cp_diff[CP_SYS] -= sum;
  489. X    cpu_states[CP_SYS] = (int)((cp_diff[CP_SYS] * 1000 + half_total) /
  490. X                   total);
  491. X    cpu_states[XCP_SPIN] = (int)((sum * 1000 + half_total) / total);
  492. X    }
  493. X#endif
  494. X
  495. X    /* sum memory statistics */
  496. X    {
  497. X    register struct page *pp;
  498. X    register int cnt;
  499. X    register int inuse;
  500. X    register int free;
  501. X    register int locked;
  502. X
  503. X    /* bop thru the array counting page types */
  504. X    pp = physpage;
  505. X    inuse = free = locked = 0;
  506. X    for (cnt = count; --cnt >= 0; pp++)
  507. X    {
  508. X        if (pp->p_free)
  509. X            free++;
  510. X        else if (pp->p_lock || pp->p_keepcnt > 0)
  511. X            locked++;
  512. X        else
  513. X            inuse++;
  514. X    }
  515. X
  516. X    /* convert memory stats to Kbytes */
  517. X    memory_stats[0] = pagetok(inuse + free);
  518. X    memory_stats[1] = pagetok(inuse);
  519. X    memory_stats[2] = pagetok(free);
  520. X    memory_stats[3] = pagetok(locked);
  521. X    }
  522. X
  523. X    /* set arrays and strings */
  524. X    si->cpustates = cpu_states;
  525. X    si->memory = memory_stats;
  526. X}
  527. X
  528. Xstatic struct handle handle;
  529. X
  530. Xcaddr_t get_process_info(si, sel, compare)
  531. X
  532. Xstruct system_info *si;
  533. Xstruct process_select *sel;
  534. Xint (*compare)();
  535. X
  536. X{
  537. X    register int i;
  538. X    register int total_procs;
  539. X    register int active_procs;
  540. X    register struct proc **prefp;
  541. X    register struct proc *pp;
  542. X
  543. X    /* these are copied out of sel for speed */
  544. X    int show_idle;
  545. X    int show_system;
  546. X    int show_uid;
  547. X    int show_command;
  548. X
  549. X    /* read all the proc structures in one fell swoop */
  550. X    (void) getkval(proc, (int *)pbase, bytes, "proc array");
  551. X
  552. X    /* get a pointer to the states summary array */
  553. X    si->procstates = process_states;
  554. X
  555. X    /* set up flags which define what we are going to select */
  556. X    show_idle = sel->idle;
  557. X    show_system = sel->system;
  558. X    show_uid = sel->uid != -1;
  559. X    show_command = sel->command != NULL;
  560. X
  561. X    /* count up process states and get pointers to interesting procs */
  562. X    total_procs = 0;
  563. X    active_procs = 0;
  564. X    bzero((char *)process_states, sizeof(process_states));
  565. X    prefp = pref;
  566. X    for (pp = pbase, i = 0; i < nproc; pp++, i++)
  567. X    {
  568. X    /*
  569. X     *  Place pointers to each valid proc structure in pref[].
  570. X     *  Process slots that are actually in use have a non-zero
  571. X     *  status field.  Processes with SSYS set are system
  572. X     *  processes---these get ignored unless show_sysprocs is set.
  573. X     */
  574. X    if (pp->p_stat != 0 &&
  575. X        (show_system || ((pp->p_flag & SSYS) == 0)))
  576. X    {
  577. X        total_procs++;
  578. X        process_states[pp->p_stat]++;
  579. X        if ((pp->p_stat != SZOMB) &&
  580. X        (show_idle || (pp->p_pctcpu != 0) || (pp->p_stat == SRUN)) &&
  581. X        (!show_uid || pp->p_uid == (uid_t)sel->uid))
  582. X        {
  583. X        *prefp++ = pp;
  584. X        active_procs++;
  585. X        }
  586. X    }
  587. X    }
  588. X
  589. X    /* if requested, sort the "interesting" processes */
  590. X    if (compare != NULL)
  591. X    {
  592. X    qsort((char *)pref, active_procs, sizeof(struct proc *), compare);
  593. X    }
  594. X
  595. X    /* remember active and total counts */
  596. X    si->p_total = total_procs;
  597. X    si->p_active = pref_len = active_procs;
  598. X
  599. X    /* pass back a handle */
  600. X    handle.next_proc = pref;
  601. X    handle.remaining = active_procs;
  602. X    return((caddr_t)&handle);
  603. X}
  604. X
  605. Xchar fmt[128];        /* static area where result is built */
  606. X
  607. Xchar *format_next_process(handle, get_userid)
  608. X
  609. Xcaddr_t handle;
  610. Xchar *(*get_userid)();
  611. X
  612. X{
  613. X    register struct proc *pp;
  614. X    register long cputime;
  615. X    register double pct;
  616. X    struct user u;
  617. X    struct handle *hp;
  618. X
  619. X    /* find and remember the next proc structure */
  620. X    hp = (struct handle *)handle;
  621. X    pp = *(hp->next_proc++);
  622. X    hp->remaining--;
  623. X    
  624. X    /* get the process's user struct and set cputime */
  625. X    if (getu(pp, &u) == -1)
  626. X    {
  627. X    (void) strcpy(u.u_comm, "<swapped>");
  628. X    cputime = 0;
  629. X    }
  630. X    else
  631. X    {
  632. X    /* set u_comm for system processes */
  633. X    if (u.u_comm[0] == '\0')
  634. X    {
  635. X        if (pp->p_pid == 0)
  636. X        {
  637. X        (void) strcpy(u.u_comm, "Swapper");
  638. X        }
  639. X        else if (pp->p_pid == 2)
  640. X        {
  641. X        (void) strcpy(u.u_comm, "Pager");
  642. X        }
  643. X    }
  644. X
  645. X    cputime = u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec;
  646. X    }
  647. X
  648. X    /* calculate the base for cpu percentages */
  649. X    pct = pctdouble(pp->p_pctcpu);
  650. X
  651. X#ifdef MULTIPROCESSOR
  652. X    /*
  653. X     *  If there is more than one cpu then add the processor number to
  654. X     *  the "run/" string.  Note that this will only show up if the
  655. X     *  process is in the run state.  Also note:  when they
  656. X     *  start making Suns with more than 9 processors this will break
  657. X     *  since the string will then be more than 5 characters.
  658. X     */
  659. X    if (ncpu > 1)
  660. X    {
  661. X    state_abbrev[SRUN][4] = (pp->p_cpuid & 0xf) + '0';
  662. X    }
  663. X#endif
  664. X#ifdef solbourne
  665. X    if (ncpu > 1)
  666. X      {
  667. X    state_abbrev[SRUN][4] = (pp->p_lastcpu) + '0';
  668. X      }
  669. X#endif
  670. X
  671. X    /* format this entry */
  672. X    sprintf(fmt,
  673. X        Proc_format,
  674. X        pp->p_pid,
  675. X        (*get_userid)(pp->p_uid),
  676. X        pp->p_pri - PZERO,
  677. X        pp->p_nice - NZERO,
  678. X        pagetok(PROCSIZE(pp)),
  679. X        pagetok(pp->p_rssize),
  680. X        state_abbrev[pp->p_stat],
  681. X        cputime / 60l,
  682. X        cputime % 60l,
  683. X        100.0 * weighted_cpu(pct, pp),
  684. X        100.0 * pct,
  685. X        printable(u.u_comm));
  686. X
  687. X    /* return the result */
  688. X    return(fmt);
  689. X}
  690. X
  691. X/*
  692. X *  getu(p, u) - get the user structure for the process whose proc structure
  693. X *    is pointed to by p.  The user structure is put in the buffer pointed
  694. X *    to by u.  Return 0 if successful, -1 on failure (such as the process
  695. X *    being swapped out).
  696. X */
  697. X
  698. Xgetu(p, u)
  699. X
  700. Xregister struct proc *p;
  701. Xstruct user *u;
  702. X
  703. X{
  704. X    register struct user *lu;
  705. X
  706. X    lu = kvm_getu(kd, p);
  707. X    if (lu == NULL)
  708. X    {
  709. X    return(-1);
  710. X    }
  711. X    else
  712. X    {
  713. X    *u = *lu;
  714. X    return(0);
  715. X    }
  716. X}
  717. X
  718. X/*
  719. X * check_nlist(nlst) - checks the nlist to see if any symbols were not
  720. X *        found.  For every symbol that was not found, a one-line
  721. X *        message is printed to stderr.  The routine returns the
  722. X *        number of symbols NOT found.
  723. X */
  724. X
  725. Xint check_nlist(nlst)
  726. X
  727. Xregister struct nlist *nlst;
  728. X
  729. X{
  730. X    register int i;
  731. X
  732. X    /* check to see if we got ALL the symbols we requested */
  733. X    /* this will write one line to stderr for every symbol not found */
  734. X
  735. X    i = 0;
  736. X    while (nlst->n_name != NULL)
  737. X    {
  738. X#ifdef i386
  739. X    if (nlst->n_value == 0)
  740. X#else
  741. X    if (nlst->n_type == 0)
  742. X#endif
  743. X    {
  744. X        /* this one wasn't found */
  745. X        fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
  746. X        i = 1;
  747. X    }
  748. X    nlst++;
  749. X    }
  750. X
  751. X    return(i);
  752. X}
  753. X
  754. X
  755. X/*
  756. X *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
  757. X *    "offset" is the byte offset into the kernel for the desired value,
  758. X *      "ptr" points to a buffer into which the value is retrieved,
  759. X *      "size" is the size of the buffer (and the object to retrieve),
  760. X *      "refstr" is a reference string used when printing error meessages,
  761. X *        if "refstr" starts with a '!', then a failure on read will not
  762. X *          be fatal (this may seem like a silly way to do things, but I
  763. X *          really didn't want the overhead of another argument).
  764. X *      
  765. X */
  766. X
  767. Xgetkval(offset, ptr, size, refstr)
  768. X
  769. Xunsigned long offset;
  770. Xint *ptr;
  771. Xint size;
  772. Xchar *refstr;
  773. X
  774. X{
  775. X    if (kvm_read(kd, offset, ptr, size) != size)
  776. X    {
  777. X    if (*refstr == '!')
  778. X    {
  779. X        return(0);
  780. X    }
  781. X    else
  782. X    {
  783. X        fprintf(stderr, "top: kvm_read for %s: %s\n",
  784. X        refstr, sys_errlist[errno]);
  785. X        quit(23);
  786. X        /*NOTREACHED*/
  787. X    }
  788. X    }
  789. X    return(1);
  790. X}
  791. X    
  792. X/* comparison routine for qsort */
  793. X
  794. X/*
  795. X *  proc_compare - comparison function for "qsort"
  796. X *    Compares the resource consumption of two processes using five
  797. X *      distinct keys.  The keys (in descending order of importance) are:
  798. X *      percent cpu, cpu ticks, state, resident set size, total virtual
  799. X *      memory usage.  The process states are ordered as follows (from least
  800. X *      to most important):  WAIT, zombie, sleep, stop, start, run.  The
  801. X *      array declaration below maps a process state index into a number
  802. X *      that reflects this ordering.
  803. X */
  804. X
  805. Xstatic unsigned char sorted_state[] =
  806. X{
  807. X    0,    /* not used        */
  808. X    3,    /* sleep        */
  809. X    1,    /* ABANDONED (WAIT)    */
  810. X    6,    /* run            */
  811. X    5,    /* start        */
  812. X    2,    /* zombie        */
  813. X    4    /* stop            */
  814. X};
  815. Xproc_compare(pp1, pp2)
  816. X
  817. Xstruct proc **pp1;
  818. Xstruct proc **pp2;
  819. X
  820. X{
  821. X    register struct proc *p1;
  822. X    register struct proc *p2;
  823. X    register int result;
  824. X    register pctcpu lresult;
  825. X
  826. X    /* remove one level of indirection */
  827. X    p1 = *pp1;
  828. X    p2 = *pp2;
  829. X
  830. X    /* compare percent cpu (pctcpu) */
  831. X    if ((lresult = p2->p_pctcpu - p1->p_pctcpu) == 0)
  832. X    {
  833. X    /* use cpticks to break the tie */
  834. X    if ((result = p2->p_cpticks - p1->p_cpticks) == 0)
  835. X    {
  836. X        /* use process state to break the tie */
  837. X        if ((result = sorted_state[p2->p_stat] -
  838. X              sorted_state[p1->p_stat])  == 0)
  839. X        {
  840. X        /* use priority to break the tie */
  841. X        if ((result = p2->p_pri - p1->p_pri) == 0)
  842. X        {
  843. X            /* use resident set size (rssize) to break the tie */
  844. X            if ((result = p2->p_rssize - p1->p_rssize) == 0)
  845. X            {
  846. X            /* use total memory to break the tie */
  847. X            result = PROCSIZE(p2) - PROCSIZE(p1);
  848. X            }
  849. X        }
  850. X        }
  851. X    }
  852. X    }
  853. X    else
  854. X    {
  855. X    result = lresult < 0 ? -1 : 1;
  856. X    }
  857. X
  858. X    return(result);
  859. X}
  860. X
  861. X/*
  862. X * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
  863. X *        the process does not exist.
  864. X *        It is EXTREMLY IMPORTANT that this function work correctly.
  865. X *        If top runs setuid root (as in SVR4), then this function
  866. X *        is the only thing that stands in the way of a serious
  867. X *        security problem.  It validates requests for the "kill"
  868. X *        and "renice" commands.
  869. X */
  870. X
  871. Xint proc_owner(pid)
  872. X
  873. Xint pid;
  874. X
  875. X{
  876. X    register int cnt;
  877. X    register struct proc **prefp;
  878. X    register struct proc *pp;
  879. X
  880. X    prefp = pref;
  881. X    cnt = pref_len;
  882. X    while (--cnt >= 0)
  883. X    {
  884. X    if ((pp = *prefp++)->p_pid == (pid_t)pid)
  885. X    {
  886. X        return((int)pp->p_uid);
  887. X    }
  888. X    }
  889. X    return(-1);
  890. X}
  891. END_OF_FILE
  892. if test 20456 -ne `wc -c <'machine/m_sunos4.c'`; then
  893.     echo shar: \"'machine/m_sunos4.c'\" unpacked with wrong size!
  894. fi
  895. # end of 'machine/m_sunos4.c'
  896. fi
  897. if test -f 'machine/m_sunos4mp.c' -a "${1}" != "-c" ; then 
  898.   echo shar: Will not clobber existing file \"'machine/m_sunos4mp.c'\"
  899. else
  900. echo shar: Extracting \"'machine/m_sunos4mp.c'\" \(19935 characters\)
  901. sed "s/^X//" >'machine/m_sunos4mp.c' <<'END_OF_FILE'
  902. X/*
  903. X * top - a top users display for Unix
  904. X *
  905. X * SYNOPSIS:  any multi-processor Sun running SunOS versions 4.1.2 or 4.1.3
  906. X *
  907. X * DESCRIPTION:
  908. X * This is the machine-dependent module for SunOS 4.x with multi-processor
  909. X * support.  This module always compiles code for multiprocessors and
  910. X * assumes that it is being compiled on a multiprocessor architecture
  911. X * such as sun4m).  This makes top work on the following systems:
  912. X *    SunOS 4.1.2 (MP architectures only)
  913. X *    SunOS 4.1.3 (MP architectures only)
  914. X *    Solbourne running os/mp 4.1b or later only
  915. X *
  916. X * LIBS:  -lkvm
  917. X *
  918. X * AUTHOR:  William LeFebvre <phil@eecs.nwu.edu>
  919. X * Solbourne support by David MacKenzie <djm@eng.umd.edu>
  920. X */
  921. X
  922. X/*
  923. X * #ifdef MULTIPROCESSOR means Sun MP or newer Solbourne
  924. X */
  925. X
  926. X#include <sys/types.h>
  927. X#include <sys/signal.h>
  928. X
  929. X/*
  930. X * When including files, we need to have MULTIPROCESSOR on so that a version
  931. X * compiled on a non-MP system will work on an MP system.  We must take
  932. X * great care, then in pur interpretation of certain preprocessor constants,
  933. X * such as NCPU, XPSTATES, XP_*.
  934. X */
  935. X#ifndef MULTIPROCESSOR
  936. X#define MULTIPROCESSOR
  937. X#endif
  938. X
  939. X/* make sure param.h gets loaded with KERNEL defined to get PZERO & NZERO */
  940. X#define KERNEL
  941. X#include <sys/param.h>
  942. X#undef KERNEL
  943. X
  944. X#include <stdio.h>
  945. X#include <kvm.h>
  946. X#include <nlist.h>
  947. X#include <math.h>
  948. X#include <sys/dir.h>
  949. X#include <sys/user.h>
  950. X#include <sys/proc.h>
  951. X#include <sys/dk.h>
  952. X#include <sys/vm.h>
  953. X#include <sys/file.h>
  954. X#include <sys/time.h>
  955. X#include <vm/page.h>
  956. X
  957. X#include "top.h"
  958. X#include "machine.h"
  959. X
  960. X/* declarations for load_avg */
  961. X#include "loadavg.h"
  962. X
  963. X/* get_process_info passes back a handle.  This is what it looks like: */
  964. X
  965. Xstruct handle
  966. X{
  967. X    struct proc **next_proc;    /* points to next valid proc pointer */
  968. X    int remaining;        /* number of pointers remaining */
  969. X};
  970. X
  971. X/* define what weighted cpu is.  */
  972. X#define weighted_cpu(pct, pp) ((pp)->p_time == 0 ? 0.0 : \
  973. X             ((pct) / (1.0 - exp((pp)->p_time * logcpu))))
  974. X
  975. X/* what we consider to be process size: */
  976. X#define PROCSIZE(pp) ((pp)->p_tsize + (pp)->p_dsize + (pp)->p_ssize)
  977. X
  978. X/* definitions for indices in the nlist array */
  979. X#define X_AVENRUN    0
  980. X#define X_CCPU        1
  981. X#define X_MPID        2
  982. X#define X_NPROC        3
  983. X#define X_PROC        4
  984. X#define X_TOTAL        5
  985. X#define X_CP_TIME    6
  986. X#define X_PAGES        7
  987. X#define X_EPAGES    8
  988. X
  989. Xstatic struct nlist nlst[] = {
  990. X#ifdef i386
  991. X    { "avenrun" },        /* 0 */
  992. X    { "ccpu" },            /* 1 */
  993. X    { "mpid" },            /* 2 */
  994. X    { "nproc" },        /* 3 */
  995. X    { "proc" },            /* 4 */
  996. X    { "total" },        /* 5 */
  997. X    { "cp_time" },        /* 6 */
  998. X    { "pages" },        /* 7 */
  999. X    { "epages" },        /* 8 */
  1000. X#else
  1001. X    { "_avenrun" },        /* 0 */
  1002. X    { "_ccpu" },        /* 1 */
  1003. X    { "_mpid" },        /* 2 */
  1004. X    { "_nproc" },        /* 3 */
  1005. X    { "_proc" },        /* 4 */
  1006. X    { "_total" },        /* 5 */
  1007. X    { "_cp_time" },        /* 6 */
  1008. X    { "_pages" },        /* 7 */
  1009. X    { "_epages" },        /* 8 */
  1010. X#define NLST_REQUIRED   9
  1011. X    { "_ncpu" },
  1012. X#define X_NCPU        9
  1013. X    { "_xp_time" },
  1014. X#define X_XP_TIME    10
  1015. X#endif
  1016. X    { 0 }
  1017. X};
  1018. X
  1019. X/*
  1020. X *  These definitions control the format of the per-process area
  1021. X */
  1022. X
  1023. Xstatic char header[] =
  1024. X  "  PID X        PRI NICE   SIZE   RES STATE   TIME   WCPU    CPU COMMAND";
  1025. X/* 0123456   -- field to fill in starts at header+6 */
  1026. X#define UNAME_START 6
  1027. X
  1028. X#define Proc_format \
  1029. X    "%5d %-8.8s %3d %4d%6dK %4dK %-5s%4d:%02d %5.2f%% %5.2f%% %.14s"
  1030. X
  1031. X
  1032. X/* process state names for the "STATE" column of the display */
  1033. X/* the extra nulls in the string "run" are for adding a slash and
  1034. X   the processor number when needed */
  1035. X
  1036. Xchar *state_abbrev[] =
  1037. X{
  1038. X    "", "sleep", "WAIT", "run\0\0\0", "start", "zomb", "stop"
  1039. X};
  1040. X
  1041. X/* values that we stash away in _init and use in later routines */
  1042. X
  1043. Xstatic double logcpu;
  1044. Xkvm_t *kd;
  1045. X
  1046. X/* these are retrieved from the kernel in _init */
  1047. X
  1048. Xstatic unsigned long proc;
  1049. Xstatic          int  nproc;
  1050. Xstatic load_avg ccpu;
  1051. Xstatic unsigned long pages;
  1052. Xstatic unsigned long epages;
  1053. Xstatic          int  ncpu = 0;
  1054. X#define IS_MP   (ncpu > 1)
  1055. X
  1056. X/* these are offsets obtained via nlist and used in the get_ functions */
  1057. X
  1058. Xstatic unsigned long mpid_offset;
  1059. Xstatic unsigned long avenrun_offset;
  1060. Xstatic unsigned long total_offset;
  1061. Xstatic unsigned long cp_time_offset;
  1062. Xstatic unsigned long xp_time_offset;
  1063. X
  1064. X/* these are for calculating cpu state percentages */
  1065. X
  1066. Xstatic long cp_time[CPUSTATES];
  1067. Xstatic long cp_old[CPUSTATES];
  1068. Xstatic long cp_diff[CPUSTATES];
  1069. Xstatic long xp_time[NCPU][XPSTATES];
  1070. X/* for now we only accumulate spin time, but extending this to pick up
  1071. X   other stuff in xp_time is trivial.  */
  1072. Xstatic long xp_old[NCPU];
  1073. X
  1074. X/* these are for detailing the process states */
  1075. X
  1076. Xint process_states[7];
  1077. Xchar *procstatenames[] = {
  1078. X    "", " sleeping, ", " ABANDONED, ", " running, ", " starting, ",
  1079. X    " zombie, ", " stopped, ",
  1080. X    NULL
  1081. X};
  1082. X
  1083. X/* these are for detailing the cpu states */
  1084. X
  1085. Xint cpu_states[5];
  1086. Xchar *cpustatenames[] = {
  1087. X    "user", "nice", "system", "idle",
  1088. X    NULL,        /* set to "spin" on MP machines */
  1089. X    NULL
  1090. X};
  1091. X#define XCP_SPIN 4
  1092. X
  1093. X/* these are for detailing the memory statistics */
  1094. X
  1095. Xint memory_stats[4];
  1096. Xchar *memorynames[] = {
  1097. X    "K available, ", "K in use, ", "K free, ", "K locked", NULL
  1098. X};
  1099. X
  1100. X/* these are for keeping track of the proc array */
  1101. X
  1102. Xstatic int bytes;
  1103. Xstatic int pref_len;
  1104. Xstatic struct proc *pbase;
  1105. Xstatic struct proc **pref;
  1106. X
  1107. X/* these are for getting the memory statistics */
  1108. X
  1109. Xstatic struct page *physpage;
  1110. Xstatic int bytesize;
  1111. Xstatic int count;
  1112. Xstatic int pageshift;        /* log base 2 of the pagesize */
  1113. X
  1114. X/* define pagetok in terms of pageshift */
  1115. X
  1116. X#define pagetok(size) ((size) << pageshift)
  1117. X
  1118. X/* useful externals */
  1119. Xextern int errno;
  1120. Xextern char *sys_errlist[];
  1121. X
  1122. Xlong lseek();
  1123. Xlong time();
  1124. Xlong percentages();
  1125. X
  1126. Xmachine_init(statics)
  1127. X
  1128. Xstruct statics *statics;
  1129. X
  1130. X{
  1131. X    register int i;
  1132. X    register int pagesize;
  1133. X
  1134. X    /* initialize the kernel interface */
  1135. X    if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "top")) == NULL)
  1136. X    {
  1137. X    perror("kvm_open");
  1138. X    return(-1);
  1139. X    }
  1140. X
  1141. X    /* get the list of symbols we want to access in the kernel */
  1142. X    if ((i = kvm_nlist(kd, nlst)) < 0)
  1143. X    {
  1144. X    fprintf(stderr, "top: nlist failed\n");
  1145. X    return(-1);
  1146. X    }
  1147. X
  1148. X    /* were ncpu and xp_time not found in the nlist? */
  1149. X    if (i > 0 && nlst[X_NCPU].n_type == 0 && nlst[X_XP_TIME].n_type == 0)
  1150. X    {
  1151. X    /* we are only running with one cpu */
  1152. X    /* so we will pretend this didn't happen and set ncpu = 1 */
  1153. X    i -= 2;
  1154. X    ncpu = 1;
  1155. X    }
  1156. X
  1157. X    /* make sure they were all found */
  1158. X    if (i > 0 && check_nlist(nlst) > 0)
  1159. X    {
  1160. X    return(-1);
  1161. X    }
  1162. X
  1163. X    /* get the symbol values out of kmem */
  1164. X    (void) getkval(nlst[X_PROC].n_value,   (int *)(&proc),    sizeof(proc),
  1165. X        nlst[X_PROC].n_name);
  1166. X    (void) getkval(nlst[X_NPROC].n_value,  &nproc,        sizeof(nproc),
  1167. X        nlst[X_NPROC].n_name);
  1168. X    (void) getkval(nlst[X_CCPU].n_value,   (int *)(&ccpu),    sizeof(ccpu),
  1169. X        nlst[X_CCPU].n_name);
  1170. X    (void) getkval(nlst[X_PAGES].n_value,  (int *)(&pages),    sizeof(pages),
  1171. X        nlst[X_PAGES].n_name);
  1172. X    (void) getkval(nlst[X_EPAGES].n_value, (int *)(&epages),    sizeof(epages),
  1173. X        nlst[X_EPAGES].n_name);
  1174. X    if (ncpu == 0)
  1175. X    {
  1176. X    /* we have not yet determined the number of processors, so
  1177. X       do that now */
  1178. X    /* assert: nlst[X_NCPU].n_type != 0 => nlst[X_NCPU].n_value != 0 */
  1179. X    (void) getkval(nlst[X_NCPU].n_value,   (int *)(&ncpu),    sizeof(ncpu),
  1180. X               nlst[X_NCPU].n_name);
  1181. X    }
  1182. X
  1183. X    /* stash away certain offsets for later use */
  1184. X    mpid_offset = nlst[X_MPID].n_value;
  1185. X    avenrun_offset = nlst[X_AVENRUN].n_value;
  1186. X    total_offset = nlst[X_TOTAL].n_value;
  1187. X    cp_time_offset = nlst[X_CP_TIME].n_value;
  1188. X    xp_time_offset = nlst[X_XP_TIME].n_value;
  1189. X
  1190. X    /* this is used in calculating WCPU -- calculate it ahead of time */
  1191. X    logcpu = log(loaddouble(ccpu));
  1192. X
  1193. X    /* allocate space for proc structure array and array of pointers */
  1194. X    bytes = nproc * sizeof(struct proc);
  1195. X    pbase = (struct proc *)malloc(bytes);
  1196. X    pref  = (struct proc **)malloc(nproc * sizeof(struct proc *));
  1197. X
  1198. X    /* Just in case ... */
  1199. X    if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL)
  1200. X    {
  1201. X    fprintf(stderr, "top: can't allocate sufficient memory\n");
  1202. X    return(-1);
  1203. X    }
  1204. X
  1205. X    /* allocate a table to hold all the page structs */
  1206. X    bytesize = epages - pages;
  1207. X    count = bytesize / sizeof(struct page);
  1208. X    physpage = (struct page *)malloc(epages - pages);
  1209. X    if (physpage == NULL)
  1210. X    {
  1211. X    fprintf(stderr, "top: can't allocate sufficient memory\n");
  1212. X    return(-1);
  1213. X    }
  1214. X   
  1215. X    /* get the page size with "getpagesize" and calculate pageshift from it */
  1216. X    pagesize = getpagesize();
  1217. X    pageshift = 0;
  1218. X    while (pagesize > 1)
  1219. X    {
  1220. X    pageshift++;
  1221. X    pagesize >>= 1;
  1222. X    }
  1223. X
  1224. X    /* we only need the amount of log(2)1024 for our conversion */
  1225. X    pageshift -= LOG1024;
  1226. X
  1227. X    /* add a slash to the "run" state abbreviation */
  1228. X    if (IS_MP)
  1229. X    {
  1230. X    state_abbrev[SRUN][3] = '/';
  1231. X    cpustatenames[XCP_SPIN] = "spin";
  1232. X    }
  1233. X
  1234. X    /* fill in the statics information */
  1235. X    statics->procstate_names = procstatenames;
  1236. X    statics->cpustate_names = cpustatenames;
  1237. X    statics->memory_names = memorynames;
  1238. X
  1239. X    /* all done! */
  1240. X    return(0);
  1241. X}
  1242. X
  1243. Xchar *format_header(uname_field)
  1244. X
  1245. Xregister char *uname_field;
  1246. X
  1247. X{
  1248. X    register char *ptr;
  1249. X
  1250. X    ptr = header + UNAME_START;
  1251. X    while (*uname_field != '\0')
  1252. X    {
  1253. X    *ptr++ = *uname_field++;
  1254. X    }
  1255. X
  1256. X    return(header);
  1257. X}
  1258. X
  1259. Xget_system_info(si)
  1260. X
  1261. Xstruct system_info *si;
  1262. X
  1263. X{
  1264. X    load_avg avenrun[3];
  1265. X    long total;
  1266. X    long half_total;
  1267. X
  1268. X    /* get the cp_time array */
  1269. X    (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),
  1270. X           "_cp_time");
  1271. X
  1272. X    if (IS_MP)
  1273. X    {
  1274. X    /* get the xp_time array as well */
  1275. X    (void) getkval(xp_time_offset, (int *)xp_time, sizeof(xp_time),
  1276. X               "_xp_time");
  1277. X    }
  1278. X
  1279. X    /* get load average array */
  1280. X    (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
  1281. X           "_avenrun");
  1282. X
  1283. X    /* get mpid -- process id of last process */
  1284. X    (void) getkval(mpid_offset, &(si->last_pid), sizeof(si->last_pid),
  1285. X           "_mpid");
  1286. X
  1287. X    /* get the array of physpage descriptors */
  1288. X    (void) getkval(pages, (int *)physpage, bytesize, "array _page");
  1289. X
  1290. X    /* convert load averages to doubles */
  1291. X    {
  1292. X    register int i;
  1293. X    register double *infoloadp;
  1294. X    register load_avg *sysloadp;
  1295. X
  1296. X    infoloadp = si->load_avg;
  1297. X    sysloadp = avenrun;
  1298. X    for (i = 0; i < 3; i++)
  1299. X    {
  1300. X        *infoloadp++ = loaddouble(*sysloadp++);
  1301. X    }
  1302. X    }
  1303. X
  1304. X    /* convert cp_time counts to percentages */
  1305. X    total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
  1306. X
  1307. X    /* calculate spin time from all processors */
  1308. X    if (IS_MP)
  1309. X    {
  1310. X    register int c;
  1311. X    register int i;
  1312. X    register long sum;
  1313. X    register long change;
  1314. X
  1315. X    /* collect differences for each processor and add them */
  1316. X    sum = 0;
  1317. X    for (i = 0; i < ncpu; i++)
  1318. X    {
  1319. X        c = xp_time[i][XP_SPIN];
  1320. X        change = c - xp_old[i];
  1321. X        if (change < 0)
  1322. X        {
  1323. X        /* counter wrapped */
  1324. X        change = (long)((unsigned long)c -
  1325. X                (unsigned long)xp_old[i]);
  1326. X        }
  1327. X        sum += change;
  1328. X        xp_old[i] = c;
  1329. X    }
  1330. X
  1331. X    /*
  1332. X     *  NOTE:  I am assuming that the ticks found in xp_time are
  1333. X     *  already included in the ticks accumulated in cp_time.  To
  1334. X     *  get an accurate reflection, therefore, we have to subtract
  1335. X     *  the spin time from the system time and recompute those two
  1336. X     *  percentages.
  1337. X     */
  1338. X    half_total = total / 2l;
  1339. X    cp_diff[CP_SYS] -= sum;
  1340. X    cpu_states[CP_SYS] = (int)((cp_diff[CP_SYS] * 1000 + half_total) /
  1341. X                   total);
  1342. X    cpu_states[XCP_SPIN] = (int)((sum * 1000 + half_total) / total);
  1343. X    }
  1344. X
  1345. X    /* sum memory statistics */
  1346. X    {
  1347. X    register struct page *pp;
  1348. X    register int cnt;
  1349. X    register int inuse;
  1350. X    register int free;
  1351. X    register int locked;
  1352. X
  1353. X    /* bop thru the array counting page types */
  1354. X    pp = physpage;
  1355. X    inuse = free = locked = 0;
  1356. X    for (cnt = count; --cnt >= 0; pp++)
  1357. X    {
  1358. X        if (pp->p_free)
  1359. X            free++;
  1360. X        else if (pp->p_lock || pp->p_keepcnt > 0)
  1361. X            locked++;
  1362. X        else
  1363. X            inuse++;
  1364. X    }
  1365. X
  1366. X    /* convert memory stats to Kbytes */
  1367. X    memory_stats[0] = pagetok(inuse + free);
  1368. X    memory_stats[1] = pagetok(inuse);
  1369. X    memory_stats[2] = pagetok(free);
  1370. X    memory_stats[3] = pagetok(locked);
  1371. X    }
  1372. X
  1373. X    /* set arrays and strings */
  1374. X    si->cpustates = cpu_states;
  1375. X    si->memory = memory_stats;
  1376. X}
  1377. X
  1378. Xstatic struct handle handle;
  1379. X
  1380. Xcaddr_t get_process_info(si, sel, compare)
  1381. X
  1382. Xstruct system_info *si;
  1383. Xstruct process_select *sel;
  1384. Xint (*compare)();
  1385. X
  1386. X{
  1387. X    register int i;
  1388. X    register int total_procs;
  1389. X    register int active_procs;
  1390. X    register struct proc **prefp;
  1391. X    register struct proc *pp;
  1392. X
  1393. X    /* these are copied out of sel for speed */
  1394. X    int show_idle;
  1395. X    int show_system;
  1396. X    int show_uid;
  1397. X    int show_command;
  1398. X
  1399. X    /* read all the proc structures in one fell swoop */
  1400. X    (void) getkval(proc, (int *)pbase, bytes, "proc array");
  1401. X
  1402. X    /* get a pointer to the states summary array */
  1403. X    si->procstates = process_states;
  1404. X
  1405. X    /* set up flags which define what we are going to select */
  1406. X    show_idle = sel->idle;
  1407. X    show_system = sel->system;
  1408. X    show_uid = sel->uid != -1;
  1409. X    show_command = sel->command != NULL;
  1410. X
  1411. X    /* count up process states and get pointers to interesting procs */
  1412. X    total_procs = 0;
  1413. X    active_procs = 0;
  1414. X    bzero((char *)process_states, sizeof(process_states));
  1415. X    prefp = pref;
  1416. X    for (pp = pbase, i = 0; i < nproc; pp++, i++)
  1417. X    {
  1418. X    /*
  1419. X     *  Place pointers to each valid proc structure in pref[].
  1420. X     *  Process slots that are actually in use have a non-zero
  1421. X     *  status field.  Processes with SSYS set are system
  1422. X     *  processes---these get ignored unless show_sysprocs is set.
  1423. X     */
  1424. X    if (pp->p_stat != 0 &&
  1425. X        (show_system || ((pp->p_flag & SSYS) == 0)))
  1426. X    {
  1427. X        total_procs++;
  1428. X        process_states[pp->p_stat]++;
  1429. X        if ((pp->p_stat != SZOMB) &&
  1430. X        (show_idle || (pp->p_pctcpu != 0) || (pp->p_stat == SRUN)) &&
  1431. X        (!show_uid || pp->p_uid == (uid_t)sel->uid))
  1432. X        {
  1433. X        *prefp++ = pp;
  1434. X        active_procs++;
  1435. X        }
  1436. X    }
  1437. X    }
  1438. X
  1439. X    /* if requested, sort the "interesting" processes */
  1440. X    if (compare != NULL)
  1441. X    {
  1442. X    qsort((char *)pref, active_procs, sizeof(struct proc *), compare);
  1443. X    }
  1444. X
  1445. X    /* remember active and total counts */
  1446. X    si->p_total = total_procs;
  1447. X    si->p_active = pref_len = active_procs;
  1448. X
  1449. X    /* pass back a handle */
  1450. X    handle.next_proc = pref;
  1451. X    handle.remaining = active_procs;
  1452. X    return((caddr_t)&handle);
  1453. X}
  1454. X
  1455. Xchar fmt[128];        /* static area where result is built */
  1456. X
  1457. Xchar *format_next_process(handle, get_userid)
  1458. X
  1459. Xcaddr_t handle;
  1460. Xchar *(*get_userid)();
  1461. X
  1462. X{
  1463. X    register struct proc *pp;
  1464. X    register long cputime;
  1465. X    register double pct;
  1466. X    struct user u;
  1467. X    struct handle *hp;
  1468. X
  1469. X    /* find and remember the next proc structure */
  1470. X    hp = (struct handle *)handle;
  1471. X    pp = *(hp->next_proc++);
  1472. X    hp->remaining--;
  1473. X    
  1474. X    /* get the process's user struct and set cputime */
  1475. X    if (getu(pp, &u) == -1)
  1476. X    {
  1477. X    (void) strcpy(u.u_comm, "<swapped>");
  1478. X    cputime = 0;
  1479. X    }
  1480. X    else
  1481. X    {
  1482. X    /* set u_comm for system processes */
  1483. X    if (u.u_comm[0] == '\0')
  1484. X    {
  1485. X        if (pp->p_pid == 0)
  1486. X        {
  1487. X        (void) strcpy(u.u_comm, "Swapper");
  1488. X        }
  1489. X        else if (pp->p_pid == 2)
  1490. X        {
  1491. X        (void) strcpy(u.u_comm, "Pager");
  1492. X        }
  1493. X    }
  1494. X
  1495. X    cputime = u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec;
  1496. X    }
  1497. X
  1498. X    /* calculate the base for cpu percentages */
  1499. X    pct = pctdouble(pp->p_pctcpu);
  1500. X
  1501. X    /*
  1502. X     *  If there is more than one cpu then add the processor number to
  1503. X     *  the "run/" string.  Note that this will only show up if the
  1504. X     *  process is in the run state.  Also note:  when they
  1505. X     *  start making Suns with more than 9 processors this will break
  1506. X     *  since the string will then be more than 5 characters.
  1507. X     */
  1508. X    if (IS_MP)
  1509. X    {
  1510. X    state_abbrev[SRUN][4] = (pp->p_cpuid & 0xf) + '0';
  1511. X    }
  1512. X
  1513. X    /* format this entry */
  1514. X    sprintf(fmt,
  1515. X        Proc_format,
  1516. X        pp->p_pid,
  1517. X        (*get_userid)(pp->p_uid),
  1518. X        pp->p_pri - PZERO,
  1519. X        pp->p_nice - NZERO,
  1520. X        pagetok(PROCSIZE(pp)),
  1521. X        pagetok(pp->p_rssize),
  1522. X        state_abbrev[pp->p_stat],
  1523. X        cputime / 60l,
  1524. X        cputime % 60l,
  1525. X        100.0 * weighted_cpu(pct, pp),
  1526. X        100.0 * pct,
  1527. X        printable(u.u_comm));
  1528. X
  1529. X    /* return the result */
  1530. X    return(fmt);
  1531. X}
  1532. X
  1533. X/*
  1534. X *  getu(p, u) - get the user structure for the process whose proc structure
  1535. X *    is pointed to by p.  The user structure is put in the buffer pointed
  1536. X *    to by u.  Return 0 if successful, -1 on failure (such as the process
  1537. X *    being swapped out).
  1538. X */
  1539. X
  1540. Xgetu(p, u)
  1541. X
  1542. Xregister struct proc *p;
  1543. Xstruct user *u;
  1544. X
  1545. X{
  1546. X    register struct user *lu;
  1547. X
  1548. X    lu = kvm_getu(kd, p);
  1549. X    if (lu == NULL)
  1550. X    {
  1551. X    return(-1);
  1552. X    }
  1553. X    else
  1554. X    {
  1555. X    *u = *lu;
  1556. X    return(0);
  1557. X    }
  1558. X}
  1559. X
  1560. X/*
  1561. X * check_nlist(nlst) - checks the nlist to see if any symbols were not
  1562. X *        found.  For every symbol that was not found, a one-line
  1563. X *        message is printed to stderr.  The routine returns the
  1564. X *        number of symbols NOT found.
  1565. X */
  1566. X
  1567. Xint check_nlist(nlst)
  1568. X
  1569. Xregister struct nlist *nlst;
  1570. X
  1571. X{
  1572. X    register int i;
  1573. X
  1574. X    /* check to see if we got ALL the symbols we requested */
  1575. X    /* this will write one line to stderr for every symbol not found */
  1576. X
  1577. X    i = 0;
  1578. X    while (nlst->n_name != NULL)
  1579. X    {
  1580. X#ifdef i386
  1581. X    if (nlst->n_value == 0)
  1582. X#else
  1583. X    if (nlst->n_type == 0)
  1584. X#endif
  1585. X    {
  1586. X        /* this one wasn't found */
  1587. X        fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
  1588. X        i = 1;
  1589. X    }
  1590. X    nlst++;
  1591. X    }
  1592. X
  1593. X    return(i);
  1594. X}
  1595. X
  1596. X
  1597. X/*
  1598. X *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
  1599. X *    "offset" is the byte offset into the kernel for the desired value,
  1600. X *      "ptr" points to a buffer into which the value is retrieved,
  1601. X *      "size" is the size of the buffer (and the object to retrieve),
  1602. X *      "refstr" is a reference string used when printing error meessages,
  1603. X *        if "refstr" starts with a '!', then a failure on read will not
  1604. X *          be fatal (this may seem like a silly way to do things, but I
  1605. X *          really didn't want the overhead of another argument).
  1606. X *      
  1607. X */
  1608. X
  1609. Xgetkval(offset, ptr, size, refstr)
  1610. X
  1611. Xunsigned long offset;
  1612. Xint *ptr;
  1613. Xint size;
  1614. Xchar *refstr;
  1615. X
  1616. X{
  1617. X    if (kvm_read(kd, offset, ptr, size) != size)
  1618. X    {
  1619. X    if (*refstr == '!')
  1620. X    {
  1621. X        return(0);
  1622. X    }
  1623. X    else
  1624. X    {
  1625. X        fprintf(stderr, "top: kvm_read for %s: %s\n",
  1626. X        refstr, sys_errlist[errno]);
  1627. X        quit(23);
  1628. X        /*NOTREACHED*/
  1629. X    }
  1630. X    }
  1631. X    return(1);
  1632. X}
  1633. X    
  1634. X/* comparison routine for qsort */
  1635. X
  1636. X/*
  1637. X *  proc_compare - comparison function for "qsort"
  1638. X *    Compares the resource consumption of two processes using five
  1639. X *      distinct keys.  The keys (in descending order of importance) are:
  1640. X *      percent cpu, cpu ticks, state, resident set size, total virtual
  1641. X *      memory usage.  The process states are ordered as follows (from least
  1642. X *      to most important):  WAIT, zombie, sleep, stop, start, run.  The
  1643. X *      array declaration below maps a process state index into a number
  1644. X *      that reflects this ordering.
  1645. X */
  1646. X
  1647. Xstatic unsigned char sorted_state[] =
  1648. X{
  1649. X    0,    /* not used        */
  1650. X    3,    /* sleep        */
  1651. X    1,    /* ABANDONED (WAIT)    */
  1652. X    6,    /* run            */
  1653. X    5,    /* start        */
  1654. X    2,    /* zombie        */
  1655. X    4    /* stop            */
  1656. X};
  1657. Xproc_compare(pp1, pp2)
  1658. X
  1659. Xstruct proc **pp1;
  1660. Xstruct proc **pp2;
  1661. X
  1662. X{
  1663. X    register struct proc *p1;
  1664. X    register struct proc *p2;
  1665. X    register int result;
  1666. X    register pctcpu lresult;
  1667. X
  1668. X    /* remove one level of indirection */
  1669. X    p1 = *pp1;
  1670. X    p2 = *pp2;
  1671. X
  1672. X    /* compare percent cpu (pctcpu) */
  1673. X    if ((lresult = p2->p_pctcpu - p1->p_pctcpu) == 0)
  1674. X    {
  1675. X    /* use cpticks to break the tie */
  1676. X    if ((result = p2->p_cpticks - p1->p_cpticks) == 0)
  1677. X    {
  1678. X        /* use process state to break the tie */
  1679. X        if ((result = sorted_state[p2->p_stat] -
  1680. X              sorted_state[p1->p_stat])  == 0)
  1681. X        {
  1682. X        /* use priority to break the tie */
  1683. X        if ((result = p2->p_pri - p1->p_pri) == 0)
  1684. X        {
  1685. X            /* use resident set size (rssize) to break the tie */
  1686. X            if ((result = p2->p_rssize - p1->p_rssize) == 0)
  1687. X            {
  1688. X            /* use total memory to break the tie */
  1689. X            result = PROCSIZE(p2) - PROCSIZE(p1);
  1690. X            }
  1691. X        }
  1692. X        }
  1693. X    }
  1694. X    }
  1695. X    else
  1696. X    {
  1697. X    result = lresult < 0 ? -1 : 1;
  1698. X    }
  1699. X
  1700. X    return(result);
  1701. X}
  1702. X
  1703. Xint proc_owner(pid)
  1704. X
  1705. Xint pid;
  1706. X
  1707. X{
  1708. X    register int ac;
  1709. X    register struct proc **prefp;
  1710. X    register struct proc *pp;
  1711. X
  1712. X    prefp = pref;
  1713. X    ac = pref_len;
  1714. X    while (--ac >= 0)
  1715. X    {
  1716. X    if ((pp = *prefp++)->p_pid == (pid_t)pid)
  1717. X    {
  1718. X        return((int)pp->p_uid);
  1719. X    }
  1720. X    }
  1721. X    return(-1);
  1722. X}
  1723. END_OF_FILE
  1724. if test 19935 -ne `wc -c <'machine/m_sunos4mp.c'`; then
  1725.     echo shar: \"'machine/m_sunos4mp.c'\" unpacked with wrong size!
  1726. fi
  1727. # end of 'machine/m_sunos4mp.c'
  1728. fi
  1729. echo shar: End of archive 12 \(of 13\).
  1730. cp /dev/null ark12isdone
  1731. MISSING=""
  1732. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do
  1733.     if test ! -f ark${I}isdone ; then
  1734.     MISSING="${MISSING} ${I}"
  1735.     fi
  1736. done
  1737. if test "${MISSING}" = "" ; then
  1738.     echo You have unpacked all 13 archives.
  1739.     echo "Now read README and INSTALL, then run Configure"
  1740.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1741. else
  1742.     echo You still need to unpack the following archives:
  1743.     echo "        " ${MISSING}
  1744. fi
  1745. ##  End of shell archive.
  1746. exit 0
  1747.