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