XEmacs 21.2.5
[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: ditto.
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 =
567         (kstat_named_t *) kstat_data_lookup (ksp, avestrings[elem]);
568       if (!kn)
569         {
570           kstat_close (kc);
571           return -1;
572         }
573       loadavg[elem] = (double)kn->value.ul / FSCALE;
574     }
575   kstat_close (kc);
576 #endif /* HAVE_KSTAT_H && HAVE_LIBKSTAT */
577
578 #if !defined (LDAV_DONE) && defined (HAVE_SYS_PSTAT_H)
579 #define LDAV_DONE
580   /* This is totally undocumented, and is not guaranteed to work, but
581      mayhap it might ....  If it does work, it will work only on HP-UX
582      8.0 or later.  -- Darryl Okahata <darrylo@sr.hp.com> */
583 #undef LOAD_AVE_TYPE            /* Make sure these don't exist. */
584 #undef LOAD_AVE_CVT
585 #undef LDAV_SYMBOL
586   struct pst_dynamic    procinfo;
587   union pstun           statbuf;
588
589   statbuf.pst_dynamic = &procinfo;
590   if (pstat (PSTAT_DYNAMIC, statbuf, sizeof (struct pst_dynamic), 0, 0) == -1)
591     return (-1);
592   loadavg[elem++] = procinfo.psd_avg_1_min;
593   loadavg[elem++] = procinfo.psd_avg_5_min;
594   loadavg[elem++] = procinfo.psd_avg_15_min;
595 #endif  /* HPUX */
596
597 #if !defined (LDAV_DONE) && defined (__linux__)
598 #define LDAV_DONE
599 #undef LOAD_AVE_TYPE
600
601 #ifndef LINUX_LDAV_FILE
602 #define LINUX_LDAV_FILE "/proc/loadavg"
603 #endif
604
605   char ldavgbuf[40];
606   double load_ave[3];
607   int fd, count;
608
609   fd = open (LINUX_LDAV_FILE, O_RDONLY);
610   if (fd == -1)
611     return -1;
612   count = read (fd, ldavgbuf, 40);
613   (void) close (fd);
614   if (count <= 0)
615     return -1;
616
617   count = sscanf (ldavgbuf, "%lf %lf %lf",
618                   &load_ave[0], &load_ave[1], &load_ave[2]);
619   if (count < 1)
620     return -1;
621
622   for (elem = 0; elem < nelem && elem < count; elem++)
623     loadavg[elem] = load_ave[elem];
624 #endif /* __linux__ */
625
626 #if !defined (LDAV_DONE) && defined (__NetBSD__) || defined (__OpenBSD__)
627 #define LDAV_DONE
628 #undef LOAD_AVE_TYPE
629
630 #ifndef NETBSD_LDAV_FILE
631 #define NETBSD_LDAV_FILE "/kern/loadavg"
632 #endif
633
634   unsigned long int load_ave[3], scale;
635   int count;
636   FILE *fp;
637
638   fp = fopen (NETBSD_LDAV_FILE, "r");
639   if (fp == NULL)
640     return -1;
641   count = fscanf (fp, "%lu %lu %lu %lu\n",
642                   &load_ave[0], &load_ave[1], &load_ave[2],
643                   &scale);
644   (void) fclose (fp);
645   if (count != 4)
646     return -1;
647
648   for (elem = 0; elem < nelem; elem++)
649     loadavg[elem] = (double) load_ave[elem] / (double) scale;
650 #endif /* __NetBSD__ or __OpenBSD__ */
651
652 #if !defined (LDAV_DONE) && defined (NeXT)
653 #define LDAV_DONE
654   /* The NeXT code was adapted from iscreen 3.2.  */
655
656   host_t host;
657   struct processor_set_basic_info info;
658   unsigned info_count;
659
660   /* We only know how to get the 1-minute average for this system,
661      so even if the caller asks for more than 1, we only return 1.  */
662
663   if (!getloadavg_initialized)
664     {
665       if (processor_set_default (host_self (), &default_set) == KERN_SUCCESS)
666         getloadavg_initialized = 1;
667     }
668
669   if (getloadavg_initialized)
670     {
671       info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
672       if (processor_set_info (default_set, PROCESSOR_SET_BASIC_INFO, &host,
673                              (processor_set_info_t) &info, &info_count)
674           != KERN_SUCCESS)
675         getloadavg_initialized = 0;
676       else
677         {
678           if (nelem > 0)
679             loadavg[elem++] = (double) info.load_average / LOAD_SCALE;
680         }
681     }
682
683   if (!getloadavg_initialized)
684     return -1;
685 #endif /* NeXT */
686
687 #if !defined (LDAV_DONE) && defined (UMAX)
688 #define LDAV_DONE
689 /* UMAX 4.2, which runs on the Encore Multimax multiprocessor, does not
690    have a /dev/kmem.  Information about the workings of the running kernel
691    can be gathered with inq_stats system calls.
692    We only know how to get the 1-minute average for this system.  */
693
694   struct proc_summary proc_sum_data;
695   struct stat_descr proc_info;
696   double load;
697   REGISTER unsigned int i, j;
698
699   if (cpus == 0)
700     {
701       REGISTER unsigned int c, i;
702       struct cpu_config conf;
703       struct stat_descr desc;
704
705       desc.sd_next = 0;
706       desc.sd_subsys = SUBSYS_CPU;
707       desc.sd_type = CPUTYPE_CONFIG;
708       desc.sd_addr = (char *) &conf;
709       desc.sd_size = sizeof conf;
710
711       if (inq_stats (1, &desc))
712         return -1;
713
714       c = 0;
715       for (i = 0; i < conf.config_maxclass; ++i)
716         {
717           struct class_stats stats;
718           memset ((char *) &stats, 0, sizeof stats);
719
720           desc.sd_type = CPUTYPE_CLASS;
721           desc.sd_objid = i;
722           desc.sd_addr = (char *) &stats;
723           desc.sd_size = sizeof stats;
724
725           if (inq_stats (1, &desc))
726             return -1;
727
728           c += stats.class_numcpus;
729         }
730       cpus = c;
731       samples = cpus < 2 ? 3 : (2 * cpus / 3);
732     }
733
734   proc_info.sd_next = 0;
735   proc_info.sd_subsys = SUBSYS_PROC;
736   proc_info.sd_type = PROCTYPE_SUMMARY;
737   proc_info.sd_addr = (char *) &proc_sum_data;
738   proc_info.sd_size = sizeof (struct proc_summary);
739   proc_info.sd_sizeused = 0;
740
741   if (inq_stats (1, &proc_info) != 0)
742     return -1;
743
744   load = proc_sum_data.ps_nrunnable;
745   j = 0;
746   for (i = samples - 1; i > 0; --i)
747     {
748       load += proc_sum_data.ps_nrun[j];
749       if (j++ == PS_NRUNSIZE)
750         j = 0;
751     }
752
753   if (nelem > 0)
754     loadavg[elem++] = load / samples / cpus;
755 #endif /* UMAX */
756
757 #if !defined (LDAV_DONE) && defined (DGUX)
758 #define LDAV_DONE
759   /* This call can return -1 for an error, but with good args
760      it's not supposed to fail.  The first argument is for no
761      apparent reason of type `long int *'.  */
762   dg_sys_info ((long int *) &load_info,
763                DG_SYS_INFO_LOAD_INFO_TYPE,
764                DG_SYS_INFO_LOAD_VERSION_0);
765
766   if (nelem > 0)
767     loadavg[elem++] = load_info.one_minute;
768   if (nelem > 1)
769     loadavg[elem++] = load_info.five_minute;
770   if (nelem > 2)
771     loadavg[elem++] = load_info.fifteen_minute;
772 #endif /* DGUX */
773
774 #if !defined (LDAV_DONE) && defined (apollo)
775 #define LDAV_DONE
776 /* Apollo code from lisch@mentorg.com (Ray Lischner).
777
778    This system call is not documented.  The load average is obtained as
779    three long integers, for the load average over the past minute,
780    five minutes, and fifteen minutes.  Each value is a scaled integer,
781    with 16 bits of integer part and 16 bits of fraction part.
782
783    I'm not sure which operating system first supported this system call,
784    but I know that SR10.2 supports it.  */
785
786   extern void proc1_$get_loadav ();
787   unsigned long load_ave[3];
788
789   proc1_$get_loadav (load_ave);
790
791   if (nelem > 0)
792     loadavg[elem++] = load_ave[0] / 65536.0;
793   if (nelem > 1)
794     loadavg[elem++] = load_ave[1] / 65536.0;
795   if (nelem > 2)
796     loadavg[elem++] = load_ave[2] / 65536.0;
797 #endif /* apollo */
798
799 #if !defined (LDAV_DONE) && defined (OSF_MIPS)
800 #define LDAV_DONE
801
802   struct tbl_loadavg load_ave;
803   table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
804   loadavg[elem++]
805     = (load_ave.tl_lscale == 0
806        ? load_ave.tl_avenrun.d[0]
807        : (load_ave.tl_avenrun.l[0] / (double) load_ave.tl_lscale));
808 #endif  /* OSF_MIPS */
809
810 #if !defined (LDAV_DONE) && (defined (MSDOS) || defined (WIN32))
811 #define LDAV_DONE
812
813   /* A faithful emulation is going to have to be saved for a rainy day.  */
814   for ( ; elem < nelem; elem++)
815     {
816       loadavg[elem] = 0.0;
817     }
818 #endif  /* MSDOS */
819
820 #if !defined (LDAV_DONE) && defined (OSF_ALPHA)
821 #define LDAV_DONE
822
823   struct tbl_loadavg load_ave;
824   table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
825   for (elem = 0; elem < nelem; elem++)
826     loadavg[elem]
827       = (load_ave.tl_lscale == 0
828        ? load_ave.tl_avenrun.d[elem]
829        : (load_ave.tl_avenrun.l[elem] / (double) load_ave.tl_lscale));
830 #endif /* OSF_ALPHA */
831
832 #if !defined (LDAV_DONE) && defined(LOAD_AVE_TYPE)
833
834   /* UNIX-specific code -- read the average from /dev/kmem.  */
835
836 #define LDAV_PRIVILEGED         /* This code requires special installation.  */
837
838   LOAD_AVE_TYPE load_ave[3];
839
840   /* Get the address of LDAV_SYMBOL.  */
841   if (offset == 0)
842     {
843 #ifndef sgi
844 #ifndef NLIST_STRUCT
845       strcpy (nl[0].n_name, LDAV_SYMBOL);
846       strcpy (nl[1].n_name, "");
847 #else /* NLIST_STRUCT */
848 #ifdef NLIST_NAME_UNION
849       nl[0].n_un.n_name = LDAV_SYMBOL;
850       nl[1].n_un.n_name = 0;
851 #else /* not NLIST_NAME_UNION */
852       nl[0].n_name = (char *) LDAV_SYMBOL;
853       nl[1].n_name = 0;
854 #endif /* not NLIST_NAME_UNION */
855 #endif /* NLIST_STRUCT */
856
857 #ifndef SUNOS_5
858       if (
859 #if !(defined (_AIX) && !defined (ps2))
860           nlist (KERNEL_FILE, nl)
861 #else  /* _AIX */
862           knlist (nl, 1, sizeof (nl[0]))
863 #endif
864           >= 0)
865           /* Omit "&& nl[0].n_type != 0 " -- it breaks on Sun386i.  */
866           {
867 #ifdef FIXUP_KERNEL_SYMBOL_ADDR
868             FIXUP_KERNEL_SYMBOL_ADDR (nl);
869 #endif
870             offset = nl[0].n_value;
871           }
872 #endif /* !SUNOS_5 */
873 #else  /* sgi */
874           int ldav_off;
875
876           ldav_off = sysmp (MP_KERNADDR, MPKA_AVENRUN);
877           if (ldav_off != -1)
878           offset = (long) ldav_off & 0x7fffffff;
879 #endif /* sgi */
880         }
881
882   /* Make sure we have /dev/kmem open.  */
883   if (!getloadavg_initialized)
884     {
885 #ifndef SUNOS_5
886       channel = open ("/dev/kmem", 0);
887       if (channel >= 0)
888         {
889           /* Set the channel to close on exec, so it does not
890              litter any child's descriptor table.  */
891 #ifdef FD_SETFD
892 #ifndef FD_CLOEXEC
893 #define FD_CLOEXEC 1
894 #endif
895           (void) fcntl (channel, F_SETFD, FD_CLOEXEC);
896 #endif
897           getloadavg_initialized = 1;
898         }
899 #else /* SUNOS_5 */
900       /* We pass 0 for the kernel, corefile, and swapfile names
901          to use the currently running kernel.  */
902       kd = kvm_open (0, 0, 0, O_RDONLY, 0);
903       if (kd != 0)
904         {
905           /* nlist the currently running kernel.  */
906           kvm_nlist (kd, nl);
907           offset = nl[0].n_value;
908           getloadavg_initialized = 1;
909         }
910 #endif /* SUNOS_5 */
911     }
912
913   /* If we can, get the load average values.  */
914   if (offset && getloadavg_initialized)
915     {
916       /* Try to read the load.  */
917 #ifndef SUNOS_5
918       if (lseek (channel, offset, 0) == -1L
919           || read (channel, (char *) load_ave, sizeof (load_ave))
920           != sizeof (load_ave))
921         {
922           close (channel);
923           getloadavg_initialized = 0;
924         }
925 #else  /* SUNOS_5 */
926       if (kvm_read (kd, offset, (char *) load_ave, sizeof (load_ave))
927           != sizeof (load_ave))
928         {
929           kvm_close (kd);
930           getloadavg_initialized = 0;
931         }
932 #endif /* SUNOS_5 */
933     }
934
935   if (offset == 0 || !getloadavg_initialized)
936     return -1;
937
938   if (nelem > 0)
939     loadavg[elem++] = LDAV_CVT (load_ave[0]);
940   if (nelem > 1)
941     loadavg[elem++] = LDAV_CVT (load_ave[1]);
942   if (nelem > 2)
943     loadavg[elem++] = LDAV_CVT (load_ave[2]);
944
945 #define LDAV_DONE
946 #endif /* !LDAV_DONE && LOAD_AVE_TYPE */
947
948   return elem;
949 }
950
951 #endif /* ! HAVE_GETLOADAVG */
952 \f
953 #ifdef TEST
954 void
955 main (int argc, char **argv)
956 {
957   int naptime = 0;
958
959   if (argc > 1)
960     naptime = atoi (argv[1]);
961
962   while (1)
963     {
964       double avg[3];
965       int loads;
966
967       errno = 0;                /* Don't be misled if it doesn't set errno.  */
968       loads = getloadavg (avg, 3);
969       if (loads == -1)
970         {
971           perror ("Error getting load average");
972           exit (1);
973         }
974       if (loads > 0)
975         printf ("1-minute: %f  ", avg[0]);
976       if (loads > 1)
977         printf ("5-minute: %f  ", avg[1]);
978       if (loads > 2)
979         printf ("15-minute: %f  ", avg[2]);
980       if (loads > 0)
981         putchar ('\n');
982
983       if (naptime == 0)
984         break;
985       sleep (naptime);
986     }
987
988   exit (0);
989 }
990 #endif /* TEST */
991
992 #else
993
994 /* Emulate getloadavg.  */
995 int
996 getloadavg (double loadavg[], int nelem)
997 {
998   int i;
999
1000   /* A faithful emulation is going to have to be saved for a rainy day.  */
1001   for (i = 0; i < nelem; i++) 
1002     {
1003       loadavg[i] = 0.0;
1004     }
1005   return i;
1006 }
1007
1008 #endif /*__GNUWIN32__*/
1009