Back to index

glibc  2.9
getsysstats.c
Go to the documentation of this file.
00001 /* Determine various system internal values, Linux version.
00002    Copyright (C) 1996-2001, 2002, 2003, 2006, 2007 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <alloca.h>
00022 #include <assert.h>
00023 #include <ctype.h>
00024 #include <dirent.h>
00025 #include <errno.h>
00026 #include <fcntl.h>
00027 #include <mntent.h>
00028 #include <paths.h>
00029 #include <stdio.h>
00030 #include <stdio_ext.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #include <unistd.h>
00034 #include <sys/sysinfo.h>
00035 
00036 #include <atomic.h>
00037 #include <not-cancel.h>
00038 
00039 
00040 /* How we can determine the number of available processors depends on
00041    the configuration.  There is currently (as of version 2.0.21) no
00042    system call to determine the number.  It is planned for the 2.1.x
00043    series to add this, though.
00044 
00045    One possibility to implement it for systems using Linux 2.0 is to
00046    examine the pseudo file /proc/cpuinfo.  Here we have one entry for
00047    each processor.
00048 
00049    But not all systems have support for the /proc filesystem.  If it
00050    is not available we simply return 1 since there is no way.  */
00051 
00052 /* Other architectures use different formats for /proc/cpuinfo.  This
00053    provides a hook for alternative parsers.  */
00054 #ifndef GET_NPROCS_PARSER
00055 # define GET_NPROCS_PARSER(FP, BUFFER, RESULT)                        \
00056   do                                                           \
00057     {                                                          \
00058       (RESULT) = 0;                                            \
00059       /* Read all lines and count the lines starting with the string  \
00060         "processor".  We don't have to fear extremely long lines since       \
00061         the kernel will not generate them.  8192 bytes are really     \
00062         enough.  */                                            \
00063       while (fgets_unlocked (BUFFER, sizeof (BUFFER), FP) != NULL)    \
00064        if (strncmp (BUFFER, "processor", 9) == 0)                     \
00065          ++(RESULT);                                           \
00066     }                                                          \
00067   while (0)
00068 #endif
00069 
00070 
00071 int
00072 __get_nprocs ()
00073 {
00074   /* XXX Here will come a test for the new system call.  */
00075 
00076   char buffer[8192];
00077   int result = 1;
00078 
00079   /* The /proc/stat format is more uniform, use it by default.  */
00080   FILE *fp = fopen ("/proc/stat", "rc");
00081   if (fp != NULL)
00082     {
00083       /* No threads use this stream.  */
00084       __fsetlocking (fp, FSETLOCKING_BYCALLER);
00085 
00086       result = 0;
00087       while (fgets_unlocked (buffer, sizeof (buffer), fp) != NULL)
00088        if (strncmp (buffer, "cpu", 3) == 0 && isdigit (buffer[3]))
00089          ++result;
00090 
00091       fclose (fp);
00092     }
00093   else
00094     {
00095       fp = fopen ("/proc/cpuinfo", "rc");
00096       if (fp != NULL)
00097        {
00098          /* No threads use this stream.  */
00099          __fsetlocking (fp, FSETLOCKING_BYCALLER);
00100          GET_NPROCS_PARSER (fp, buffer, result);
00101          fclose (fp);
00102        }
00103     }
00104 
00105   return result;
00106 }
00107 weak_alias (__get_nprocs, get_nprocs)
00108 
00109 
00110 /* On some architectures it is possible to distinguish between configured
00111    and active cpus.  */
00112 int
00113 __get_nprocs_conf ()
00114 {
00115   /* XXX Here will come a test for the new system call.  */
00116 
00117   /* Try to use the sysfs filesystem.  It has actual information about
00118      online processors.  */
00119   DIR *dir = __opendir ("/sys/devices/system/cpu");
00120   if (dir != NULL)
00121     {
00122       int count = 0;
00123       struct dirent64 *d;
00124 
00125       while ((d = __readdir64 (dir)) != NULL)
00126        /* NB: the sysfs has d_type support.  */
00127        if (d->d_type == DT_DIR && strncmp (d->d_name, "cpu", 3) == 0)
00128          {
00129            char *endp;
00130            unsigned long int nr = strtoul (d->d_name + 3, &endp, 10);
00131            if (nr != ULONG_MAX && endp != d->d_name + 3 && *endp == '\0')
00132              ++count;
00133          }
00134 
00135       __closedir (dir);
00136 
00137       return count;
00138     }
00139 
00140   int result = 1;
00141 
00142 #ifdef GET_NPROCS_CONF_PARSER
00143   /* If we haven't found an appropriate entry return 1.  */
00144   FILE *fp = fopen ("/proc/cpuinfo", "rc");
00145   if (fp != NULL)
00146     {
00147       char buffer[8192];
00148 
00149       /* No threads use this stream.  */
00150       __fsetlocking (fp, FSETLOCKING_BYCALLER);
00151       GET_NPROCS_CONF_PARSER (fp, buffer, result);
00152       fclose (fp);
00153     }
00154 #else
00155   result = __get_nprocs ();
00156 #endif
00157 
00158   return result;
00159 }
00160 weak_alias (__get_nprocs_conf, get_nprocs_conf)
00161 
00162 /* General function to get information about memory status from proc
00163    filesystem.  */
00164 static long int
00165 internal_function
00166 phys_pages_info (const char *format)
00167 {
00168   char buffer[8192];
00169   long int result = -1;
00170 
00171   /* If we haven't found an appropriate entry return 1.  */
00172   FILE *fp = fopen ("/proc/meminfo", "rc");
00173   if (fp != NULL)
00174     {
00175       /* No threads use this stream.  */
00176       __fsetlocking (fp, FSETLOCKING_BYCALLER);
00177 
00178       result = 0;
00179       /* Read all lines and count the lines starting with the
00180         string "processor".  We don't have to fear extremely long
00181         lines since the kernel will not generate them.  8192
00182         bytes are really enough.  */
00183       while (fgets_unlocked (buffer, sizeof buffer, fp) != NULL)
00184        if (sscanf (buffer, format, &result) == 1)
00185          {
00186            result /= (__getpagesize () / 1024);
00187            break;
00188          }
00189 
00190       fclose (fp);
00191     }
00192 
00193   if (result == -1)
00194     /* We cannot get the needed value: signal an error.  */
00195     __set_errno (ENOSYS);
00196 
00197   return result;
00198 }
00199 
00200 
00201 /* Return the number of pages of physical memory in the system.  There
00202    is currently (as of version 2.0.21) no system call to determine the
00203    number.  It is planned for the 2.1.x series to add this, though.
00204 
00205    One possibility to implement it for systems using Linux 2.0 is to
00206    examine the pseudo file /proc/cpuinfo.  Here we have one entry for
00207    each processor.
00208 
00209    But not all systems have support for the /proc filesystem.  If it
00210    is not available we return -1 as an error signal.  */
00211 long int
00212 __get_phys_pages ()
00213 {
00214   /* XXX Here will come a test for the new system call.  */
00215 
00216   return phys_pages_info ("MemTotal: %ld kB");
00217 }
00218 weak_alias (__get_phys_pages, get_phys_pages)
00219 
00220 
00221 /* Return the number of available pages of physical memory in the
00222    system.  There is currently (as of version 2.0.21) no system call
00223    to determine the number.  It is planned for the 2.1.x series to add
00224    this, though.
00225 
00226    One possibility to implement it for systems using Linux 2.0 is to
00227    examine the pseudo file /proc/cpuinfo.  Here we have one entry for
00228    each processor.
00229 
00230    But not all systems have support for the /proc filesystem.  If it
00231    is not available we return -1 as an error signal.  */
00232 long int
00233 __get_avphys_pages ()
00234 {
00235   /* XXX Here will come a test for the new system call.  */
00236 
00237   return phys_pages_info ("MemFree: %ld kB");
00238 }
00239 weak_alias (__get_avphys_pages, get_avphys_pages)