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