]> code.delx.au - gnu-emacs/blob - src/getloadavg.c
(init_baud_rate) [USE_GETOBAUD]: Use getobaud.
[gnu-emacs] / src / getloadavg.c
1 /* Get the system load averages.
2 Copyright (C) 1985, 86, 87, 88, 89, 91, 92, 93, 1994
3 Free Software Foundation, Inc.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
18
19 /* Compile-time symbols that this file uses:
20
21 FIXUP_KERNEL_SYMBOL_ADDR() Adjust address in returned struct nlist.
22 KERNEL_FILE Pathname of the kernel to nlist.
23 LDAV_CVT() Scale the load average from the kernel.
24 Returns a double.
25 LDAV_SYMBOL Name of kernel symbol giving load average.
26 LOAD_AVE_TYPE Type of the load average array in the kernel.
27 Must be defined unless one of
28 apollo, DGUX, NeXT, or UMAX is defined;
29 otherwise, no load average is available.
30 NLIST_STRUCT Include nlist.h, not a.out.h, and
31 the nlist n_name element is a pointer,
32 not an array.
33 NLIST_NAME_UNION struct nlist has an n_un member, not n_name.
34 LINUX_LDAV_FILE [__linux__]: File containing load averages.
35
36 Specific system predefines this file uses, aside from setting
37 default values if not emacs:
38
39 apollo
40 BSD Real BSD, not just BSD-like.
41 DGUX
42 eunice UNIX emulator under VMS.
43 hpux
44 NeXT
45 sgi
46 sequent Sequent Dynix 3.x.x (BSD)
47 _SEQUENT_ Sequent DYNIX/ptx 1.x.x (SYSV)
48 sony_news NEWS-OS (works at least for 4.1C)
49 UMAX
50 UMAX4_3
51 VMS
52 __linux__ Linux: assumes /proc filesystem mounted.
53 Support from Michael K. Johnson.
54 __NetBSD__ NetBSD: assumes /kern filesystem mounted.
55
56 In addition, to avoid nesting many #ifdefs, we internally set
57 LDAV_DONE to indicate that the load average has been computed.
58
59 We also #define LDAV_PRIVILEGED if a program will require
60 special installation to be able to call getloadavg. */
61
62 #include <sys/types.h>
63
64 /* Both the Emacs and non-Emacs sections want this. Some
65 configuration files' definitions for the LOAD_AVE_CVT macro (like
66 sparc.h's) use macros like FSCALE, defined here. */
67 #ifdef unix
68 #include <sys/param.h>
69 #endif
70
71
72 #ifdef HAVE_CONFIG_H
73 #if defined (emacs) || defined (CONFIG_BROKETS)
74 /* We use <config.h> instead of "config.h" so that a compilation
75 using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
76 (which it would do because it found this file in $srcdir). */
77 #include <config.h>
78 #else
79 #include "config.h"
80 #endif
81 #endif
82
83 /* Exclude all the code except the test program at the end
84 if the system has its own `getloadavg' function.
85
86 The declaration of `errno' is needed by the test program
87 as well as the function itself, so it comes first. */
88
89 #include <errno.h>
90
91 #ifndef errno
92 extern int errno;
93 #endif
94
95 #ifndef HAVE_GETLOADAVG
96
97
98 /* The existing Emacs configuration files define a macro called
99 LOAD_AVE_CVT, which accepts a value of type LOAD_AVE_TYPE, and
100 returns the load average multiplied by 100. What we actually want
101 is a macro called LDAV_CVT, which returns the load average as an
102 unmultiplied double.
103
104 For backwards compatibility, we'll define LDAV_CVT in terms of
105 LOAD_AVE_CVT, but future machine config files should just define
106 LDAV_CVT directly. */
107
108 #if !defined(LDAV_CVT) && defined(LOAD_AVE_CVT)
109 #define LDAV_CVT(n) (LOAD_AVE_CVT (n) / 100.0)
110 #endif
111
112 #if !defined (BSD) && defined (ultrix)
113 /* Ultrix behaves like BSD on Vaxen. */
114 #define BSD
115 #endif
116
117 #ifdef NeXT
118 /* NeXT in the 2.{0,1,2} releases defines BSD in <sys/param.h>, which
119 conflicts with the definition understood in this file, that this
120 really is BSD. */
121 #undef BSD
122
123 /* NeXT defines FSCALE in <sys/param.h>. However, we take FSCALE being
124 defined to mean that the nlist method should be used, which is not true. */
125 #undef FSCALE
126 #endif
127
128 /* Set values that are different from the defaults, which are
129 set a little farther down with #ifndef. */
130
131
132 /* Some shorthands. */
133
134 #if defined (HPUX) && !defined (hpux)
135 #define hpux
136 #endif
137
138 #if defined(hp300) && !defined(hpux)
139 #define MORE_BSD
140 #endif
141
142 #if defined(ultrix) && defined(mips)
143 #define decstation
144 #endif
145
146 #if defined(sun) && defined(SVR4)
147 #define SUNOS_5
148 #endif
149
150 #if defined (__osf__) && (defined (__alpha) || defined (__alpha__))
151 #define OSF_ALPHA
152 #endif
153
154 #if defined (__osf__) && (defined (mips) || defined (__mips__))
155 #define OSF_MIPS
156 #include <sys/table.h>
157 #endif
158
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
165
166
167 /* VAX C can't handle multi-line #ifs, or lines longer than 256 chars. */
168 #ifndef LOAD_AVE_TYPE
169
170 #ifdef MORE_BSD
171 #define LOAD_AVE_TYPE long
172 #endif
173
174 #ifdef sun
175 #define LOAD_AVE_TYPE long
176 #endif
177
178 #ifdef decstation
179 #define LOAD_AVE_TYPE long
180 #endif
181
182 #ifdef _SEQUENT_
183 #define LOAD_AVE_TYPE long
184 #endif
185
186 #ifdef sgi
187 #define LOAD_AVE_TYPE long
188 #endif
189
190 #ifdef SVR4
191 #define LOAD_AVE_TYPE long
192 #endif
193
194 #ifdef sony_news
195 #define LOAD_AVE_TYPE long
196 #endif
197
198 #ifdef sequent
199 #define LOAD_AVE_TYPE long
200 #endif
201
202 #ifdef OSF_ALPHA
203 #define LOAD_AVE_TYPE long
204 #endif
205
206 #if defined (ardent) && defined (titan)
207 #define LOAD_AVE_TYPE long
208 #endif
209
210 #ifdef tek4300
211 #define LOAD_AVE_TYPE long
212 #endif
213
214 #endif /* No LOAD_AVE_TYPE. */
215
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
222
223
224 #ifndef FSCALE
225
226 /* SunOS and some others define FSCALE in sys/param.h. */
227
228 #ifdef MORE_BSD
229 #define FSCALE 2048.0
230 #endif
231
232 #if defined(MIPS) || defined(SVR4) || defined(decstation)
233 #define FSCALE 256
234 #endif
235
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
242
243 #if defined (ardent) && defined (titan)
244 #define FSCALE 65536.0
245 #endif
246
247 #ifdef tek4300
248 #define FSCALE 100.0
249 #endif
250
251 #endif /* Not FSCALE. */
252
253 #if !defined (LDAV_CVT) && defined (FSCALE)
254 #define LDAV_CVT(n) (((double) (n)) / FSCALE)
255 #endif
256
257 /* VAX C can't handle multi-line #ifs, or lines longer that 256 characters. */
258 #ifndef NLIST_STRUCT
259
260 #ifdef MORE_BSD
261 #define NLIST_STRUCT
262 #endif
263
264 #ifdef sun
265 #define NLIST_STRUCT
266 #endif
267
268 #ifdef decstation
269 #define NLIST_STRUCT
270 #endif
271
272 #ifdef hpux
273 #define NLIST_STRUCT
274 #endif
275
276 #if defined (_SEQUENT_) || defined (sequent)
277 #define NLIST_STRUCT
278 #endif
279
280 #ifdef sgi
281 #define NLIST_STRUCT
282 #endif
283
284 #ifdef SVR4
285 #define NLIST_STRUCT
286 #endif
287
288 #ifdef sony_news
289 #define NLIST_STRUCT
290 #endif
291
292 #ifdef OSF_ALPHA
293 #define NLIST_STRUCT
294 #endif
295
296 #if defined (ardent) && defined (titan)
297 #define NLIST_STRUCT
298 #endif
299
300 #ifdef tex4300
301 #define NLIST_STRUCT
302 #endif
303
304 #ifdef butterfly
305 #define NLIST_STRUCT
306 #endif
307
308 #endif /* defined (NLIST_STRUCT) */
309
310
311 #if defined(sgi) || (defined(mips) && !defined(BSD))
312 #define FIXUP_KERNEL_SYMBOL_ADDR(nl) ((nl)[0].n_value &= ~(1 << 31))
313 #endif
314
315
316 #if !defined (KERNEL_FILE) && defined (sequent)
317 #define KERNEL_FILE "/dynix"
318 #endif
319
320 #if !defined (KERNEL_FILE) && defined (hpux)
321 #define KERNEL_FILE "/hp-ux"
322 #endif
323
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
327
328
329 #if !defined (LDAV_SYMBOL) && defined (alliant)
330 #define LDAV_SYMBOL "_Loadavg"
331 #endif
332
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
336
337 #ifdef HAVE_UNISTD_H
338 #include <unistd.h>
339 #endif
340
341 #include <stdio.h>
342
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
348
349 #ifdef LOAD_AVE_TYPE
350
351 #ifndef VMS
352 #ifndef NLIST_STRUCT
353 #include <a.out.h>
354 #else /* NLIST_STRUCT */
355 #include <nlist.h>
356 #endif /* NLIST_STRUCT */
357
358 #ifdef SUNOS_5
359 #include <fcntl.h>
360 #include <kvm.h>
361 #endif
362
363 #ifndef KERNEL_FILE
364 #define KERNEL_FILE "/vmunix"
365 #endif /* KERNEL_FILE */
366
367 #ifndef LDAV_SYMBOL
368 #define LDAV_SYMBOL "_avenrun"
369 #endif /* LDAV_SYMBOL */
370
371 #else /* VMS */
372
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 */
380
381 #ifndef LDAV_CVT
382 #define LDAV_CVT(n) ((double) (n))
383 #endif /* !LDAV_CVT */
384
385 #endif /* LOAD_AVE_TYPE */
386
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 */
394
395 #ifdef sgi
396 #include <sys/sysmp.h>
397 #endif /* sgi */
398
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>
405
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 */
421
422 #ifdef DGUX
423 #include <sys/dg_sys_info.h>
424 #endif
425
426 #if defined(HAVE_FCNTL_H) || defined(_POSIX_VERSION)
427 #include <fcntl.h>
428 #else
429 #include <sys/file.h>
430 #endif
431 \f
432 /* Avoid static vars inside a function since in HPUX they dump as pure. */
433
434 #ifdef NeXT
435 static processor_set_t default_set;
436 static int getloadavg_initialized;
437 #endif /* NeXT */
438
439 #ifdef UMAX
440 static unsigned int cpus = 0;
441 static unsigned int samples;
442 #endif /* UMAX */
443
444 #ifdef DGUX
445 static struct dg_sys_info_load_info load_info; /* what-a-mouthful! */
446 #endif /* DGUX */
447
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;
455
456 #if !defined(VMS) && !defined(sgi)
457 static struct nlist nl[2];
458 #endif /* Not VMS or sgi */
459
460 #ifdef SUNOS_5
461 static kvm_t *kd;
462 #endif /* SUNOS_5 */
463
464 #endif /* LOAD_AVE_TYPE */
465 \f
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. */
470
471 int
472 getloadavg (loadavg, nelem)
473 double loadavg[];
474 int nelem;
475 {
476 int elem = 0; /* Return value. */
477
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
485
486 #if !defined (LDAV_DONE) && defined (__linux__)
487 #define LDAV_DONE
488 #undef LOAD_AVE_TYPE
489
490 #ifndef LINUX_LDAV_FILE
491 #define LINUX_LDAV_FILE "/proc/loadavg"
492 #endif
493
494 char ldavgbuf[40];
495 double load_ave[3];
496 int fd, count;
497
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;
505
506 count = sscanf (ldavgbuf, "%lf %lf %lf",
507 &load_ave[0], &load_ave[1], &load_ave[2]);
508 if (count < 1)
509 return -1;
510
511 for (elem = 0; elem < nelem && elem < count; elem++)
512 loadavg[elem] = load_ave[elem];
513
514 return elem;
515
516 #endif /* __linux__ */
517
518 #if !defined (LDAV_DONE) && defined (__NetBSD__)
519 #define LDAV_DONE
520 #undef LOAD_AVE_TYPE
521
522 #ifndef NETBSD_LDAV_FILE
523 #define NETBSD_LDAV_FILE "/kern/loadavg"
524 #endif
525
526 unsigned long int load_ave[3], scale;
527 int count;
528 FILE *fp;
529
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;
539
540 for (elem = 0; elem < nelem; elem++)
541 loadavg[elem] = (double) load_ave[elem] / (double) scale;
542
543 return elem;
544
545 #endif /* __NetBSD__ */
546
547 #if !defined (LDAV_DONE) && defined (NeXT)
548 #define LDAV_DONE
549 /* The NeXT code was adapted from iscreen 3.2. */
550
551 host_t host;
552 struct processor_set_basic_info info;
553 unsigned info_count;
554
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. */
557
558 if (!getloadavg_initialized)
559 {
560 if (processor_set_default (host_self (), &default_set) == KERN_SUCCESS)
561 getloadavg_initialized = 1;
562 }
563
564 if (getloadavg_initialized)
565 {
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
572 {
573 if (nelem > 0)
574 loadavg[elem++] = (double) info.load_average / LOAD_SCALE;
575 }
576 }
577
578 if (!getloadavg_initialized)
579 return -1;
580 #endif /* NeXT */
581
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. */
588
589 struct proc_summary proc_sum_data;
590 struct stat_descr proc_info;
591 double load;
592 register unsigned int i, j;
593
594 if (cpus == 0)
595 {
596 register unsigned int c, i;
597 struct cpu_config conf;
598 struct stat_descr desc;
599
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;
605
606 if (inq_stats (1, &desc))
607 return -1;
608
609 c = 0;
610 for (i = 0; i < conf.config_maxclass; ++i)
611 {
612 struct class_stats stats;
613 bzero ((char *) &stats, sizeof stats);
614
615 desc.sd_type = CPUTYPE_CLASS;
616 desc.sd_objid = i;
617 desc.sd_addr = (char *) &stats;
618 desc.sd_size = sizeof stats;
619
620 if (inq_stats (1, &desc))
621 return -1;
622
623 c += stats.class_numcpus;
624 }
625 cpus = c;
626 samples = cpus < 2 ? 3 : (2 * cpus / 3);
627 }
628
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;
635
636 if (inq_stats (1, &proc_info) != 0)
637 return -1;
638
639 load = proc_sum_data.ps_nrunnable;
640 j = 0;
641 for (i = samples - 1; i > 0; --i)
642 {
643 load += proc_sum_data.ps_nrun[j];
644 if (j++ == PS_NRUNSIZE)
645 j = 0;
646 }
647
648 if (nelem > 0)
649 loadavg[elem++] = load / samples / cpus;
650 #endif /* UMAX */
651
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);
660
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 */
668
669 #if !defined (LDAV_DONE) && defined (apollo)
670 #define LDAV_DONE
671 /* Apollo code from lisch@mentorg.com (Ray Lischner).
672
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.
677
678 I'm not sure which operating system first supported this system call,
679 but I know that SR10.2 supports it. */
680
681 extern void proc1_$get_loadav ();
682 unsigned long load_ave[3];
683
684 proc1_$get_loadav (load_ave);
685
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 */
693
694 #if !defined (LDAV_DONE) && defined (OSF_MIPS)
695 #define LDAV_DONE
696
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 */
704
705 #if !defined (LDAV_DONE) && defined (VMS)
706 /* VMS specific code -- read from the Load Ave driver. */
707
708 LOAD_AVE_TYPE load_ave[3];
709 static int getloadavg_initialized = 0;
710 #ifdef eunice
711 struct
712 {
713 int dsc$w_length;
714 char *dsc$a_pointer;
715 } descriptor;
716 #endif
717
718 /* Ensure that there is a channel open to the load ave device. */
719 if (!getloadavg_initialized)
720 {
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;
730 }
731
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))
736 {
737 sys$dassgn (channel);
738 getloadavg_initialized = 0;
739 }
740
741 if (!getloadavg_initialized)
742 return -1;
743 #endif /* VMS */
744
745 #if !defined (LDAV_DONE) && defined(LOAD_AVE_TYPE) && !defined(VMS)
746
747 /* UNIX-specific code -- read the average from /dev/kmem. */
748
749 #define LDAV_PRIVILEGED /* This code requires special installation. */
750
751 LOAD_AVE_TYPE load_ave[3];
752
753 /* Get the address of LDAV_SYMBOL. */
754 if (offset == 0)
755 {
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 */
769
770 #ifndef SUNOS_5
771 if (nlist (KERNEL_FILE, nl) >= 0)
772 /* Omit "&& nl[0].n_type != 0 " -- it breaks on Sun386i. */
773 {
774 #ifdef FIXUP_KERNEL_SYMBOL_ADDR
775 FIXUP_KERNEL_SYMBOL_ADDR (nl);
776 #endif
777 offset = nl[0].n_value;
778 }
779 #endif /* !SUNOS_5 */
780 #else /* sgi */
781 int ldav_off;
782
783 ldav_off = sysmp (MP_KERNADDR, MPKA_AVENRUN);
784 if (ldav_off != -1)
785 offset = (long) ldav_off & 0x7fffffff;
786 #endif /* sgi */
787 }
788
789 /* Make sure we have /dev/kmem open. */
790 if (!getloadavg_initialized)
791 {
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)
801 {
802 /* nlist the currently running kernel. */
803 kvm_nlist (kd, nl);
804 offset = nl[0].n_value;
805 getloadavg_initialized = 1;
806 }
807 #endif /* SUNOS_5 */
808 }
809
810 /* If we can, get the load average values. */
811 if (offset && getloadavg_initialized)
812 {
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))
818 {
819 close (channel);
820 getloadavg_initialized = 0;
821 }
822 #else /* SUNOS_5 */
823 if (kvm_read (kd, offset, (char *) load_ave, sizeof (load_ave))
824 != sizeof (load_ave))
825 {
826 kvm_close (kd);
827 getloadavg_initialized = 0;
828 }
829 #endif /* SUNOS_5 */
830 }
831
832 if (offset == 0 || !getloadavg_initialized)
833 return -1;
834 #endif /* LOAD_AVE_TYPE and not VMS */
835
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]);
843
844 #define LDAV_DONE
845 #endif /* !LDAV_DONE && LOAD_AVE_TYPE */
846
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
855 }
856
857 #endif /* ! HAVE_GETLOADAVG */
858 \f
859 #ifdef TEST
860 void
861 main (argc, argv)
862 int argc;
863 char **argv;
864 {
865 int naptime = 0;
866
867 if (argc > 1)
868 naptime = atoi (argv[1]);
869
870 while (1)
871 {
872 double avg[3];
873 int loads;
874
875 errno = 0; /* Don't be misled if it doesn't set errno. */
876 loads = getloadavg (avg, 3);
877 if (loads == -1)
878 {
879 perror ("Error getting load average");
880 exit (1);
881 }
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');
890
891 if (naptime == 0)
892 break;
893 sleep (naptime);
894 }
895
896 exit (0);
897 }
898 #endif /* TEST */