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