(Goals): Say that only first target in first rule is default goal.
[make.git] / getloadavg.c
blob0f730a7ab2b998336a8a7fc61ee1759463ce1baf
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 #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
83 /* Exclude all the code except the test program at the end
84 if the system has its own `getloadavg' function.
86 The declaration of `errno' is needed by the test program
87 as well as the function itself, so it comes first. */
89 #include <errno.h>
91 #ifndef errno
92 extern int errno;
93 #endif
95 #ifndef HAVE_GETLOADAVG
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.
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. */
108 #if !defined(LDAV_CVT) && defined(LOAD_AVE_CVT)
109 #define LDAV_CVT(n) (LOAD_AVE_CVT (n) / 100.0)
110 #endif
112 #if !defined (BSD) && defined (ultrix)
113 /* Ultrix behaves like BSD on Vaxen. */
114 #define BSD
115 #endif
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
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
128 /* Set values that are different from the defaults, which are
129 set a little farther down with #ifndef. */
132 /* Some shorthands. */
134 #if defined (HPUX) && !defined (hpux)
135 #define hpux
136 #endif
138 #if defined(hp300) && !defined(hpux)
139 #define MORE_BSD
140 #endif
142 #if defined(ultrix) && defined(mips)
143 #define decstation
144 #endif
146 #if defined(sun) && defined(SVR4)
147 #define SUNOS_5
148 #endif
150 #if defined (__osf__) && (defined (__alpha) || defined (__alpha__))
151 #define OSF_ALPHA
152 #endif
154 #if defined (__osf__) && (defined (mips) || defined (__mips__))
155 #define OSF_MIPS
156 #include <sys/table.h>
157 #endif
159 /* UTek's /bin/cc on the 4300 has no architecture specific cpp define by
160 default, but _MACH_IND_SYS_TYPES is defined in <sys/types.h>. Combine
161 that with a couple of other things and we'll have a unique match. */
162 #if !defined (tek4300) && defined (unix) && defined (m68k) && defined (mc68000) && defined (mc68020) && defined (_MACH_IND_SYS_TYPES)
163 #define tek4300 /* Define by emacs, but not by other users. */
164 #endif
167 /* VAX C can't handle multi-line #ifs, or lines longer than 256 chars. */
168 #ifndef LOAD_AVE_TYPE
170 #ifdef MORE_BSD
171 #define LOAD_AVE_TYPE long
172 #endif
174 #ifdef sun
175 #define LOAD_AVE_TYPE long
176 #endif
178 #ifdef decstation
179 #define LOAD_AVE_TYPE long
180 #endif
182 #ifdef _SEQUENT_
183 #define LOAD_AVE_TYPE long
184 #endif
186 #ifdef sgi
187 #define LOAD_AVE_TYPE long
188 #endif
190 #ifdef SVR4
191 #define LOAD_AVE_TYPE long
192 #endif
194 #ifdef sony_news
195 #define LOAD_AVE_TYPE long
196 #endif
198 #ifdef sequent
199 #define LOAD_AVE_TYPE long
200 #endif
202 #ifdef OSF_ALPHA
203 #define LOAD_AVE_TYPE long
204 #endif
206 #if defined (ardent) && defined (titan)
207 #define LOAD_AVE_TYPE long
208 #endif
210 #ifdef tek4300
211 #define LOAD_AVE_TYPE long
212 #endif
214 #endif /* No LOAD_AVE_TYPE. */
216 #ifdef OSF_ALPHA
217 /* <sys/param.h> defines an incorrect value for FSCALE on Alpha OSF/1,
218 according to ghazi@noc.rutgers.edu. */
219 #undef FSCALE
220 #define FSCALE 1024.0
221 #endif
224 #ifndef FSCALE
226 /* SunOS and some others define FSCALE in sys/param.h. */
228 #ifdef MORE_BSD
229 #define FSCALE 2048.0
230 #endif
232 #if defined(MIPS) || defined(SVR4) || defined(decstation)
233 #define FSCALE 256
234 #endif
236 #if defined (sgi) || defined (sequent)
237 /* Sometimes both MIPS and sgi are defined, so FSCALE was just defined
238 above under #ifdef MIPS. But we want the sgi value. */
239 #undef FSCALE
240 #define FSCALE 1000.0
241 #endif
243 #if defined (ardent) && defined (titan)
244 #define FSCALE 65536.0
245 #endif
247 #ifdef tek4300
248 #define FSCALE 100.0
249 #endif
251 #endif /* Not FSCALE. */
253 #if !defined (LDAV_CVT) && defined (FSCALE)
254 #define LDAV_CVT(n) (((double) (n)) / FSCALE)
255 #endif
257 /* VAX C can't handle multi-line #ifs, or lines longer that 256 characters. */
258 #ifndef NLIST_STRUCT
260 #ifdef MORE_BSD
261 #define NLIST_STRUCT
262 #endif
264 #ifdef sun
265 #define NLIST_STRUCT
266 #endif
268 #ifdef decstation
269 #define NLIST_STRUCT
270 #endif
272 #ifdef hpux
273 #define NLIST_STRUCT
274 #endif
276 #if defined (_SEQUENT_) || defined (sequent)
277 #define NLIST_STRUCT
278 #endif
280 #ifdef sgi
281 #define NLIST_STRUCT
282 #endif
284 #ifdef SVR4
285 #define NLIST_STRUCT
286 #endif
288 #ifdef sony_news
289 #define NLIST_STRUCT
290 #endif
292 #ifdef OSF_ALPHA
293 #define NLIST_STRUCT
294 #endif
296 #if defined (ardent) && defined (titan)
297 #define NLIST_STRUCT
298 #endif
300 #ifdef tex4300
301 #define NLIST_STRUCT
302 #endif
304 #ifdef butterfly
305 #define NLIST_STRUCT
306 #endif
308 #endif /* defined (NLIST_STRUCT) */
311 #if defined(sgi) || (defined(mips) && !defined(BSD))
312 #define FIXUP_KERNEL_SYMBOL_ADDR(nl) ((nl)[0].n_value &= ~(1 << 31))
313 #endif
316 #if !defined (KERNEL_FILE) && defined (sequent)
317 #define KERNEL_FILE "/dynix"
318 #endif
320 #if !defined (KERNEL_FILE) && defined (hpux)
321 #define KERNEL_FILE "/hp-ux"
322 #endif
324 #if !defined(KERNEL_FILE) && (defined(_SEQUENT_) || defined(MIPS) || defined(SVR4) || defined(ISC) || defined (sgi) || defined(SVR4) || (defined (ardent) && defined (titan)))
325 #define KERNEL_FILE "/unix"
326 #endif
329 #if !defined (LDAV_SYMBOL) && defined (alliant)
330 #define LDAV_SYMBOL "_Loadavg"
331 #endif
333 #if !defined(LDAV_SYMBOL) && ((defined(hpux) && !defined(hp9000s300)) || defined(_SEQUENT_) || defined(SVR4) || defined(ISC) || defined(sgi) || (defined (ardent) && defined (titan)))
334 #define LDAV_SYMBOL "avenrun"
335 #endif
337 #ifdef HAVE_UNISTD_H
338 #include <unistd.h>
339 #endif
341 #include <stdio.h>
343 /* LOAD_AVE_TYPE should only get defined if we're going to use the
344 nlist method. */
345 #if !defined(LOAD_AVE_TYPE) && (defined(BSD) || defined(LDAV_CVT) || defined(KERNEL_FILE) || defined(LDAV_SYMBOL))
346 #define LOAD_AVE_TYPE double
347 #endif
349 #ifdef LOAD_AVE_TYPE
351 #ifndef VMS
352 #ifndef NLIST_STRUCT
353 #include <a.out.h>
354 #else /* NLIST_STRUCT */
355 #include <nlist.h>
356 #endif /* NLIST_STRUCT */
358 #ifdef SUNOS_5
359 #include <fcntl.h>
360 #include <kvm.h>
361 #endif
363 #ifndef KERNEL_FILE
364 #define KERNEL_FILE "/vmunix"
365 #endif /* KERNEL_FILE */
367 #ifndef LDAV_SYMBOL
368 #define LDAV_SYMBOL "_avenrun"
369 #endif /* LDAV_SYMBOL */
371 #else /* VMS */
373 #ifndef eunice
374 #include <iodef.h>
375 #include <descrip.h>
376 #else /* eunice */
377 #include <vms/iodef.h>
378 #endif /* eunice */
379 #endif /* VMS */
381 #ifndef LDAV_CVT
382 #define LDAV_CVT(n) ((double) (n))
383 #endif /* !LDAV_CVT */
385 #endif /* LOAD_AVE_TYPE */
387 #ifdef NeXT
388 #ifdef HAVE_MACH_MACH_H
389 #include <mach/mach.h>
390 #else
391 #include <mach.h>
392 #endif
393 #endif /* NeXT */
395 #ifdef sgi
396 #include <sys/sysmp.h>
397 #endif /* sgi */
399 #ifdef UMAX
400 #include <stdio.h>
401 #include <signal.h>
402 #include <sys/time.h>
403 #include <sys/wait.h>
404 #include <sys/syscall.h>
406 #ifdef UMAX_43
407 #include <machine/cpu.h>
408 #include <inq_stats/statistics.h>
409 #include <inq_stats/sysstats.h>
410 #include <inq_stats/cpustats.h>
411 #include <inq_stats/procstats.h>
412 #else /* Not UMAX_43. */
413 #include <sys/sysdefs.h>
414 #include <sys/statistics.h>
415 #include <sys/sysstats.h>
416 #include <sys/cpudefs.h>
417 #include <sys/cpustats.h>
418 #include <sys/procstats.h>
419 #endif /* Not UMAX_43. */
420 #endif /* UMAX */
422 #ifdef DGUX
423 #include <sys/dg_sys_info.h>
424 #endif
426 #if defined(HAVE_FCNTL_H) || defined(_POSIX_VERSION)
427 #include <fcntl.h>
428 #else
429 #include <sys/file.h>
430 #endif
432 /* Avoid static vars inside a function since in HPUX they dump as pure. */
434 #ifdef NeXT
435 static processor_set_t default_set;
436 static int getloadavg_initialized;
437 #endif /* NeXT */
439 #ifdef UMAX
440 static unsigned int cpus = 0;
441 static unsigned int samples;
442 #endif /* UMAX */
444 #ifdef DGUX
445 static struct dg_sys_info_load_info load_info; /* what-a-mouthful! */
446 #endif /* DGUX */
448 #ifdef LOAD_AVE_TYPE
449 /* File descriptor open to /dev/kmem or VMS load ave driver. */
450 static int channel;
451 /* Nonzero iff channel is valid. */
452 static int getloadavg_initialized;
453 /* Offset in kmem to seek to read load average, or 0 means invalid. */
454 static long offset;
456 #if !defined(VMS) && !defined(sgi)
457 static struct nlist nl[2];
458 #endif /* Not VMS or sgi */
460 #ifdef SUNOS_5
461 static kvm_t *kd;
462 #endif /* SUNOS_5 */
464 #endif /* LOAD_AVE_TYPE */
466 /* Put the 1 minute, 5 minute and 15 minute load averages
467 into the first NELEM elements of LOADAVG.
468 Return the number written (never more than 3, but may be less than NELEM),
469 or -1 if an error occurred. */
472 getloadavg (loadavg, nelem)
473 double loadavg[];
474 int nelem;
476 int elem = 0; /* Return value. */
478 #ifdef NO_GET_LOAD_AVG
479 #define LDAV_DONE
480 /* Set errno to zero to indicate that there was no particular error;
481 this function just can't work at all on this system. */
482 errno = 0;
483 elem = -1;
484 #endif
486 #if !defined (LDAV_DONE) && defined (__linux__)
487 #define LDAV_DONE
488 #undef LOAD_AVE_TYPE
490 #ifndef LINUX_LDAV_FILE
491 #define LINUX_LDAV_FILE "/proc/loadavg"
492 #endif
494 char ldavgbuf[40];
495 double load_ave[3];
496 int fd, count;
498 fd = open (LINUX_LDAV_FILE, O_RDONLY);
499 if (fd == -1)
500 return -1;
501 count = read (fd, ldavgbuf, 40);
502 (void) close (fd);
503 if (count <= 0)
504 return -1;
506 count = sscanf (ldavgbuf, "%lf %lf %lf",
507 &load_ave[0], &load_ave[1], &load_ave[2]);
508 if (count < 1)
509 return -1;
511 for (elem = 0; elem < nelem && elem < count; elem++)
512 loadavg[elem] = load_ave[elem];
514 return elem;
516 #endif /* __linux__ */
518 #if !defined (LDAV_DONE) && defined (__NetBSD__)
519 #define LDAV_DONE
520 #undef LOAD_AVE_TYPE
522 #ifndef NETBSD_LDAV_FILE
523 #define NETBSD_LDAV_FILE "/kern/loadavg"
524 #endif
526 unsigned long int load_ave[3], scale;
527 int count;
528 FILE *fp;
530 fp = fopen (NETBSD_LDAV_FILE, "r");
531 if (fp == NULL)
532 return -1;
533 count = fscanf (fp, "%lu %lu %lu %lu\n",
534 &load_ave[0], &load_ave[1], &load_ave[2],
535 &scale);
536 (void) fclose (fp);
537 if (count != 4)
538 return -1;
540 for (elem = 0; elem < nelem; elem++)
541 loadavg[elem] = (double) load_ave[elem] / (double) scale;
543 return elem;
545 #endif /* __NetBSD__ */
547 #if !defined (LDAV_DONE) && defined (NeXT)
548 #define LDAV_DONE
549 /* The NeXT code was adapted from iscreen 3.2. */
551 host_t host;
552 struct processor_set_basic_info info;
553 unsigned info_count;
555 /* We only know how to get the 1-minute average for this system,
556 so even if the caller asks for more than 1, we only return 1. */
558 if (!getloadavg_initialized)
560 if (processor_set_default (host_self (), &default_set) == KERN_SUCCESS)
561 getloadavg_initialized = 1;
564 if (getloadavg_initialized)
566 info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
567 if (processor_set_info (default_set, PROCESSOR_SET_BASIC_INFO, &host,
568 (processor_set_info_t) &info, &info_count)
569 != KERN_SUCCESS)
570 getloadavg_initialized = 0;
571 else
573 if (nelem > 0)
574 loadavg[elem++] = (double) info.load_average / LOAD_SCALE;
578 if (!getloadavg_initialized)
579 return -1;
580 #endif /* NeXT */
582 #if !defined (LDAV_DONE) && defined (UMAX)
583 #define LDAV_DONE
584 /* UMAX 4.2, which runs on the Encore Multimax multiprocessor, does not
585 have a /dev/kmem. Information about the workings of the running kernel
586 can be gathered with inq_stats system calls.
587 We only know how to get the 1-minute average for this system. */
589 struct proc_summary proc_sum_data;
590 struct stat_descr proc_info;
591 double load;
592 register unsigned int i, j;
594 if (cpus == 0)
596 register unsigned int c, i;
597 struct cpu_config conf;
598 struct stat_descr desc;
600 desc.sd_next = 0;
601 desc.sd_subsys = SUBSYS_CPU;
602 desc.sd_type = CPUTYPE_CONFIG;
603 desc.sd_addr = (char *) &conf;
604 desc.sd_size = sizeof conf;
606 if (inq_stats (1, &desc))
607 return -1;
609 c = 0;
610 for (i = 0; i < conf.config_maxclass; ++i)
612 struct class_stats stats;
613 bzero ((char *) &stats, sizeof stats);
615 desc.sd_type = CPUTYPE_CLASS;
616 desc.sd_objid = i;
617 desc.sd_addr = (char *) &stats;
618 desc.sd_size = sizeof stats;
620 if (inq_stats (1, &desc))
621 return -1;
623 c += stats.class_numcpus;
625 cpus = c;
626 samples = cpus < 2 ? 3 : (2 * cpus / 3);
629 proc_info.sd_next = 0;
630 proc_info.sd_subsys = SUBSYS_PROC;
631 proc_info.sd_type = PROCTYPE_SUMMARY;
632 proc_info.sd_addr = (char *) &proc_sum_data;
633 proc_info.sd_size = sizeof (struct proc_summary);
634 proc_info.sd_sizeused = 0;
636 if (inq_stats (1, &proc_info) != 0)
637 return -1;
639 load = proc_sum_data.ps_nrunnable;
640 j = 0;
641 for (i = samples - 1; i > 0; --i)
643 load += proc_sum_data.ps_nrun[j];
644 if (j++ == PS_NRUNSIZE)
645 j = 0;
648 if (nelem > 0)
649 loadavg[elem++] = load / samples / cpus;
650 #endif /* UMAX */
652 #if !defined (LDAV_DONE) && defined (DGUX)
653 #define LDAV_DONE
654 /* This call can return -1 for an error, but with good args
655 it's not supposed to fail. The first argument is for no
656 apparent reason of type `long int *'. */
657 dg_sys_info ((long int *) &load_info,
658 DG_SYS_INFO_LOAD_INFO_TYPE,
659 DG_SYS_INFO_LOAD_VERSION_0);
661 if (nelem > 0)
662 loadavg[elem++] = load_info.one_minute;
663 if (nelem > 1)
664 loadavg[elem++] = load_info.five_minute;
665 if (nelem > 2)
666 loadavg[elem++] = load_info.fifteen_minute;
667 #endif /* DGUX */
669 #if !defined (LDAV_DONE) && defined (apollo)
670 #define LDAV_DONE
671 /* Apollo code from lisch@mentorg.com (Ray Lischner).
673 This system call is not documented. The load average is obtained as
674 three long integers, for the load average over the past minute,
675 five minutes, and fifteen minutes. Each value is a scaled integer,
676 with 16 bits of integer part and 16 bits of fraction part.
678 I'm not sure which operating system first supported this system call,
679 but I know that SR10.2 supports it. */
681 extern void proc1_$get_loadav ();
682 unsigned long load_ave[3];
684 proc1_$get_loadav (load_ave);
686 if (nelem > 0)
687 loadavg[elem++] = load_ave[0] / 65536.0;
688 if (nelem > 1)
689 loadavg[elem++] = load_ave[1] / 65536.0;
690 if (nelem > 2)
691 loadavg[elem++] = load_ave[2] / 65536.0;
692 #endif /* apollo */
694 #if !defined (LDAV_DONE) && defined (OSF_MIPS)
695 #define LDAV_DONE
697 struct tbl_loadavg load_ave;
698 table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
699 loadavg[elem++]
700 = (load_ave.tl_lscale == 0
701 ? load_ave.tl_avenrun.d[0]
702 : (load_ave.tl_avenrun.l[0] / (double) load_ave.tl_lscale));
703 #endif /* OSF_MIPS */
705 #if !defined (LDAV_DONE) && defined (VMS)
706 /* VMS specific code -- read from the Load Ave driver. */
708 LOAD_AVE_TYPE load_ave[3];
709 static int getloadavg_initialized = 0;
710 #ifdef eunice
711 struct
713 int dsc$w_length;
714 char *dsc$a_pointer;
715 } descriptor;
716 #endif
718 /* Ensure that there is a channel open to the load ave device. */
719 if (!getloadavg_initialized)
721 /* Attempt to open the channel. */
722 #ifdef eunice
723 descriptor.dsc$w_length = 18;
724 descriptor.dsc$a_pointer = "$$VMS_LOAD_AVERAGE";
725 #else
726 $DESCRIPTOR (descriptor, "LAV0:");
727 #endif
728 if (sys$assign (&descriptor, &channel, 0, 0) & 1)
729 getloadavg_initialized = 1;
732 /* Read the load average vector. */
733 if (getloadavg_initialized
734 && !(sys$qiow (0, channel, IO$_READVBLK, 0, 0, 0,
735 load_ave, 12, 0, 0, 0, 0) & 1))
737 sys$dassgn (channel);
738 getloadavg_initialized = 0;
741 if (!getloadavg_initialized)
742 return -1;
743 #endif /* VMS */
745 #if !defined (LDAV_DONE) && defined(LOAD_AVE_TYPE) && !defined(VMS)
747 /* UNIX-specific code -- read the average from /dev/kmem. */
749 #define LDAV_PRIVILEGED /* This code requires special installation. */
751 LOAD_AVE_TYPE load_ave[3];
753 /* Get the address of LDAV_SYMBOL. */
754 if (offset == 0)
756 #ifndef sgi
757 #ifndef NLIST_STRUCT
758 strcpy (nl[0].n_name, LDAV_SYMBOL);
759 strcpy (nl[1].n_name, "");
760 #else /* NLIST_STRUCT */
761 #ifdef NLIST_NAME_UNION
762 nl[0].n_un.n_name = LDAV_SYMBOL;
763 nl[1].n_un.n_name = 0;
764 #else /* not NLIST_NAME_UNION */
765 nl[0].n_name = LDAV_SYMBOL;
766 nl[1].n_name = 0;
767 #endif /* not NLIST_NAME_UNION */
768 #endif /* NLIST_STRUCT */
770 #ifndef SUNOS_5
771 if (nlist (KERNEL_FILE, nl) >= 0)
772 /* Omit "&& nl[0].n_type != 0 " -- it breaks on Sun386i. */
774 #ifdef FIXUP_KERNEL_SYMBOL_ADDR
775 FIXUP_KERNEL_SYMBOL_ADDR (nl);
776 #endif
777 offset = nl[0].n_value;
779 #endif /* !SUNOS_5 */
780 #else /* sgi */
781 int ldav_off;
783 ldav_off = sysmp (MP_KERNADDR, MPKA_AVENRUN);
784 if (ldav_off != -1)
785 offset = (long) ldav_off & 0x7fffffff;
786 #endif /* sgi */
789 /* Make sure we have /dev/kmem open. */
790 if (!getloadavg_initialized)
792 #ifndef SUNOS_5
793 channel = open ("/dev/kmem", 0);
794 if (channel >= 0)
795 getloadavg_initialized = 1;
796 #else /* SUNOS_5 */
797 /* We pass 0 for the kernel, corefile, and swapfile names
798 to use the currently running kernel. */
799 kd = kvm_open (0, 0, 0, O_RDONLY, 0);
800 if (kd != 0)
802 /* nlist the currently running kernel. */
803 kvm_nlist (kd, nl);
804 offset = nl[0].n_value;
805 getloadavg_initialized = 1;
807 #endif /* SUNOS_5 */
810 /* If we can, get the load average values. */
811 if (offset && getloadavg_initialized)
813 /* Try to read the load. */
814 #ifndef SUNOS_5
815 if (lseek (channel, offset, 0) == -1L
816 || read (channel, (char *) load_ave, sizeof (load_ave))
817 != sizeof (load_ave))
819 close (channel);
820 getloadavg_initialized = 0;
822 #else /* SUNOS_5 */
823 if (kvm_read (kd, offset, (char *) load_ave, sizeof (load_ave))
824 != sizeof (load_ave))
826 kvm_close (kd);
827 getloadavg_initialized = 0;
829 #endif /* SUNOS_5 */
832 if (offset == 0 || !getloadavg_initialized)
833 return -1;
834 #endif /* LOAD_AVE_TYPE and not VMS */
836 #if !defined (LDAV_DONE) && defined (LOAD_AVE_TYPE) /* Including VMS. */
837 if (nelem > 0)
838 loadavg[elem++] = LDAV_CVT (load_ave[0]);
839 if (nelem > 1)
840 loadavg[elem++] = LDAV_CVT (load_ave[1]);
841 if (nelem > 2)
842 loadavg[elem++] = LDAV_CVT (load_ave[2]);
844 #define LDAV_DONE
845 #endif /* !LDAV_DONE && LOAD_AVE_TYPE */
847 #ifdef LDAV_DONE
848 return elem;
849 #else
850 /* Set errno to zero to indicate that there was no particular error;
851 this function just can't work at all on this system. */
852 errno = 0;
853 return -1;
854 #endif
857 #endif /* ! HAVE_GETLOADAVG */
859 #ifdef TEST
860 void
861 main (argc, argv)
862 int argc;
863 char **argv;
865 int naptime = 0;
867 if (argc > 1)
868 naptime = atoi (argv[1]);
870 while (1)
872 double avg[3];
873 int loads;
875 errno = 0; /* Don't be misled if it doesn't set errno. */
876 loads = getloadavg (avg, 3);
877 if (loads == -1)
879 perror ("Error getting load average");
880 exit (1);
882 if (loads > 0)
883 printf ("1-minute: %f ", avg[0]);
884 if (loads > 1)
885 printf ("5-minute: %f ", avg[1]);
886 if (loads > 2)
887 printf ("15-minute: %f ", avg[2]);
888 if (loads > 0)
889 putchar ('\n');
891 if (naptime == 0)
892 break;
893 sleep (naptime);
896 exit (0);
898 #endif /* TEST */