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