(Fexpand_abbrev): Remove unused variables.
[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
8eda6c51 312/* VAX C can't handle multi-line #ifs, or lines longer that 256 characters. */
3da4f367 313# ifndef NLIST_STRUCT
8eda6c51 314
3da4f367
JM
315# ifdef MORE_BSD
316# define NLIST_STRUCT
317# endif
8eda6c51 318
3da4f367
JM
319# ifdef sun
320# define NLIST_STRUCT
321# endif
8eda6c51 322
3da4f367
JM
323# ifdef decstation
324# define NLIST_STRUCT
325# endif
8eda6c51 326
3da4f367
JM
327# ifdef hpux
328# define NLIST_STRUCT
329# endif
8eda6c51 330
3da4f367
JM
331# if defined (_SEQUENT_) || defined (sequent)
332# define NLIST_STRUCT
333# endif
8eda6c51 334
3da4f367
JM
335# ifdef sgi
336# define NLIST_STRUCT
337# endif
8eda6c51 338
3da4f367
JM
339# ifdef SVR4
340# define NLIST_STRUCT
341# endif
1e5ba5b5 342
3da4f367
JM
343# ifdef sony_news
344# define NLIST_STRUCT
345# endif
8eda6c51 346
3da4f367
JM
347# ifdef OSF_ALPHA
348# define NLIST_STRUCT
349# endif
8eda6c51 350
3da4f367
JM
351# if defined (ardent) && defined (titan)
352# define NLIST_STRUCT
353# endif
8eda6c51 354
3da4f367
JM
355# ifdef tek4300
356# define NLIST_STRUCT
357# endif
8eda6c51 358
3da4f367
JM
359# ifdef butterfly
360# define NLIST_STRUCT
361# endif
8eda6c51 362
3da4f367
JM
363# if defined(alliant) && defined(i860) /* Alliant FX/2800 */
364# define NLIST_STRUCT
365# endif
59c0e567 366
3da4f367
JM
367# ifdef _AIX
368# define NLIST_STRUCT
369# endif
bc77c95c 370
3da4f367 371# endif /* defined (NLIST_STRUCT) */
8eda6c51 372
1e5ba5b5 373
3da4f367
JM
374# if defined(sgi) || (defined(mips) && !defined(BSD))
375# define FIXUP_KERNEL_SYMBOL_ADDR(nl) ((nl)[0].n_value &= ~(1 << 31))
376# endif
1e5ba5b5
RM
377
378
3da4f367
JM
379# if !defined (KERNEL_FILE) && defined (sequent)
380# define KERNEL_FILE "/dynix"
381# endif
1e5ba5b5 382
3da4f367
JM
383# if !defined (KERNEL_FILE) && defined (hpux)
384# define KERNEL_FILE "/hp-ux"
385# endif
1e5ba5b5 386
3da4f367
JM
387# if !defined(KERNEL_FILE) && (defined(_SEQUENT_) || defined(MIPS) || defined(SVR4) || defined(ISC) || defined (sgi) || (defined (ardent) && defined (titan)))
388# define KERNEL_FILE "/unix"
389# endif
1e5ba5b5
RM
390
391
3da4f367
JM
392# if !defined (LDAV_SYMBOL) && defined (alliant)
393# define LDAV_SYMBOL "_Loadavg"
394# endif
1e5ba5b5 395
3da4f367
JM
396# if !defined(LDAV_SYMBOL) && ((defined(hpux) && !defined(hp9000s300)) || defined(_SEQUENT_) || defined(SVR4) || defined(ISC) || defined(sgi) || (defined (ardent) && defined (titan)) || defined (_AIX))
397# define LDAV_SYMBOL "avenrun"
398# endif
1e5ba5b5 399
3da4f367
JM
400# ifdef HAVE_UNISTD_H
401# include <unistd.h>
402# endif
1e5ba5b5 403
3da4f367 404# include <stdio.h>
1e5ba5b5
RM
405
406/* LOAD_AVE_TYPE should only get defined if we're going to use the
407 nlist method. */
3da4f367
JM
408# if !defined(LOAD_AVE_TYPE) && (defined(BSD) || defined(LDAV_CVT) || defined(KERNEL_FILE) || defined(LDAV_SYMBOL))
409# define LOAD_AVE_TYPE double
410# endif
411
412# ifdef LOAD_AVE_TYPE
413
414# ifndef VMS
415# ifndef __linux__
416# ifndef NLIST_STRUCT
417# include <a.out.h>
418# else /* NLIST_STRUCT */
419# include <nlist.h>
420# endif /* NLIST_STRUCT */
421
422# ifdef SUNOS_5
423# include <fcntl.h>
424# include <kvm.h>
425# include <kstat.h>
426# endif
427
428# if defined (hpux) && defined (HAVE_PSTAT_GETDYNAMIC)
429# include <sys/pstat.h>
430# endif
431
432# ifndef KERNEL_FILE
433# define KERNEL_FILE "/vmunix"
434# endif /* KERNEL_FILE */
435
436# ifndef LDAV_SYMBOL
437# define LDAV_SYMBOL "_avenrun"
438# endif /* LDAV_SYMBOL */
439# endif /* __linux__ */
440
441# else /* VMS */
442
443# ifndef eunice
444# include <iodef.h>
445# include <descrip.h>
446# else /* eunice */
447# include <vms/iodef.h>
448# endif /* eunice */
449# endif /* VMS */
450
451# ifndef LDAV_CVT
452# define LDAV_CVT(n) ((double) (n))
453# endif /* !LDAV_CVT */
454
455# endif /* LOAD_AVE_TYPE */
456
d282be16
RS
457# if defined(__GNU__) && !defined (NeXT)
458/* Note that NeXT Openstep defines __GNU__ even though it should not. */
459/* GNU system acts much like NeXT, for load average purposes,
460 but not exactly. */
2c30b2fc
MB
461# define NeXT
462# define host_self mach_host_self
463# endif
464
3da4f367
JM
465# ifdef NeXT
466# ifdef HAVE_MACH_MACH_H
467# include <mach/mach.h>
468# else
469# include <mach.h>
470# endif
471# endif /* NeXT */
472
473# ifdef sgi
474# include <sys/sysmp.h>
475# endif /* sgi */
476
477# ifdef UMAX
478# include <stdio.h>
479# include <signal.h>
480# include <sys/time.h>
481# include <sys/wait.h>
482# include <sys/syscall.h>
483
484# ifdef UMAX_43
485# include <machine/cpu.h>
486# include <inq_stats/statistics.h>
487# include <inq_stats/sysstats.h>
488# include <inq_stats/cpustats.h>
489# include <inq_stats/procstats.h>
490# else /* Not UMAX_43. */
491# include <sys/sysdefs.h>
492# include <sys/statistics.h>
493# include <sys/sysstats.h>
494# include <sys/cpudefs.h>
495# include <sys/cpustats.h>
496# include <sys/procstats.h>
497# endif /* Not UMAX_43. */
498# endif /* UMAX */
499
500# ifdef DGUX
501# include <sys/dg_sys_info.h>
502# endif
503
504# if defined(HAVE_FCNTL_H) || defined(_POSIX_VERSION)
505# include <fcntl.h>
506# else
507# include <sys/file.h>
508# endif
1e5ba5b5 509\f
102f4b17 510
1e5ba5b5
RM
511/* Avoid static vars inside a function since in HPUX they dump as pure. */
512
3da4f367 513# ifdef NeXT
1e5ba5b5
RM
514static processor_set_t default_set;
515static int getloadavg_initialized;
3da4f367 516# endif /* NeXT */
1e5ba5b5 517
3da4f367 518# ifdef UMAX
1e5ba5b5
RM
519static unsigned int cpus = 0;
520static unsigned int samples;
3da4f367 521# endif /* UMAX */
1e5ba5b5 522
3da4f367 523# ifdef DGUX
1e5ba5b5 524static struct dg_sys_info_load_info load_info; /* what-a-mouthful! */
3da4f367 525# endif /* DGUX */
1e5ba5b5 526
102f4b17 527#if !defined(HAVE_LIBKSTAT) && defined(LOAD_AVE_TYPE)
1e5ba5b5
RM
528/* File descriptor open to /dev/kmem or VMS load ave driver. */
529static int channel;
530/* Nonzero iff channel is valid. */
531static int getloadavg_initialized;
532/* Offset in kmem to seek to read load average, or 0 means invalid. */
533static long offset;
534
102f4b17 535#if !defined(VMS) && !defined(sgi) && !defined(__linux__)
1e5ba5b5 536static struct nlist nl[2];
432eec29 537#endif /* Not VMS or sgi */
1e5ba5b5 538
102f4b17 539#ifdef SUNOS_5
1e5ba5b5 540static kvm_t *kd;
102f4b17 541#endif /* SUNOS_5 */
1e5ba5b5 542
432eec29 543#endif /* LOAD_AVE_TYPE && !HAVE_LIBKSTAT */
1e5ba5b5
RM
544\f
545/* Put the 1 minute, 5 minute and 15 minute load averages
546 into the first NELEM elements of LOADAVG.
039e9c8b 547 Return the number written (never more than 3, but may be less than NELEM),
1e5ba5b5
RM
548 or -1 if an error occurred. */
549
550int
551getloadavg (loadavg, nelem)
552 double loadavg[];
553 int nelem;
554{
555 int elem = 0; /* Return value. */
556
3da4f367
JM
557# ifdef NO_GET_LOAD_AVG
558# define LDAV_DONE
7ee260fe
RM
559 /* Set errno to zero to indicate that there was no particular error;
560 this function just can't work at all on this system. */
561 errno = 0;
562 elem = -1;
3da4f367 563# endif
7ee260fe 564
6b2e9efd 565# if !defined (LDAV_DONE) && defined (HAVE_LIBKSTAT)
4e98d4fa 566/* Use libkstat because we don't have to be root. */
3da4f367 567# define LDAV_DONE
4e98d4fa
RS
568 kstat_ctl_t *kc;
569 kstat_t *ksp;
570 kstat_named_t *kn;
571
572 kc = kstat_open ();
3da4f367
JM
573 if (kc == 0)
574 return -1;
4e98d4fa 575 ksp = kstat_lookup (kc, "unix", 0, "system_misc");
3da4f367
JM
576 if (ksp == 0 )
577 return -1;
578 if (kstat_read (kc, ksp, 0) == -1)
579 return -1;
73a46a9c 580
4e98d4fa
RS
581
582 kn = kstat_data_lookup (ksp, "avenrun_1min");
583 if (kn == 0)
584 {
585 /* Return -1 if no load average information is available. */
586 nelem = 0;
587 elem = -1;
588 }
589
590 if (nelem >= 1)
591 loadavg[elem++] = (double) kn->value.ul/FSCALE;
592
593 if (nelem >= 2)
594 {
595 kn = kstat_data_lookup (ksp, "avenrun_5min");
596 if (kn != 0)
597 {
598 loadavg[elem++] = (double) kn->value.ul/FSCALE;
599
600 if (nelem >= 3)
601 {
602 kn = kstat_data_lookup (ksp, "avenrun_15min");
603 if (kn != 0)
604 loadavg[elem++] = (double) kn->value.ul/FSCALE;
605 }
606 }
607 }
608
609 kstat_close (kc);
6b2e9efd 610# endif /* HAVE_LIBKSTAT */
4e98d4fa 611
3da4f367
JM
612# if !defined (LDAV_DONE) && defined (hpux) && defined (HAVE_PSTAT_GETDYNAMIC)
613/* Use pstat_getdynamic() because we don't have to be root. */
614# define LDAV_DONE
615# undef LOAD_AVE_TYPE
1e5ba5b5 616
3da4f367
JM
617 struct pst_dynamic dyn_info;
618 if (pstat_getdynamic (&dyn_info, sizeof (dyn_info), 0, 0) < 0)
619 return -1;
620 if (nelem > 0)
621 loadavg[elem++] = dyn_info.psd_avg_1_min;
622 if (nelem > 1)
623 loadavg[elem++] = dyn_info.psd_avg_5_min;
624 if (nelem > 2)
625 loadavg[elem++] = dyn_info.psd_avg_15_min;
626
627# endif /* hpux && HAVE_PSTAT_GETDYNAMIC */
628
629# if !defined (LDAV_DONE) && defined (__linux__)
630# define LDAV_DONE
631# undef LOAD_AVE_TYPE
632
633# ifndef LINUX_LDAV_FILE
634# define LINUX_LDAV_FILE "/proc/loadavg"
635# endif
1e5ba5b5
RM
636
637 char ldavgbuf[40];
638 double load_ave[3];
639 int fd, count;
640
641 fd = open (LINUX_LDAV_FILE, O_RDONLY);
642 if (fd == -1)
643 return -1;
644 count = read (fd, ldavgbuf, 40);
645 (void) close (fd);
646 if (count <= 0)
647 return -1;
648
649 count = sscanf (ldavgbuf, "%lf %lf %lf",
650 &load_ave[0], &load_ave[1], &load_ave[2]);
651 if (count < 1)
652 return -1;
653
654 for (elem = 0; elem < nelem && elem < count; elem++)
655 loadavg[elem] = load_ave[elem];
656
657 return elem;
658
3da4f367 659# endif /* __linux__ */
1e5ba5b5 660
3da4f367
JM
661# if !defined (LDAV_DONE) && defined (__NetBSD__)
662# define LDAV_DONE
663# undef LOAD_AVE_TYPE
9eb8034b 664
3da4f367
JM
665# ifndef NETBSD_LDAV_FILE
666# define NETBSD_LDAV_FILE "/kern/loadavg"
667# endif
9eb8034b
RM
668
669 unsigned long int load_ave[3], scale;
670 int count;
671 FILE *fp;
672
8f090e85 673 fp = fopen (NETBSD_LDAV_FILE, "r");
9eb8034b
RM
674 if (fp == NULL)
675 return -1;
676 count = fscanf (fp, "%lu %lu %lu %lu\n",
677 &load_ave[0], &load_ave[1], &load_ave[2],
678 &scale);
679 (void) fclose (fp);
680 if (count != 4)
681 return -1;
682
683 for (elem = 0; elem < nelem; elem++)
684 loadavg[elem] = (double) load_ave[elem] / (double) scale;
685
686 return elem;
687
3da4f367 688# endif /* __NetBSD__ */
9eb8034b 689
3da4f367
JM
690# if !defined (LDAV_DONE) && defined (NeXT)
691# define LDAV_DONE
1e5ba5b5
RM
692 /* The NeXT code was adapted from iscreen 3.2. */
693
694 host_t host;
695 struct processor_set_basic_info info;
696 unsigned info_count;
697
039e9c8b
DM
698 /* We only know how to get the 1-minute average for this system,
699 so even if the caller asks for more than 1, we only return 1. */
1e5ba5b5
RM
700
701 if (!getloadavg_initialized)
702 {
703 if (processor_set_default (host_self (), &default_set) == KERN_SUCCESS)
704 getloadavg_initialized = 1;
705 }
706
707 if (getloadavg_initialized)
708 {
709 info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
710 if (processor_set_info (default_set, PROCESSOR_SET_BASIC_INFO, &host,
3da4f367 711 (processor_set_info_t) &info, &info_count)
1e5ba5b5
RM
712 != KERN_SUCCESS)
713 getloadavg_initialized = 0;
714 else
715 {
716 if (nelem > 0)
717 loadavg[elem++] = (double) info.load_average / LOAD_SCALE;
718 }
719 }
720
721 if (!getloadavg_initialized)
722 return -1;
3da4f367 723# endif /* NeXT */
1e5ba5b5 724
3da4f367
JM
725# if !defined (LDAV_DONE) && defined (UMAX)
726# define LDAV_DONE
1e5ba5b5
RM
727/* UMAX 4.2, which runs on the Encore Multimax multiprocessor, does not
728 have a /dev/kmem. Information about the workings of the running kernel
729 can be gathered with inq_stats system calls.
730 We only know how to get the 1-minute average for this system. */
731
732 struct proc_summary proc_sum_data;
733 struct stat_descr proc_info;
734 double load;
735 register unsigned int i, j;
736
737 if (cpus == 0)
738 {
739 register unsigned int c, i;
740 struct cpu_config conf;
741 struct stat_descr desc;
742
743 desc.sd_next = 0;
744 desc.sd_subsys = SUBSYS_CPU;
745 desc.sd_type = CPUTYPE_CONFIG;
746 desc.sd_addr = (char *) &conf;
747 desc.sd_size = sizeof conf;
748
749 if (inq_stats (1, &desc))
750 return -1;
751
752 c = 0;
753 for (i = 0; i < conf.config_maxclass; ++i)
754 {
755 struct class_stats stats;
756 bzero ((char *) &stats, sizeof stats);
757
758 desc.sd_type = CPUTYPE_CLASS;
759 desc.sd_objid = i;
760 desc.sd_addr = (char *) &stats;
761 desc.sd_size = sizeof stats;
762
763 if (inq_stats (1, &desc))
764 return -1;
765
766 c += stats.class_numcpus;
767 }
768 cpus = c;
769 samples = cpus < 2 ? 3 : (2 * cpus / 3);
770 }
771
772 proc_info.sd_next = 0;
773 proc_info.sd_subsys = SUBSYS_PROC;
774 proc_info.sd_type = PROCTYPE_SUMMARY;
775 proc_info.sd_addr = (char *) &proc_sum_data;
776 proc_info.sd_size = sizeof (struct proc_summary);
777 proc_info.sd_sizeused = 0;
778
779 if (inq_stats (1, &proc_info) != 0)
780 return -1;
781
782 load = proc_sum_data.ps_nrunnable;
783 j = 0;
784 for (i = samples - 1; i > 0; --i)
785 {
786 load += proc_sum_data.ps_nrun[j];
787 if (j++ == PS_NRUNSIZE)
788 j = 0;
789 }
790
791 if (nelem > 0)
792 loadavg[elem++] = load / samples / cpus;
3da4f367 793# endif /* UMAX */
1e5ba5b5 794
3da4f367
JM
795# if !defined (LDAV_DONE) && defined (DGUX)
796# define LDAV_DONE
1e5ba5b5
RM
797 /* This call can return -1 for an error, but with good args
798 it's not supposed to fail. The first argument is for no
799 apparent reason of type `long int *'. */
800 dg_sys_info ((long int *) &load_info,
801 DG_SYS_INFO_LOAD_INFO_TYPE,
802 DG_SYS_INFO_LOAD_VERSION_0);
803
804 if (nelem > 0)
805 loadavg[elem++] = load_info.one_minute;
806 if (nelem > 1)
807 loadavg[elem++] = load_info.five_minute;
808 if (nelem > 2)
809 loadavg[elem++] = load_info.fifteen_minute;
3da4f367 810# endif /* DGUX */
1e5ba5b5 811
3da4f367
JM
812# if !defined (LDAV_DONE) && defined (apollo)
813# define LDAV_DONE
1e5ba5b5
RM
814/* Apollo code from lisch@mentorg.com (Ray Lischner).
815
816 This system call is not documented. The load average is obtained as
817 three long integers, for the load average over the past minute,
818 five minutes, and fifteen minutes. Each value is a scaled integer,
819 with 16 bits of integer part and 16 bits of fraction part.
820
821 I'm not sure which operating system first supported this system call,
822 but I know that SR10.2 supports it. */
823
824 extern void proc1_$get_loadav ();
825 unsigned long load_ave[3];
826
827 proc1_$get_loadav (load_ave);
828
829 if (nelem > 0)
830 loadavg[elem++] = load_ave[0] / 65536.0;
831 if (nelem > 1)
832 loadavg[elem++] = load_ave[1] / 65536.0;
833 if (nelem > 2)
834 loadavg[elem++] = load_ave[2] / 65536.0;
3da4f367 835# endif /* apollo */
1e5ba5b5 836
3da4f367
JM
837# if !defined (LDAV_DONE) && defined (OSF_MIPS)
838# define LDAV_DONE
1e5ba5b5
RM
839
840 struct tbl_loadavg load_ave;
841 table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
7ee260fe
RM
842 loadavg[elem++]
843 = (load_ave.tl_lscale == 0
844 ? load_ave.tl_avenrun.d[0]
845 : (load_ave.tl_avenrun.l[0] / (double) load_ave.tl_lscale));
3da4f367 846# endif /* OSF_MIPS */
1e5ba5b5 847
383ebe49 848# if !defined (LDAV_DONE) && (defined (__MSDOS__) || defined (WINDOWS32))
3da4f367 849# define LDAV_DONE
a7ee71e8
RS
850
851 /* A faithful emulation is going to have to be saved for a rainy day. */
26ff97e7 852 for ( ; elem < nelem; elem++)
a7ee71e8
RS
853 {
854 loadavg[elem] = 0.0;
855 }
383ebe49 856# endif /* __MSDOS__ || WINDOWS32 */
a7ee71e8 857
3da4f367
JM
858# if !defined (LDAV_DONE) && defined (OSF_ALPHA)
859# define LDAV_DONE
bbd619d7
RS
860
861 struct tbl_loadavg load_ave;
862 table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
863 for (elem = 0; elem < nelem; elem++)
864 loadavg[elem]
865 = (load_ave.tl_lscale == 0
866 ? load_ave.tl_avenrun.d[elem]
867 : (load_ave.tl_avenrun.l[elem] / (double) load_ave.tl_lscale));
3da4f367 868# endif /* OSF_ALPHA */
bbd619d7 869
3da4f367 870# if !defined (LDAV_DONE) && defined (VMS)
1e5ba5b5
RM
871 /* VMS specific code -- read from the Load Ave driver. */
872
873 LOAD_AVE_TYPE load_ave[3];
874 static int getloadavg_initialized = 0;
3da4f367 875# ifdef eunice
1e5ba5b5
RM
876 struct
877 {
878 int dsc$w_length;
879 char *dsc$a_pointer;
880 } descriptor;
3da4f367 881# endif
1e5ba5b5
RM
882
883 /* Ensure that there is a channel open to the load ave device. */
884 if (!getloadavg_initialized)
885 {
886 /* Attempt to open the channel. */
3da4f367 887# ifdef eunice
1e5ba5b5
RM
888 descriptor.dsc$w_length = 18;
889 descriptor.dsc$a_pointer = "$$VMS_LOAD_AVERAGE";
3da4f367 890# else
1e5ba5b5 891 $DESCRIPTOR (descriptor, "LAV0:");
3da4f367 892# endif
1e5ba5b5
RM
893 if (sys$assign (&descriptor, &channel, 0, 0) & 1)
894 getloadavg_initialized = 1;
895 }
896
897 /* Read the load average vector. */
898 if (getloadavg_initialized
899 && !(sys$qiow (0, channel, IO$_READVBLK, 0, 0, 0,
900 load_ave, 12, 0, 0, 0, 0) & 1))
901 {
902 sys$dassgn (channel);
903 getloadavg_initialized = 0;
904 }
905
906 if (!getloadavg_initialized)
907 return -1;
3da4f367 908# endif /* VMS */
1e5ba5b5 909
3da4f367 910# if !defined (LDAV_DONE) && defined(LOAD_AVE_TYPE) && !defined(VMS)
1e5ba5b5
RM
911
912 /* UNIX-specific code -- read the average from /dev/kmem. */
913
3da4f367 914# define LDAV_PRIVILEGED /* This code requires special installation. */
1e5ba5b5
RM
915
916 LOAD_AVE_TYPE load_ave[3];
917
918 /* Get the address of LDAV_SYMBOL. */
919 if (offset == 0)
920 {
3da4f367
JM
921# ifndef sgi
922# ifndef NLIST_STRUCT
1e5ba5b5
RM
923 strcpy (nl[0].n_name, LDAV_SYMBOL);
924 strcpy (nl[1].n_name, "");
3da4f367
JM
925# else /* NLIST_STRUCT */
926# ifdef NLIST_NAME_UNION
1e5ba5b5
RM
927 nl[0].n_un.n_name = LDAV_SYMBOL;
928 nl[1].n_un.n_name = 0;
3da4f367 929# else /* not NLIST_NAME_UNION */
1e5ba5b5
RM
930 nl[0].n_name = LDAV_SYMBOL;
931 nl[1].n_name = 0;
3da4f367
JM
932# endif /* not NLIST_NAME_UNION */
933# endif /* NLIST_STRUCT */
1e5ba5b5 934
3da4f367 935# ifndef SUNOS_5
bc77c95c 936 if (
3da4f367 937# if !(defined (_AIX) && !defined (ps2))
bc77c95c 938 nlist (KERNEL_FILE, nl)
3da4f367 939# else /* _AIX */
bc77c95c 940 knlist (nl, 1, sizeof (nl[0]))
3da4f367 941# endif
bc77c95c
RM
942 >= 0)
943 /* Omit "&& nl[0].n_type != 0 " -- it breaks on Sun386i. */
944 {
3da4f367 945# ifdef FIXUP_KERNEL_SYMBOL_ADDR
bc77c95c 946 FIXUP_KERNEL_SYMBOL_ADDR (nl);
3da4f367 947# endif
bc77c95c
RM
948 offset = nl[0].n_value;
949 }
3da4f367
JM
950# endif /* !SUNOS_5 */
951# else /* sgi */
952 int ldav_off;
953
954 ldav_off = sysmp (MP_KERNADDR, MPKA_AVENRUN);
955 if (ldav_off != -1)
956 offset = (long) ldav_off & 0x7fffffff;
957# endif /* sgi */
958 }
1e5ba5b5
RM
959
960 /* Make sure we have /dev/kmem open. */
961 if (!getloadavg_initialized)
962 {
3da4f367 963# ifndef SUNOS_5
1e5ba5b5
RM
964 channel = open ("/dev/kmem", 0);
965 if (channel >= 0)
00f7bd72
RM
966 {
967 /* Set the channel to close on exec, so it does not
968 litter any child's descriptor table. */
071b0719 969# ifdef F_SETFD
3da4f367
JM
970# ifndef FD_CLOEXEC
971# define FD_CLOEXEC 1
972# endif
00f7bd72 973 (void) fcntl (channel, F_SETFD, FD_CLOEXEC);
3da4f367 974# endif
00f7bd72
RM
975 getloadavg_initialized = 1;
976 }
3da4f367 977# else /* SUNOS_5 */
fb3ebe6c
DM
978 /* We pass 0 for the kernel, corefile, and swapfile names
979 to use the currently running kernel. */
1e5ba5b5 980 kd = kvm_open (0, 0, 0, O_RDONLY, 0);
26ff97e7 981 if (kd != 0)
1e5ba5b5 982 {
fb3ebe6c 983 /* nlist the currently running kernel. */
1e5ba5b5 984 kvm_nlist (kd, nl);
fb3ebe6c 985 offset = nl[0].n_value;
1e5ba5b5
RM
986 getloadavg_initialized = 1;
987 }
3da4f367 988# endif /* SUNOS_5 */
1e5ba5b5
RM
989 }
990
991 /* If we can, get the load average values. */
992 if (offset && getloadavg_initialized)
993 {
994 /* Try to read the load. */
3da4f367 995# ifndef SUNOS_5
1e5ba5b5
RM
996 if (lseek (channel, offset, 0) == -1L
997 || read (channel, (char *) load_ave, sizeof (load_ave))
998 != sizeof (load_ave))
999 {
1000 close (channel);
1001 getloadavg_initialized = 0;
1002 }
3da4f367 1003# else /* SUNOS_5 */
1e5ba5b5
RM
1004 if (kvm_read (kd, offset, (char *) load_ave, sizeof (load_ave))
1005 != sizeof (load_ave))
1006 {
1007 kvm_close (kd);
1008 getloadavg_initialized = 0;
1009 }
3da4f367 1010# endif /* SUNOS_5 */
1e5ba5b5
RM
1011 }
1012
1013 if (offset == 0 || !getloadavg_initialized)
1014 return -1;
3da4f367 1015# endif /* LOAD_AVE_TYPE and not VMS */
1e5ba5b5 1016
3da4f367 1017# if !defined (LDAV_DONE) && defined (LOAD_AVE_TYPE) /* Including VMS. */
1e5ba5b5
RM
1018 if (nelem > 0)
1019 loadavg[elem++] = LDAV_CVT (load_ave[0]);
1020 if (nelem > 1)
1021 loadavg[elem++] = LDAV_CVT (load_ave[1]);
1022 if (nelem > 2)
1023 loadavg[elem++] = LDAV_CVT (load_ave[2]);
1024
3da4f367
JM
1025# define LDAV_DONE
1026# endif /* !LDAV_DONE && LOAD_AVE_TYPE */
1e5ba5b5 1027
3da4f367 1028# ifdef LDAV_DONE
1e5ba5b5 1029 return elem;
3da4f367 1030# else
1e5ba5b5
RM
1031 /* Set errno to zero to indicate that there was no particular error;
1032 this function just can't work at all on this system. */
1033 errno = 0;
1034 return -1;
3da4f367 1035# endif
1e5ba5b5 1036}
04402ae3
RM
1037
1038#endif /* ! HAVE_GETLOADAVG */
1e5ba5b5
RM
1039\f
1040#ifdef TEST
75c0d095 1041int
1e5ba5b5
RM
1042main (argc, argv)
1043 int argc;
1044 char **argv;
1045{
1046 int naptime = 0;
1047
1048 if (argc > 1)
1049 naptime = atoi (argv[1]);
1050
1e5ba5b5
RM
1051 while (1)
1052 {
1053 double avg[3];
1054 int loads;
1055
1056 errno = 0; /* Don't be misled if it doesn't set errno. */
1057 loads = getloadavg (avg, 3);
1058 if (loads == -1)
1059 {
1060 perror ("Error getting load average");
1061 exit (1);
1062 }
1063 if (loads > 0)
1064 printf ("1-minute: %f ", avg[0]);
1065 if (loads > 1)
1066 printf ("5-minute: %f ", avg[1]);
1067 if (loads > 2)
1068 printf ("15-minute: %f ", avg[2]);
1069 if (loads > 0)
1070 putchar ('\n');
db6730c7
RM
1071
1072 if (naptime == 0)
1073 break;
1e5ba5b5
RM
1074 sleep (naptime);
1075 }
db6730c7
RM
1076
1077 exit (0);
1e5ba5b5
RM
1078}
1079#endif /* TEST */