nptl: Remove INVALID_TD_P

And use the new __pthread_descriptor_valid function that checks
for 'joinstate' to get the thread state instead of 'tid'.  The
joinstate is set by the kernel when the thread exits.

Checked on x86_64-linux-gnu.

Reviewed-by: Florian Weimer <fweimer@redhat.com>
This commit is contained in:
Adhemerval Zanella 2025-12-11 17:47:20 -03:00
parent 5da15b15ad
commit f7648bf443
7 changed files with 129 additions and 5 deletions

View File

@ -29,7 +29,7 @@ __pthread_getcpuclockid (pthread_t threadid, clockid_t *clockid)
struct pthread *pd = (struct pthread *) threadid; struct pthread *pd = (struct pthread *) threadid;
/* Make sure the descriptor is valid. */ /* Make sure the descriptor is valid. */
if (INVALID_TD_P (pd)) if (!__pthread_descriptor_valid (pd))
/* Not a valid thread handle. */ /* Not a valid thread handle. */
return ESRCH; return ESRCH;

View File

@ -28,7 +28,7 @@ __pthread_getschedparam (pthread_t threadid, int *policy,
struct pthread *pd = (struct pthread *) threadid; struct pthread *pd = (struct pthread *) threadid;
/* Make sure the descriptor is valid. */ /* Make sure the descriptor is valid. */
if (INVALID_TD_P (pd)) if (!__pthread_descriptor_valid (pd))
/* Not a valid thread handle. */ /* Not a valid thread handle. */
return ESRCH; return ESRCH;

View File

@ -29,7 +29,7 @@ __pthread_setschedparam (pthread_t threadid, int policy,
struct pthread *pd = (struct pthread *) threadid; struct pthread *pd = (struct pthread *) threadid;
/* Make sure the descriptor is valid. */ /* Make sure the descriptor is valid. */
if (INVALID_TD_P (pd)) if (!__pthread_descriptor_valid (pd))
/* Not a valid thread handle. */ /* Not a valid thread handle. */
return ESRCH; return ESRCH;

View File

@ -29,7 +29,7 @@ __pthread_setschedprio (pthread_t threadid, int prio)
struct pthread *pd = (struct pthread *) threadid; struct pthread *pd = (struct pthread *) threadid;
/* Make sure the descriptor is valid. */ /* Make sure the descriptor is valid. */
if (INVALID_TD_P (pd)) if (!__pthread_descriptor_valid (pd))
/* Not a valid thread handle. */ /* Not a valid thread handle. */
return ESRCH; return ESRCH;

View File

@ -216,7 +216,11 @@ libc_hidden_proto (__pthread_current_priority)
/* This will not catch all invalid descriptors but is better than /* This will not catch all invalid descriptors but is better than
nothing. And if the test triggers the thread descriptor is nothing. And if the test triggers the thread descriptor is
guaranteed to be invalid. */ guaranteed to be invalid. */
#define INVALID_TD_P(pd) __builtin_expect ((pd)->tid <= 0, 0) static inline bool
__pthread_descriptor_valid (struct pthread *pd)
{
return atomic_load_relaxed (&pd->joinstate) != THREAD_STATE_EXITED;
}
extern void __pthread_unwind (__pthread_unwind_buf_t *__buf) extern void __pthread_unwind (__pthread_unwind_buf_t *__buf)
__cleanup_fct_attribute __attribute ((__noreturn__)) __cleanup_fct_attribute __attribute ((__noreturn__))

View File

@ -212,6 +212,7 @@ tests += \
tst-pt-vfork1 \ tst-pt-vfork1 \
tst-pt-vfork2 \ tst-pt-vfork2 \
tst-pthread-exit-signal \ tst-pthread-exit-signal \
tst-pthread-exited \
tst-pthread-mutexattr \ tst-pthread-mutexattr \
tst-pthread-mutexattr-2 \ tst-pthread-mutexattr-2 \
tst-pthread-raise-blocked-self \ tst-pthread-raise-blocked-self \

View File

@ -0,0 +1,119 @@
/* Test pthread interface which should return ESRCH when issued
with a terminated pthread_t.
Copyright (C) 2025 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <errno.h>
#include <signal.h>
#include <stddef.h>
#include <grp.h>
#include <pwd.h>
#include <support/check.h>
#include <support/support.h>
#include <support/xthread.h>
#include <unistd.h>
static void *
noop_thread (void *closure)
{
return NULL;
}
enum { nthreads = 8 };
static int
do_test_default (void)
{
pthread_t thrs[nthreads];
for (int i = 0; i < nthreads; i++)
thrs[i] = xpthread_create (NULL, noop_thread, NULL);
support_wait_for_thread_exit ();
for (int i = 0; i < nthreads; i++)
{
clockid_t clk;
TEST_COMPARE (pthread_getcpuclockid (thrs[i], &clk), ESRCH);
struct sched_param sch = { 0 };
int policy;
TEST_COMPARE (pthread_getschedparam (thrs[i], &policy, &sch), ESRCH);
TEST_COMPARE (pthread_setschedparam (thrs[i], SCHED_FIFO, &sch), ESRCH);
TEST_COMPARE (pthread_setschedprio (thrs[i], 0), ESRCH);
}
for (int i = 0; i < nthreads; i++)
xpthread_join (thrs[i]);
return 0;
}
static void *
detached_pause_thread (void *closure)
{
pthread_detach (pthread_self ());
pause ();
return NULL;
}
static void
do_test_detached (void)
{
pthread_t thrs[nthreads];
for (int i = 0; i < nthreads; i++)
thrs[i] = xpthread_create (NULL, detached_pause_thread, NULL);
for (int i = 0; i < nthreads; i++)
{
clockid_t clk;
TEST_COMPARE (pthread_getcpuclockid (thrs[i], &clk), 0);
struct sched_param sch = { 0 };
int policy;
TEST_COMPARE (pthread_getschedparam (thrs[i], &policy, &sch), 0);
sch.sched_priority = 8;
TEST_COMPARE (pthread_setschedparam (thrs[i], SCHED_FIFO, &sch), EPERM);
TEST_COMPARE (pthread_setschedprio (thrs[i], 0), 0);
}
}
static int
do_test (void)
{
/* The test relies on pthread setup failures that succeed as root. */
if (geteuid () == 0)
{
struct passwd *pwd = getpwnam ("nobody");
if (pwd == NULL)
FAIL_UNSUPPORTED ("iuser nobody doesn't exist");
TEST_VERIFY_EXIT (setresuid (pwd->pw_uid, pwd->pw_uid, -1) == 0);
}
do_test_default ();
do_test_detached ();
return 0;
}
#include <support/test-driver.c>