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