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