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