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