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