home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / e20313sr.zip / emacs / 20.3.1 / src / getloadavg.c < prev    next >
C/C++ Source or Header  |  1999-07-31  |  28KB  |  1,072 lines

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