[gcc r17-2397] libgomp: Robustify omp_get_device_distances [PR125877]

Tobias Burnus via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:929b1c42f3d23dcffacdedb005ab83d3607b47ce

commit r17-2397-g929b1c42f3d23dcffacdedb005ab83d3607b47ce
Author: Tobias Burnus <[email protected]>
Date:   Tue Jul 14 16:09:54 2026 +0200

    libgomp: Robustify omp_get_device_distances [PR125877]
    
    libgomp/ChangeLog:
    
            PR libgomp/125877
            * config/linux/numa.c (gomp_get_numa_distance): Avoid data race issue
            during initalization and handle non-contiguous node numbering.

Diff:
---
 libgomp/config/linux/numa.c | 186 ++++++++++++++++++++++++++++++++------------
 1 file changed, 136 insertions(+), 50 deletions(-)

diff --git a/libgomp/config/linux/numa.c b/libgomp/config/linux/numa.c
index a3d84870e6e8..85214e56dc41 100644
--- a/libgomp/config/linux/numa.c
+++ b/libgomp/config/linux/numa.c
@@ -37,9 +37,6 @@
 #include <sys/syscall.h>
 
 
-static int num_numa_nodes = 0;
-static int *numa_distances = NULL;
-
 int
 gomp_get_current_numa_node ()
 {
@@ -51,59 +48,148 @@ gomp_get_current_numa_node ()
 int
 gomp_get_numa_distance (int node1, int node2)
 {
-  if (node1 < 0 || node2 < 0 || num_numa_nodes < 0)
-    return -1;
+  /* num_numa_nodes: 0 = uninit, -1 = being initialized, -2 = error,
+		     > 0 = the number of numa nodes.
+     numa_distances: a 2D array of #nodes * #nodes with the distances.
+     remap: map the numa number to the index in numa_distances;
+	    as numa numbers might not be contiguous.
+     num_remap: size of the remap array.  */
+  static int num_numa_nodes = 0;
+  static int *numa_distances = NULL;
+  static unsigned num_remap = 0;
+  static unsigned *remap = NULL;
 
-  if (numa_distances == NULL)
+retry:
+  int num = __atomic_load_n (&num_numa_nodes, MEMMODEL_RELAXED);
+  if (node1 < 0 || node2 < 0 || num <= -2)
+    return -1;
+  if (num > 0)
     {
-      num_numa_nodes = -1;
-      DIR *dir = opendir ("/sys/devices/system/node");
-      if (!dir)
+      if (node1 > num_remap || node2 > num_remap)
 	return -1;
-      struct dirent *dp;
-      int cnt = 0;
-      errno = 0;
-      while ((dp = readdir(dir)) != NULL)
-	if (strncmp ("node", dp->d_name, 4 /* strlen ("node") */) == 0)
-	  cnt++;
-	else if (errno)
-	  {
-	    closedir (dir);
-	    return -1;
-	  }
-      closedir (dir);
-      numa_distances = (int *) gomp_malloc (sizeof (int) * cnt * cnt);
+      node1 = remap[node1];
+      node2 = remap[node2];
+      if (node1 >= num || node2 >= num)
+	return -1;
+      return numa_distances[node1 * num_numa_nodes + node2];
+    }
+
+  /* Obtain distance data - or busy wait until another thread did so.  */
+  int val = 0;
+  if (!__atomic_compare_exchange_n (&num_numa_nodes, &val, -1, false,
+				    MEMMODEL_ACQUIRE, MEMMODEL_ACQUIRE))
+    {
+      while (-1 == __atomic_load_n (&num_numa_nodes, MEMMODEL_ACQUIRE));
+      __asm volatile ("" : : : "memory");
+      goto retry;
+    }
+
+  /* Obtain numa nodes.  */
 
-      constexpr int len = sizeof ("/sys/devices/system/node/node12345/"
-				  "distance");
-      char filename[len];
+  num = 0;
+  FILE *f = fopen ("/sys/devices/system/node/online", "r");
+  if (f == NULL)
+    goto fail;
+  char *lineptr = NULL;
+  size_t nline;
+  if (getline (&lineptr, &nline, f) <= 0)
+    {
+      free (lineptr);
+      fclose (f);
+      goto fail;
+    }
+  fclose (f);
+
+  /* Create mapping array between the node number and contiguous
+     n-th online node count. */
+  unsigned constexpr UNSET_REMAP = (unsigned) -1;
+  num_remap = 8;
+  remap = malloc (sizeof (*remap) * num_remap);
+  if (!remap)
+    goto fail;
+  for (int i = 0; i < num_remap; i++)
+    remap[i] = UNSET_REMAP;
+  char *q = lineptr;
+  while (*q && *q != '\n')
+    {
+      unsigned nfirst, nlast;
+      char *end;
 
-      for (int i = 0; i < cnt; i++)
+      errno = 0;
+      nfirst = strtoul (q, &end, 10);
+      if (errno || end == q)
+	goto fail;
+      q = end;
+      nlast = nfirst;
+      if (*q == '-')
+	{
+	  errno = 0;
+	  nlast = strtoul (q + 1, &end, 10);
+	  if (errno || end == q + 1 || nlast < nfirst)
+	    goto fail;
+	  q = end;
+	}
+      if (num_remap <= nlast)
 	{
-	  if (len < snprintf (filename, sizeof (filename),
-			      "/sys/devices/system/node/node%d/distance", i))
-	    return -1;
-	  int distance = -1;
-	  FILE *in = fopen (filename, "r");
-	  if (!in)
-	    {
-	      free (numa_distances);
-	      return -1;
-	    }
-	  for (int j = 0; j < cnt; j++)
-	    {
-	      fscanf (in, "%d", &distance);
-	      if (distance == -1)
-		{
-		  fclose (in);
-		  free (numa_distances);
-		  return -1;
-		}
-	      numa_distances[i * cnt + j] = distance;
-	    }
-	  fclose (in);
+	  int n = nlast > 2 * num_remap ? nlast + 1 : num_remap * 2;
+	  remap = realloc (remap, sizeof (*remap) * n);
+	  if (!remap || n <= nlast)
+	    goto fail;
+	  for (int i = num_remap; i < n; i++)
+	    remap[i] = UNSET_REMAP;
+	  num_remap = n;
 	}
-      num_numa_nodes = cnt;
+      for (; nfirst <= nlast; nfirst++)
+	remap[nfirst] = num++;
+      if (*q == ',')
+	++q;
     }
-  return numa_distances[node1 * num_numa_nodes + node2];
+  free (lineptr);
+  lineptr = NULL;
+
+  /* Fill distance data.  */
+  numa_distances = (int *) gomp_malloc (sizeof (*numa_distances) * num * num);
+
+  for (int i = 0; i < num_remap; i++)
+    if (remap[i] == UNSET_REMAP)
+      continue;
+    else
+      {
+	constexpr int len = sizeof ("/sys/devices/system/node/node12345/"
+				    "distance");
+	char filename[len];
+	int node = remap[i];
+	if (node < 0)
+	  goto fail;
+	if (len < snprintf (filename, sizeof (filename),
+			    "/sys/devices/system/node/node%d/distance", i))
+	  goto fail;
+	FILE *in = fopen (filename, "r");
+	if (!in)
+	  goto fail;
+	for (int j = 0; j < num; j++)
+	  {
+	    /* Distance -1 might happen on virtualized systems or when the
+	       kernel reports "No NUMA configuration found".  The code assumes
+	       that only distance values show up for online nodes.  */
+	    int distance;
+	    if (fscanf (in, "%d", &distance) != 1)
+	      {
+		fclose (in);
+		goto fail;
+	      }
+	    numa_distances[node * num + j] = distance;
+	  }
+	fclose (in);
+      }
+  __asm volatile ("" : : : "memory");
+  __atomic_store_n (&num_numa_nodes, num, MEMMODEL_RELAXED);
+  goto retry;
+
+fail:
+  free (lineptr);
+  free (remap);
+  free (numa_distances);
+  __atomic_store_n (&num_numa_nodes, -2, MEMMODEL_RELAXED);
+  return -1;
 }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.