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