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