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