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