!235 nptl: pthread_kill race condition issues fixed
From: @liqingqing_1229 Reviewed-by: @wangbin224 Signed-off-by: @wangbin224
This commit is contained in:
commit
fcfe225ad2
15
glibc.spec
15
glibc.spec
@ -65,7 +65,7 @@
|
||||
##############################################################################
|
||||
Name: glibc
|
||||
Version: 2.34
|
||||
Release: 20
|
||||
Release: 21
|
||||
Summary: The GNU libc libraries
|
||||
License: %{all_license}
|
||||
URL: http://www.gnu.org/software/glibc/
|
||||
@ -121,6 +121,11 @@ Patch34: x86-64-Use-testl-to-check-__x86_string_control.patch
|
||||
Patch35: AArch64-Update-A64FX-memset-not-to-degrade-at-16KB.patch
|
||||
Patch36: support-Add-support_wait_for_thread_exit.patch
|
||||
Patch37: nptl-pthread_kill-pthread_cancel-should-not-fail-aft.patch
|
||||
Patch38: nptl-Fix-race-between-pthread_kill-and-thread-exit-b.patch
|
||||
Patch39: nptl-pthread_kill-needs-to-return-ESRCH-for-old-prog.patch
|
||||
Patch40: nptl-Fix-type-of-pthread_mutexattr_getrobust_np-pthr.patch
|
||||
Patch41: nptl-Avoid-setxid-deadlock-with-blocked-signals-in-t.patch
|
||||
Patch42: nptl-pthread_kill-must-send-signals-to-a-specific-th.patch
|
||||
|
||||
#Patch9000: turn-REP_STOSB_THRESHOLD-from-2k-to-1M.patch
|
||||
Patch9001: delete-no-hard-link-to-avoid-all_language-package-to.patch
|
||||
@ -1310,6 +1315,14 @@ fi
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Mon Nov 8 2021 Qingqing Li<liqingqing3@huawei.com> - 2.34-21
|
||||
- nptl: pthread_kill race condition issues fixed.
|
||||
uplink: https://sourceware.org/bugzilla/show_bug.cgi?id=19193
|
||||
https://sourceware.org/bugzilla/show_bug.cgi?id=12889
|
||||
https://sourceware.org/bugzilla/show_bug.cgi?id=28036
|
||||
https://sourceware.org/bugzilla/show_bug.cgi?id=28363
|
||||
https://sourceware.org/bugzilla/show_bug.cgi?id=28407
|
||||
|
||||
* Thu Nov 4 2021 Qingqing Li<liqingqing3@huawei.com> - 2.34-20
|
||||
- nptl: pthread_kill and pthread_cancel return success
|
||||
for satisfy posix standard.
|
||||
|
||||
137
nptl-Avoid-setxid-deadlock-with-blocked-signals-in-t.patch
Normal file
137
nptl-Avoid-setxid-deadlock-with-blocked-signals-in-t.patch
Normal file
@ -0,0 +1,137 @@
|
||||
From 2849e2f53311b66853cb5159b64cba2bddbfb854 Mon Sep 17 00:00:00 2001
|
||||
From: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Thu, 23 Sep 2021 09:55:54 +0200
|
||||
Subject: [PATCH] nptl: Avoid setxid deadlock with blocked signals in thread
|
||||
exit [BZ #28361]
|
||||
|
||||
As part of the fix for bug 12889, signals are blocked during
|
||||
thread exit, so that application code cannot run on the thread that
|
||||
is about to exit. This would cause problems if the application
|
||||
expected signals to be delivered after the signal handler revealed
|
||||
the thread to still exist, despite pthread_kill can no longer be used
|
||||
to send signals to it. However, glibc internally uses the SIGSETXID
|
||||
signal in a way that is incompatible with signal blocking, due to the
|
||||
way the setxid handshake delays thread exit until the setxid operation
|
||||
has completed. With a blocked SIGSETXID, the handshake can never
|
||||
complete, causing a deadlock.
|
||||
|
||||
As a band-aid, restore the previous handshake protocol by not blocking
|
||||
SIGSETXID during thread exit.
|
||||
|
||||
The new test sysdeps/pthread/tst-pthread-setuid-loop.c is based on
|
||||
a downstream test by Martin Osvald.
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
Tested-by: Carlos O'Donell <carlos@redhat.com>
|
||||
---
|
||||
nptl/pthread_create.c | 12 +++++-
|
||||
sysdeps/pthread/Makefile | 1 +
|
||||
sysdeps/pthread/tst-pthread-setuid-loop.c | 61 +++++++++++++++++++++++++++++++
|
||||
3 files changed, 72 insertions(+), 2 deletions(-)
|
||||
create mode 100644 sysdeps/pthread/tst-pthread-setuid-loop.c
|
||||
|
||||
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
|
||||
index a559f86..d6ea43a 100644
|
||||
--- a/nptl/pthread_create.c
|
||||
+++ b/nptl/pthread_create.c
|
||||
@@ -487,8 +487,16 @@ start_thread (void *arg)
|
||||
|
||||
/* This prevents sending a signal from this thread to itself during
|
||||
its final stages. This must come after the exit call above
|
||||
- because atexit handlers must not run with signals blocked. */
|
||||
- __libc_signal_block_all (NULL);
|
||||
+ because atexit handlers must not run with signals blocked.
|
||||
+
|
||||
+ Do not block SIGSETXID. The setxid handshake below expects the
|
||||
+ signal to be delivered. (SIGSETXID cannot run application code,
|
||||
+ nor does it use pthread_kill.) Reuse the pd->sigmask space for
|
||||
+ computing the signal mask, to save stack space. */
|
||||
+ __sigfillset (&pd->sigmask);
|
||||
+ __sigdelset (&pd->sigmask, SIGSETXID);
|
||||
+ INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_BLOCK, &pd->sigmask, NULL,
|
||||
+ __NSIG_BYTES);
|
||||
|
||||
/* Tell __pthread_kill_internal that this thread is about to exit.
|
||||
If there is a __pthread_kill_internal in progress, this delays
|
||||
diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile
|
||||
index 48dba71..d4bd2d4 100644
|
||||
--- a/sysdeps/pthread/Makefile
|
||||
+++ b/sysdeps/pthread/Makefile
|
||||
@@ -118,6 +118,7 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \
|
||||
tst-unload \
|
||||
tst-unwind-thread \
|
||||
tst-pt-vfork1 tst-pt-vfork2 tst-vfork1x tst-vfork2x \
|
||||
+ tst-pthread-setuid-loop \
|
||||
tst-pthread_cancel-exited \
|
||||
tst-pthread_cancel-select-loop \
|
||||
tst-pthread_kill-exited \
|
||||
diff --git a/sysdeps/pthread/tst-pthread-setuid-loop.c b/sysdeps/pthread/tst-pthread-setuid-loop.c
|
||||
new file mode 100644
|
||||
index 0000000..fda2a49
|
||||
--- /dev/null
|
||||
+++ b/sysdeps/pthread/tst-pthread-setuid-loop.c
|
||||
@@ -0,0 +1,61 @@
|
||||
+/* Test that setuid, pthread_create, thread exit do not deadlock (bug 28361).
|
||||
+ Copyright (C) 2021 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 <support/check.h>
|
||||
+#include <support/xthread.h>
|
||||
+#include <unistd.h>
|
||||
+
|
||||
+/* How many threads to launch during each iteration. */
|
||||
+enum { threads = 4 };
|
||||
+
|
||||
+/* How many iterations to perform. This value seems to reproduce
|
||||
+ bug 28361 in a bout one in three runs. */
|
||||
+enum { iterations = 5000 };
|
||||
+
|
||||
+/* Cache of the real user ID used by setuid_thread. */
|
||||
+static uid_t uid;
|
||||
+
|
||||
+/* Start routine for the threads. */
|
||||
+static void *
|
||||
+setuid_thread (void *closure)
|
||||
+{
|
||||
+ TEST_COMPARE (setuid (uid), 0);
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ /* The setxid machinery is still invoked even if the UID is
|
||||
+ unchanged. (The kernel might reset other credentials as part of
|
||||
+ the system call.) */
|
||||
+ uid = getuid ();
|
||||
+
|
||||
+ for (int i = 0; i < iterations; ++i)
|
||||
+ {
|
||||
+ pthread_t thread_ids[threads];
|
||||
+ for (int j = 0; j < threads; ++j)
|
||||
+ thread_ids[j] = xpthread_create (NULL, setuid_thread, NULL);
|
||||
+ for (int j = 0; j < threads; ++j)
|
||||
+ xpthread_join (thread_ids[j]);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
424
nptl-Fix-race-between-pthread_kill-and-thread-exit-b.patch
Normal file
424
nptl-Fix-race-between-pthread_kill-and-thread-exit-b.patch
Normal file
@ -0,0 +1,424 @@
|
||||
From 526c3cf11ee9367344b6b15d669e4c3cb461a2be Mon Sep 17 00:00:00 2001
|
||||
From: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Mon, 13 Sep 2021 11:06:08 +0200
|
||||
Subject: [PATCH] nptl: Fix race between pthread_kill and thread exit (bug
|
||||
12889)
|
||||
|
||||
A new thread exit lock and flag are introduced. They are used to
|
||||
detect that the thread is about to exit or has exited in
|
||||
__pthread_kill_internal, and the signal is not sent in this case.
|
||||
|
||||
The test sysdeps/pthread/tst-pthread_cancel-select-loop.c is derived
|
||||
from a downstream test originally written by Marek Polacek.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
---
|
||||
nptl/allocatestack.c | 3 +
|
||||
nptl/descr.h | 6 ++
|
||||
nptl/pthread_create.c | 14 +++
|
||||
nptl/pthread_kill.c | 65 +++++++-----
|
||||
sysdeps/pthread/Makefile | 2 +
|
||||
sysdeps/pthread/tst-pthread_cancel-select-loop.c | 87 ++++++++++++++++
|
||||
sysdeps/pthread/tst-pthread_kill-exiting.c | 123 +++++++++++++++++++++++
|
||||
7 files changed, 275 insertions(+), 25 deletions(-)
|
||||
create mode 100644 sysdeps/pthread/tst-pthread_cancel-select-loop.c
|
||||
create mode 100644 sysdeps/pthread/tst-pthread_kill-exiting.c
|
||||
|
||||
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
|
||||
index 0356993..fa81007 100644
|
||||
--- a/nptl/allocatestack.c
|
||||
+++ b/nptl/allocatestack.c
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <futex-internal.h>
|
||||
#include <kernel-features.h>
|
||||
#include <nptl-stack.h>
|
||||
+#include <libc-lock.h>
|
||||
|
||||
/* Default alignment of stack. */
|
||||
#ifndef STACK_ALIGN
|
||||
@@ -126,6 +127,8 @@ get_cached_stack (size_t *sizep, void **memp)
|
||||
/* No pending event. */
|
||||
result->nextevent = NULL;
|
||||
|
||||
+ result->exiting = false;
|
||||
+ __libc_lock_init (result->exit_lock);
|
||||
result->tls_state = (struct tls_internal_t) { 0 };
|
||||
|
||||
/* Clear the DTV. */
|
||||
diff --git a/nptl/descr.h b/nptl/descr.h
|
||||
index e1c8831..41ee56f 100644
|
||||
--- a/nptl/descr.h
|
||||
+++ b/nptl/descr.h
|
||||
@@ -395,6 +395,12 @@ struct pthread
|
||||
PTHREAD_CANCEL_ASYNCHRONOUS). */
|
||||
unsigned char canceltype;
|
||||
|
||||
+ /* Used in __pthread_kill_internal to detected a thread that has
|
||||
+ exited or is about to exit. exit_lock must only be acquired
|
||||
+ after blocking signals. */
|
||||
+ bool exiting;
|
||||
+ int exit_lock; /* A low-level lock (for use with __libc_lock_init etc). */
|
||||
+
|
||||
/* Used on strsignal. */
|
||||
struct tls_internal_t tls_state;
|
||||
|
||||
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
|
||||
index 7607f36..a559f86 100644
|
||||
--- a/nptl/pthread_create.c
|
||||
+++ b/nptl/pthread_create.c
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <sys/single_threaded.h>
|
||||
#include <version.h>
|
||||
#include <clone_internal.h>
|
||||
+#include <futex-internal.h>
|
||||
|
||||
#include <shlib-compat.h>
|
||||
|
||||
@@ -484,6 +485,19 @@ start_thread (void *arg)
|
||||
/* This was the last thread. */
|
||||
exit (0);
|
||||
|
||||
+ /* This prevents sending a signal from this thread to itself during
|
||||
+ its final stages. This must come after the exit call above
|
||||
+ because atexit handlers must not run with signals blocked. */
|
||||
+ __libc_signal_block_all (NULL);
|
||||
+
|
||||
+ /* Tell __pthread_kill_internal that this thread is about to exit.
|
||||
+ If there is a __pthread_kill_internal in progress, this delays
|
||||
+ the thread exit until the signal has been queued by the kernel
|
||||
+ (so that the TID used to send it remains valid). */
|
||||
+ __libc_lock_lock (pd->exit_lock);
|
||||
+ pd->exiting = true;
|
||||
+ __libc_lock_unlock (pd->exit_lock);
|
||||
+
|
||||
#ifndef __ASSUME_SET_ROBUST_LIST
|
||||
/* If this thread has any robust mutexes locked, handle them now. */
|
||||
# if __PTHREAD_MUTEX_HAVE_PREV
|
||||
diff --git a/nptl/pthread_kill.c b/nptl/pthread_kill.c
|
||||
index 5d4c86f..fb7862e 100644
|
||||
--- a/nptl/pthread_kill.c
|
||||
+++ b/nptl/pthread_kill.c
|
||||
@@ -16,6 +16,7 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
+#include <libc-lock.h>
|
||||
#include <unistd.h>
|
||||
#include <pthreadP.h>
|
||||
#include <shlib-compat.h>
|
||||
@@ -23,37 +24,51 @@
|
||||
int
|
||||
__pthread_kill_internal (pthread_t threadid, int signo)
|
||||
{
|
||||
- pid_t tid;
|
||||
struct pthread *pd = (struct pthread *) threadid;
|
||||
-
|
||||
if (pd == THREAD_SELF)
|
||||
- /* It is a special case to handle raise() implementation after a vfork
|
||||
- call (which does not update the PD tid field). */
|
||||
- tid = INLINE_SYSCALL_CALL (gettid);
|
||||
- else
|
||||
- /* Force load of pd->tid into local variable or register. Otherwise
|
||||
- if a thread exits between ESRCH test and tgkill, we might return
|
||||
- EINVAL, because pd->tid would be cleared by the kernel. */
|
||||
- tid = atomic_forced_read (pd->tid);
|
||||
-
|
||||
- int val;
|
||||
- if (__glibc_likely (tid > 0))
|
||||
{
|
||||
- pid_t pid = __getpid ();
|
||||
-
|
||||
- val = INTERNAL_SYSCALL_CALL (tgkill, pid, tid, signo);
|
||||
- val = (INTERNAL_SYSCALL_ERROR_P (val)
|
||||
- ? INTERNAL_SYSCALL_ERRNO (val) : 0);
|
||||
+ /* Use the actual TID from the kernel, so that it refers to the
|
||||
+ current thread even if called after vfork. There is no
|
||||
+ signal blocking in this case, so that the signal is delivered
|
||||
+ immediately, before __pthread_kill_internal returns: a signal
|
||||
+ sent to the thread itself needs to be delivered
|
||||
+ synchronously. (It is unclear if Linux guarantees the
|
||||
+ delivery of all pending signals after unblocking in the code
|
||||
+ below. POSIX only guarantees delivery of a single signal,
|
||||
+ which may not be the right one.) */
|
||||
+ pid_t tid = INTERNAL_SYSCALL_CALL (gettid);
|
||||
+ int ret = INTERNAL_SYSCALL_CALL (kill, tid, signo);
|
||||
+ return INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0;
|
||||
}
|
||||
+
|
||||
+ /* Block all signals, as required by pd->exit_lock. */
|
||||
+ sigset_t old_mask;
|
||||
+ __libc_signal_block_all (&old_mask);
|
||||
+ __libc_lock_lock (pd->exit_lock);
|
||||
+
|
||||
+ int ret;
|
||||
+ if (pd->exiting)
|
||||
+ /* The thread is about to exit (or has exited). Sending the
|
||||
+ signal is either not observable (the target thread has already
|
||||
+ blocked signals at this point), or it will fail, or it might be
|
||||
+ delivered to a new, unrelated thread that has reused the TID.
|
||||
+ So do not actually send the signal. Do not report an error
|
||||
+ because the threadid argument is still valid (the thread ID
|
||||
+ lifetime has not ended), and ESRCH (for example) would be
|
||||
+ misleading. */
|
||||
+ ret = 0;
|
||||
else
|
||||
- /* The kernel reports that the thread has exited. POSIX specifies
|
||||
- the ESRCH error only for the case when the lifetime of a thread
|
||||
- ID has ended, but calling pthread_kill on such a thread ID is
|
||||
- undefined in glibc. Therefore, do not treat kernel thread exit
|
||||
- as an error. */
|
||||
- val = 0;
|
||||
+ {
|
||||
+ /* Using tgkill is a safety measure. pd->exit_lock ensures that
|
||||
+ the target thread cannot exit. */
|
||||
+ ret = INTERNAL_SYSCALL_CALL (tgkill, __getpid (), pd->tid, signo);
|
||||
+ ret = INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0;
|
||||
+ }
|
||||
+
|
||||
+ __libc_lock_unlock (pd->exit_lock);
|
||||
+ __libc_signal_restore_set (&old_mask);
|
||||
|
||||
- return val;
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
int
|
||||
diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile
|
||||
index dedfa0d..48dba71 100644
|
||||
--- a/sysdeps/pthread/Makefile
|
||||
+++ b/sysdeps/pthread/Makefile
|
||||
@@ -119,7 +119,9 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \
|
||||
tst-unwind-thread \
|
||||
tst-pt-vfork1 tst-pt-vfork2 tst-vfork1x tst-vfork2x \
|
||||
tst-pthread_cancel-exited \
|
||||
+ tst-pthread_cancel-select-loop \
|
||||
tst-pthread_kill-exited \
|
||||
+ tst-pthread_kill-exiting \
|
||||
# tests
|
||||
|
||||
tests-time64 := \
|
||||
diff --git a/sysdeps/pthread/tst-pthread_cancel-select-loop.c b/sysdeps/pthread/tst-pthread_cancel-select-loop.c
|
||||
new file mode 100644
|
||||
index 0000000..a620875
|
||||
--- /dev/null
|
||||
+++ b/sysdeps/pthread/tst-pthread_cancel-select-loop.c
|
||||
@@ -0,0 +1,87 @@
|
||||
+/* Test that pthread_cancel succeeds during thread exit.
|
||||
+ Copyright (C) 2021 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/>. */
|
||||
+
|
||||
+/* This test tries to trigger an internal race condition in
|
||||
+ pthread_cancel, where the cancellation signal is sent after the
|
||||
+ thread has begun the cancellation process. This can result in a
|
||||
+ spurious ESRCH error. For the original bug 12889, the window is
|
||||
+ quite small, so the bug was not reproduced in every run. */
|
||||
+
|
||||
+#include <stdbool.h>
|
||||
+#include <stddef.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/xthread.h>
|
||||
+#include <support/xunistd.h>
|
||||
+#include <sys/select.h>
|
||||
+#include <unistd.h>
|
||||
+
|
||||
+/* Set to true by timeout_thread_function when the test should
|
||||
+ terminate. */
|
||||
+static bool timeout;
|
||||
+
|
||||
+static void *
|
||||
+timeout_thread_function (void *unused)
|
||||
+{
|
||||
+ usleep (5 * 1000 * 1000);
|
||||
+ __atomic_store_n (&timeout, true, __ATOMIC_RELAXED);
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+/* Used for blocking the select function below. */
|
||||
+static int pipe_fds[2];
|
||||
+
|
||||
+static void *
|
||||
+canceled_thread_function (void *unused)
|
||||
+{
|
||||
+ while (true)
|
||||
+ {
|
||||
+ fd_set rfs;
|
||||
+ fd_set wfs;
|
||||
+ fd_set efs;
|
||||
+ FD_ZERO (&rfs);
|
||||
+ FD_ZERO (&wfs);
|
||||
+ FD_ZERO (&efs);
|
||||
+ FD_SET (pipe_fds[0], &rfs);
|
||||
+
|
||||
+ /* If the cancellation request is recognized early, the thread
|
||||
+ begins exiting while the cancellation signal arrives. */
|
||||
+ select (FD_SETSIZE, &rfs, &wfs, &efs, NULL);
|
||||
+ }
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ xpipe (pipe_fds);
|
||||
+ pthread_t thr_timeout = xpthread_create (NULL, timeout_thread_function, NULL);
|
||||
+
|
||||
+ while (!__atomic_load_n (&timeout, __ATOMIC_RELAXED))
|
||||
+ {
|
||||
+ pthread_t thr = xpthread_create (NULL, canceled_thread_function, NULL);
|
||||
+ xpthread_cancel (thr);
|
||||
+ TEST_VERIFY (xpthread_join (thr) == PTHREAD_CANCELED);
|
||||
+ }
|
||||
+
|
||||
+ xpthread_join (thr_timeout);
|
||||
+ xclose (pipe_fds[0]);
|
||||
+ xclose (pipe_fds[1]);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/sysdeps/pthread/tst-pthread_kill-exiting.c b/sysdeps/pthread/tst-pthread_kill-exiting.c
|
||||
new file mode 100644
|
||||
index 0000000..f803e94
|
||||
--- /dev/null
|
||||
+++ b/sysdeps/pthread/tst-pthread_kill-exiting.c
|
||||
@@ -0,0 +1,123 @@
|
||||
+/* Test that pthread_kill succeeds during thread exit.
|
||||
+ Copyright (C) 2021 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/>. */
|
||||
+
|
||||
+/* This test verifies that pthread_kill for a thread that is exiting
|
||||
+ succeeds (with or without actually delivering the signal). */
|
||||
+
|
||||
+#include <array_length.h>
|
||||
+#include <stdbool.h>
|
||||
+#include <stddef.h>
|
||||
+#include <support/xsignal.h>
|
||||
+#include <support/xthread.h>
|
||||
+#include <unistd.h>
|
||||
+
|
||||
+/* Set to true by timeout_thread_function when the test should
|
||||
+ terminate. */
|
||||
+static bool timeout;
|
||||
+
|
||||
+static void *
|
||||
+timeout_thread_function (void *unused)
|
||||
+{
|
||||
+ usleep (1000 * 1000);
|
||||
+ __atomic_store_n (&timeout, true, __ATOMIC_RELAXED);
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+/* Used to synchronize the sending threads with the target thread and
|
||||
+ main thread. */
|
||||
+static pthread_barrier_t barrier_1;
|
||||
+static pthread_barrier_t barrier_2;
|
||||
+
|
||||
+/* The target thread to which signals are to be sent. */
|
||||
+static pthread_t target_thread;
|
||||
+
|
||||
+/* Set by the main thread to true after timeout has been set to
|
||||
+ true. */
|
||||
+static bool exiting;
|
||||
+
|
||||
+static void *
|
||||
+sender_thread_function (void *unused)
|
||||
+{
|
||||
+ while (true)
|
||||
+ {
|
||||
+ /* Wait until target_thread has been initialized. The target
|
||||
+ thread and main thread participate in this barrier. */
|
||||
+ xpthread_barrier_wait (&barrier_1);
|
||||
+
|
||||
+ if (exiting)
|
||||
+ break;
|
||||
+
|
||||
+ xpthread_kill (target_thread, SIGUSR1);
|
||||
+
|
||||
+ /* Communicate that the signal has been sent. The main thread
|
||||
+ participates in this barrier. */
|
||||
+ xpthread_barrier_wait (&barrier_2);
|
||||
+ }
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static void *
|
||||
+target_thread_function (void *unused)
|
||||
+{
|
||||
+ target_thread = pthread_self ();
|
||||
+ xpthread_barrier_wait (&barrier_1);
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ xsignal (SIGUSR1, SIG_IGN);
|
||||
+
|
||||
+ pthread_t thr_timeout = xpthread_create (NULL, timeout_thread_function, NULL);
|
||||
+
|
||||
+ pthread_t threads[4];
|
||||
+ xpthread_barrier_init (&barrier_1, NULL, array_length (threads) + 2);
|
||||
+ xpthread_barrier_init (&barrier_2, NULL, array_length (threads) + 1);
|
||||
+
|
||||
+ for (int i = 0; i < array_length (threads); ++i)
|
||||
+ threads[i] = xpthread_create (NULL, sender_thread_function, NULL);
|
||||
+
|
||||
+ while (!__atomic_load_n (&timeout, __ATOMIC_RELAXED))
|
||||
+ {
|
||||
+ xpthread_create (NULL, target_thread_function, NULL);
|
||||
+
|
||||
+ /* Wait for the target thread to be set up and signal sending to
|
||||
+ start. */
|
||||
+ xpthread_barrier_wait (&barrier_1);
|
||||
+
|
||||
+ /* Wait for signal sending to complete. */
|
||||
+ xpthread_barrier_wait (&barrier_2);
|
||||
+
|
||||
+ xpthread_join (target_thread);
|
||||
+ }
|
||||
+
|
||||
+ exiting = true;
|
||||
+
|
||||
+ /* Signal the sending threads to exit. */
|
||||
+ xpthread_create (NULL, target_thread_function, NULL);
|
||||
+ xpthread_barrier_wait (&barrier_1);
|
||||
+
|
||||
+ for (int i = 0; i < array_length (threads); ++i)
|
||||
+ xpthread_join (threads[i]);
|
||||
+ xpthread_join (thr_timeout);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
37
nptl-Fix-type-of-pthread_mutexattr_getrobust_np-pthr.patch
Normal file
37
nptl-Fix-type-of-pthread_mutexattr_getrobust_np-pthr.patch
Normal file
@ -0,0 +1,37 @@
|
||||
From f3e664563361dc17530113b3205998d1f19dc4d9 Mon Sep 17 00:00:00 2001
|
||||
From: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue, 21 Sep 2021 07:12:56 +0200
|
||||
Subject: [PATCH] nptl: Fix type of pthread_mutexattr_getrobust_np,
|
||||
pthread_mutexattr_setrobust_np (bug 28036)
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
Tested-by: Carlos O'Donell <carlos@redhat.com>
|
||||
---
|
||||
sysdeps/nptl/pthread.h | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
|
||||
index f1b7f2b..43146e9 100644
|
||||
--- a/sysdeps/nptl/pthread.h
|
||||
+++ b/sysdeps/nptl/pthread.h
|
||||
@@ -933,7 +933,7 @@ extern int pthread_mutexattr_getrobust (const pthread_mutexattr_t *__attr,
|
||||
# ifdef __USE_GNU
|
||||
# ifdef __REDIRECT_NTH
|
||||
extern int __REDIRECT_NTH (pthread_mutexattr_getrobust_np,
|
||||
- (pthread_mutex_t *, int *),
|
||||
+ (pthread_mutexattr_t *, int *),
|
||||
pthread_mutexattr_getrobust) __nonnull ((1))
|
||||
__attribute_deprecated_msg__ ("\
|
||||
pthread_mutexattr_getrobust_np is deprecated, use pthread_mutexattr_getrobust");
|
||||
@@ -949,7 +949,7 @@ extern int pthread_mutexattr_setrobust (pthread_mutexattr_t *__attr,
|
||||
# ifdef __USE_GNU
|
||||
# ifdef __REDIRECT_NTH
|
||||
extern int __REDIRECT_NTH (pthread_mutexattr_setrobust_np,
|
||||
- (pthread_mutex_t *, int),
|
||||
+ (pthread_mutexattr_t *, int),
|
||||
pthread_mutexattr_setrobust) __nonnull ((1))
|
||||
__attribute_deprecated_msg__ ("\
|
||||
pthread_mutexattr_setrobust_np is deprecated, use pthread_mutexattr_setrobust");
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
162
nptl-pthread_kill-must-send-signals-to-a-specific-th.patch
Normal file
162
nptl-pthread_kill-must-send-signals-to-a-specific-th.patch
Normal file
@ -0,0 +1,162 @@
|
||||
From eae81d70574e923ce3c59078b8df857ae192efa6 Mon Sep 17 00:00:00 2001
|
||||
From: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri, 1 Oct 2021 18:16:41 +0200
|
||||
Subject: [PATCH] nptl: pthread_kill must send signals to a specific thread [BZ
|
||||
#28407]
|
||||
|
||||
The choice between the kill vs tgkill system calls is not just about
|
||||
the TID reuse race, but also about whether the signal is sent to the
|
||||
whole process (and any thread in it) or to a specific thread.
|
||||
|
||||
This was caught by the openposix test suite:
|
||||
|
||||
LTP: openposix test suite - FAIL: SIGUSR1 is member of new thread pendingset.
|
||||
<https://gitlab.com/cki-project/kernel-tests/-/issues/764>
|
||||
|
||||
Fixes commit 526c3cf11ee9367344b6b15d669e4c3cb461a2be ("nptl: Fix race
|
||||
between pthread_kill and thread exit (bug 12889)").
|
||||
|
||||
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
||||
Tested-by: Carlos O'Donell <carlos@redhat.com>
|
||||
---
|
||||
nptl/pthread_kill.c | 4 +-
|
||||
sysdeps/pthread/Makefile | 1 +
|
||||
sysdeps/pthread/tst-pthread-raise-blocked-self.c | 92 ++++++++++++++++++++++++
|
||||
3 files changed, 94 insertions(+), 3 deletions(-)
|
||||
create mode 100644 sysdeps/pthread/tst-pthread-raise-blocked-self.c
|
||||
|
||||
diff --git a/nptl/pthread_kill.c b/nptl/pthread_kill.c
|
||||
index a44dc8f..35bf1f9 100644
|
||||
--- a/nptl/pthread_kill.c
|
||||
+++ b/nptl/pthread_kill.c
|
||||
@@ -40,7 +40,7 @@ __pthread_kill_implementation (pthread_t threadid, int signo, int no_tid)
|
||||
below. POSIX only guarantees delivery of a single signal,
|
||||
which may not be the right one.) */
|
||||
pid_t tid = INTERNAL_SYSCALL_CALL (gettid);
|
||||
- int ret = INTERNAL_SYSCALL_CALL (kill, tid, signo);
|
||||
+ int ret = INTERNAL_SYSCALL_CALL (tgkill, __getpid (), tid, signo);
|
||||
return INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0;
|
||||
}
|
||||
|
||||
@@ -59,8 +59,6 @@ __pthread_kill_implementation (pthread_t threadid, int signo, int no_tid)
|
||||
ret = no_tid;
|
||||
else
|
||||
{
|
||||
- /* Using tgkill is a safety measure. pd->exit_lock ensures that
|
||||
- the target thread cannot exit. */
|
||||
ret = INTERNAL_SYSCALL_CALL (tgkill, __getpid (), pd->tid, signo);
|
||||
ret = INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0;
|
||||
}
|
||||
diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile
|
||||
index d4bd2d4..0af9c59 100644
|
||||
--- a/sysdeps/pthread/Makefile
|
||||
+++ b/sysdeps/pthread/Makefile
|
||||
@@ -121,6 +121,7 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \
|
||||
tst-pthread-setuid-loop \
|
||||
tst-pthread_cancel-exited \
|
||||
tst-pthread_cancel-select-loop \
|
||||
+ tst-pthread-raise-blocked-self \
|
||||
tst-pthread_kill-exited \
|
||||
tst-pthread_kill-exiting \
|
||||
# tests
|
||||
diff --git a/sysdeps/pthread/tst-pthread-raise-blocked-self.c b/sysdeps/pthread/tst-pthread-raise-blocked-self.c
|
||||
new file mode 100644
|
||||
index 0000000..128e1a6
|
||||
--- /dev/null
|
||||
+++ b/sysdeps/pthread/tst-pthread-raise-blocked-self.c
|
||||
@@ -0,0 +1,92 @@
|
||||
+/* Test that raise sends signal to current thread even if blocked.
|
||||
+ Copyright (C) 2021 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 <signal.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/xsignal.h>
|
||||
+#include <support/xthread.h>
|
||||
+#include <pthread.h>
|
||||
+#include <unistd.h>
|
||||
+
|
||||
+/* Used to create a dummy thread ID distinct from all other thread
|
||||
+ IDs. */
|
||||
+static void *
|
||||
+noop (void *ignored)
|
||||
+{
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static volatile pthread_t signal_thread;
|
||||
+
|
||||
+static void
|
||||
+signal_handler (int signo)
|
||||
+{
|
||||
+ signal_thread = pthread_self ();
|
||||
+}
|
||||
+
|
||||
+/* Used to ensure that waiting_thread has launched and can accept
|
||||
+ signals. */
|
||||
+static pthread_barrier_t barrier;
|
||||
+
|
||||
+static void *
|
||||
+waiting_thread (void *ignored)
|
||||
+{
|
||||
+ xpthread_barrier_wait (&barrier);
|
||||
+ pause ();
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ xsignal (SIGUSR1, signal_handler);
|
||||
+ xpthread_barrier_init (&barrier, NULL, 2);
|
||||
+
|
||||
+ /* Distinct thread ID value to */
|
||||
+ pthread_t dummy = xpthread_create (NULL, noop, NULL);
|
||||
+ signal_thread = dummy;
|
||||
+
|
||||
+ pthread_t helper = xpthread_create (NULL, waiting_thread, NULL);
|
||||
+
|
||||
+ /* Make sure that the thread is running. */
|
||||
+ xpthread_barrier_wait (&barrier);
|
||||
+
|
||||
+ /* Block signals on this thread. */
|
||||
+ sigset_t set;
|
||||
+ sigfillset (&set);
|
||||
+ xpthread_sigmask (SIG_BLOCK, &set, NULL);
|
||||
+
|
||||
+ /* Send the signal to this thread. It must not be delivered. */
|
||||
+ raise (SIGUSR1);
|
||||
+ TEST_VERIFY (signal_thread == dummy);
|
||||
+
|
||||
+ /* Wait a bit to give a chance for signal delivery (increases
|
||||
+ chances of failure with bug 28407). */
|
||||
+ usleep (50 * 1000);
|
||||
+
|
||||
+ /* Unblocking should cause synchronous delivery of the signal. */
|
||||
+ xpthread_sigmask (SIG_UNBLOCK, &set, NULL);
|
||||
+ TEST_VERIFY (signal_thread == pthread_self ());
|
||||
+
|
||||
+ xpthread_cancel (helper);
|
||||
+ xpthread_join (helper);
|
||||
+ xpthread_join (dummy);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
142
nptl-pthread_kill-needs-to-return-ESRCH-for-old-prog.patch
Normal file
142
nptl-pthread_kill-needs-to-return-ESRCH-for-old-prog.patch
Normal file
@ -0,0 +1,142 @@
|
||||
From 95dba35bf05e4a5d69dfae5e9c9d4df3646a7f93 Mon Sep 17 00:00:00 2001
|
||||
From: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Mon, 20 Sep 2021 14:56:08 +0200
|
||||
Subject: [PATCH] nptl: pthread_kill needs to return ESRCH for old programs
|
||||
(bug 19193)
|
||||
|
||||
The fix for bug 19193 breaks some old applications which appear
|
||||
to use pthread_kill to probe if a thread is still running, something
|
||||
that is not supported by POSIX.
|
||||
---
|
||||
nptl/pthread_kill.c | 37 ++++++++++++++++++++++++-------
|
||||
sysdeps/pthread/tst-pthread_kill-exited.c | 21 ++++++++++++++++--
|
||||
2 files changed, 48 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/nptl/pthread_kill.c b/nptl/pthread_kill.c
|
||||
index fb7862e..a44dc8f 100644
|
||||
--- a/nptl/pthread_kill.c
|
||||
+++ b/nptl/pthread_kill.c
|
||||
@@ -21,8 +21,11 @@
|
||||
#include <pthreadP.h>
|
||||
#include <shlib-compat.h>
|
||||
|
||||
-int
|
||||
-__pthread_kill_internal (pthread_t threadid, int signo)
|
||||
+/* Sends SIGNO to THREADID. If the thread is about to exit or has
|
||||
+ already exited on the kernel side, return NO_TID. Otherwise return
|
||||
+ 0 or an error code. */
|
||||
+static int
|
||||
+__pthread_kill_implementation (pthread_t threadid, int signo, int no_tid)
|
||||
{
|
||||
struct pthread *pd = (struct pthread *) threadid;
|
||||
if (pd == THREAD_SELF)
|
||||
@@ -52,11 +55,8 @@ __pthread_kill_internal (pthread_t threadid, int signo)
|
||||
signal is either not observable (the target thread has already
|
||||
blocked signals at this point), or it will fail, or it might be
|
||||
delivered to a new, unrelated thread that has reused the TID.
|
||||
- So do not actually send the signal. Do not report an error
|
||||
- because the threadid argument is still valid (the thread ID
|
||||
- lifetime has not ended), and ESRCH (for example) would be
|
||||
- misleading. */
|
||||
- ret = 0;
|
||||
+ So do not actually send the signal. */
|
||||
+ ret = no_tid;
|
||||
else
|
||||
{
|
||||
/* Using tgkill is a safety measure. pd->exit_lock ensures that
|
||||
@@ -72,6 +72,15 @@ __pthread_kill_internal (pthread_t threadid, int signo)
|
||||
}
|
||||
|
||||
int
|
||||
+__pthread_kill_internal (pthread_t threadid, int signo)
|
||||
+{
|
||||
+ /* Do not report an error in the no-tid case because the threadid
|
||||
+ argument is still valid (the thread ID lifetime has not ended),
|
||||
+ and ESRCH (for example) would be misleading. */
|
||||
+ return __pthread_kill_implementation (threadid, signo, 0);
|
||||
+}
|
||||
+
|
||||
+int
|
||||
__pthread_kill (pthread_t threadid, int signo)
|
||||
{
|
||||
/* Disallow sending the signal we use for cancellation, timers,
|
||||
@@ -81,6 +90,7 @@ __pthread_kill (pthread_t threadid, int signo)
|
||||
|
||||
return __pthread_kill_internal (threadid, signo);
|
||||
}
|
||||
+
|
||||
/* Some architectures (for instance arm) might pull raise through libgcc, so
|
||||
avoid the symbol version if it ends up being used on ld.so. */
|
||||
#if !IS_IN(rtld)
|
||||
@@ -88,6 +98,17 @@ libc_hidden_def (__pthread_kill)
|
||||
versioned_symbol (libc, __pthread_kill, pthread_kill, GLIBC_2_34);
|
||||
|
||||
# if OTHER_SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34)
|
||||
-compat_symbol (libc, __pthread_kill, pthread_kill, GLIBC_2_0);
|
||||
+/* Variant which returns ESRCH in the no-TID case, for backwards
|
||||
+ compatibility. */
|
||||
+int
|
||||
+attribute_compat_text_section
|
||||
+__pthread_kill_esrch (pthread_t threadid, int signo)
|
||||
+{
|
||||
+ if (__is_internal_signal (signo))
|
||||
+ return EINVAL;
|
||||
+
|
||||
+ return __pthread_kill_implementation (threadid, signo, ESRCH);
|
||||
+}
|
||||
+compat_symbol (libc, __pthread_kill_esrch, pthread_kill, GLIBC_2_0);
|
||||
# endif
|
||||
#endif
|
||||
diff --git a/sysdeps/pthread/tst-pthread_kill-exited.c b/sysdeps/pthread/tst-pthread_kill-exited.c
|
||||
index 7575fb6..a2fddad 100644
|
||||
--- a/sysdeps/pthread/tst-pthread_kill-exited.c
|
||||
+++ b/sysdeps/pthread/tst-pthread_kill-exited.c
|
||||
@@ -16,11 +16,15 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
-/* This test verifies that pthread_kill returns 0 (and not ESRCH) for
|
||||
- a thread that has exited on the kernel side. */
|
||||
+/* This test verifies that the default pthread_kill returns 0 (and not
|
||||
+ ESRCH) for a thread that has exited on the kernel side. */
|
||||
|
||||
+#include <errno.h>
|
||||
+#include <pthread.h>
|
||||
+#include <shlib-compat.h>
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
+#include <support/check.h>
|
||||
#include <support/support.h>
|
||||
#include <support/xthread.h>
|
||||
|
||||
@@ -30,6 +34,12 @@ noop_thread (void *closure)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+#if TEST_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34) && PTHREAD_IN_LIBC
|
||||
+extern __typeof (pthread_kill) compat_pthread_kill;
|
||||
+compat_symbol_reference (libpthread, compat_pthread_kill, pthread_kill,
|
||||
+ GLIBC_2_0);
|
||||
+#endif
|
||||
+
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
@@ -37,7 +47,14 @@ do_test (void)
|
||||
|
||||
support_wait_for_thread_exit ();
|
||||
|
||||
+ /* NB: Always uses the default symbol due to separate compilation. */
|
||||
xpthread_kill (thr, SIGUSR1);
|
||||
+
|
||||
+#if TEST_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34) && PTHREAD_IN_LIBC
|
||||
+ /* Old binaries need the non-conforming ESRCH error code. */
|
||||
+ TEST_COMPARE (compat_pthread_kill (thr, SIGUSR1), ESRCH);
|
||||
+#endif
|
||||
+
|
||||
xpthread_join (thr);
|
||||
|
||||
return 0;
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user