home *** CD-ROM | disk | FTP | other *** search
/ OpenStep (Enterprise) / OpenStepENTCD.toast / OEDEV / GNUSRC.Z / getloadavg.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-08-01  |  21.8 KB  |  939 lines

  1. /* Get the system load averages.
  2.    Copyright (C) 1985, 86, 87, 88, 89, 91, 92, 93, 1994, 1995
  3.        Free Software Foundation, Inc.
  4.  
  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License as published by
  7.    the Free Software Foundation; either version 2, or (at your option)
  8.    any later version.
  9.  
  10.    This program is distributed in the hope that it will be useful,
  11.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.    GNU General Public License for more details.
  14.  
  15.    You should have received a copy of the GNU General Public License
  16.    along with this program; if not, write to the Free Software
  17.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. /* Compile-time symbols that this file uses:
  20.  
  21.    FIXUP_KERNEL_SYMBOL_ADDR()    Adjust address in returned struct nlist.
  22.    KERNEL_FILE            Pathname of the kernel to nlist.
  23.    LDAV_CVT()            Scale the load average from the kernel.
  24.                 Returns a double.
  25.    LDAV_SYMBOL            Name of kernel symbol giving load average.
  26.    LOAD_AVE_TYPE        Type of the load average array in the kernel.
  27.                 Must be defined unless one of
  28.                 apollo, DGUX, NeXT, or UMAX is defined;
  29.                 otherwise, no load average is available.
  30.    NLIST_STRUCT            Include nlist.h, not a.out.h, and
  31.                 the nlist n_name element is a pointer,
  32.                 not an array.
  33.    NLIST_NAME_UNION        struct nlist has an n_un member, not n_name.
  34.    LINUX_LDAV_FILE        [__linux__]: File containing load averages.
  35.  
  36.    Specific system predefines this file uses, aside from setting
  37.    default values if not emacs:
  38.  
  39.    apollo
  40.    BSD                Real BSD, not just BSD-like.
  41.    DGUX
  42.    eunice            UNIX emulator under VMS.
  43.    hpux
  44.    NeXT
  45.    sgi
  46.    sequent            Sequent Dynix 3.x.x (BSD)
  47.    _SEQUENT_            Sequent DYNIX/ptx 1.x.x (SYSV)
  48.    sony_news                    NEWS-OS (works at least for 4.1C)
  49.    UMAX
  50.    UMAX4_3
  51.    VMS
  52.    __linux__            Linux: assumes /proc filesystem mounted.
  53.                    Support from Michael K. Johnson.
  54.    __NetBSD__            NetBSD: assumes /kern filesystem mounted.
  55.  
  56.    In addition, to avoid nesting many #ifdefs, we internally set
  57.    LDAV_DONE to indicate that the load average has been computed.
  58.  
  59.    We also #define LDAV_PRIVILEGED if a program will require
  60.    special installation to be able to call getloadavg.  */
  61.  
  62. /* This should always be first.  */
  63. #ifdef HAVE_CONFIG_H
  64. #include <config.h>
  65. #endif
  66.  
  67. #include <sys/types.h>
  68.  
  69. /* Both the Emacs and non-Emacs sections want this.  Some
  70.    configuration files' definitions for the LOAD_AVE_CVT macro (like
  71.    sparc.h's) use macros like FSCALE, defined here.  */
  72. #ifdef unix
  73. #include <sys/param.h>
  74. #endif
  75.  
  76.  
  77. /* Exclude all the code except the test program at the end
  78.    if the system has its own `getloadavg' function.
  79.  
  80.    The declaration of `errno' is needed by the test program
  81.    as well as the function itself, so it comes first.  */
  82.  
  83. #include <errno.h>
  84.  
  85. #ifndef errno
  86. extern int errno;
  87. #endif
  88.  
  89. #ifndef HAVE_GETLOADAVG
  90.  
  91.  
  92. /* The existing Emacs configuration files define a macro called
  93.    LOAD_AVE_CVT, which accepts a value of type LOAD_AVE_TYPE, and
  94.    returns the load average multiplied by 100.  What we actually want
  95.    is a macro called LDAV_CVT, which returns the load average as an
  96.    unmultiplied double.
  97.  
  98.    For backwards compatibility, we'll define LDAV_CVT in terms of
  99.    LOAD_AVE_CVT, but future machine config files should just define
  100.    LDAV_CVT directly.  */
  101.  
  102. #if !defined(LDAV_CVT) && defined(LOAD_AVE_CVT)
  103. #define LDAV_CVT(n) (LOAD_AVE_CVT (n) / 100.0)
  104. #endif
  105.  
  106. #if !defined (BSD) && defined (ultrix)
  107. /* Ultrix behaves like BSD on Vaxen.  */
  108. #define BSD
  109. #endif
  110.  
  111. #ifdef NeXT
  112. /* NeXT in the 2.{0,1,2} releases defines BSD in <sys/param.h>, which
  113.    conflicts with the definition understood in this file, that this
  114.    really is BSD. */
  115. #undef BSD
  116.  
  117. /* NeXT defines FSCALE in <sys/param.h>.  However, we take FSCALE being
  118.    defined to mean that the nlist method should be used, which is not true.  */
  119. #undef FSCALE
  120. #endif
  121.  
  122. /* Set values that are different from the defaults, which are
  123.    set a little farther down with #ifndef.  */
  124.  
  125.  
  126. /* Some shorthands.  */
  127.  
  128. #if defined (HPUX) && !defined (hpux)
  129. #define hpux
  130. #endif
  131.  
  132. #if defined(hp300) && !defined(hpux)
  133. #define MORE_BSD
  134. #endif
  135.  
  136. #if defined(ultrix) && defined(mips)
  137. #define decstation
  138. #endif
  139.  
  140. #if defined(sun) && defined(SVR4)
  141. #define SUNOS_5
  142. #endif
  143.  
  144. #if defined (__osf__) && (defined (__alpha) || defined (__alpha__))
  145. #define OSF_ALPHA
  146. #include <sys/table.h>
  147. #endif
  148.  
  149. #if defined (__osf__) && (defined (mips) || defined (__mips__))
  150. #define OSF_MIPS
  151. #include <sys/table.h>
  152. #endif
  153.  
  154. /* UTek's /bin/cc on the 4300 has no architecture specific cpp define by
  155.    default, but _MACH_IND_SYS_TYPES is defined in <sys/types.h>.  Combine
  156.    that with a couple of other things and we'll have a unique match.  */
  157. #if !defined (tek4300) && defined (unix) && defined (m68k) && defined (mc68000) && defined (mc68020) && defined (_MACH_IND_SYS_TYPES)
  158. #define tek4300            /* Define by emacs, but not by other users.  */
  159. #endif
  160.  
  161.  
  162. /* VAX C can't handle multi-line #ifs, or lines longer than 256 chars.  */
  163. #ifndef LOAD_AVE_TYPE
  164.  
  165. #ifdef MORE_BSD
  166. #define LOAD_AVE_TYPE long
  167. #endif
  168.  
  169. #ifdef sun
  170. #define LOAD_AVE_TYPE long
  171. #endif
  172.  
  173. #ifdef decstation
  174. #define LOAD_AVE_TYPE long
  175. #endif
  176.  
  177. #ifdef _SEQUENT_
  178. #define LOAD_AVE_TYPE long
  179. #endif
  180.  
  181. #ifdef sgi
  182. #define LOAD_AVE_TYPE long
  183. #endif
  184.  
  185. #ifdef SVR4
  186. #define LOAD_AVE_TYPE long
  187. #endif
  188.  
  189. #ifdef sony_news
  190. #define LOAD_AVE_TYPE long
  191. #endif
  192.  
  193. #ifdef sequent
  194. #define LOAD_AVE_TYPE long
  195. #endif
  196.  
  197. #ifdef OSF_ALPHA
  198. #define LOAD_AVE_TYPE long
  199. #endif
  200.  
  201. #if defined (ardent) && defined (titan)
  202. #define LOAD_AVE_TYPE long
  203. #endif
  204.  
  205. #ifdef tek4300
  206. #define LOAD_AVE_TYPE long
  207. #endif
  208.  
  209. #if defined(alliant) && defined(i860) /* Alliant FX/2800 */
  210. #define LOAD_AVE_TYPE long
  211. #endif
  212.  
  213. #ifdef _AIX
  214. #define LOAD_AVE_TYPE long
  215. #endif
  216.  
  217. #endif /* No LOAD_AVE_TYPE.  */
  218.  
  219. #ifdef OSF_ALPHA
  220. /* <sys/param.h> defines an incorrect value for FSCALE on Alpha OSF/1,
  221.    according to ghazi@noc.rutgers.edu.  */
  222. #undef FSCALE
  223. #define FSCALE 1024.0
  224. #endif
  225.  
  226. #if defined(alliant) && defined(i860) /* Alliant FX/2800 */
  227. /* <sys/param.h> defines an incorrect value for FSCALE on an
  228.    Alliant FX/2800 Concentrix 2.2, according to ghazi@noc.rutgers.edu.  */
  229. #undef FSCALE
  230. #define FSCALE 100.0
  231. #endif
  232.  
  233.  
  234. #ifndef    FSCALE
  235.  
  236. /* SunOS and some others define FSCALE in sys/param.h.  */
  237.  
  238. #ifdef MORE_BSD
  239. #define FSCALE 2048.0
  240. #endif
  241.  
  242. #if defined(MIPS) || defined(SVR4) || defined(decstation)
  243. #define FSCALE 256
  244. #endif
  245.  
  246. #if defined (sgi) || defined (sequent)
  247. /* Sometimes both MIPS and sgi are defined, so FSCALE was just defined
  248.    above under #ifdef MIPS.  But we want the sgi value.  */
  249. #undef FSCALE
  250. #define    FSCALE 1000.0
  251. #endif
  252.  
  253. #if defined (ardent) && defined (titan)
  254. #define FSCALE 65536.0
  255. #endif
  256.  
  257. #ifdef tek4300
  258. #define FSCALE 100.0
  259. #endif
  260.  
  261. #ifdef _AIX
  262. #define FSCALE 65536.0
  263. #endif
  264.  
  265. #endif    /* Not FSCALE.  */
  266.  
  267. #if !defined (LDAV_CVT) && defined (FSCALE)
  268. #define    LDAV_CVT(n) (((double) (n)) / FSCALE)
  269. #endif
  270.  
  271. /* VAX C can't handle multi-line #ifs, or lines longer that 256 characters.  */
  272. #ifndef NLIST_STRUCT
  273.  
  274. #ifdef MORE_BSD
  275. #define NLIST_STRUCT
  276. #endif
  277.  
  278. #ifdef sun
  279. #define NLIST_STRUCT
  280. #endif
  281.  
  282. #ifdef decstation
  283. #define NLIST_STRUCT
  284. #endif
  285.  
  286. #ifdef hpux
  287. #define NLIST_STRUCT
  288. #endif
  289.  
  290. #if defined (_SEQUENT_) || defined (sequent)
  291. #define NLIST_STRUCT
  292. #endif
  293.  
  294. #ifdef sgi
  295. #define NLIST_STRUCT
  296. #endif
  297.  
  298. #ifdef SVR4
  299. #define NLIST_STRUCT
  300. #endif
  301.  
  302. #ifdef sony_news
  303. #define NLIST_STRUCT
  304. #endif
  305.  
  306. #ifdef OSF_ALPHA
  307. #define NLIST_STRUCT
  308. #endif
  309.  
  310. #if defined (ardent) && defined (titan)
  311. #define NLIST_STRUCT
  312. #endif
  313.  
  314. #ifdef tek4300
  315. #define NLIST_STRUCT
  316. #endif
  317.  
  318. #ifdef butterfly
  319. #define NLIST_STRUCT
  320. #endif
  321.  
  322. #if defined(alliant) && defined(i860) /* Alliant FX/2800 */
  323. #define NLIST_STRUCT
  324. #endif
  325.  
  326. #ifdef _AIX
  327. #define NLIST_STRUCT
  328. #endif
  329.  
  330. #endif /* defined (NLIST_STRUCT) */
  331.  
  332.  
  333. #if defined(sgi) || (defined(mips) && !defined(BSD))
  334. #define FIXUP_KERNEL_SYMBOL_ADDR(nl) ((nl)[0].n_value &= ~(1 << 31))
  335. #endif
  336.  
  337.  
  338. #if !defined (KERNEL_FILE) && defined (sequent)
  339. #define KERNEL_FILE "/dynix"
  340. #endif
  341.  
  342. #if !defined (KERNEL_FILE) && defined (hpux)
  343. #define KERNEL_FILE "/hp-ux"
  344. #endif
  345.  
  346. #if !defined(KERNEL_FILE) && (defined(_SEQUENT_) || defined(MIPS) || defined(SVR4) || defined(ISC) || defined (sgi) || defined(SVR4) || (defined (ardent) && defined (titan)))
  347. #define KERNEL_FILE "/unix"
  348. #endif
  349.  
  350.  
  351. #if !defined (LDAV_SYMBOL) && defined (alliant)
  352. #define LDAV_SYMBOL "_Loadavg"
  353. #endif
  354.  
  355. #if !defined(LDAV_SYMBOL) && ((defined(hpux) && !defined(hp9000s300)) || defined(_SEQUENT_) || defined(SVR4) || defined(ISC) || defined(sgi) || (defined (ardent) && defined (titan)) || defined (_AIX))
  356. #define LDAV_SYMBOL "avenrun"
  357. #endif
  358.  
  359. #ifdef HAVE_UNISTD_H
  360. #include <unistd.h>
  361. #endif
  362.  
  363. #include <stdio.h>
  364.  
  365. /* LOAD_AVE_TYPE should only get defined if we're going to use the
  366.    nlist method.  */
  367. #if !defined(LOAD_AVE_TYPE) && (defined(BSD) || defined(LDAV_CVT) || defined(KERNEL_FILE) || defined(LDAV_SYMBOL))
  368. #define LOAD_AVE_TYPE double
  369. #endif
  370.  
  371. #ifdef LOAD_AVE_TYPE
  372.  
  373. #ifndef VMS
  374. #ifndef NLIST_STRUCT
  375. #include <a.out.h>
  376. #else /* NLIST_STRUCT */
  377. #include <nlist.h>
  378. #endif /* NLIST_STRUCT */
  379.  
  380. #ifdef SUNOS_5
  381. #include <fcntl.h>
  382. #include <kvm.h>
  383. #endif
  384.  
  385. #ifndef KERNEL_FILE
  386. #define KERNEL_FILE "/vmunix"
  387. #endif /* KERNEL_FILE */
  388.  
  389. #ifndef LDAV_SYMBOL
  390. #define LDAV_SYMBOL "_avenrun"
  391. #endif /* LDAV_SYMBOL */
  392.  
  393. #else /* VMS */
  394.  
  395. #ifndef eunice
  396. #include <iodef.h>
  397. #include <descrip.h>
  398. #else /* eunice */
  399. #include <vms/iodef.h>
  400. #endif /* eunice */
  401. #endif /* VMS */
  402.  
  403. #ifndef LDAV_CVT
  404. #define LDAV_CVT(n) ((double) (n))
  405. #endif /* !LDAV_CVT */
  406.  
  407. #endif /* LOAD_AVE_TYPE */
  408.  
  409. #ifdef NeXT
  410. #ifdef HAVE_MACH_MACH_H
  411. #include <mach/mach.h>
  412. #else
  413. #include <mach.h>
  414. #endif
  415. #endif /* NeXT */
  416.  
  417. #ifdef sgi
  418. #include <sys/sysmp.h>
  419. #endif /* sgi */
  420.  
  421. #ifdef UMAX
  422. #include <stdio.h>
  423. #include <signal.h>
  424. #include <sys/time.h>
  425. #include <sys/wait.h>
  426. #include <sys/syscall.h>
  427.  
  428. #ifdef UMAX_43
  429. #include <machine/cpu.h>
  430. #include <inq_stats/statistics.h>
  431. #include <inq_stats/sysstats.h>
  432. #include <inq_stats/cpustats.h>
  433. #include <inq_stats/procstats.h>
  434. #else /* Not UMAX_43.  */
  435. #include <sys/sysdefs.h>
  436. #include <sys/statistics.h>
  437. #include <sys/sysstats.h>
  438. #include <sys/cpudefs.h>
  439. #include <sys/cpustats.h>
  440. #include <sys/procstats.h>
  441. #endif /* Not UMAX_43.  */
  442. #endif /* UMAX */
  443.  
  444. #ifdef DGUX
  445. #include <sys/dg_sys_info.h>
  446. #endif
  447.  
  448. #if defined(HAVE_FCNTL_H) || defined(_POSIX_VERSION)
  449. #include <fcntl.h>
  450. #else
  451. #include <sys/file.h>
  452. #endif
  453.  
  454. /* Avoid static vars inside a function since in HPUX they dump as pure.  */
  455.  
  456. #ifdef NeXT
  457. static processor_set_t default_set;
  458. static int getloadavg_initialized;
  459. #endif /* NeXT */
  460.  
  461. #ifdef UMAX
  462. static unsigned int cpus = 0;
  463. static unsigned int samples;
  464. #endif /* UMAX */
  465.  
  466. #ifdef DGUX
  467. static struct dg_sys_info_load_info load_info;    /* what-a-mouthful! */
  468. #endif /* DGUX */
  469.  
  470. #ifdef LOAD_AVE_TYPE
  471. /* File descriptor open to /dev/kmem or VMS load ave driver.  */
  472. static int channel;
  473. /* Nonzero iff channel is valid.  */
  474. static int getloadavg_initialized;
  475. /* Offset in kmem to seek to read load average, or 0 means invalid.  */
  476. static long offset;
  477.  
  478. #if !defined(VMS) && !defined(sgi)
  479. static struct nlist nl[2];
  480. #endif /* Not VMS or sgi */
  481.  
  482. #ifdef SUNOS_5
  483. static kvm_t *kd;
  484. #endif /* SUNOS_5 */
  485.  
  486. #endif /* LOAD_AVE_TYPE */
  487.  
  488. /* Put the 1 minute, 5 minute and 15 minute load averages
  489.    into the first NELEM elements of LOADAVG.
  490.    Return the number written (never more than 3, but may be less than NELEM),
  491.    or -1 if an error occurred.  */
  492.  
  493. int
  494. getloadavg (loadavg, nelem)
  495.      double loadavg[];
  496.      int nelem;
  497. {
  498.   int elem = 0;            /* Return value.  */
  499.  
  500. #ifdef NO_GET_LOAD_AVG
  501. #define LDAV_DONE
  502.   /* Set errno to zero to indicate that there was no particular error;
  503.      this function just can't work at all on this system.  */
  504.   errno = 0;
  505.   elem = -1;
  506. #endif
  507.  
  508. #if !defined (LDAV_DONE) && defined (__linux__)
  509. #define LDAV_DONE
  510. #undef LOAD_AVE_TYPE
  511.  
  512. #ifndef LINUX_LDAV_FILE
  513. #define LINUX_LDAV_FILE "/proc/loadavg"
  514. #endif
  515.  
  516.   char ldavgbuf[40];
  517.   double load_ave[3];
  518.   int fd, count;
  519.  
  520.   fd = open (LINUX_LDAV_FILE, O_RDONLY);
  521.   if (fd == -1)
  522.     return -1;
  523.   count = read (fd, ldavgbuf, 40);
  524.   (void) close (fd);
  525.   if (count <= 0)
  526.     return -1;
  527.  
  528.   count = sscanf (ldavgbuf, "%lf %lf %lf",
  529.           &load_ave[0], &load_ave[1], &load_ave[2]);
  530.   if (count < 1)
  531.     return -1;
  532.  
  533.   for (elem = 0; elem < nelem && elem < count; elem++)
  534.     loadavg[elem] = load_ave[elem];
  535.  
  536.   return elem;
  537.  
  538. #endif /* __linux__ */
  539.  
  540. #if !defined (LDAV_DONE) && defined (__NetBSD__)
  541. #define LDAV_DONE
  542. #undef LOAD_AVE_TYPE
  543.  
  544. #ifndef NETBSD_LDAV_FILE
  545. #define NETBSD_LDAV_FILE "/kern/loadavg"
  546. #endif
  547.  
  548.   unsigned long int load_ave[3], scale;
  549.   int count;
  550.   FILE *fp;
  551.  
  552.   fp = fopen (NETBSD_LDAV_FILE, "r");
  553.   if (fp == NULL)
  554.     return -1;
  555.   count = fscanf (fp, "%lu %lu %lu %lu\n",
  556.           &load_ave[0], &load_ave[1], &load_ave[2],
  557.           &scale);
  558.   (void) fclose (fp);
  559.   if (count != 4)
  560.     return -1;
  561.  
  562.   for (elem = 0; elem < nelem; elem++)
  563.     loadavg[elem] = (double) load_ave[elem] / (double) scale;
  564.  
  565.   return elem;
  566.  
  567. #endif /* __NetBSD__ */
  568.  
  569. #if !defined (LDAV_DONE) && defined (NeXT)
  570. #define LDAV_DONE
  571.   /* The NeXT code was adapted from iscreen 3.2.  */
  572.  
  573.   host_t host;
  574.   struct processor_set_basic_info info;
  575.   unsigned info_count;
  576.  
  577.   /* We only know how to get the 1-minute average for this system,
  578.      so even if the caller asks for more than 1, we only return 1.  */
  579.  
  580.   if (!getloadavg_initialized)
  581.     {
  582.       if (processor_set_default (host_self (), &default_set) == KERN_SUCCESS)
  583.     getloadavg_initialized = 1;
  584.     }
  585.  
  586.   if (getloadavg_initialized)
  587.     {
  588.       info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
  589.       if (processor_set_info (default_set, PROCESSOR_SET_BASIC_INFO, &host,
  590.                  (processor_set_info_t) &info, &info_count)
  591.       != KERN_SUCCESS)
  592.     getloadavg_initialized = 0;
  593.       else
  594.     {
  595.       if (nelem > 0)
  596.         loadavg[elem++] = (double) info.load_average / LOAD_SCALE;
  597.     }
  598.     }
  599.  
  600.   if (!getloadavg_initialized)
  601.     return -1;
  602. #endif /* NeXT */
  603.  
  604. #if !defined (LDAV_DONE) && defined (UMAX)
  605. #define LDAV_DONE
  606. /* UMAX 4.2, which runs on the Encore Multimax multiprocessor, does not
  607.    have a /dev/kmem.  Information about the workings of the running kernel
  608.    can be gathered with inq_stats system calls.
  609.    We only know how to get the 1-minute average for this system.  */
  610.  
  611.   struct proc_summary proc_sum_data;
  612.   struct stat_descr proc_info;
  613.   double load;
  614.   register unsigned int i, j;
  615.  
  616.   if (cpus == 0)
  617.     {
  618.       register unsigned int c, i;
  619.       struct cpu_config conf;
  620.       struct stat_descr desc;
  621.  
  622.       desc.sd_next = 0;
  623.       desc.sd_subsys = SUBSYS_CPU;
  624.       desc.sd_type = CPUTYPE_CONFIG;
  625.       desc.sd_addr = (char *) &conf;
  626.       desc.sd_size = sizeof conf;
  627.  
  628.       if (inq_stats (1, &desc))
  629.     return -1;
  630.  
  631.       c = 0;
  632.       for (i = 0; i < conf.config_maxclass; ++i)
  633.     {
  634.       struct class_stats stats;
  635.       bzero ((char *) &stats, sizeof stats);
  636.  
  637.       desc.sd_type = CPUTYPE_CLASS;
  638.       desc.sd_objid = i;
  639.       desc.sd_addr = (char *) &stats;
  640.       desc.sd_size = sizeof stats;
  641.  
  642.       if (inq_stats (1, &desc))
  643.         return -1;
  644.  
  645.       c += stats.class_numcpus;
  646.     }
  647.       cpus = c;
  648.       samples = cpus < 2 ? 3 : (2 * cpus / 3);
  649.     }
  650.  
  651.   proc_info.sd_next = 0;
  652.   proc_info.sd_subsys = SUBSYS_PROC;
  653.   proc_info.sd_type = PROCTYPE_SUMMARY;
  654.   proc_info.sd_addr = (char *) &proc_sum_data;
  655.   proc_info.sd_size = sizeof (struct proc_summary);
  656.   proc_info.sd_sizeused = 0;
  657.  
  658.   if (inq_stats (1, &proc_info) != 0)
  659.     return -1;
  660.  
  661.   load = proc_sum_data.ps_nrunnable;
  662.   j = 0;
  663.   for (i = samples - 1; i > 0; --i)
  664.     {
  665.       load += proc_sum_data.ps_nrun[j];
  666.       if (j++ == PS_NRUNSIZE)
  667.     j = 0;
  668.     }
  669.  
  670.   if (nelem > 0)
  671.     loadavg[elem++] = load / samples / cpus;
  672. #endif /* UMAX */
  673.  
  674. #if !defined (LDAV_DONE) && defined (DGUX)
  675. #define LDAV_DONE
  676.   /* This call can return -1 for an error, but with good args
  677.      it's not supposed to fail.  The first argument is for no
  678.      apparent reason of type `long int *'.  */
  679.   dg_sys_info ((long int *) &load_info,
  680.            DG_SYS_INFO_LOAD_INFO_TYPE,
  681.            DG_SYS_INFO_LOAD_VERSION_0);
  682.  
  683.   if (nelem > 0)
  684.     loadavg[elem++] = load_info.one_minute;
  685.   if (nelem > 1)
  686.     loadavg[elem++] = load_info.five_minute;
  687.   if (nelem > 2)
  688.     loadavg[elem++] = load_info.fifteen_minute;
  689. #endif /* DGUX */
  690.  
  691. #if !defined (LDAV_DONE) && defined (apollo)
  692. #define LDAV_DONE
  693. /* Apollo code from lisch@mentorg.com (Ray Lischner).
  694.  
  695.    This system call is not documented.  The load average is obtained as
  696.    three long integers, for the load average over the past minute,
  697.    five minutes, and fifteen minutes.  Each value is a scaled integer,
  698.    with 16 bits of integer part and 16 bits of fraction part.
  699.  
  700.    I'm not sure which operating system first supported this system call,
  701.    but I know that SR10.2 supports it.  */
  702.  
  703.   extern void proc1_$get_loadav ();
  704.   unsigned long load_ave[3];
  705.  
  706.   proc1_$get_loadav (load_ave);
  707.  
  708.   if (nelem > 0)
  709.     loadavg[elem++] = load_ave[0] / 65536.0;
  710.   if (nelem > 1)
  711.     loadavg[elem++] = load_ave[1] / 65536.0;
  712.   if (nelem > 2)
  713.     loadavg[elem++] = load_ave[2] / 65536.0;
  714. #endif /* apollo */
  715.  
  716. #if !defined (LDAV_DONE) && defined (OSF_MIPS)
  717. #define LDAV_DONE
  718.  
  719.   struct tbl_loadavg load_ave;
  720.   table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
  721.   loadavg[elem++]
  722.     = (load_ave.tl_lscale == 0
  723.        ? load_ave.tl_avenrun.d[0]
  724.        : (load_ave.tl_avenrun.l[0] / (double) load_ave.tl_lscale));
  725. #endif    /* OSF_MIPS */
  726.  
  727. #if !defined (LDAV_DONE) && defined (OSF_ALPHA)
  728. #define LDAV_DONE
  729.  
  730.   struct tbl_loadavg load_ave;
  731.   table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
  732.   for (elem = 0; elem < nelem; elem++)
  733.     loadavg[elem]
  734.       = (load_ave.tl_lscale == 0
  735.        ? load_ave.tl_avenrun.d[elem]
  736.        : (load_ave.tl_avenrun.l[elem] / (double) load_ave.tl_lscale));
  737. #endif /* OSF_ALPHA */
  738.  
  739. #if !defined (LDAV_DONE) && defined (VMS)
  740.   /* VMS specific code -- read from the Load Ave driver.  */
  741.  
  742.   LOAD_AVE_TYPE load_ave[3];
  743.   static int getloadavg_initialized = 0;
  744. #ifdef eunice
  745.   struct
  746.   {
  747.     int dsc$w_length;
  748.     char *dsc$a_pointer;
  749.   } descriptor;
  750. #endif
  751.  
  752.   /* Ensure that there is a channel open to the load ave device.  */
  753.   if (!getloadavg_initialized)
  754.     {
  755.       /* Attempt to open the channel.  */
  756. #ifdef eunice
  757.       descriptor.dsc$w_length = 18;
  758.       descriptor.dsc$a_pointer = "$$VMS_LOAD_AVERAGE";
  759. #else
  760.       $DESCRIPTOR (descriptor, "LAV0:");
  761. #endif
  762.       if (sys$assign (&descriptor, &channel, 0, 0) & 1)
  763.     getloadavg_initialized = 1;
  764.     }
  765.  
  766.   /* Read the load average vector.  */
  767.   if (getloadavg_initialized
  768.       && !(sys$qiow (0, channel, IO$_READVBLK, 0, 0, 0,
  769.              load_ave, 12, 0, 0, 0, 0) & 1))
  770.     {
  771.       sys$dassgn (channel);
  772.       getloadavg_initialized = 0;
  773.     }
  774.  
  775.   if (!getloadavg_initialized)
  776.     return -1;
  777. #endif /* VMS */
  778.  
  779. #if !defined (LDAV_DONE) && defined(LOAD_AVE_TYPE) && !defined(VMS)
  780.  
  781.   /* UNIX-specific code -- read the average from /dev/kmem.  */
  782.  
  783. #define LDAV_PRIVILEGED        /* This code requires special installation.  */
  784.  
  785.   LOAD_AVE_TYPE load_ave[3];
  786.  
  787.   /* Get the address of LDAV_SYMBOL.  */
  788.   if (offset == 0)
  789.     {
  790. #ifndef sgi
  791. #ifndef NLIST_STRUCT
  792.       strcpy (nl[0].n_name, LDAV_SYMBOL);
  793.       strcpy (nl[1].n_name, "");
  794. #else /* NLIST_STRUCT */
  795. #ifdef NLIST_NAME_UNION
  796.       nl[0].n_un.n_name = LDAV_SYMBOL;
  797.       nl[1].n_un.n_name = 0;
  798. #else /* not NLIST_NAME_UNION */
  799.       nl[0].n_name = LDAV_SYMBOL;
  800.       nl[1].n_name = 0;
  801. #endif /* not NLIST_NAME_UNION */
  802. #endif /* NLIST_STRUCT */
  803.  
  804. #ifndef SUNOS_5
  805.       if (
  806. #ifndef _AIX
  807.       nlist (KERNEL_FILE, nl)
  808. #else  /* _AIX */
  809.       knlist (nl, 1, sizeof (nl[0]))
  810. #endif
  811.       >= 0)
  812.       /* Omit "&& nl[0].n_type != 0 " -- it breaks on Sun386i.  */
  813.       {
  814. #ifdef FIXUP_KERNEL_SYMBOL_ADDR
  815.         FIXUP_KERNEL_SYMBOL_ADDR (nl);
  816. #endif
  817.         offset = nl[0].n_value;
  818.       }
  819. #endif /* !SUNOS_5 */
  820. #else  /* sgi */
  821.       int ldav_off;
  822.  
  823.       ldav_off = sysmp (MP_KERNADDR, MPKA_AVENRUN);
  824.       if (ldav_off != -1)
  825.       offset = (long) ldav_off & 0x7fffffff;
  826. #endif /* sgi */
  827.     }
  828.  
  829.   /* Make sure we have /dev/kmem open.  */
  830.   if (!getloadavg_initialized)
  831.     {
  832. #ifndef SUNOS_5
  833.       channel = open ("/dev/kmem", 0);
  834.       if (channel >= 0)
  835.     getloadavg_initialized = 1;
  836. #else /* SUNOS_5 */
  837.       /* We pass 0 for the kernel, corefile, and swapfile names
  838.      to use the currently running kernel.  */
  839.       kd = kvm_open (0, 0, 0, O_RDONLY, 0);
  840.       if (kd != 0) 
  841.     {
  842.       /* nlist the currently running kernel.  */
  843.       kvm_nlist (kd, nl);
  844.       offset = nl[0].n_value;
  845.       getloadavg_initialized = 1;
  846.     }
  847. #endif /* SUNOS_5 */
  848.     }
  849.  
  850.   /* If we can, get the load average values.  */
  851.   if (offset && getloadavg_initialized)
  852.     {
  853.       /* Try to read the load.  */
  854. #ifndef SUNOS_5
  855.       if (lseek (channel, offset, 0) == -1L
  856.       || read (channel, (char *) load_ave, sizeof (load_ave))
  857.       != sizeof (load_ave))
  858.     {
  859.       close (channel);
  860.       getloadavg_initialized = 0;
  861.     }
  862. #else  /* SUNOS_5 */
  863.       if (kvm_read (kd, offset, (char *) load_ave, sizeof (load_ave))
  864.       != sizeof (load_ave))
  865.         {
  866.           kvm_close (kd);
  867.           getloadavg_initialized = 0;
  868.     }
  869. #endif /* SUNOS_5 */
  870.     }
  871.  
  872.   if (offset == 0 || !getloadavg_initialized)
  873.     return -1;
  874. #endif /* LOAD_AVE_TYPE and not VMS */
  875.  
  876. #if !defined (LDAV_DONE) && defined (LOAD_AVE_TYPE) /* Including VMS.  */
  877.   if (nelem > 0)
  878.     loadavg[elem++] = LDAV_CVT (load_ave[0]);
  879.   if (nelem > 1)
  880.     loadavg[elem++] = LDAV_CVT (load_ave[1]);
  881.   if (nelem > 2)
  882.     loadavg[elem++] = LDAV_CVT (load_ave[2]);
  883.  
  884. #define LDAV_DONE
  885. #endif /* !LDAV_DONE && LOAD_AVE_TYPE */
  886.  
  887. #ifdef LDAV_DONE
  888.   return elem;
  889. #else
  890.   /* Set errno to zero to indicate that there was no particular error;
  891.      this function just can't work at all on this system.  */
  892.   errno = 0;
  893.   return -1;
  894. #endif
  895. }
  896.  
  897. #endif /* ! HAVE_GETLOADAVG */
  898.  
  899. #ifdef TEST
  900. void
  901. main (argc, argv)
  902.      int argc;
  903.      char **argv;
  904. {
  905.   int naptime = 0;
  906.  
  907.   if (argc > 1)
  908.     naptime = atoi (argv[1]);
  909.  
  910.   while (1)
  911.     {
  912.       double avg[3];
  913.       int loads;
  914.  
  915.       errno = 0;        /* Don't be misled if it doesn't set errno.  */
  916.       loads = getloadavg (avg, 3);
  917.       if (loads == -1)
  918.     {
  919.       perror ("Error getting load average");
  920.       exit (1);
  921.     }
  922.       if (loads > 0)
  923.     printf ("1-minute: %f  ", avg[0]);
  924.       if (loads > 1)
  925.     printf ("5-minute: %f  ", avg[1]);
  926.       if (loads > 2)
  927.     printf ("15-minute: %f  ", avg[2]);
  928.       if (loads > 0)
  929.     putchar ('\n');
  930.  
  931.       if (naptime == 0)
  932.     break;
  933.       sleep (naptime);
  934.     }
  935.  
  936.   exit (0);
  937. }
  938. #endif /* TEST */
  939.