Add VMS updates from Martin Zinser.
[make.git] / getloadavg.c
blob7d575cd6a1ea18c42c3648df07c6c8010e5a3247
1 /* Get the system load averages.
2 Copyright (C) 1985, 86, 87, 88, 89, 91, 92, 93, 1994, 1995, 1997
3 Free Software Foundation, Inc.
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
18 USA. */
20 /* Compile-time symbols that this file uses:
22 HAVE_PSTAT_GETDYNAMIC Define this if your system has the
23 pstat_getdynamic function. I think it
24 is unique to HPUX9. The best way to get the
25 definition is through the AC_FUNC_GETLOADAVG
26 macro that comes with autoconf 2.13 or newer.
27 If that isn't an option, then just put
28 AC_CHECK_FUNCS(pstat_getdynamic) in your
29 configure.in file.
30 FIXUP_KERNEL_SYMBOL_ADDR() Adjust address in returned struct nlist.
31 KERNEL_FILE Pathname of the kernel to nlist.
32 LDAV_CVT() Scale the load average from the kernel.
33 Returns a double.
34 LDAV_SYMBOL Name of kernel symbol giving load average.
35 LOAD_AVE_TYPE Type of the load average array in the kernel.
36 Must be defined unless one of
37 apollo, DGUX, NeXT, or UMAX is defined;
38 or we have libkstat;
39 otherwise, no load average is available.
40 NLIST_STRUCT Include nlist.h, not a.out.h, and
41 the nlist n_name element is a pointer,
42 not an array.
43 HAVE_STRUCT_NLIST_N_UN_N_NAME struct nlist has an n_un member, not n_name.
44 LINUX_LDAV_FILE [__linux__]: File containing load averages.
46 Specific system predefines this file uses, aside from setting
47 default values if not emacs:
49 apollo
50 BSD Real BSD, not just BSD-like.
51 convex
52 DGUX
53 eunice UNIX emulator under VMS.
54 hpux
55 __MSDOS__ No-op for MSDOS.
56 NeXT
57 sgi
58 sequent Sequent Dynix 3.x.x (BSD)
59 _SEQUENT_ Sequent DYNIX/ptx 1.x.x (SYSV)
60 sony_news NEWS-OS (works at least for 4.1C)
61 UMAX
62 UMAX4_3
63 VMS
64 WINDOWS32 No-op for Windows95/NT.
65 __linux__ Linux: assumes /proc filesystem mounted.
66 Support from Michael K. Johnson.
67 __NetBSD__ NetBSD: assumes /kern filesystem mounted.
69 In addition, to avoid nesting many #ifdefs, we internally set
70 LDAV_DONE to indicate that the load average has been computed.
72 We also #define LDAV_PRIVILEGED if a program will require
73 special installation to be able to call getloadavg. */
75 /* This should always be first. */
76 #ifdef HAVE_CONFIG_H
77 # include <config.h>
78 #endif
80 #include <sys/types.h>
82 /* Both the Emacs and non-Emacs sections want this. Some
83 configuration files' definitions for the LOAD_AVE_CVT macro (like
84 sparc.h's) use macros like FSCALE, defined here. */
85 #if defined (unix) || defined (__unix)
86 # include <sys/param.h>
87 #endif
90 /* Exclude all the code except the test program at the end
91 if the system has its own `getloadavg' function.
93 The declaration of `errno' is needed by the test program
94 as well as the function itself, so it comes first. */
96 #include <errno.h>
98 #ifndef errno
99 extern int errno;
100 #endif
102 #if HAVE_LOCALE_H
103 # include <locale.h>
104 #endif
105 #if !HAVE_SETLOCALE
106 # define setlocale(Category, Locale) /* empty */
107 #endif
109 #ifndef HAVE_GETLOADAVG
112 /* The existing Emacs configuration files define a macro called
113 LOAD_AVE_CVT, which accepts a value of type LOAD_AVE_TYPE, and
114 returns the load average multiplied by 100. What we actually want
115 is a macro called LDAV_CVT, which returns the load average as an
116 unmultiplied double.
118 For backwards compatibility, we'll define LDAV_CVT in terms of
119 LOAD_AVE_CVT, but future machine config files should just define
120 LDAV_CVT directly. */
122 # if !defined(LDAV_CVT) && defined(LOAD_AVE_CVT)
123 # define LDAV_CVT(n) (LOAD_AVE_CVT (n) / 100.0)
124 # endif
126 # if !defined (BSD) && defined (ultrix)
127 /* Ultrix behaves like BSD on Vaxen. */
128 # define BSD
129 # endif
131 # ifdef NeXT
132 /* NeXT in the 2.{0,1,2} releases defines BSD in <sys/param.h>, which
133 conflicts with the definition understood in this file, that this
134 really is BSD. */
135 # undef BSD
137 /* NeXT defines FSCALE in <sys/param.h>. However, we take FSCALE being
138 defined to mean that the nlist method should be used, which is not true. */
139 # undef FSCALE
140 # endif
142 /* Same issues as for NeXT apply to the HURD-based GNU system. */
143 # ifdef __GNU__
144 # undef BSD
145 # undef FSCALE
146 # endif /* __GNU__ */
148 /* Set values that are different from the defaults, which are
149 set a little farther down with #ifndef. */
152 /* Some shorthands. */
154 # if defined (HPUX) && !defined (hpux)
155 # define hpux
156 # endif
158 # if defined (__hpux) && !defined (hpux)
159 # define hpux
160 # endif
162 # if defined (__sun) && !defined (sun)
163 # define sun
164 # endif
166 # if defined(hp300) && !defined(hpux)
167 # define MORE_BSD
168 # endif
170 # if defined(ultrix) && defined(mips)
171 # define decstation
172 # endif
174 # if defined (__SVR4) && !defined (SVR4)
175 # define SVR4
176 # endif
178 # if (defined(sun) && defined(SVR4)) || defined (SOLARIS2)
179 # define SUNOS_5
180 # endif
182 # if defined (__osf__) && (defined (__alpha) || defined (__alpha__))
183 # define OSF_ALPHA
184 # include <sys/mbuf.h>
185 # include <sys/socket.h>
186 # include <net/route.h>
187 # include <sys/table.h>
188 # endif
190 # if defined (__osf__) && (defined (mips) || defined (__mips__))
191 # define OSF_MIPS
192 # include <sys/table.h>
193 # endif
195 /* UTek's /bin/cc on the 4300 has no architecture specific cpp define by
196 default, but _MACH_IND_SYS_TYPES is defined in <sys/types.h>. Combine
197 that with a couple of other things and we'll have a unique match. */
198 # if !defined (tek4300) && defined (unix) && defined (m68k) && defined (mc68000) && defined (mc68020) && defined (_MACH_IND_SYS_TYPES)
199 # define tek4300 /* Define by emacs, but not by other users. */
200 # endif
202 /* AC_FUNC_GETLOADAVG thinks QNX is SVR4, but it isn't. */
203 # if defined(__QNX__)
204 # undef SVR4
205 # endif
207 /* VAX C can't handle multi-line #ifs, or lines longer than 256 chars. */
208 # ifndef LOAD_AVE_TYPE
210 # ifdef MORE_BSD
211 # define LOAD_AVE_TYPE long
212 # endif
214 # ifdef sun
215 # define LOAD_AVE_TYPE long
216 # endif
218 # ifdef decstation
219 # define LOAD_AVE_TYPE long
220 # endif
222 # ifdef _SEQUENT_
223 # define LOAD_AVE_TYPE long
224 # endif
226 # ifdef sgi
227 # define LOAD_AVE_TYPE long
228 # endif
230 # ifdef SVR4
231 # define LOAD_AVE_TYPE long
232 # endif
234 # ifdef sony_news
235 # define LOAD_AVE_TYPE long
236 # endif
238 # ifdef sequent
239 # define LOAD_AVE_TYPE long
240 # endif
242 # ifdef OSF_ALPHA
243 # define LOAD_AVE_TYPE long
244 # endif
246 # if defined (ardent) && defined (titan)
247 # define LOAD_AVE_TYPE long
248 # endif
250 # ifdef tek4300
251 # define LOAD_AVE_TYPE long
252 # endif
254 # if defined(alliant) && defined(i860) /* Alliant FX/2800 */
255 # define LOAD_AVE_TYPE long
256 # endif
258 # ifdef _AIX
259 # define LOAD_AVE_TYPE long
260 # endif
262 # ifdef convex
263 # define LOAD_AVE_TYPE double
264 # ifndef LDAV_CVT
265 # define LDAV_CVT(n) (n)
266 # endif
267 # endif
269 # endif /* No LOAD_AVE_TYPE. */
271 # ifdef OSF_ALPHA
272 /* <sys/param.h> defines an incorrect value for FSCALE on Alpha OSF/1,
273 according to ghazi@noc.rutgers.edu. */
274 # undef FSCALE
275 # define FSCALE 1024.0
276 # endif
278 # if defined(alliant) && defined(i860) /* Alliant FX/2800 */
279 /* <sys/param.h> defines an incorrect value for FSCALE on an
280 Alliant FX/2800 Concentrix 2.2, according to ghazi@noc.rutgers.edu. */
281 # undef FSCALE
282 # define FSCALE 100.0
283 # endif
286 # ifndef FSCALE
288 /* SunOS and some others define FSCALE in sys/param.h. */
290 # ifdef MORE_BSD
291 # define FSCALE 2048.0
292 # endif
294 # if defined(MIPS) || defined(SVR4) || defined(decstation)
295 # define FSCALE 256
296 # endif
298 # if defined (sgi) || defined (sequent)
299 /* Sometimes both MIPS and sgi are defined, so FSCALE was just defined
300 above under #ifdef MIPS. But we want the sgi value. */
301 # undef FSCALE
302 # define FSCALE 1000.0
303 # endif
305 # if defined (ardent) && defined (titan)
306 # define FSCALE 65536.0
307 # endif
309 # ifdef tek4300
310 # define FSCALE 100.0
311 # endif
313 # ifdef _AIX
314 # define FSCALE 65536.0
315 # endif
317 # endif /* Not FSCALE. */
319 # if !defined (LDAV_CVT) && defined (FSCALE)
320 # define LDAV_CVT(n) (((double) (n)) / FSCALE)
321 # endif
324 # if defined(sgi) || (defined(mips) && !defined(BSD))
325 # define FIXUP_KERNEL_SYMBOL_ADDR(nl) ((nl)[0].n_value &= ~(1 << 31))
326 # endif
329 # if !defined (KERNEL_FILE) && defined (sequent)
330 # define KERNEL_FILE "/dynix"
331 # endif
333 # if !defined (KERNEL_FILE) && defined (hpux)
334 # define KERNEL_FILE "/hp-ux"
335 # endif
337 # if !defined(KERNEL_FILE) && (defined(_SEQUENT_) || defined(MIPS) || defined(SVR4) || defined(ISC) || defined (sgi) || (defined (ardent) && defined (titan)))
338 # define KERNEL_FILE "/unix"
339 # endif
342 # if !defined (LDAV_SYMBOL) && defined (alliant)
343 # define LDAV_SYMBOL "_Loadavg"
344 # endif
346 # if !defined(LDAV_SYMBOL) && ((defined(hpux) && !defined(hp9000s300)) || defined(_SEQUENT_) || defined(SVR4) || defined(ISC) || defined(sgi) || (defined (ardent) && defined (titan)) || defined (_AIX))
347 # define LDAV_SYMBOL "avenrun"
348 # endif
350 # ifdef HAVE_UNISTD_H
351 # include <unistd.h>
352 # endif
354 # include <stdio.h>
356 /* LOAD_AVE_TYPE should only get defined if we're going to use the
357 nlist method. */
358 # if !defined(LOAD_AVE_TYPE) && (defined(BSD) || defined(LDAV_CVT) || defined(KERNEL_FILE) || defined(LDAV_SYMBOL))
359 # define LOAD_AVE_TYPE double
360 # endif
362 # ifdef LOAD_AVE_TYPE
364 # ifndef VMS
365 # ifndef __linux__
366 # ifdef HAVE_NLIST_H
367 # include <nlist.h>
368 # else
369 # include <a.out.h>
370 # endif
372 # ifdef SUNOS_5
373 # include <fcntl.h>
374 # include <kvm.h>
375 # include <kstat.h>
376 # endif
378 # if defined (hpux) && defined (HAVE_PSTAT_GETDYNAMIC)
379 # include <sys/pstat.h>
380 # endif
382 # ifndef KERNEL_FILE
383 # define KERNEL_FILE "/vmunix"
384 # endif /* KERNEL_FILE */
386 # ifndef LDAV_SYMBOL
387 # define LDAV_SYMBOL "_avenrun"
388 # endif /* LDAV_SYMBOL */
389 # endif /* __linux__ */
391 # else /* VMS */
393 # ifndef eunice
394 # include <iodef.h>
395 # include <descrip.h>
396 # else /* eunice */
397 # include <vms/iodef.h>
398 # endif /* eunice */
399 # endif /* VMS */
401 # ifndef LDAV_CVT
402 # define LDAV_CVT(n) ((double) (n))
403 # endif /* !LDAV_CVT */
405 # endif /* LOAD_AVE_TYPE */
407 # if defined(__GNU__) && !defined (NeXT)
408 /* Note that NeXT Openstep defines __GNU__ even though it should not. */
409 /* GNU system acts much like NeXT, for load average purposes,
410 but not exactly. */
411 # define NeXT
412 # define host_self mach_host_self
413 # endif
415 # ifdef NeXT
416 # ifdef HAVE_MACH_MACH_H
417 # include <mach/mach.h>
418 # else
419 # include <mach.h>
420 # endif
421 # endif /* NeXT */
423 # ifdef sgi
424 # include <sys/sysmp.h>
425 # endif /* sgi */
427 # ifdef UMAX
428 # include <stdio.h>
429 # include <signal.h>
430 # include <sys/time.h>
431 # include <sys/wait.h>
432 # include <sys/syscall.h>
434 # ifdef UMAX_43
435 # include <machine/cpu.h>
436 # include <inq_stats/statistics.h>
437 # include <inq_stats/sysstats.h>
438 # include <inq_stats/cpustats.h>
439 # include <inq_stats/procstats.h>
440 # else /* Not UMAX_43. */
441 # include <sys/sysdefs.h>
442 # include <sys/statistics.h>
443 # include <sys/sysstats.h>
444 # include <sys/cpudefs.h>
445 # include <sys/cpustats.h>
446 # include <sys/procstats.h>
447 # endif /* Not UMAX_43. */
448 # endif /* UMAX */
450 # ifdef DGUX
451 # include <sys/dg_sys_info.h>
452 # endif
454 # if defined(HAVE_FCNTL_H) || defined(_POSIX_VERSION)
455 # include <fcntl.h>
456 # else
457 # include <sys/file.h>
458 # endif
461 /* Avoid static vars inside a function since in HPUX they dump as pure. */
463 # ifdef NeXT
464 static processor_set_t default_set;
465 static int getloadavg_initialized;
466 # endif /* NeXT */
468 # ifdef UMAX
469 static unsigned int cpus = 0;
470 static unsigned int samples;
471 # endif /* UMAX */
473 # ifdef DGUX
474 static struct dg_sys_info_load_info load_info; /* what-a-mouthful! */
475 # endif /* DGUX */
477 #if !defined(HAVE_LIBKSTAT) && defined(LOAD_AVE_TYPE)
478 /* File descriptor open to /dev/kmem or VMS load ave driver. */
479 static int channel;
480 /* Nonzero iff channel is valid. */
481 static int getloadavg_initialized;
482 /* Offset in kmem to seek to read load average, or 0 means invalid. */
483 static long offset;
485 #if !defined(VMS) && !defined(sgi) && !defined(__linux__)
486 static struct nlist nl[2];
487 #endif /* Not VMS or sgi */
489 #ifdef SUNOS_5
490 static kvm_t *kd;
491 #endif /* SUNOS_5 */
493 #endif /* LOAD_AVE_TYPE && !HAVE_LIBKSTAT */
495 /* Put the 1 minute, 5 minute and 15 minute load averages
496 into the first NELEM elements of LOADAVG.
497 Return the number written (never more than 3, but may be less than NELEM),
498 or -1 if an error occurred. */
501 getloadavg (loadavg, nelem)
502 double loadavg[];
503 int nelem;
505 int elem = 0; /* Return value. */
507 # ifdef NO_GET_LOAD_AVG
508 # define LDAV_DONE
509 /* Set errno to zero to indicate that there was no particular error;
510 this function just can't work at all on this system. */
511 errno = 0;
512 elem = -1;
513 # endif
515 # if !defined (LDAV_DONE) && defined (HAVE_LIBKSTAT)
516 /* Use libkstat because we don't have to be root. */
517 # define LDAV_DONE
518 kstat_ctl_t *kc;
519 kstat_t *ksp;
520 kstat_named_t *kn;
522 kc = kstat_open ();
523 if (kc == 0)
524 return -1;
525 ksp = kstat_lookup (kc, "unix", 0, "system_misc");
526 if (ksp == 0 )
527 return -1;
528 if (kstat_read (kc, ksp, 0) == -1)
529 return -1;
532 kn = kstat_data_lookup (ksp, "avenrun_1min");
533 if (kn == 0)
535 /* Return -1 if no load average information is available. */
536 nelem = 0;
537 elem = -1;
540 if (nelem >= 1)
541 loadavg[elem++] = (double) kn->value.ul/FSCALE;
543 if (nelem >= 2)
545 kn = kstat_data_lookup (ksp, "avenrun_5min");
546 if (kn != 0)
548 loadavg[elem++] = (double) kn->value.ul/FSCALE;
550 if (nelem >= 3)
552 kn = kstat_data_lookup (ksp, "avenrun_15min");
553 if (kn != 0)
554 loadavg[elem++] = (double) kn->value.ul/FSCALE;
559 kstat_close (kc);
560 # endif /* HAVE_LIBKSTAT */
562 # if !defined (LDAV_DONE) && defined (hpux) && defined (HAVE_PSTAT_GETDYNAMIC)
563 /* Use pstat_getdynamic() because we don't have to be root. */
564 # define LDAV_DONE
565 # undef LOAD_AVE_TYPE
567 struct pst_dynamic dyn_info;
568 if (pstat_getdynamic (&dyn_info, sizeof (dyn_info), 0, 0) < 0)
569 return -1;
570 if (nelem > 0)
571 loadavg[elem++] = dyn_info.psd_avg_1_min;
572 if (nelem > 1)
573 loadavg[elem++] = dyn_info.psd_avg_5_min;
574 if (nelem > 2)
575 loadavg[elem++] = dyn_info.psd_avg_15_min;
577 # endif /* hpux && HAVE_PSTAT_GETDYNAMIC */
579 # if !defined (LDAV_DONE) && defined (__linux__)
580 # define LDAV_DONE
581 # undef LOAD_AVE_TYPE
583 # ifndef LINUX_LDAV_FILE
584 # define LINUX_LDAV_FILE "/proc/loadavg"
585 # endif
587 char ldavgbuf[40];
588 double load_ave[3];
589 int fd, count;
591 fd = open (LINUX_LDAV_FILE, O_RDONLY);
592 if (fd == -1)
593 return -1;
594 count = read (fd, ldavgbuf, 40);
595 (void) close (fd);
596 if (count <= 0)
597 return -1;
599 /* The following sscanf must use the C locale. */
600 setlocale (LC_NUMERIC, "C");
601 count = sscanf (ldavgbuf, "%lf %lf %lf",
602 &load_ave[0], &load_ave[1], &load_ave[2]);
603 setlocale (LC_NUMERIC, "");
604 if (count < 1)
605 return -1;
607 for (elem = 0; elem < nelem && elem < count; elem++)
608 loadavg[elem] = load_ave[elem];
610 return elem;
612 # endif /* __linux__ */
614 # if !defined (LDAV_DONE) && defined (__NetBSD__)
615 # define LDAV_DONE
616 # undef LOAD_AVE_TYPE
618 # ifndef NETBSD_LDAV_FILE
619 # define NETBSD_LDAV_FILE "/kern/loadavg"
620 # endif
622 unsigned long int load_ave[3], scale;
623 int count;
624 FILE *fp;
626 fp = fopen (NETBSD_LDAV_FILE, "r");
627 if (fp == NULL)
628 return -1;
629 count = fscanf (fp, "%lu %lu %lu %lu\n",
630 &load_ave[0], &load_ave[1], &load_ave[2],
631 &scale);
632 (void) fclose (fp);
633 if (count != 4)
634 return -1;
636 for (elem = 0; elem < nelem; elem++)
637 loadavg[elem] = (double) load_ave[elem] / (double) scale;
639 return elem;
641 # endif /* __NetBSD__ */
643 # if !defined (LDAV_DONE) && defined (NeXT)
644 # define LDAV_DONE
645 /* The NeXT code was adapted from iscreen 3.2. */
647 host_t host;
648 struct processor_set_basic_info info;
649 unsigned info_count;
651 /* We only know how to get the 1-minute average for this system,
652 so even if the caller asks for more than 1, we only return 1. */
654 if (!getloadavg_initialized)
656 if (processor_set_default (host_self (), &default_set) == KERN_SUCCESS)
657 getloadavg_initialized = 1;
660 if (getloadavg_initialized)
662 info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
663 if (processor_set_info (default_set, PROCESSOR_SET_BASIC_INFO, &host,
664 (processor_set_info_t) &info, &info_count)
665 != KERN_SUCCESS)
666 getloadavg_initialized = 0;
667 else
669 if (nelem > 0)
670 loadavg[elem++] = (double) info.load_average / LOAD_SCALE;
674 if (!getloadavg_initialized)
675 return -1;
676 # endif /* NeXT */
678 # if !defined (LDAV_DONE) && defined (UMAX)
679 # define LDAV_DONE
680 /* UMAX 4.2, which runs on the Encore Multimax multiprocessor, does not
681 have a /dev/kmem. Information about the workings of the running kernel
682 can be gathered with inq_stats system calls.
683 We only know how to get the 1-minute average for this system. */
685 struct proc_summary proc_sum_data;
686 struct stat_descr proc_info;
687 double load;
688 register unsigned int i, j;
690 if (cpus == 0)
692 register unsigned int c, i;
693 struct cpu_config conf;
694 struct stat_descr desc;
696 desc.sd_next = 0;
697 desc.sd_subsys = SUBSYS_CPU;
698 desc.sd_type = CPUTYPE_CONFIG;
699 desc.sd_addr = (char *) &conf;
700 desc.sd_size = sizeof conf;
702 if (inq_stats (1, &desc))
703 return -1;
705 c = 0;
706 for (i = 0; i < conf.config_maxclass; ++i)
708 struct class_stats stats;
709 bzero ((char *) &stats, sizeof stats);
711 desc.sd_type = CPUTYPE_CLASS;
712 desc.sd_objid = i;
713 desc.sd_addr = (char *) &stats;
714 desc.sd_size = sizeof stats;
716 if (inq_stats (1, &desc))
717 return -1;
719 c += stats.class_numcpus;
721 cpus = c;
722 samples = cpus < 2 ? 3 : (2 * cpus / 3);
725 proc_info.sd_next = 0;
726 proc_info.sd_subsys = SUBSYS_PROC;
727 proc_info.sd_type = PROCTYPE_SUMMARY;
728 proc_info.sd_addr = (char *) &proc_sum_data;
729 proc_info.sd_size = sizeof (struct proc_summary);
730 proc_info.sd_sizeused = 0;
732 if (inq_stats (1, &proc_info) != 0)
733 return -1;
735 load = proc_sum_data.ps_nrunnable;
736 j = 0;
737 for (i = samples - 1; i > 0; --i)
739 load += proc_sum_data.ps_nrun[j];
740 if (j++ == PS_NRUNSIZE)
741 j = 0;
744 if (nelem > 0)
745 loadavg[elem++] = load / samples / cpus;
746 # endif /* UMAX */
748 # if !defined (LDAV_DONE) && defined (DGUX)
749 # define LDAV_DONE
750 /* This call can return -1 for an error, but with good args
751 it's not supposed to fail. The first argument is for no
752 apparent reason of type `long int *'. */
753 dg_sys_info ((long int *) &load_info,
754 DG_SYS_INFO_LOAD_INFO_TYPE,
755 DG_SYS_INFO_LOAD_VERSION_0);
757 if (nelem > 0)
758 loadavg[elem++] = load_info.one_minute;
759 if (nelem > 1)
760 loadavg[elem++] = load_info.five_minute;
761 if (nelem > 2)
762 loadavg[elem++] = load_info.fifteen_minute;
763 # endif /* DGUX */
765 # if !defined (LDAV_DONE) && defined (apollo)
766 # define LDAV_DONE
767 /* Apollo code from lisch@mentorg.com (Ray Lischner).
769 This system call is not documented. The load average is obtained as
770 three long integers, for the load average over the past minute,
771 five minutes, and fifteen minutes. Each value is a scaled integer,
772 with 16 bits of integer part and 16 bits of fraction part.
774 I'm not sure which operating system first supported this system call,
775 but I know that SR10.2 supports it. */
777 extern void proc1_$get_loadav ();
778 unsigned long load_ave[3];
780 proc1_$get_loadav (load_ave);
782 if (nelem > 0)
783 loadavg[elem++] = load_ave[0] / 65536.0;
784 if (nelem > 1)
785 loadavg[elem++] = load_ave[1] / 65536.0;
786 if (nelem > 2)
787 loadavg[elem++] = load_ave[2] / 65536.0;
788 # endif /* apollo */
790 # if !defined (LDAV_DONE) && defined (OSF_MIPS)
791 # define LDAV_DONE
793 struct tbl_loadavg load_ave;
794 table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
795 loadavg[elem++]
796 = (load_ave.tl_lscale == 0
797 ? load_ave.tl_avenrun.d[0]
798 : (load_ave.tl_avenrun.l[0] / (double) load_ave.tl_lscale));
799 # endif /* OSF_MIPS */
801 # if !defined (LDAV_DONE) && (defined (__MSDOS__) || defined (WINDOWS32))
802 # define LDAV_DONE
804 /* A faithful emulation is going to have to be saved for a rainy day. */
805 for ( ; elem < nelem; elem++)
807 loadavg[elem] = 0.0;
809 # endif /* __MSDOS__ || WINDOWS32 */
811 # if !defined (LDAV_DONE) && defined (OSF_ALPHA)
812 # define LDAV_DONE
814 struct tbl_loadavg load_ave;
815 table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
816 for (elem = 0; elem < nelem; elem++)
817 loadavg[elem]
818 = (load_ave.tl_lscale == 0
819 ? load_ave.tl_avenrun.d[elem]
820 : (load_ave.tl_avenrun.l[elem] / (double) load_ave.tl_lscale));
821 # endif /* OSF_ALPHA */
823 # if !defined (LDAV_DONE) && defined (VMS)
824 /* VMS specific code -- read from the Load Ave driver. */
826 LOAD_AVE_TYPE load_ave[3];
827 static int getloadavg_initialized = 0;
828 # ifdef eunice
829 struct
831 int dsc$w_length;
832 char *dsc$a_pointer;
833 } descriptor;
834 # endif
836 /* Ensure that there is a channel open to the load ave device. */
837 if (!getloadavg_initialized)
839 /* Attempt to open the channel. */
840 # ifdef eunice
841 descriptor.dsc$w_length = 18;
842 descriptor.dsc$a_pointer = "$$VMS_LOAD_AVERAGE";
843 # else
844 $DESCRIPTOR (descriptor, "LAV0:");
845 # endif
846 if (sys$assign (&descriptor, &channel, 0, 0) & 1)
847 getloadavg_initialized = 1;
850 /* Read the load average vector. */
851 if (getloadavg_initialized
852 && !(sys$qiow (0, channel, IO$_READVBLK, 0, 0, 0,
853 load_ave, 12, 0, 0, 0, 0) & 1))
855 sys$dassgn (channel);
856 getloadavg_initialized = 0;
859 if (!getloadavg_initialized)
860 return -1;
861 # endif /* VMS */
863 # if !defined (LDAV_DONE) && defined(LOAD_AVE_TYPE) && !defined(VMS)
865 /* UNIX-specific code -- read the average from /dev/kmem. */
867 # define LDAV_PRIVILEGED /* This code requires special installation. */
869 LOAD_AVE_TYPE load_ave[3];
871 /* Get the address of LDAV_SYMBOL. */
872 if (offset == 0)
874 # ifndef sgi
875 # ifndef NLIST_STRUCT
876 strcpy (nl[0].n_name, LDAV_SYMBOL);
877 strcpy (nl[1].n_name, "");
878 # else /* NLIST_STRUCT */
879 # ifdef HAVE_STRUCT_NLIST_N_UN_N_NAME
880 nl[0].n_un.n_name = LDAV_SYMBOL;
881 nl[1].n_un.n_name = 0;
882 # else /* not HAVE_STRUCT_NLIST_N_UN_N_NAME */
883 nl[0].n_name = LDAV_SYMBOL;
884 nl[1].n_name = 0;
885 # endif /* not HAVE_STRUCT_NLIST_N_UN_N_NAME */
886 # endif /* NLIST_STRUCT */
888 # ifndef SUNOS_5
889 if (
890 # if !(defined (_AIX) && !defined (ps2))
891 nlist (KERNEL_FILE, nl)
892 # else /* _AIX */
893 knlist (nl, 1, sizeof (nl[0]))
894 # endif
895 >= 0)
896 /* Omit "&& nl[0].n_type != 0 " -- it breaks on Sun386i. */
898 # ifdef FIXUP_KERNEL_SYMBOL_ADDR
899 FIXUP_KERNEL_SYMBOL_ADDR (nl);
900 # endif
901 offset = nl[0].n_value;
903 # endif /* !SUNOS_5 */
904 # else /* sgi */
905 int ldav_off;
907 ldav_off = sysmp (MP_KERNADDR, MPKA_AVENRUN);
908 if (ldav_off != -1)
909 offset = (long) ldav_off & 0x7fffffff;
910 # endif /* sgi */
913 /* Make sure we have /dev/kmem open. */
914 if (!getloadavg_initialized)
916 # ifndef SUNOS_5
917 channel = open ("/dev/kmem", 0);
918 if (channel >= 0)
920 /* Set the channel to close on exec, so it does not
921 litter any child's descriptor table. */
922 # ifdef F_SETFD
923 # ifndef FD_CLOEXEC
924 # define FD_CLOEXEC 1
925 # endif
926 (void) fcntl (channel, F_SETFD, FD_CLOEXEC);
927 # endif
928 getloadavg_initialized = 1;
930 # else /* SUNOS_5 */
931 /* We pass 0 for the kernel, corefile, and swapfile names
932 to use the currently running kernel. */
933 kd = kvm_open (0, 0, 0, O_RDONLY, 0);
934 if (kd != 0)
936 /* nlist the currently running kernel. */
937 kvm_nlist (kd, nl);
938 offset = nl[0].n_value;
939 getloadavg_initialized = 1;
941 # endif /* SUNOS_5 */
944 /* If we can, get the load average values. */
945 if (offset && getloadavg_initialized)
947 /* Try to read the load. */
948 # ifndef SUNOS_5
949 if (lseek (channel, offset, 0) == -1L
950 || read (channel, (char *) load_ave, sizeof (load_ave))
951 != sizeof (load_ave))
953 close (channel);
954 getloadavg_initialized = 0;
956 # else /* SUNOS_5 */
957 if (kvm_read (kd, offset, (char *) load_ave, sizeof (load_ave))
958 != sizeof (load_ave))
960 kvm_close (kd);
961 getloadavg_initialized = 0;
963 # endif /* SUNOS_5 */
966 if (offset == 0 || !getloadavg_initialized)
967 return -1;
968 # endif /* LOAD_AVE_TYPE and not VMS */
970 # if !defined (LDAV_DONE) && defined (LOAD_AVE_TYPE) /* Including VMS. */
971 if (nelem > 0)
972 loadavg[elem++] = LDAV_CVT (load_ave[0]);
973 if (nelem > 1)
974 loadavg[elem++] = LDAV_CVT (load_ave[1]);
975 if (nelem > 2)
976 loadavg[elem++] = LDAV_CVT (load_ave[2]);
978 # define LDAV_DONE
979 # endif /* !LDAV_DONE && LOAD_AVE_TYPE */
981 # ifdef LDAV_DONE
982 return elem;
983 # else
984 /* Set errno to zero to indicate that there was no particular error;
985 this function just can't work at all on this system. */
986 errno = 0;
987 return -1;
988 # endif
991 #endif /* ! HAVE_GETLOADAVG */
993 #ifdef TEST
994 #include "make.h"
997 main (argc, argv)
998 int argc;
999 char **argv;
1001 int naptime = 0;
1003 if (argc > 1)
1004 naptime = atoi (argv[1]);
1006 while (1)
1008 double avg[3];
1009 int loads;
1011 errno = 0; /* Don't be misled if it doesn't set errno. */
1012 loads = getloadavg (avg, 3);
1013 if (loads == -1)
1015 perror ("Error getting load average");
1016 exit (1);
1018 if (loads > 0)
1019 printf ("1-minute: %f ", avg[0]);
1020 if (loads > 1)
1021 printf ("5-minute: %f ", avg[1]);
1022 if (loads > 2)
1023 printf ("15-minute: %f ", avg[2]);
1024 if (loads > 0)
1025 putchar ('\n');
1027 if (naptime == 0)
1028 break;
1029 sleep (naptime);
1032 exit (0);
1034 #endif /* TEST */