home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / emacs-19.28-src.tgz / tar.out / fsf / emacs / src / getloadavg.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  22KB  |  899 lines

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