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