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