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