From: Adhemerval Zanella Date: Thu, 11 Dec 2025 20:47:21 +0000 (-0300) Subject: support: Add support_thread_state_wait X-Git-Tag: glibc-2.43~71 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=793f68010146984d9f5d1bcfda58006b0033ab76;p=thirdparty%2Fglibc.git support: Add support_thread_state_wait 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//task//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 --- diff --git a/support/process_state.h b/support/process_state.h index 36126c363f..e9b41cb554 100644 --- a/support/process_state.h +++ b/support/process_state.h @@ -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 diff --git a/support/support_process_state.c b/support/support_process_state.c index 8f8e118ce9..b20a284177 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 . */ +#include #include #include #include @@ -27,8 +28,9 @@ #include #include -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//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//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//task//status + checking on third field. */ + + char path[sizeof ("/proc/") + + INT_STRLEN_BOUND (pid_t) + 1 /* / */ + + sizeof ("task/") + + INT_STRLEN_BOUND (pid_t) + 1 /* / */ + + 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); +}