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