autoupdate
[gnulib.git] / lib / getloadavg.c
index 2a50131..a7bac49 100644 (file)
@@ -1,15 +1,16 @@
 /* Get the system load averages.
 
    Copyright (C) 1985, 1986, 1987, 1988, 1989, 1991, 1992, 1993, 1994,
-   1995, 1997, 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc.
+   1995, 1997, 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free
+   Software Foundation, Inc.
 
    NOTE: The canonical source of this file is maintained with gnulib.
    Bugs can be reported to bug-gnulib@gnu.org.
 
-   This program is free software; you can redistribute it and/or modify
+   This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -17,9 +18,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
-   USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 /* Compile-time symbols that this file uses:
 
@@ -31,6 +30,8 @@
                                If that isn't an option, then just put
                                AC_CHECK_FUNCS(pstat_getdynamic) in your
                                configure.in file.
+   HAVE_LIBPERFSTAT Define this if your system has the
+                               perfstat_cpu_total function in libperfstat (AIX).
    FIXUP_KERNEL_SYMBOL_ADDR()  Adjust address in returned struct nlist.
    KERNEL_FILE                 Name of the kernel file to nlist.
    LDAV_CVT()                  Scale the load average from the kernel.
@@ -43,8 +44,8 @@
                                otherwise, no load average is available.
    HAVE_NLIST_H                 nlist.h is available.  NLIST_STRUCT defaults
                                 to this.
-   NLIST_STRUCT                        Include nlist.h, not a.out.h, and
-                               the nlist n_name element is a pointer,
+   NLIST_STRUCT                        Include nlist.h, not a.out.h.
+   N_NAME_POINTER              The nlist n_name element is a pointer,
                                not an array.
    HAVE_STRUCT_NLIST_N_UN_N_NAME `n_un.n_name' is member of `struct nlist'.
    LINUX_LDAV_FILE             [__linux__, __CYGWIN__]: File containing
    We also #define LDAV_PRIVILEGED if a program will require
    special installation to be able to call getloadavg.  */
 
-/* This should always be first.  */
-#ifdef HAVE_CONFIG_H
+/* "configure" defines CONFIGURING_GETLOADAVG to sidestep problems
+   with partially-configured source directories.  */
+
+#ifndef CONFIGURING_GETLOADAVG
 # include <config.h>
+# include <stdbool.h>
 #endif
 
+/* Specification.  */
+#include <stdlib.h>
+
 #include <errno.h>
-#include <stdbool.h>
 #include <stdio.h>
-#include <stdlib.h>
 
 /* Exclude all the code except the test program at the end
    if the system has its own `getloadavg' function.  */
 #  include <sys/socket.h>
 #  include <net/route.h>
 #  include <sys/table.h>
+/* Tru64 4.0D's table.h redefines sys */
+#  undef sys
 # endif
 
 # if defined (__osf__) && (defined (mips) || defined (__mips__))
 #   define LOAD_AVE_TYPE long
 #  endif
 
-#  ifdef _AIX
+#  if defined _AIX && ! defined HAVE_LIBPERFSTAT
 #   define LOAD_AVE_TYPE long
 #  endif
 
 # endif
 
 
-# ifndef       FSCALE
+# ifndef FSCALE
 
 /* SunOS and some others define FSCALE in sys/param.h.  */
 
 #   define FSCALE 100.0
 #  endif
 
-#  ifdef _AIX
+#  if defined _AIX && !defined HAVE_LIBPERFSTAT
 #   define FSCALE 65536.0
 #  endif
 
 #  define LDAV_SYMBOL "_Loadavg"
 # endif
 
-# if !defined (LDAV_SYMBOL) && ((defined (hpux) && !defined (hp9000s300)) || defined (_SEQUENT_) || defined (SVR4) || defined (ISC) || defined (sgi) || (defined (ardent) && defined (titan)) || defined (_AIX))
+# 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)))
 #  define LDAV_SYMBOL "avenrun"
 # endif
 
 
 # ifdef LOAD_AVE_TYPE
 
-#  ifndef VMS
+#  ifndef __VMS
 #   ifndef __linux__
 #    ifndef NLIST_STRUCT
 #     include <a.out.h>
 #    endif /* LDAV_SYMBOL */
 #   endif /* __linux__ */
 
-#  else /* VMS */
+#  else /* __VMS */
 
 #   ifndef eunice
 #    include <iodef.h>
 #   else /* eunice */
 #    include <vms/iodef.h>
 #   endif /* eunice */
-#  endif /* VMS */
+#  endif /* __VMS */
 
 #  ifndef LDAV_CVT
 #   define LDAV_CVT(n) ((double) (n))
 
 # endif /* LOAD_AVE_TYPE */
 
+# if defined HAVE_LIBPERFSTAT
+#  include <sys/protosw.h>
+#  include <libperfstat.h>
+#  include <sys/proc.h>
+#  ifndef SBITS
+#   define SBITS 16
+#  endif
+# endif
+
 # if defined (__GNU__) && !defined (NeXT)
 /* Note that NeXT Openstep defines __GNU__ even though it should not.  */
 /* GNU system acts much like NeXT, for load average purposes,
@@ -473,9 +489,9 @@ static bool getloadavg_initialized;
 /* Offset in kmem to seek to read load average, or 0 means invalid.  */
 static long offset;
 
-#  if !defined (VMS) && !defined (sgi) && !defined (__linux__)
+#  if ! defined __VMS && ! defined sgi && ! defined __linux__
 static struct nlist nl[2];
-#  endif /* Not VMS or sgi */
+#  endif
 
 #  ifdef SUNOS_5
 static kvm_t *kd;
@@ -565,6 +581,22 @@ getloadavg (double loadavg[], int nelem)
 
 # endif /* hpux && HAVE_PSTAT_GETDYNAMIC */
 
+# if ! defined LDAV_DONE && defined HAVE_LIBPERFSTAT
+#  define LDAV_DONE
+#  undef LOAD_AVE_TYPE
+/* Use perfstat_cpu_total because we don't have to be root. */
+  {
+    perfstat_cpu_total_t cpu_stats;
+    int result = perfstat_cpu_total (NULL, &cpu_stats, sizeof cpu_stats, 1);
+    if (result == -1)
+      return result;
+    loadavg[0] = cpu_stats.loadavg[0] / (double)(1 << SBITS);
+    loadavg[1] = cpu_stats.loadavg[1] / (double)(1 << SBITS);
+    loadavg[2] = cpu_stats.loadavg[2] / (double)(1 << SBITS);
+    elem = 3;
+  }
+# endif
+
 # if !defined (LDAV_DONE) && (defined (__linux__) || defined (__CYGWIN__))
 #  define LDAV_DONE
 #  undef LOAD_AVE_TYPE
@@ -589,8 +621,11 @@ getloadavg (double loadavg[], int nelem)
   for (elem = 0; elem < nelem; elem++)
     {
       char *endptr;
-      double d = c_strtod (ptr, &endptr);
-      if (ptr == endptr)
+      double d;
+
+      errno = 0;
+      d = c_strtod (ptr, &endptr);
+      if (ptr == endptr || (d == 0 && errno != 0))
        {
          if (elem == 0)
            return -1;
@@ -813,7 +848,7 @@ getloadavg (double loadavg[], int nelem)
         : (load_ave.tl_avenrun.l[elem] / (double) load_ave.tl_lscale));
 # endif /* OSF_ALPHA */
 
-# if !defined (LDAV_DONE) && defined (VMS)
+# if ! defined LDAV_DONE && defined __VMS
   /* VMS specific code -- read from the Load Ave driver.  */
 
   LOAD_AVE_TYPE load_ave[3];
@@ -851,9 +886,9 @@ getloadavg (double loadavg[], int nelem)
 
   if (!getloadavg_initialized)
     return -1;
-# endif /* VMS */
+# endif /* ! defined LDAV_DONE && defined __VMS */
 
-# if !defined (LDAV_DONE) && defined (LOAD_AVE_TYPE) && !defined (VMS)
+# if ! defined LDAV_DONE && defined LOAD_AVE_TYPE && ! defined __VMS
 
   /* UNIX-specific code -- read the average from /dev/kmem.  */
 
@@ -865,7 +900,7 @@ getloadavg (double loadavg[], int nelem)
   if (offset == 0)
     {
 #  ifndef sgi
-#   ifndef NLIST_STRUCT
+#   if ! defined NLIST_STRUCT || ! defined N_NAME_POINTER
       strcpy (nl[0].n_name, LDAV_SYMBOL);
       strcpy (nl[1].n_name, "");
 #   else /* NLIST_STRUCT */
@@ -953,7 +988,7 @@ getloadavg (double loadavg[], int nelem)
 
   if (offset == 0 || !getloadavg_initialized)
     return -1;
-# endif /* LOAD_AVE_TYPE and not VMS */
+# endif /* ! defined LDAV_DONE && defined LOAD_AVE_TYPE && ! defined __VMS */
 
 # if !defined (LDAV_DONE) && defined (LOAD_AVE_TYPE) /* Including VMS.  */
   if (nelem > 0)