076f82
commit 007e054d786be340699c634e3a3b30ab1fde1a7a
076f82
Author: Dmitry V. Levin <ldv@altlinux.org>
076f82
Date:   Sat Feb 5 08:00:00 2022 +0000
076f82
076f82
    linux: fix accuracy of get_nprocs and get_nprocs_conf [BZ #28865]
076f82
    
076f82
    get_nprocs() and get_nprocs_conf() use various methods to obtain an
076f82
    accurate number of processors.  Re-introduce __get_nprocs_sched() as
076f82
    a source of information, and fix the order in which these methods are
076f82
    used to return the most accurate information.  The primary source of
076f82
    information used in both functions remains unchanged.
076f82
    
076f82
    This also changes __get_nprocs_sched() error return value from 2 to 0,
076f82
    but all its users are already prepared to handle that.
076f82
    
076f82
    Old fallback order:
076f82
      get_nprocs:
076f82
        /sys/devices/system/cpu/online -> /proc/stat -> 2
076f82
      get_nprocs_conf:
076f82
        /sys/devices/system/cpu/ -> /proc/stat -> 2
076f82
    
076f82
    New fallback order:
076f82
      get_nprocs:
076f82
        /sys/devices/system/cpu/online -> /proc/stat -> sched_getaffinity -> 2
076f82
      get_nprocs_conf:
076f82
        /sys/devices/system/cpu/ -> /proc/stat -> sched_getaffinity -> 2
076f82
    
076f82
    Fixes: 342298278e ("linux: Revert the use of sched_getaffinity on get_nproc")
076f82
    Closes: BZ #28865
076f82
    Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
076f82
    
076f82
    (cherry picked from commit e1d32b836410767270a3adf1f82b1a47e6e4cd51)
076f82
076f82
diff --git a/sysdeps/unix/sysv/linux/getsysstats.c b/sysdeps/unix/sysv/linux/getsysstats.c
076f82
index 7babd947aa902e77..327802b14c7326a3 100644
076f82
--- a/sysdeps/unix/sysv/linux/getsysstats.c
076f82
+++ b/sysdeps/unix/sysv/linux/getsysstats.c
076f82
@@ -51,9 +51,8 @@ __get_nprocs_sched (void)
076f82
        is an arbitrary values assuming such systems should be rare and there
076f82
        is no offline cpus.  */
076f82
     return max_num_cpus;
076f82
-  /* Some other error.  2 is conservative (not a uniprocessor system, so
076f82
-     atomics are needed). */
076f82
-  return 2;
076f82
+  /* Some other error.  */
076f82
+  return 0;
076f82
 }
076f82
 
076f82
 static char *
076f82
@@ -109,22 +108,19 @@ next_line (int fd, char *const buffer, char **cp, char **re,
076f82
 }
076f82
 
076f82
 static int
076f82
-get_nproc_stat (char *buffer, size_t buffer_size)
076f82
+get_nproc_stat (void)
076f82
 {
076f82
+  enum { buffer_size = 1024 };
076f82
+  char buffer[buffer_size];
076f82
   char *buffer_end = buffer + buffer_size;
076f82
   char *cp = buffer_end;
076f82
   char *re = buffer_end;
076f82
-
076f82
-  /* Default to an SMP system in case we cannot obtain an accurate
076f82
-     number.  */
076f82
-  int result = 2;
076f82
+  int result = 0;
076f82
 
076f82
   const int flags = O_RDONLY | O_CLOEXEC;
076f82
   int fd = __open_nocancel ("/proc/stat", flags);
076f82
   if (fd != -1)
076f82
     {
076f82
-      result = 0;
076f82
-
076f82
       char *l;
076f82
       while ((l = next_line (fd, buffer, &cp, &re, buffer_end)) != NULL)
076f82
 	/* The current format of /proc/stat has all the cpu* entries
076f82
@@ -140,8 +136,8 @@ get_nproc_stat (char *buffer, size_t buffer_size)
076f82
   return result;
076f82
 }
076f82
 
076f82
-int
076f82
-__get_nprocs (void)
076f82
+static int
076f82
+get_nprocs_cpu_online (void)
076f82
 {
076f82
   enum { buffer_size = 1024 };
076f82
   char buffer[buffer_size];
076f82
@@ -180,7 +176,8 @@ __get_nprocs (void)
076f82
 		  }
076f82
 	      }
076f82
 
076f82
-	    result += m - n + 1;
076f82
+	    if (m >= n)
076f82
+	      result += m - n + 1;
076f82
 
076f82
 	    l = endp;
076f82
 	    if (l < re && *l == ',')
076f82
@@ -189,28 +186,18 @@ __get_nprocs (void)
076f82
 	while (l < re && *l != '\n');
076f82
 
076f82
       __close_nocancel_nostatus (fd);
076f82
-
076f82
-      if (result > 0)
076f82
-	return result;
076f82
     }
076f82
 
076f82
-  return get_nproc_stat (buffer, buffer_size);
076f82
+  return result;
076f82
 }
076f82
-libc_hidden_def (__get_nprocs)
076f82
-weak_alias (__get_nprocs, get_nprocs)
076f82
-
076f82
 
076f82
-/* On some architectures it is possible to distinguish between configured
076f82
-   and active cpus.  */
076f82
-int
076f82
-__get_nprocs_conf (void)
076f82
+static int
076f82
+get_nprocs_cpu (void)
076f82
 {
076f82
-  /* Try to use the sysfs filesystem.  It has actual information about
076f82
-     online processors.  */
076f82
+  int count = 0;
076f82
   DIR *dir = __opendir ("/sys/devices/system/cpu");
076f82
   if (dir != NULL)
076f82
     {
076f82
-      int count = 0;
076f82
       struct dirent64 *d;
076f82
 
076f82
       while ((d = __readdir64 (dir)) != NULL)
076f82
@@ -225,12 +212,57 @@ __get_nprocs_conf (void)
076f82
 
076f82
       __closedir (dir);
076f82
 
076f82
-      return count;
076f82
     }
076f82
+  return count;
076f82
+}
076f82
 
076f82
-  enum { buffer_size = 1024 };
076f82
-  char buffer[buffer_size];
076f82
-  return get_nproc_stat (buffer, buffer_size);
076f82
+static int
076f82
+get_nprocs_fallback (void)
076f82
+{
076f82
+  int result;
076f82
+
076f82
+  /* Try /proc/stat first.  */
076f82
+  result = get_nproc_stat ();
076f82
+  if (result != 0)
076f82
+    return result;
076f82
+
076f82
+  /* Try sched_getaffinity.  */
076f82
+  result = __get_nprocs_sched ();
076f82
+  if (result != 0)
076f82
+    return result;
076f82
+
076f82
+  /* We failed to obtain an accurate number.  Be conservative: return
076f82
+     the smallest number meaning that this is not a uniprocessor system,
076f82
+     so atomics are needed.  */
076f82
+  return 2;
076f82
+}
076f82
+
076f82
+int
076f82
+__get_nprocs (void)
076f82
+{
076f82
+  /* Try /sys/devices/system/cpu/online first.  */
076f82
+  int result = get_nprocs_cpu_online ();
076f82
+  if (result != 0)
076f82
+    return result;
076f82
+
076f82
+  /* Fall back to /proc/stat and sched_getaffinity.  */
076f82
+  return get_nprocs_fallback ();
076f82
+}
076f82
+libc_hidden_def (__get_nprocs)
076f82
+weak_alias (__get_nprocs, get_nprocs)
076f82
+
076f82
+/* On some architectures it is possible to distinguish between configured
076f82
+   and active cpus.  */
076f82
+int
076f82
+__get_nprocs_conf (void)
076f82
+{
076f82
+  /* Try /sys/devices/system/cpu/ first.  */
076f82
+  int result = get_nprocs_cpu ();
076f82
+  if (result != 0)
076f82
+    return result;
076f82
+
076f82
+  /* Fall back to /proc/stat and sched_getaffinity.  */
076f82
+  return get_nprocs_fallback ();
076f82
 }
076f82
 libc_hidden_def (__get_nprocs_conf)
076f82
 weak_alias (__get_nprocs_conf, get_nprocs_conf)