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