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