XEmacs 21.2.22 "Mercedes".
[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 (apollo)
772 #define LDAV_DONE
773 /* Apollo code from lisch@mentorg.com (Ray Lischner).
774
775    This system call is not documented.  The load average is obtained as
776    three long integers, for the load average over the past minute,
777    five minutes, and fifteen minutes.  Each value is a scaled integer,
778    with 16 bits of integer part and 16 bits of fraction part.
779
780    I'm not sure which operating system first supported this system call,
781    but I know that SR10.2 supports it.  */
782
783   extern void proc1_$get_loadav ();
784   unsigned long load_ave[3];
785
786   proc1_$get_loadav (load_ave);
787
788   if (nelem > 0)
789     loadavg[elem++] = load_ave[0] / 65536.0;
790   if (nelem > 1)
791     loadavg[elem++] = load_ave[1] / 65536.0;
792   if (nelem > 2)
793     loadavg[elem++] = load_ave[2] / 65536.0;
794 #endif /* apollo */
795
796 #if !defined (LDAV_DONE) && defined (OSF_MIPS)
797 #define LDAV_DONE
798
799   struct tbl_loadavg load_ave;
800   table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
801   loadavg[elem++]
802     = (load_ave.tl_lscale == 0
803        ? load_ave.tl_avenrun.d[0]
804        : (load_ave.tl_avenrun.l[0] / (double) load_ave.tl_lscale));
805 #endif  /* OSF_MIPS */
806
807 #if !defined (LDAV_DONE) && (defined (MSDOS) || defined (WIN32))
808 #define LDAV_DONE
809
810   /* A faithful emulation is going to have to be saved for a rainy day.  */
811   for ( ; elem < nelem; elem++)
812     {
813       loadavg[elem] = 0.0;
814     }
815 #endif  /* MSDOS */
816
817 #if !defined (LDAV_DONE) && defined (OSF_ALPHA)
818 #define LDAV_DONE
819
820   struct tbl_loadavg load_ave;
821   table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
822   for (elem = 0; elem < nelem; elem++)
823     loadavg[elem]
824       = (load_ave.tl_lscale == 0
825        ? load_ave.tl_avenrun.d[elem]
826        : (load_ave.tl_avenrun.l[elem] / (double) load_ave.tl_lscale));
827 #endif /* OSF_ALPHA */
828
829 #if !defined (LDAV_DONE) && defined(LOAD_AVE_TYPE)
830
831   /* UNIX-specific code -- read the average from /dev/kmem.  */
832
833 #define LDAV_PRIVILEGED         /* This code requires special installation.  */
834
835   LOAD_AVE_TYPE load_ave[3];
836
837   /* Get the address of LDAV_SYMBOL.  */
838   if (offset == 0)
839     {
840 #ifndef sgi
841 #ifndef NLIST_STRUCT
842       strcpy (nl[0].n_name, LDAV_SYMBOL);
843       strcpy (nl[1].n_name, "");
844 #else /* NLIST_STRUCT */
845 #ifdef NLIST_NAME_UNION
846       nl[0].n_un.n_name = LDAV_SYMBOL;
847       nl[1].n_un.n_name = 0;
848 #else /* not NLIST_NAME_UNION */
849       nl[0].n_name = (char *) LDAV_SYMBOL;
850       nl[1].n_name = 0;
851 #endif /* not NLIST_NAME_UNION */
852 #endif /* NLIST_STRUCT */
853
854 #ifndef SUNOS_5
855       if (
856 #if !(defined (_AIX) && !defined (ps2))
857           nlist (KERNEL_FILE, nl)
858 #else  /* _AIX */
859           knlist (nl, 1, sizeof (nl[0]))
860 #endif
861           >= 0)
862           /* Omit "&& nl[0].n_type != 0 " -- it breaks on Sun386i.  */
863           {
864 #ifdef FIXUP_KERNEL_SYMBOL_ADDR
865             FIXUP_KERNEL_SYMBOL_ADDR (nl);
866 #endif
867             offset = nl[0].n_value;
868           }
869 #endif /* !SUNOS_5 */
870 #else  /* sgi */
871           int ldav_off;
872
873           ldav_off = sysmp (MP_KERNADDR, MPKA_AVENRUN);
874           if (ldav_off != -1)
875           offset = (long) ldav_off & 0x7fffffff;
876 #endif /* sgi */
877         }
878
879   /* Make sure we have /dev/kmem open.  */
880   if (!getloadavg_initialized)
881     {
882 #ifndef SUNOS_5
883       channel = open ("/dev/kmem", 0);
884       if (channel >= 0)
885         {
886           /* Set the channel to close on exec, so it does not
887              litter any child's descriptor table.  */
888 #ifdef FD_SETFD
889 #ifndef FD_CLOEXEC
890 #define FD_CLOEXEC 1
891 #endif
892           (void) fcntl (channel, F_SETFD, FD_CLOEXEC);
893 #endif
894           getloadavg_initialized = 1;
895         }
896 #else /* SUNOS_5 */
897       /* We pass 0 for the kernel, corefile, and swapfile names
898          to use the currently running kernel.  */
899       kd = kvm_open (0, 0, 0, O_RDONLY, 0);
900       if (kd != 0)
901         {
902           /* nlist the currently running kernel.  */
903           kvm_nlist (kd, nl);
904           offset = nl[0].n_value;
905           getloadavg_initialized = 1;
906         }
907 #endif /* SUNOS_5 */
908     }
909
910   /* If we can, get the load average values.  */
911   if (offset && getloadavg_initialized)
912     {
913       /* Try to read the load.  */
914 #ifndef SUNOS_5
915       if (lseek (channel, offset, 0) == -1L
916           || read (channel, (char *) load_ave, sizeof (load_ave))
917           != sizeof (load_ave))
918         {
919           close (channel);
920           getloadavg_initialized = 0;
921         }
922 #else  /* SUNOS_5 */
923       if (kvm_read (kd, offset, (char *) load_ave, sizeof (load_ave))
924           != sizeof (load_ave))
925         {
926           kvm_close (kd);
927           getloadavg_initialized = 0;
928         }
929 #endif /* SUNOS_5 */
930     }
931
932   if (offset == 0 || !getloadavg_initialized)
933     return -1;
934
935   if (nelem > 0)
936     loadavg[elem++] = LDAV_CVT (load_ave[0]);
937   if (nelem > 1)
938     loadavg[elem++] = LDAV_CVT (load_ave[1]);
939   if (nelem > 2)
940     loadavg[elem++] = LDAV_CVT (load_ave[2]);
941
942 #define LDAV_DONE
943 #endif /* !LDAV_DONE && LOAD_AVE_TYPE */
944
945   return elem;
946 }
947
948 #endif /* ! HAVE_GETLOADAVG */
949 \f
950 #ifdef TEST
951 void
952 main (int argc, char **argv)
953 {
954   int naptime = 0;
955
956   if (argc > 1)
957     naptime = atoi (argv[1]);
958
959   while (1)
960     {
961       double avg[3];
962       int loads;
963
964       errno = 0;                /* Don't be misled if it doesn't set errno.  */
965       loads = getloadavg (avg, 3);
966       if (loads == -1)
967         {
968           perror ("Error getting load average");
969           exit (1);
970         }
971       if (loads > 0)
972         printf ("1-minute: %f  ", avg[0]);
973       if (loads > 1)
974         printf ("5-minute: %f  ", avg[1]);
975       if (loads > 2)
976         printf ("15-minute: %f  ", avg[2]);
977       if (loads > 0)
978         putchar ('\n');
979
980       if (naptime == 0)
981         break;
982       sleep (naptime);
983     }
984
985   exit (0);
986 }
987 #endif /* TEST */
988
989 #else
990
991 /* Emulate getloadavg.  */
992 int
993 getloadavg (double loadavg[], int nelem)
994 {
995   int i;
996
997   /* A faithful emulation is going to have to be saved for a rainy day.  */
998   for (i = 0; i < nelem; i++) 
999     {
1000       loadavg[i] = 0.0;
1001     }
1002   return i;
1003 }
1004
1005 #endif /*__GNUWIN32__*/
1006 #endif /* WINDOWSNT */