Replace with FSF version.
[coreutils.git] / lib / getloadavg.c
blob2411e6a92254aee586f379a5ed57c8946107c9a9
1 /* Get the system load averages.
2 Copyright (C) 1985, 86, 87, 88, 89, 91, 92, 93, 1994, 1995
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 FIXUP_KERNEL_SYMBOL_ADDR() Adjust address in returned struct nlist.
23 KERNEL_FILE Pathname of the kernel to nlist.
24 LDAV_CVT() Scale the load average from the kernel.
25 Returns a double.
26 LDAV_SYMBOL Name of kernel symbol giving load average.
27 LOAD_AVE_TYPE Type of the load average array in the kernel.
28 Must be defined unless one of
29 apollo, DGUX, NeXT, or UMAX is defined;
30 otherwise, no load average is available.
31 NLIST_STRUCT Include nlist.h, not a.out.h, and
32 the nlist n_name element is a pointer,
33 not an array.
34 NLIST_NAME_UNION struct nlist has an n_un member, not n_name.
35 LINUX_LDAV_FILE [__linux__]: File containing load averages.
37 Specific system predefines this file uses, aside from setting
38 default values if not emacs:
40 apollo
41 BSD Real BSD, not just BSD-like.
42 convex
43 DGUX
44 eunice UNIX emulator under VMS.
45 hpux
46 MSDOS No-op for MSDOS.
47 NeXT
48 sgi
49 sequent Sequent Dynix 3.x.x (BSD)
50 _SEQUENT_ Sequent DYNIX/ptx 1.x.x (SYSV)
51 sony_news NEWS-OS (works at least for 4.1C)
52 UMAX
53 UMAX4_3
54 VMS
55 WIN32 No-op for Windows95/NT.
56 __linux__ Linux: assumes /proc filesystem mounted.
57 Support from Michael K. Johnson.
58 __NetBSD__ NetBSD: assumes /kern filesystem mounted.
60 In addition, to avoid nesting many #ifdefs, we internally set
61 LDAV_DONE to indicate that the load average has been computed.
63 We also #define LDAV_PRIVILEGED if a program will require
64 special installation to be able to call getloadavg. */
66 /* This should always be first. */
67 #ifdef HAVE_CONFIG_H
68 #include <config.h>
69 #endif
71 #include <sys/types.h>
73 /* Both the Emacs and non-Emacs sections want this. Some
74 configuration files' definitions for the LOAD_AVE_CVT macro (like
75 sparc.h's) use macros like FSCALE, defined here. */
76 #ifdef unix
77 #include <sys/param.h>
78 #endif
81 /* Exclude all the code except the test program at the end
82 if the system has its own `getloadavg' function.
84 The declaration of `errno' is needed by the test program
85 as well as the function itself, so it comes first. */
87 #include <errno.h>
89 #ifndef errno
90 extern int errno;
91 #endif
93 #ifndef HAVE_GETLOADAVG
96 /* The existing Emacs configuration files define a macro called
97 LOAD_AVE_CVT, which accepts a value of type LOAD_AVE_TYPE, and
98 returns the load average multiplied by 100. What we actually want
99 is a macro called LDAV_CVT, which returns the load average as an
100 unmultiplied double.
102 For backwards compatibility, we'll define LDAV_CVT in terms of
103 LOAD_AVE_CVT, but future machine config files should just define
104 LDAV_CVT directly. */
106 #if !defined(LDAV_CVT) && defined(LOAD_AVE_CVT)
107 #define LDAV_CVT(n) (LOAD_AVE_CVT (n) / 100.0)
108 #endif
110 #if !defined (BSD) && defined (ultrix)
111 /* Ultrix behaves like BSD on Vaxen. */
112 #define BSD
113 #endif
115 #ifdef NeXT
116 /* NeXT in the 2.{0,1,2} releases defines BSD in <sys/param.h>, which
117 conflicts with the definition understood in this file, that this
118 really is BSD. */
119 #undef BSD
121 /* NeXT defines FSCALE in <sys/param.h>. However, we take FSCALE being
122 defined to mean that the nlist method should be used, which is not true. */
123 #undef FSCALE
124 #endif
126 /* Set values that are different from the defaults, which are
127 set a little farther down with #ifndef. */
130 /* Some shorthands. */
132 #if defined (HPUX) && !defined (hpux)
133 #define hpux
134 #endif
136 #if defined(hp300) && !defined(hpux)
137 #define MORE_BSD
138 #endif
140 #if defined(ultrix) && defined(mips)
141 #define decstation
142 #endif
144 #if (defined(sun) && defined(SVR4)) || defined (SOLARIS2)
145 #define SUNOS_5
146 #endif
148 #if defined (__osf__) && (defined (__alpha) || defined (__alpha__))
149 #define OSF_ALPHA
150 #include <sys/table.h>
151 #endif
153 #if defined (__osf__) && (defined (mips) || defined (__mips__))
154 #define OSF_MIPS
155 #include <sys/table.h>
156 #endif
158 /* UTek's /bin/cc on the 4300 has no architecture specific cpp define by
159 default, but _MACH_IND_SYS_TYPES is defined in <sys/types.h>. Combine
160 that with a couple of other things and we'll have a unique match. */
161 #if !defined (tek4300) && defined (unix) && defined (m68k) && defined (mc68000) && defined (mc68020) && defined (_MACH_IND_SYS_TYPES)
162 #define tek4300 /* Define by emacs, but not by other users. */
163 #endif
166 /* VAX C can't handle multi-line #ifs, or lines longer than 256 chars. */
167 #ifndef LOAD_AVE_TYPE
169 #ifdef MORE_BSD
170 #define LOAD_AVE_TYPE long
171 #endif
173 #ifdef sun
174 #define LOAD_AVE_TYPE long
175 #endif
177 #ifdef decstation
178 #define LOAD_AVE_TYPE long
179 #endif
181 #ifdef _SEQUENT_
182 #define LOAD_AVE_TYPE long
183 #endif
185 #ifdef sgi
186 #define LOAD_AVE_TYPE long
187 #endif
189 #ifdef SVR4
190 #define LOAD_AVE_TYPE long
191 #endif
193 #ifdef sony_news
194 #define LOAD_AVE_TYPE long
195 #endif
197 #ifdef sequent
198 #define LOAD_AVE_TYPE long
199 #endif
201 #ifdef OSF_ALPHA
202 #define LOAD_AVE_TYPE long
203 #endif
205 #if defined (ardent) && defined (titan)
206 #define LOAD_AVE_TYPE long
207 #endif
209 #ifdef tek4300
210 #define LOAD_AVE_TYPE long
211 #endif
213 #if defined(alliant) && defined(i860) /* Alliant FX/2800 */
214 #define LOAD_AVE_TYPE long
215 #endif
217 #ifdef _AIX
218 #define LOAD_AVE_TYPE long
219 #endif
221 #ifdef convex
222 #define LOAD_AVE_TYPE double
223 #ifndef LDAV_CVT
224 #define LDAV_CVT(n) (n)
225 #endif
226 #endif
228 #endif /* No LOAD_AVE_TYPE. */
230 #ifdef OSF_ALPHA
231 /* <sys/param.h> defines an incorrect value for FSCALE on Alpha OSF/1,
232 according to ghazi@noc.rutgers.edu. */
233 #undef FSCALE
234 #define FSCALE 1024.0
235 #endif
237 #if defined(alliant) && defined(i860) /* Alliant FX/2800 */
238 /* <sys/param.h> defines an incorrect value for FSCALE on an
239 Alliant FX/2800 Concentrix 2.2, according to ghazi@noc.rutgers.edu. */
240 #undef FSCALE
241 #define FSCALE 100.0
242 #endif
245 #ifndef FSCALE
247 /* SunOS and some others define FSCALE in sys/param.h. */
249 #ifdef MORE_BSD
250 #define FSCALE 2048.0
251 #endif
253 #if defined(MIPS) || defined(SVR4) || defined(decstation)
254 #define FSCALE 256
255 #endif
257 #if defined (sgi) || defined (sequent)
258 /* Sometimes both MIPS and sgi are defined, so FSCALE was just defined
259 above under #ifdef MIPS. But we want the sgi value. */
260 #undef FSCALE
261 #define FSCALE 1000.0
262 #endif
264 #if defined (ardent) && defined (titan)
265 #define FSCALE 65536.0
266 #endif
268 #ifdef tek4300
269 #define FSCALE 100.0
270 #endif
272 #ifdef _AIX
273 #define FSCALE 65536.0
274 #endif
276 #endif /* Not FSCALE. */
278 #if !defined (LDAV_CVT) && defined (FSCALE)
279 #define LDAV_CVT(n) (((double) (n)) / FSCALE)
280 #endif
282 /* VAX C can't handle multi-line #ifs, or lines longer that 256 characters. */
283 #ifndef NLIST_STRUCT
285 #ifdef MORE_BSD
286 #define NLIST_STRUCT
287 #endif
289 #ifdef sun
290 #define NLIST_STRUCT
291 #endif
293 #ifdef decstation
294 #define NLIST_STRUCT
295 #endif
297 #ifdef hpux
298 #define NLIST_STRUCT
299 #endif
301 #if defined (_SEQUENT_) || defined (sequent)
302 #define NLIST_STRUCT
303 #endif
305 #ifdef sgi
306 #define NLIST_STRUCT
307 #endif
309 #ifdef SVR4
310 #define NLIST_STRUCT
311 #endif
313 #ifdef sony_news
314 #define NLIST_STRUCT
315 #endif
317 #ifdef OSF_ALPHA
318 #define NLIST_STRUCT
319 #endif
321 #if defined (ardent) && defined (titan)
322 #define NLIST_STRUCT
323 #endif
325 #ifdef tek4300
326 #define NLIST_STRUCT
327 #endif
329 #ifdef butterfly
330 #define NLIST_STRUCT
331 #endif
333 #if defined(alliant) && defined(i860) /* Alliant FX/2800 */
334 #define NLIST_STRUCT
335 #endif
337 #ifdef _AIX
338 #define NLIST_STRUCT
339 #endif
341 #endif /* defined (NLIST_STRUCT) */
344 #if defined(sgi) || (defined(mips) && !defined(BSD))
345 #define FIXUP_KERNEL_SYMBOL_ADDR(nl) ((nl)[0].n_value &= ~(1 << 31))
346 #endif
349 #if !defined (KERNEL_FILE) && defined (sequent)
350 #define KERNEL_FILE "/dynix"
351 #endif
353 #if !defined (KERNEL_FILE) && defined (hpux)
354 #define KERNEL_FILE "/hp-ux"
355 #endif
357 #if !defined(KERNEL_FILE) && (defined(_SEQUENT_) || defined(MIPS) || defined(SVR4) || defined(ISC) || defined (sgi) || defined(SVR4) || (defined (ardent) && defined (titan)))
358 #define KERNEL_FILE "/unix"
359 #endif
362 #if !defined (LDAV_SYMBOL) && defined (alliant)
363 #define LDAV_SYMBOL "_Loadavg"
364 #endif
366 #if !defined(LDAV_SYMBOL) && ((defined(hpux) && !defined(hp9000s300)) || defined(_SEQUENT_) || defined(SVR4) || defined(ISC) || defined(sgi) || (defined (ardent) && defined (titan)) || defined (_AIX))
367 #define LDAV_SYMBOL "avenrun"
368 #endif
370 #ifdef HAVE_UNISTD_H
371 #include <unistd.h>
372 #endif
374 #include <stdio.h>
376 /* LOAD_AVE_TYPE should only get defined if we're going to use the
377 nlist method. */
378 #if !defined(LOAD_AVE_TYPE) && (defined(BSD) || defined(LDAV_CVT) || defined(KERNEL_FILE) || defined(LDAV_SYMBOL))
379 #define LOAD_AVE_TYPE double
380 #endif
382 #ifdef LOAD_AVE_TYPE
384 #ifndef VMS
385 #ifndef NLIST_STRUCT
386 #include <a.out.h>
387 #else /* NLIST_STRUCT */
388 #include <nlist.h>
389 #endif /* NLIST_STRUCT */
391 #ifdef SUNOS_5
392 #include <fcntl.h>
393 #include <kvm.h>
394 #include <kstat.h>
395 #endif
397 #ifndef KERNEL_FILE
398 #define KERNEL_FILE "/vmunix"
399 #endif /* KERNEL_FILE */
401 #ifndef LDAV_SYMBOL
402 #define LDAV_SYMBOL "_avenrun"
403 #endif /* LDAV_SYMBOL */
405 #else /* VMS */
407 #ifndef eunice
408 #include <iodef.h>
409 #include <descrip.h>
410 #else /* eunice */
411 #include <vms/iodef.h>
412 #endif /* eunice */
413 #endif /* VMS */
415 #ifndef LDAV_CVT
416 #define LDAV_CVT(n) ((double) (n))
417 #endif /* !LDAV_CVT */
419 #endif /* LOAD_AVE_TYPE */
421 #ifdef NeXT
422 #ifdef HAVE_MACH_MACH_H
423 #include <mach/mach.h>
424 #else
425 #include <mach.h>
426 #endif
427 #endif /* NeXT */
429 #ifdef sgi
430 #include <sys/sysmp.h>
431 #endif /* sgi */
433 #ifdef UMAX
434 #include <stdio.h>
435 #include <signal.h>
436 #include <sys/time.h>
437 #include <sys/wait.h>
438 #include <sys/syscall.h>
440 #ifdef UMAX_43
441 #include <machine/cpu.h>
442 #include <inq_stats/statistics.h>
443 #include <inq_stats/sysstats.h>
444 #include <inq_stats/cpustats.h>
445 #include <inq_stats/procstats.h>
446 #else /* Not UMAX_43. */
447 #include <sys/sysdefs.h>
448 #include <sys/statistics.h>
449 #include <sys/sysstats.h>
450 #include <sys/cpudefs.h>
451 #include <sys/cpustats.h>
452 #include <sys/procstats.h>
453 #endif /* Not UMAX_43. */
454 #endif /* UMAX */
456 #ifdef DGUX
457 #include <sys/dg_sys_info.h>
458 #endif
460 #if defined(HAVE_FCNTL_H) || defined(_POSIX_VERSION)
461 #include <fcntl.h>
462 #else
463 #include <sys/file.h>
464 #endif
466 /* Avoid static vars inside a function since in HPUX they dump as pure. */
468 #ifdef NeXT
469 static processor_set_t default_set;
470 static int getloadavg_initialized;
471 #endif /* NeXT */
473 #ifdef UMAX
474 static unsigned int cpus = 0;
475 static unsigned int samples;
476 #endif /* UMAX */
478 #ifdef DGUX
479 static struct dg_sys_info_load_info load_info; /* what-a-mouthful! */
480 #endif /* DGUX */
482 #ifdef LOAD_AVE_TYPE
483 /* File descriptor open to /dev/kmem or VMS load ave driver. */
484 static int channel;
485 /* Nonzero iff channel is valid. */
486 static int getloadavg_initialized;
487 /* Offset in kmem to seek to read load average, or 0 means invalid. */
488 static long offset;
490 #if !defined(VMS) && !defined(sgi)
491 static struct nlist nl[2];
492 #endif /* Not VMS or sgi */
494 #ifdef SUNOS_5
495 static kvm_t *kd;
496 #endif /* SUNOS_5 */
498 #endif /* LOAD_AVE_TYPE */
500 /* Put the 1 minute, 5 minute and 15 minute load averages
501 into the first NELEM elements of LOADAVG.
502 Return the number written (never more than 3, but may be less than NELEM),
503 or -1 if an error occurred. */
506 getloadavg (loadavg, nelem)
507 double loadavg[];
508 int nelem;
510 int elem = 0; /* Return value. */
512 #ifdef NO_GET_LOAD_AVG
513 #define LDAV_DONE
514 /* Set errno to zero to indicate that there was no particular error;
515 this function just can't work at all on this system. */
516 errno = 0;
517 elem = -1;
518 #endif
520 #if !defined (LDAV_DONE) && defined (SUNOS_5)
521 /* Use libkstat because we don't have to be root. */
522 #define LDAV_DONE
523 kstat_ctl_t *kc;
524 kstat_t *ksp;
525 kstat_named_t *kn;
527 kc = kstat_open ();
528 if (kc == 0) return -1;
529 ksp = kstat_lookup (kc, "unix", 0, "system_misc");
530 if (ksp == 0 ) return -1;
531 if (kstat_read (kc, ksp, 0) == -1) return -1;
534 kn = kstat_data_lookup (ksp, "avenrun_1min");
535 if (kn == 0)
537 /* Return -1 if no load average information is available. */
538 nelem = 0;
539 elem = -1;
542 if (nelem >= 1)
543 loadavg[elem++] = (double) kn->value.ul/FSCALE;
545 if (nelem >= 2)
547 kn = kstat_data_lookup (ksp, "avenrun_5min");
548 if (kn != 0)
550 loadavg[elem++] = (double) kn->value.ul/FSCALE;
552 if (nelem >= 3)
554 kn = kstat_data_lookup (ksp, "avenrun_15min");
555 if (kn != 0)
556 loadavg[elem++] = (double) kn->value.ul/FSCALE;
561 kstat_close (kc);
562 #endif /* SUNOS_5 */
564 #if !defined (LDAV_DONE) && defined (__linux__)
565 #define LDAV_DONE
566 #undef LOAD_AVE_TYPE
568 #ifndef LINUX_LDAV_FILE
569 #define LINUX_LDAV_FILE "/proc/loadavg"
570 #endif
572 char ldavgbuf[40];
573 double load_ave[3];
574 int fd, count;
576 fd = open (LINUX_LDAV_FILE, O_RDONLY);
577 if (fd == -1)
578 return -1;
579 count = read (fd, ldavgbuf, 40);
580 (void) close (fd);
581 if (count <= 0)
582 return -1;
584 count = sscanf (ldavgbuf, "%lf %lf %lf",
585 &load_ave[0], &load_ave[1], &load_ave[2]);
586 if (count < 1)
587 return -1;
589 for (elem = 0; elem < nelem && elem < count; elem++)
590 loadavg[elem] = load_ave[elem];
592 return elem;
594 #endif /* __linux__ */
596 #if !defined (LDAV_DONE) && defined (__NetBSD__)
597 #define LDAV_DONE
598 #undef LOAD_AVE_TYPE
600 #ifndef NETBSD_LDAV_FILE
601 #define NETBSD_LDAV_FILE "/kern/loadavg"
602 #endif
604 unsigned long int load_ave[3], scale;
605 int count;
606 FILE *fp;
608 fp = fopen (NETBSD_LDAV_FILE, "r");
609 if (fp == NULL)
610 return -1;
611 count = fscanf (fp, "%lu %lu %lu %lu\n",
612 &load_ave[0], &load_ave[1], &load_ave[2],
613 &scale);
614 (void) fclose (fp);
615 if (count != 4)
616 return -1;
618 for (elem = 0; elem < nelem; elem++)
619 loadavg[elem] = (double) load_ave[elem] / (double) scale;
621 return elem;
623 #endif /* __NetBSD__ */
625 #if !defined (LDAV_DONE) && defined (NeXT)
626 #define LDAV_DONE
627 /* The NeXT code was adapted from iscreen 3.2. */
629 host_t host;
630 struct processor_set_basic_info info;
631 unsigned info_count;
633 /* We only know how to get the 1-minute average for this system,
634 so even if the caller asks for more than 1, we only return 1. */
636 if (!getloadavg_initialized)
638 if (processor_set_default (host_self (), &default_set) == KERN_SUCCESS)
639 getloadavg_initialized = 1;
642 if (getloadavg_initialized)
644 info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
645 if (processor_set_info (default_set, PROCESSOR_SET_BASIC_INFO, &host,
646 (processor_set_info_t) &info, &info_count)
647 != KERN_SUCCESS)
648 getloadavg_initialized = 0;
649 else
651 if (nelem > 0)
652 loadavg[elem++] = (double) info.load_average / LOAD_SCALE;
656 if (!getloadavg_initialized)
657 return -1;
658 #endif /* NeXT */
660 #if !defined (LDAV_DONE) && defined (UMAX)
661 #define LDAV_DONE
662 /* UMAX 4.2, which runs on the Encore Multimax multiprocessor, does not
663 have a /dev/kmem. Information about the workings of the running kernel
664 can be gathered with inq_stats system calls.
665 We only know how to get the 1-minute average for this system. */
667 struct proc_summary proc_sum_data;
668 struct stat_descr proc_info;
669 double load;
670 register unsigned int i, j;
672 if (cpus == 0)
674 register unsigned int c, i;
675 struct cpu_config conf;
676 struct stat_descr desc;
678 desc.sd_next = 0;
679 desc.sd_subsys = SUBSYS_CPU;
680 desc.sd_type = CPUTYPE_CONFIG;
681 desc.sd_addr = (char *) &conf;
682 desc.sd_size = sizeof conf;
684 if (inq_stats (1, &desc))
685 return -1;
687 c = 0;
688 for (i = 0; i < conf.config_maxclass; ++i)
690 struct class_stats stats;
691 bzero ((char *) &stats, sizeof stats);
693 desc.sd_type = CPUTYPE_CLASS;
694 desc.sd_objid = i;
695 desc.sd_addr = (char *) &stats;
696 desc.sd_size = sizeof stats;
698 if (inq_stats (1, &desc))
699 return -1;
701 c += stats.class_numcpus;
703 cpus = c;
704 samples = cpus < 2 ? 3 : (2 * cpus / 3);
707 proc_info.sd_next = 0;
708 proc_info.sd_subsys = SUBSYS_PROC;
709 proc_info.sd_type = PROCTYPE_SUMMARY;
710 proc_info.sd_addr = (char *) &proc_sum_data;
711 proc_info.sd_size = sizeof (struct proc_summary);
712 proc_info.sd_sizeused = 0;
714 if (inq_stats (1, &proc_info) != 0)
715 return -1;
717 load = proc_sum_data.ps_nrunnable;
718 j = 0;
719 for (i = samples - 1; i > 0; --i)
721 load += proc_sum_data.ps_nrun[j];
722 if (j++ == PS_NRUNSIZE)
723 j = 0;
726 if (nelem > 0)
727 loadavg[elem++] = load / samples / cpus;
728 #endif /* UMAX */
730 #if !defined (LDAV_DONE) && defined (DGUX)
731 #define LDAV_DONE
732 /* This call can return -1 for an error, but with good args
733 it's not supposed to fail. The first argument is for no
734 apparent reason of type `long int *'. */
735 dg_sys_info ((long int *) &load_info,
736 DG_SYS_INFO_LOAD_INFO_TYPE,
737 DG_SYS_INFO_LOAD_VERSION_0);
739 if (nelem > 0)
740 loadavg[elem++] = load_info.one_minute;
741 if (nelem > 1)
742 loadavg[elem++] = load_info.five_minute;
743 if (nelem > 2)
744 loadavg[elem++] = load_info.fifteen_minute;
745 #endif /* DGUX */
747 #if !defined (LDAV_DONE) && defined (apollo)
748 #define LDAV_DONE
749 /* Apollo code from lisch@mentorg.com (Ray Lischner).
751 This system call is not documented. The load average is obtained as
752 three long integers, for the load average over the past minute,
753 five minutes, and fifteen minutes. Each value is a scaled integer,
754 with 16 bits of integer part and 16 bits of fraction part.
756 I'm not sure which operating system first supported this system call,
757 but I know that SR10.2 supports it. */
759 extern void proc1_$get_loadav ();
760 unsigned long load_ave[3];
762 proc1_$get_loadav (load_ave);
764 if (nelem > 0)
765 loadavg[elem++] = load_ave[0] / 65536.0;
766 if (nelem > 1)
767 loadavg[elem++] = load_ave[1] / 65536.0;
768 if (nelem > 2)
769 loadavg[elem++] = load_ave[2] / 65536.0;
770 #endif /* apollo */
772 #if !defined (LDAV_DONE) && defined (OSF_MIPS)
773 #define LDAV_DONE
775 struct tbl_loadavg load_ave;
776 table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
777 loadavg[elem++]
778 = (load_ave.tl_lscale == 0
779 ? load_ave.tl_avenrun.d[0]
780 : (load_ave.tl_avenrun.l[0] / (double) load_ave.tl_lscale));
781 #endif /* OSF_MIPS */
783 #if !defined (LDAV_DONE) && (defined (MSDOS) || defined (WIN32))
784 #define LDAV_DONE
786 /* A faithful emulation is going to have to be saved for a rainy day. */
787 for ( ; elem < nelem; elem++)
789 loadavg[elem] = 0.0;
791 #endif /* MSDOS */
793 #if !defined (LDAV_DONE) && defined (OSF_ALPHA)
794 #define LDAV_DONE
796 struct tbl_loadavg load_ave;
797 table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
798 for (elem = 0; elem < nelem; elem++)
799 loadavg[elem]
800 = (load_ave.tl_lscale == 0
801 ? load_ave.tl_avenrun.d[elem]
802 : (load_ave.tl_avenrun.l[elem] / (double) load_ave.tl_lscale));
803 #endif /* OSF_ALPHA */
805 #if !defined (LDAV_DONE) && defined (VMS)
806 /* VMS specific code -- read from the Load Ave driver. */
808 LOAD_AVE_TYPE load_ave[3];
809 static int getloadavg_initialized = 0;
810 #ifdef eunice
811 struct
813 int dsc$w_length;
814 char *dsc$a_pointer;
815 } descriptor;
816 #endif
818 /* Ensure that there is a channel open to the load ave device. */
819 if (!getloadavg_initialized)
821 /* Attempt to open the channel. */
822 #ifdef eunice
823 descriptor.dsc$w_length = 18;
824 descriptor.dsc$a_pointer = "$$VMS_LOAD_AVERAGE";
825 #else
826 $DESCRIPTOR (descriptor, "LAV0:");
827 #endif
828 if (sys$assign (&descriptor, &channel, 0, 0) & 1)
829 getloadavg_initialized = 1;
832 /* Read the load average vector. */
833 if (getloadavg_initialized
834 && !(sys$qiow (0, channel, IO$_READVBLK, 0, 0, 0,
835 load_ave, 12, 0, 0, 0, 0) & 1))
837 sys$dassgn (channel);
838 getloadavg_initialized = 0;
841 if (!getloadavg_initialized)
842 return -1;
843 #endif /* VMS */
845 #if !defined (LDAV_DONE) && defined(LOAD_AVE_TYPE) && !defined(VMS)
847 /* UNIX-specific code -- read the average from /dev/kmem. */
849 #define LDAV_PRIVILEGED /* This code requires special installation. */
851 LOAD_AVE_TYPE load_ave[3];
853 /* Get the address of LDAV_SYMBOL. */
854 if (offset == 0)
856 #ifndef sgi
857 #ifndef NLIST_STRUCT
858 strcpy (nl[0].n_name, LDAV_SYMBOL);
859 strcpy (nl[1].n_name, "");
860 #else /* NLIST_STRUCT */
861 #ifdef NLIST_NAME_UNION
862 nl[0].n_un.n_name = LDAV_SYMBOL;
863 nl[1].n_un.n_name = 0;
864 #else /* not NLIST_NAME_UNION */
865 nl[0].n_name = LDAV_SYMBOL;
866 nl[1].n_name = 0;
867 #endif /* not NLIST_NAME_UNION */
868 #endif /* NLIST_STRUCT */
870 #ifndef SUNOS_5
871 if (
872 #if !(defined (_AIX) && !defined (ps2))
873 nlist (KERNEL_FILE, nl)
874 #else /* _AIX */
875 knlist (nl, 1, sizeof (nl[0]))
876 #endif
877 >= 0)
878 /* Omit "&& nl[0].n_type != 0 " -- it breaks on Sun386i. */
880 #ifdef FIXUP_KERNEL_SYMBOL_ADDR
881 FIXUP_KERNEL_SYMBOL_ADDR (nl);
882 #endif
883 offset = nl[0].n_value;
885 #endif /* !SUNOS_5 */
886 #else /* sgi */
887 int ldav_off;
889 ldav_off = sysmp (MP_KERNADDR, MPKA_AVENRUN);
890 if (ldav_off != -1)
891 offset = (long) ldav_off & 0x7fffffff;
892 #endif /* sgi */
895 /* Make sure we have /dev/kmem open. */
896 if (!getloadavg_initialized)
898 #ifndef SUNOS_5
899 channel = open ("/dev/kmem", 0);
900 if (channel >= 0)
902 /* Set the channel to close on exec, so it does not
903 litter any child's descriptor table. */
904 #ifdef FD_SETFD
905 #ifndef FD_CLOEXEC
906 #define FD_CLOEXEC 1
907 #endif
908 (void) fcntl (channel, F_SETFD, FD_CLOEXEC);
909 #endif
910 getloadavg_initialized = 1;
912 #else /* SUNOS_5 */
913 /* We pass 0 for the kernel, corefile, and swapfile names
914 to use the currently running kernel. */
915 kd = kvm_open (0, 0, 0, O_RDONLY, 0);
916 if (kd != 0)
918 /* nlist the currently running kernel. */
919 kvm_nlist (kd, nl);
920 offset = nl[0].n_value;
921 getloadavg_initialized = 1;
923 #endif /* SUNOS_5 */
926 /* If we can, get the load average values. */
927 if (offset && getloadavg_initialized)
929 /* Try to read the load. */
930 #ifndef SUNOS_5
931 if (lseek (channel, offset, 0) == -1L
932 || read (channel, (char *) load_ave, sizeof (load_ave))
933 != sizeof (load_ave))
935 close (channel);
936 getloadavg_initialized = 0;
938 #else /* SUNOS_5 */
939 if (kvm_read (kd, offset, (char *) load_ave, sizeof (load_ave))
940 != sizeof (load_ave))
942 kvm_close (kd);
943 getloadavg_initialized = 0;
945 #endif /* SUNOS_5 */
948 if (offset == 0 || !getloadavg_initialized)
949 return -1;
950 #endif /* LOAD_AVE_TYPE and not VMS */
952 #if !defined (LDAV_DONE) && defined (LOAD_AVE_TYPE) /* Including VMS. */
953 if (nelem > 0)
954 loadavg[elem++] = LDAV_CVT (load_ave[0]);
955 if (nelem > 1)
956 loadavg[elem++] = LDAV_CVT (load_ave[1]);
957 if (nelem > 2)
958 loadavg[elem++] = LDAV_CVT (load_ave[2]);
960 #define LDAV_DONE
961 #endif /* !LDAV_DONE && LOAD_AVE_TYPE */
963 #ifdef LDAV_DONE
964 return elem;
965 #else
966 /* Set errno to zero to indicate that there was no particular error;
967 this function just can't work at all on this system. */
968 errno = 0;
969 return -1;
970 #endif
973 #endif /* ! HAVE_GETLOADAVG */
975 #ifdef TEST
976 void
977 main (argc, argv)
978 int argc;
979 char **argv;
981 int naptime = 0;
983 if (argc > 1)
984 naptime = atoi (argv[1]);
986 while (1)
988 double avg[3];
989 int loads;
991 errno = 0; /* Don't be misled if it doesn't set errno. */
992 loads = getloadavg (avg, 3);
993 if (loads == -1)
995 perror ("Error getting load average");
996 exit (1);
998 if (loads > 0)
999 printf ("1-minute: %f ", avg[0]);
1000 if (loads > 1)
1001 printf ("5-minute: %f ", avg[1]);
1002 if (loads > 2)
1003 printf ("15-minute: %f ", avg[2]);
1004 if (loads > 0)
1005 putchar ('\n');
1007 if (naptime == 0)
1008 break;
1009 sleep (naptime);
1012 exit (0);
1014 #endif /* TEST */