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