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