comparison src/getloadavg.c @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children 0293115a14e9
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 /* Get the system load averages.
2 Copyright (C) 1985, 1986, 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995
3 Free Software Foundation, Inc.
4
5 This file is part of XEmacs.
6
7 XEmacs is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
10 later version.
11
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with XEmacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22 /* Synched up with: FSF 19.31. */
23
24 /* Compile-time symbols that this file uses:
25
26 FIXUP_KERNEL_SYMBOL_ADDR() Adjust address in returned struct nlist.
27 KERNEL_FILE Pathname of the kernel to nlist.
28 LDAV_CVT() Scale the load average from the kernel.
29 Returns a double.
30 LDAV_SYMBOL Name of kernel symbol giving load average.
31 LOAD_AVE_TYPE Type of the load average array in the kernel.
32 Must be defined unless one of
33 apollo, DGUX, NeXT, or UMAX is defined;
34 otherwise, no load average is available.
35 Does not need to be defined if HPUX is
36 defined and HPUX_PRE_8_0 is not defined.
37 NLIST_STRUCT Include nlist.h, not a.out.h, and
38 the nlist n_name element is a pointer,
39 not an array.
40 NLIST_NAME_UNION struct nlist has an n_un member, not n_name.
41 LINUX_LDAV_FILE [__linux__]: File containing load averages.
42
43 Specific system predefines this file uses, aside from setting
44 default values if not emacs:
45
46 apollo
47 BSD Real BSD, not just BSD-like.
48 convex
49 DGUX
50 eunice UNIX emulator under VMS.
51 hpux
52 MSDOS No-op for MSDOS.
53 NeXT
54 sgi
55 sequent Sequent Dynix 3.x.x (BSD)
56 _SEQUENT_ Sequent DYNIX/ptx 1.x.x (SYSV)
57 sony_news NEWS-OS (works at least for 4.1C)
58 UMAX
59 UMAX4_3
60 VMS
61 WIN32 No-op for Windows95/NT.
62 __linux__ Linux: assumes /proc filesystem mounted.
63 Support from Michael K. Johnson.
64 __NetBSD__ NetBSD: assumes /kern filesystem mounted.
65
66 In addition, to avoid nesting many #ifdefs, we internally set
67 LDAV_DONE to indicate that the load average has been computed.
68
69 We also #define LDAV_PRIVILEGED if a program will require
70 special installation to be able to call getloadavg. */
71
72 /* This should always be first. */
73 #ifdef HAVE_CONFIG_H
74 #include <config.h>
75 #endif
76
77 #include <sys/types.h>
78
79 /* Both the Emacs and non-Emacs sections want this. Some
80 configuration files' definitions for the LOAD_AVE_CVT macro (like
81 sparc.h's) use macros like FSCALE, defined here. */
82 #ifdef unix
83 #include <sys/param.h>
84 #endif
85
86
87 #ifdef emacs
88 #include "lisp.h" /* for encapsulated open, close, read, write */
89 #endif
90
91 /* Exclude all the code except the test program at the end
92 if the system has its own `getloadavg' function.
93
94 The declaration of `errno' is needed by the test program
95 as well as the function itself, so it comes first. */
96
97 #include <errno.h>
98
99 #ifndef errno
100 extern int errno;
101 #endif
102
103 #ifndef HAVE_GETLOADAVG
104
105 /* The existing Emacs configuration files define a macro called
106 LOAD_AVE_CVT, which accepts a value of type LOAD_AVE_TYPE, and
107 returns the load average multiplied by 100. What we actually want
108 is a macro called LDAV_CVT, which returns the load average as an
109 unmultiplied double.
110
111 For backwards compatibility, we'll define LDAV_CVT in terms of
112 LOAD_AVE_CVT, but future machine config files should just define
113 LDAV_CVT directly. */
114
115 #if !defined(LDAV_CVT) && defined(LOAD_AVE_CVT)
116 #define LDAV_CVT(n) (LOAD_AVE_CVT (n) / 100.0)
117 #endif
118
119 #if !defined (BSD) && defined (ultrix)
120 /* Ultrix behaves like BSD on Vaxen. */
121 #define BSD
122 #endif
123
124 #ifdef NeXT
125 /* NeXT in the 2.{0,1,2} releases defines BSD in <sys/param.h>, which
126 conflicts with the definition understood in this file, that this
127 really is BSD. */
128 #undef BSD
129
130 /* NeXT defines FSCALE in <sys/param.h>. However, we take FSCALE being
131 defined to mean that the nlist method should be used, which is not true. */
132 #undef FSCALE
133 #endif
134
135 /* Set values that are different from the defaults, which are
136 set a little farther down with #ifndef. */
137
138
139 /* Some shorthands. */
140
141 #if defined (HPUX) && !defined (hpux)
142 #define hpux
143 #endif
144
145 #if defined(hp300) && !defined(hpux)
146 #define MORE_BSD
147 #endif
148
149 #if defined(ultrix) && defined(mips)
150 #define decstation
151 #endif
152
153 #if defined(sun) && defined(USG)
154 #define SUNOS_5
155 #endif
156
157 #if defined (__osf__) && (defined (__alpha) || defined (__alpha__))
158 #define OSF_ALPHA
159 #include <sys/table.h>
160 #endif
161
162 #if defined (__osf__) && (defined (mips) || defined (__mips__))
163 #define OSF_MIPS
164 #include <sys/table.h>
165 #endif
166
167 /* UTek's /bin/cc on the 4300 has no architecture specific cpp define by
168 default, but _MACH_IND_SYS_TYPES is defined in <sys/types.h>. Combine
169 that with a couple of other things and we'll have a unique match. */
170 #if !defined (tek4300) && defined (unix) && defined (m68k) && defined (mc68000) && defined (mc68020) && defined (_MACH_IND_SYS_TYPES)
171 #define tek4300 /* Define by emacs, but not by other users. */
172 #endif
173
174
175 /* VAX C can't handle multi-line #ifs, or lines longer than 256 chars. */
176 #ifndef LOAD_AVE_TYPE
177
178 #ifdef MORE_BSD
179 #define LOAD_AVE_TYPE long
180 #endif
181
182 #ifdef sun
183 #define LOAD_AVE_TYPE long
184 #endif
185
186 #ifdef decstation
187 #define LOAD_AVE_TYPE long
188 #endif
189
190 #ifdef _SEQUENT_
191 #define LOAD_AVE_TYPE long
192 #endif
193
194 #ifdef sgi
195 #define LOAD_AVE_TYPE long
196 #endif
197
198 #ifdef SVR4
199 #define LOAD_AVE_TYPE long
200 #endif
201
202 #ifdef sony_news
203 #define LOAD_AVE_TYPE long
204 #endif
205
206 #ifdef sequent
207 #define LOAD_AVE_TYPE long
208 #endif
209
210 #ifdef OSF_ALPHA
211 #define LOAD_AVE_TYPE long
212 #endif
213
214 #if defined (ardent) && defined (titan)
215 #define LOAD_AVE_TYPE long
216 #endif
217
218 #ifdef tek4300
219 #define LOAD_AVE_TYPE long
220 #endif
221
222 #if defined(alliant) && defined(i860) /* Alliant FX/2800 */
223 #define LOAD_AVE_TYPE long
224 #endif
225
226 #ifdef _AIX
227 #define LOAD_AVE_TYPE long
228 #endif
229
230 #ifdef convex
231 #define LOAD_AVE_TYPE double
232 #ifndef LDAV_CVT
233 #define LDAV_CVT(n) (n)
234 #endif
235 #endif
236
237 #endif /* No LOAD_AVE_TYPE. */
238
239 #ifdef OSF_ALPHA
240 /* <sys/param.h> defines an incorrect value for FSCALE on Alpha OSF/1,
241 according to ghazi@noc.rutgers.edu. */
242 #undef FSCALE
243 #define FSCALE 1024.0
244 #endif
245
246 #if defined(alliant) && defined(i860) /* Alliant FX/2800 */
247 /* <sys/param.h> defines an incorrect value for FSCALE on an
248 Alliant FX/2800 Concentrix 2.2, according to ghazi@noc.rutgers.edu. */
249 #undef FSCALE
250 #define FSCALE 100.0
251 #endif
252
253
254 #ifndef FSCALE
255
256 /* SunOS and some others define FSCALE in sys/param.h. */
257
258 #ifdef MORE_BSD
259 #define FSCALE 2048.0
260 #endif
261
262 #if defined(MIPS) || defined(SVR4) || defined(decstation)
263 #define FSCALE 256
264 #endif
265
266 #if defined (sgi) || defined (sequent)
267 /* Sometimes both MIPS and sgi are defined, so FSCALE was just defined
268 above under #ifdef MIPS. But we want the sgi value. */
269 #undef FSCALE
270 #define FSCALE 1000.0
271 #endif
272
273 #if defined (ardent) && defined (titan)
274 #define FSCALE 65536.0
275 #endif
276
277 #ifdef tek4300
278 #define FSCALE 100.0
279 #endif
280
281 #ifdef _AIX
282 #define FSCALE 65536.0
283 #endif
284
285 #endif /* Not FSCALE. */
286
287 #if !defined (LDAV_CVT) && defined (FSCALE)
288 #define LDAV_CVT(n) (((double) (n)) / FSCALE)
289 #endif
290
291 /* VAX C can't handle multi-line #ifs, or lines longer that 256 characters. */
292 #ifndef NLIST_STRUCT
293
294 /* XEmacs addition */
295 #ifdef _AIX
296 #define NLIST_STRUCT
297 #endif
298
299 #ifdef MORE_BSD
300 #define NLIST_STRUCT
301 #endif
302
303 #ifdef sun
304 #define NLIST_STRUCT
305 #endif
306
307 #ifdef decstation
308 #define NLIST_STRUCT
309 #endif
310
311 #ifdef hpux
312 #define NLIST_STRUCT
313 #endif
314
315 #if defined (_SEQUENT_) || defined (sequent)
316 #define NLIST_STRUCT
317 #endif
318
319 #ifdef sgi
320 #define NLIST_STRUCT
321 #endif
322
323 #ifdef SVR4
324 #define NLIST_STRUCT
325 #endif
326
327 #ifdef sony_news
328 #define NLIST_STRUCT
329 #endif
330
331 #ifdef OSF_ALPHA
332 #define NLIST_STRUCT
333 #endif
334
335 #if defined (ardent) && defined (titan)
336 #define NLIST_STRUCT
337 #endif
338
339 #ifdef tek4300
340 #define NLIST_STRUCT
341 #endif
342
343 #ifdef butterfly
344 #define NLIST_STRUCT
345 #endif
346
347 #if defined(alliant) && defined(i860) /* Alliant FX/2800 */
348 #define NLIST_STRUCT
349 #endif
350
351 #ifdef _AIX
352 #define NLIST_STRUCT
353 #endif
354
355 #endif /* defined (NLIST_STRUCT) */
356
357
358 #if defined(sgi) || (defined(mips) && !defined(BSD))
359 #define FIXUP_KERNEL_SYMBOL_ADDR(nl) ((nl)[0].n_value &= ~(1 << 31))
360 #endif
361
362
363 #if !defined (KERNEL_FILE) && defined (sequent)
364 #define KERNEL_FILE "/dynix"
365 #endif
366
367 #if !defined (KERNEL_FILE) && defined (hpux)
368 #define KERNEL_FILE "/hp-ux"
369 #endif
370
371 #if !defined(KERNEL_FILE) && (defined(_SEQUENT_) || defined(MIPS) || defined(SVR4) || defined(ISC) || defined (sgi) || defined(SVR4) || (defined (ardent) && defined (titan)))
372 #define KERNEL_FILE "/unix"
373 #endif
374
375
376 #if !defined (LDAV_SYMBOL) && defined (alliant)
377 #define LDAV_SYMBOL "_Loadavg"
378 #endif
379
380 #if !defined(LDAV_SYMBOL) && ((defined(hpux) && !defined(hp9000s300)) || defined(_SEQUENT_) || defined(SVR4) || defined(ISC) || defined(sgi) || (defined (ardent) && defined (titan)) || defined (_AIX))
381 #define LDAV_SYMBOL "avenrun"
382 #endif
383
384 #include <stdlib.h>
385 #include <unistd.h>
386
387 #include <stdio.h>
388
389 /* LOAD_AVE_TYPE should only get defined if we're going to use the
390 nlist method. */
391 #if !defined(LOAD_AVE_TYPE) && (defined(BSD) || defined(LDAV_CVT) || defined(KERNEL_FILE) || defined(LDAV_SYMBOL))
392 #define LOAD_AVE_TYPE double
393 #endif
394
395 #ifdef LOAD_AVE_TYPE
396
397 #ifndef VMS
398 #ifndef NLIST_STRUCT
399 #include <a.out.h>
400 #else /* NLIST_STRUCT */
401 #include <nlist.h>
402 #endif /* NLIST_STRUCT */
403
404 #ifdef SUNOS_5
405 #include <fcntl.h>
406 #include <kvm.h>
407 #endif
408
409 #ifndef KERNEL_FILE
410 #define KERNEL_FILE "/vmunix"
411 #endif /* KERNEL_FILE */
412
413 #ifndef LDAV_SYMBOL
414 #define LDAV_SYMBOL "_avenrun"
415 #endif /* LDAV_SYMBOL */
416
417 #else /* VMS */
418
419 #ifndef eunice
420 #include <iodef.h>
421 #include <descrip.h>
422 #else /* eunice */
423 #include <vms/iodef.h>
424 #endif /* eunice */
425 #endif /* VMS */
426
427 #ifndef LDAV_CVT
428 #define LDAV_CVT(n) ((double) (n))
429 #endif /* !LDAV_CVT */
430
431 #endif /* LOAD_AVE_TYPE */
432
433 #ifdef NeXT
434 /* This undef is needed to shut up the NeXT compiler about a stupid
435 non-problem. */
436 #undef index
437 #ifdef HAVE_MACH_MACH_H
438 #include <mach/mach.h>
439 #else
440 #include <mach.h>
441 #endif
442 #endif /* NeXT */
443
444 #ifdef sgi
445 #include <sys/sysmp.h>
446 #endif /* sgi */
447
448 #ifdef UMAX
449 #include <stdio.h>
450 #include <signal.h>
451 #include <sys/time.h>
452 #include <sys/wait.h>
453 #include <sys/syscall.h>
454
455 #ifdef UMAX_43
456 #include <machine/cpu.h>
457 #include <inq_stats/statistics.h>
458 #include <inq_stats/sysstats.h>
459 #include <inq_stats/cpustats.h>
460 #include <inq_stats/procstats.h>
461 #else /* Not UMAX_43. */
462 #include <sys/sysdefs.h>
463 #include <sys/statistics.h>
464 #include <sys/sysstats.h>
465 #include <sys/cpudefs.h>
466 #include <sys/cpustats.h>
467 #include <sys/procstats.h>
468 #endif /* Not UMAX_43. */
469 #endif /* UMAX */
470
471 #ifdef DGUX
472 #include <sys/dg_sys_info.h>
473 #endif
474
475 /* XEmacs addition */
476 #if !defined(LDAV_DONE) && defined(HPUX) && !defined (HPUX_PRE_8_0)
477 #include <sys/pstat.h>
478 #endif
479
480 #if defined(HAVE_FCNTL_H) || defined(_POSIX_VERSION)
481 #include <fcntl.h>
482 #else
483 #include <sys/file.h>
484 #endif
485
486 /* Avoid static vars inside a function since in HPUX they dump as pure. */
487
488 #ifdef NeXT
489 static processor_set_t default_set;
490 static int getloadavg_initialized;
491 #endif /* NeXT */
492
493 #ifdef UMAX
494 static unsigned int cpus = 0;
495 static unsigned int samples;
496 #endif /* UMAX */
497
498 #ifdef DGUX
499 static struct dg_sys_info_load_info load_info; /* what-a-mouthful! */
500 #endif /* DGUX */
501
502 #ifdef LOAD_AVE_TYPE
503 #if defined (VMS) || !defined (SUNOS_5)
504 /* File descriptor open to /dev/kmem or VMS load ave driver. */
505 static int channel;
506 #endif /* VMS || !SUNOS_5 */
507 /* Nonzero iff channel is valid. */
508 static int getloadavg_initialized;
509 /* Offset in kmem to seek to read load average, or 0 means invalid. */
510 static long offset;
511
512 #if !defined(VMS) && !defined(sgi)
513 static struct nlist nl[2];
514 #endif /* Not VMS or sgi */
515
516 #ifdef SUNOS_5
517 static kvm_t *kd;
518 #endif /* SUNOS_5 */
519
520 #endif /* LOAD_AVE_TYPE */
521
522 /* Put the 1 minute, 5 minute and 15 minute load averages
523 into the first NELEM elements of LOADAVG.
524 Return the number written (never more than 3, but may be less than NELEM),
525 or -1 if an error occurred. */
526
527 int
528 getloadavg (double loadavg[], int nelem)
529 {
530 int elem = 0; /* Return value. */
531
532 #ifdef NO_GET_LOAD_AVG
533 #define LDAV_DONE
534 /* Set errno to zero to indicate that there was no particular error;
535 this function just can't work at all on this system. */
536 errno = 0;
537 elem = -1;
538 #endif
539
540 #if !defined (LDAV_DONE) && defined (__linux__)
541 #define LDAV_DONE
542 #undef LOAD_AVE_TYPE
543
544 #ifndef LINUX_LDAV_FILE
545 #define LINUX_LDAV_FILE "/proc/loadavg"
546 #endif
547
548 char ldavgbuf[40];
549 double load_ave[3];
550 int fd, count;
551
552 fd = open (LINUX_LDAV_FILE, O_RDONLY);
553 if (fd == -1)
554 return -1;
555 count = read (fd, ldavgbuf, 40);
556 (void) close (fd);
557 if (count <= 0)
558 return -1;
559
560 count = sscanf (ldavgbuf, "%lf %lf %lf",
561 &load_ave[0], &load_ave[1], &load_ave[2]);
562 if (count < 1)
563 return -1;
564
565 for (elem = 0; elem < nelem && elem < count; elem++)
566 loadavg[elem] = load_ave[elem];
567
568 return elem;
569
570 #endif /* __linux__ */
571
572 #if !defined (LDAV_DONE) && defined (__NetBSD__)
573 #define LDAV_DONE
574 #undef LOAD_AVE_TYPE
575
576 #ifndef NETBSD_LDAV_FILE
577 #define NETBSD_LDAV_FILE "/kern/loadavg"
578 #endif
579
580 unsigned long int load_ave[3], scale;
581 int count;
582 FILE *fp;
583
584 fp = fopen (NETBSD_LDAV_FILE, "r");
585 if (fp == NULL)
586 return -1;
587 count = fscanf (fp, "%lu %lu %lu %lu\n",
588 &load_ave[0], &load_ave[1], &load_ave[2],
589 &scale);
590 (void) fclose (fp);
591 if (count != 4)
592 return -1;
593
594 for (elem = 0; elem < nelem; elem++)
595 loadavg[elem] = (double) load_ave[elem] / (double) scale;
596
597 return elem;
598
599 #endif /* __NetBSD__ */
600
601 #if !defined (LDAV_DONE) && defined (NeXT)
602 #define LDAV_DONE
603 /* The NeXT code was adapted from iscreen 3.2. */
604
605 host_t host;
606 struct processor_set_basic_info info;
607 unsigned info_count;
608
609 if (nelem > 1)
610 {
611 /* We only know how to get the 1-minute average for this system. */
612 errno = EINVAL;
613 return -1;
614 }
615
616 if (!getloadavg_initialized)
617 {
618 if (processor_set_default (host_self (), &default_set) == KERN_SUCCESS)
619 getloadavg_initialized = 1;
620 }
621
622 if (getloadavg_initialized)
623 {
624 info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
625 if (processor_set_info (default_set, PROCESSOR_SET_BASIC_INFO, &host,
626 (processor_set_info_t) &info, &info_count)
627 != KERN_SUCCESS)
628 getloadavg_initialized = 0;
629 else
630 {
631 if (nelem > 0)
632 loadavg[elem++] = (double) info.load_average / LOAD_SCALE;
633 }
634 }
635
636 if (!getloadavg_initialized)
637 return -1;
638 #endif /* NeXT */
639
640 #if !defined (LDAV_DONE) && defined (UMAX)
641 #define LDAV_DONE
642 /* UMAX 4.2, which runs on the Encore Multimax multiprocessor, does not
643 have a /dev/kmem. Information about the workings of the running kernel
644 can be gathered with inq_stats system calls.
645 We only know how to get the 1-minute average for this system. */
646
647 struct proc_summary proc_sum_data;
648 struct stat_descr proc_info;
649 double load;
650 unsigned int i, j;
651
652 if (cpus == 0)
653 {
654 unsigned int c, i;
655 struct cpu_config conf;
656 struct stat_descr desc;
657
658 desc.sd_next = 0;
659 desc.sd_subsys = SUBSYS_CPU;
660 desc.sd_type = CPUTYPE_CONFIG;
661 desc.sd_addr = (char *) &conf;
662 desc.sd_size = sizeof conf;
663
664 if (inq_stats (1, &desc))
665 return -1;
666
667 c = 0;
668 for (i = 0; i < conf.config_maxclass; ++i)
669 {
670 struct class_stats stats;
671 bzero ((char *) &stats, sizeof stats);
672
673 desc.sd_type = CPUTYPE_CLASS;
674 desc.sd_objid = i;
675 desc.sd_addr = (char *) &stats;
676 desc.sd_size = sizeof stats;
677
678 if (inq_stats (1, &desc))
679 return -1;
680
681 c += stats.class_numcpus;
682 }
683 cpus = c;
684 samples = cpus < 2 ? 3 : (2 * cpus / 3);
685 }
686
687 proc_info.sd_next = 0;
688 proc_info.sd_subsys = SUBSYS_PROC;
689 proc_info.sd_type = PROCTYPE_SUMMARY;
690 proc_info.sd_addr = (char *) &proc_sum_data;
691 proc_info.sd_size = sizeof (struct proc_summary);
692 proc_info.sd_sizeused = 0;
693
694 if (inq_stats (1, &proc_info) != 0)
695 return -1;
696
697 load = proc_sum_data.ps_nrunnable;
698 j = 0;
699 for (i = samples - 1; i > 0; --i)
700 {
701 load += proc_sum_data.ps_nrun[j];
702 if (j++ == PS_NRUNSIZE)
703 j = 0;
704 }
705
706 if (nelem > 0)
707 loadavg[elem++] = load / samples / cpus;
708 #endif /* UMAX */
709
710 #if !defined (LDAV_DONE) && defined (DGUX)
711 #define LDAV_DONE
712 /* This call can return -1 for an error, but with good args
713 it's not supposed to fail. The first argument is for no
714 apparent reason of type `long int *'. */
715 dg_sys_info ((long int *) &load_info,
716 DG_SYS_INFO_LOAD_INFO_TYPE,
717 DG_SYS_INFO_LOAD_VERSION_0);
718
719 if (nelem > 0)
720 loadavg[elem++] = load_info.one_minute;
721 if (nelem > 1)
722 loadavg[elem++] = load_info.five_minute;
723 if (nelem > 2)
724 loadavg[elem++] = load_info.fifteen_minute;
725 #endif /* DGUX */
726
727 #if !defined (LDAV_DONE) && defined (apollo)
728 #define LDAV_DONE
729 /* Apollo code from lisch@mentorg.com (Ray Lischner).
730
731 This system call is not documented. The load average is obtained as
732 three long integers, for the load average over the past minute,
733 five minutes, and fifteen minutes. Each value is a scaled integer,
734 with 16 bits of integer part and 16 bits of fraction part.
735
736 I'm not sure which operating system first supported this system call,
737 but I know that SR10.2 supports it. */
738
739 extern void proc1_$get_loadav ();
740 unsigned long load_ave[3];
741
742 proc1_$get_loadav (load_ave);
743
744 if (nelem > 0)
745 loadavg[elem++] = load_ave[0] / 65536.0;
746 if (nelem > 1)
747 loadavg[elem++] = load_ave[1] / 65536.0;
748 if (nelem > 2)
749 loadavg[elem++] = load_ave[2] / 65536.0;
750 #endif /* apollo */
751
752 #if !defined (LDAV_DONE) && defined (OSF_MIPS)
753 #define LDAV_DONE
754
755 struct tbl_loadavg load_ave;
756 table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
757 while (elem < nelem && elem < 3)
758 {
759 loadavg[elem++] = (load_ave.tl_lscale == 0
760 ? load_ave.tl_avenrun.d[0]
761 : (load_ave.tl_avenrun.l[0] / (double) load_ave.tl_lscale));
762 }
763 #endif /* OSF_MIPS */
764
765 #if !defined (LDAV_DONE) && (defined (MSDOS) || defined (WIN32))
766 #define LDAV_DONE
767
768 /* A faithful emulation is going to have to be saved for a rainy day. */
769 for ( ; elem < nelem; elem++)
770 {
771 loadavg[elem] = 0.0;
772 }
773 #endif /* MSDOS */
774
775 #if !defined (LDAV_DONE) && defined (OSF_ALPHA)
776 #define LDAV_DONE
777
778 struct tbl_loadavg load_ave;
779 table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
780 for (elem = 0; elem < nelem; elem++)
781 loadavg[elem]
782 = (load_ave.tl_lscale == 0
783 ? load_ave.tl_avenrun.d[elem]
784 : (load_ave.tl_avenrun.l[elem] / (double) load_ave.tl_lscale));
785 #endif /* OSF_ALPHA */
786
787 #if !defined (LDAV_DONE) && defined (VMS)
788 /* VMS specific code -- read from the Load Ave driver. */
789
790 LOAD_AVE_TYPE load_ave[3];
791 static int getloadavg_initialized = 0;
792 #ifdef eunice
793 struct
794 {
795 int dsc$w_length;
796 char *dsc$a_pointer;
797 } descriptor;
798 #endif
799
800 /* Ensure that there is a channel open to the load ave device. */
801 if (!getloadavg_initialized)
802 {
803 /* Attempt to open the channel. */
804 #ifdef eunice
805 descriptor.dsc$w_length = 18;
806 descriptor.dsc$a_pointer = "$$VMS_LOAD_AVERAGE";
807 #else
808 $DESCRIPTOR (descriptor, "LAV0:");
809 #endif
810 if (sys$assign (&descriptor, &channel, 0, 0) & 1)
811 getloadavg_initialized = 1;
812 }
813
814 /* Read the load average vector. */
815 if (getloadavg_initialized
816 && !(sys$qiow (0, channel, IO$_READVBLK, 0, 0, 0,
817 load_ave, 12, 0, 0, 0, 0) & 1))
818 {
819 sys$dassgn (channel);
820 getloadavg_initialized = 0;
821 }
822
823 if (!getloadavg_initialized)
824 return -1;
825 #endif /* VMS */
826
827 #if !defined (LDAV_DONE) && defined (HPUX) && !defined (HPUX_PRE_8_0)
828 #define LDAV_DONE
829 /*
830 * This is totally undocumented, and is not guaranteed to work, but
831 * mayhap it might .... If it does work, it will work only on HP-UX
832 * 8.0 or later. -- Darryl Okahata <darrylo@sr.hp.com>
833 */
834 #undef LOAD_AVE_TYPE /* Make sure these don't exist. */
835 #undef LOAD_AVE_CVT
836 #undef LDAV_SYMBOL
837 struct pst_dynamic procinfo;
838 union pstun statbuf;
839
840 statbuf.pst_dynamic = &procinfo;
841 if (pstat (PSTAT_DYNAMIC, statbuf, sizeof (struct pst_dynamic), 0, 0) == -1)
842 return (-1);
843 loadavg[elem++] = procinfo.psd_avg_1_min;
844 loadavg[elem++] = procinfo.psd_avg_5_min;
845 loadavg[elem++] = procinfo.psd_avg_15_min;
846 #endif /* HPUX */
847
848 #if !defined (LDAV_DONE) && defined(LOAD_AVE_TYPE) && !defined(VMS)
849
850 /* UNIX-specific code -- read the average from /dev/kmem. */
851
852 #define LDAV_PRIVILEGED /* This code requires special installation. */
853
854 LOAD_AVE_TYPE load_ave[3];
855
856 /* Get the address of LDAV_SYMBOL. */
857 if (offset == 0)
858 {
859 #ifndef sgi
860 #ifndef NLIST_STRUCT
861 strcpy (nl[0].n_name, LDAV_SYMBOL);
862 strcpy (nl[1].n_name, "");
863 #else /* NLIST_STRUCT */
864 #ifdef NLIST_NAME_UNION
865 nl[0].n_un.n_name = LDAV_SYMBOL;
866 nl[1].n_un.n_name = 0;
867 #else /* not NLIST_NAME_UNION */
868 nl[0].n_name = (char *) LDAV_SYMBOL;
869 nl[1].n_name = 0;
870 #endif /* not NLIST_NAME_UNION */
871 #endif /* NLIST_STRUCT */
872
873 #ifndef SUNOS_5
874 if (
875 #if !(defined (_AIX) && !defined (ps2))
876 nlist (KERNEL_FILE, nl)
877 #else /* _AIX */
878 knlist (nl, 1, sizeof (nl[0]))
879 #endif
880 >= 0)
881 /* Omit "&& nl[0].n_type != 0 " -- it breaks on Sun386i. */
882 {
883 #ifdef FIXUP_KERNEL_SYMBOL_ADDR
884 FIXUP_KERNEL_SYMBOL_ADDR (nl);
885 #endif
886 offset = nl[0].n_value;
887 }
888 #endif /* !SUNOS_5 */
889 #else /* sgi */
890 int ldav_off;
891
892 ldav_off = sysmp (MP_KERNADDR, MPKA_AVENRUN);
893 if (ldav_off != -1)
894 offset = (long) ldav_off & 0x7fffffff;
895 #endif /* sgi */
896 }
897
898 /* Make sure we have /dev/kmem open. */
899 if (!getloadavg_initialized)
900 {
901 #ifndef SUNOS_5
902 channel = open ("/dev/kmem", 0);
903 if (channel >= 0)
904 {
905 /* Set the channel to close on exec, so it does not
906 litter any child's descriptor table. */
907 #ifdef FD_SETFD
908 #ifndef FD_CLOEXEC
909 #define FD_CLOEXEC 1
910 #endif
911 (void) fcntl (channel, F_SETFD, FD_CLOEXEC);
912 #endif
913 getloadavg_initialized = 1;
914 }
915 #else /* SUNOS_5 */
916 /* We pass 0 for the kernel, corefile, and swapfile names
917 to use the currently running kernel. */
918 kd = kvm_open (0, 0, 0, O_RDONLY, 0);
919 if (kd != 0)
920 {
921 /* nlist the currently running kernel. */
922 kvm_nlist (kd, nl);
923 offset = nl[0].n_value;
924 getloadavg_initialized = 1;
925 }
926 #endif /* SUNOS_5 */
927 }
928
929 /* If we can, get the load average values. */
930 if (offset && getloadavg_initialized)
931 {
932 /* Try to read the load. */
933 #ifndef SUNOS_5
934 if (lseek (channel, offset, 0) == -1L
935 || read (channel, (char *) load_ave, sizeof (load_ave))
936 != sizeof (load_ave))
937 {
938 close (channel);
939 getloadavg_initialized = 0;
940 }
941 #else /* SUNOS_5 */
942 if (kvm_read (kd, offset, (char *) load_ave, sizeof (load_ave))
943 != sizeof (load_ave))
944 {
945 kvm_close (kd);
946 getloadavg_initialized = 0;
947 }
948 #endif /* SUNOS_5 */
949 }
950
951 if (offset == 0 || !getloadavg_initialized)
952 return -1;
953 #endif /* LOAD_AVE_TYPE and not VMS */
954
955 #if !defined (LDAV_DONE) && defined (LOAD_AVE_TYPE) /* Including VMS. */
956 if (nelem > 0)
957 loadavg[elem++] = LDAV_CVT (load_ave[0]);
958 if (nelem > 1)
959 loadavg[elem++] = LDAV_CVT (load_ave[1]);
960 if (nelem > 2)
961 loadavg[elem++] = LDAV_CVT (load_ave[2]);
962
963 #define LDAV_DONE
964 #endif /* !LDAV_DONE && LOAD_AVE_TYPE */
965
966 #ifdef LDAV_DONE
967 return elem;
968 #else
969 /* Set errno to zero to indicate that there was no particular error;
970 this function just can't work at all on this system. */
971 errno = 0;
972 return -1;
973 #endif
974 }
975
976 #endif /* ! HAVE_GETLOADAVG */
977
978 #ifdef TEST
979 void
980 main (int argc, char **argv)
981 {
982 int naptime = 0;
983
984 if (argc > 1)
985 naptime = atoi (argv[1]);
986
987 while (1)
988 {
989 double avg[3];
990 int loads;
991
992 errno = 0; /* Don't be misled if it doesn't set errno. */
993 loads = getloadavg (avg, 3);
994 if (loads == -1)
995 {
996 perror ("Error getting load average");
997 exit (1);
998 }
999 if (loads > 0)
1000 printf ("1-minute: %f ", avg[0]);
1001 if (loads > 1)
1002 printf ("5-minute: %f ", avg[1]);
1003 if (loads > 2)
1004 printf ("15-minute: %f ", avg[2]);
1005 if (loads > 0)
1006 putchar ('\n');
1007
1008 if (naptime == 0)
1009 break;
1010 sleep (naptime);
1011 }
1012
1013 exit (0);
1014 }
1015 #endif /* TEST */