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