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