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