]> git.feebdaed.xyz Git - 0xmirror/glibc.git/commitdiff
support: Add support_thread_state_wait
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>
Thu, 11 Dec 2025 20:47:21 +0000 (17:47 -0300)
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>
Fri, 19 Dec 2025 16:23:06 +0000 (13:23 -0300)
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.

Reviewed-by: Florian Weimer <fweimer@redhat.com>
support/process_state.h
support/support_process_state.c

index 36126c363fbb19fc05e9b0964a68745b7d6b1e49..e9b41cb5547f0ee96856a39eccce486b4f72a33a 100644 (file)
@@ -43,4 +43,13 @@ 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.
+   NB: this function does not guard against TID reuse (the kernel might
+   assign the TID to a different thread between the gettid and the function
+   call if the thread exits and another is created).  It is the caller's
+   responsibility to ensure the call is safe to use.  */
+enum support_process_state
+support_thread_state_wait (pid_t pid, enum support_process_state state);
+
 #endif
index 8f8e118ce9e1a9431e9e5969934b93152fbee5f6..b20a284177794ec6ab9efe3bc4728068048e5f43 100644 (file)
@@ -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);
+}