[PATCH 5/6] support: Add support_thread_state_wait

Adhemerval Zanella adhemerval.zanella@linaro.org
Thu Dec 11 20:47:21 GMT 2025


Same as support_process_state_wait, but wait for the task TID
(obtained with gettid) from the current process.  Since the kernel
might remove the /proc/<pid>/task/<tid>/status at any time if the
thread terminates, the code needs to handle possible
fopen/getline/fclose failures due to an inexistent file.
---
 support/process_state.h         |  5 +++
 support/support_process_state.c | 71 ++++++++++++++++++++++++++++-----
 2 files changed, 67 insertions(+), 9 deletions(-)

diff --git a/support/process_state.h b/support/process_state.h
index 36126c363f..27344f8929 100644
--- a/support/process_state.h
+++ b/support/process_state.h
@@ -43,4 +43,9 @@ enum support_process_state
 enum support_process_state
 support_process_state_wait (pid_t pid, enum support_process_state state);
 
+/* Same as support_process_state_wait, but wait for the task TID (obtained
+   with gettid) from the current process.  */
+enum support_process_state
+support_thread_state_wait (pid_t pid, enum support_process_state state);
+
 #endif
diff --git a/support/support_process_state.c b/support/support_process_state.c
index 8f8e118ce9..9f34e135bb 100644
--- a/support/support_process_state.c
+++ b/support/support_process_state.c
@@ -16,6 +16,7 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
+#include <errno.h>
 #include <stdlib.h>
 #include <time.h>
 #include <string.h>
@@ -27,8 +28,9 @@
 #include <support/xstdio.h>
 #include <support/check.h>
 
-enum support_process_state
-support_process_state_wait (pid_t pid, enum support_process_state state)
+static enum support_process_state
+support_process_state_wait_common (FILE *fstatus,
+				   enum support_process_state state)
 {
 #ifdef __linux__
   /* For Linux it does a polling check on /proc/<pid>/status checking on
@@ -50,22 +52,29 @@ support_process_state_wait (pid_t pid, enum support_process_state state)
     { support_process_state_parked,       'P' },
   };
 
-  char spath[sizeof ("/proc/") + INT_STRLEN_BOUND (pid_t) + sizeof ("/status") + 1];
-  snprintf (spath, sizeof (spath), "/proc/%i/status", pid);
-
-  FILE *fstatus = xfopen (spath, "r");
   char *line = NULL;
   size_t linesiz = 0;
 
   for (;;)
     {
       char cur_state = CHAR_MAX;
-      while (xgetline (&line, &linesiz, fstatus) > 0)
+      ssize_t r;
+      while ((r = getline (&line, &linesiz, fstatus)) > 0)
 	if (strncmp (line, "State:", strlen ("State:")) == 0)
 	  {
 	    TEST_COMPARE (sscanf (line, "%*s %c", &cur_state), 1);
 	    break;
 	  }
+      /* The procfs file for the /proc/self/task/tid might be removed by the
+	 kernel if the thread exits before the getline call.  In this case
+	 returns that the thread is dead.  */
+      if (r == -1 && errno == ESRCH)
+	{
+	  free (line);
+	  fclose (fstatus);
+	  return support_process_state_dead;
+	}
+      TEST_VERIFY (ferror (fstatus) == 0);
       /* Fallback to nanosleep for invalid state.  */
       if (cur_state == CHAR_MAX)
 	break;
@@ -74,7 +83,7 @@ support_process_state_wait (pid_t pid, enum support_process_state state)
 	if (state & process_states[i].s && cur_state == process_states[i].v)
 	  {
 	    free (line);
-	    xfclose (fstatus);
+	    fclose (fstatus);
 	    return process_states[i].s;
 	  }
 
@@ -86,10 +95,54 @@ support_process_state_wait (pid_t pid, enum support_process_state state)
     }
 
   free (line);
-  xfclose (fstatus);
+  fclose (fstatus);
   /* Fallback to nanosleep if an invalid state is found.  */
 #endif
   nanosleep (&(struct timespec) { 1, 0 }, NULL);
 
   return support_process_state_invalid;
 }
+
+enum support_process_state
+support_process_state_wait (pid_t pid, enum support_process_state state)
+{
+  FILE *fstatus = NULL;
+
+#ifdef __linux__
+  /* For Linux it does a polling check on /proc/<pid>/status checking on
+     third field.  */
+
+  char path[sizeof ("/proc/")
+	    + INT_STRLEN_BOUND (pid_t)
+	    + sizeof ("/status") + 1];
+  snprintf (path, sizeof (path), "/proc/%i/status", pid);
+  fstatus = xfopen (path, "r");
+#endif
+
+  return support_process_state_wait_common (fstatus, state);
+}
+
+enum support_process_state
+support_thread_state_wait (pid_t tid, enum support_process_state state)
+{
+  FILE *fstatus = NULL;
+
+#ifdef __linux__
+  /* For Linux it does a polling check on /proc/<getpid()>/task/<tid>/status
+     checking on third field.  */
+
+  char path[sizeof ("/proc/")
+	    + INT_STRLEN_BOUND (pid_t) + 1 /* <getpid()>/ */
+	    + sizeof ("task/")
+	    + INT_STRLEN_BOUND (pid_t) + 1 /* <tid>/ */
+	    + sizeof ("/status") + 1];
+  snprintf (path, sizeof (path), "/proc/%i/task/%i/status", getpid (), tid);
+  fstatus = fopen (path, "r");
+  /* The thread might already being terminated and there is no check whether
+     tid is a valid descriptior.  */
+  if (fstatus == NULL)
+    return support_process_state_dead;
+#endif
+
+  return support_process_state_wait_common (fstatus, state);
+}
-- 
2.43.0



More information about the Libc-alpha mailing list