SHA256
3
0
forked from pool/glibc

Accepting request 677136 from home:Andreas_Schwab:Factory

- pthread-rwlock-trylock-stalls.patch: nptl: Fix pthread_rwlock_try*lock
  stalls (BZ #23844)
- arm-systemtap-probe-constraint.patch: arm: Use "nr" constraint for
  Systemtap probes (BZ #24164)
- pthread-mutex-barrier.patch: Add compiler barriers around modifications
  of the robust mutex list for pthread_mutex_trylock (BZ #24180)
- fork-handler-lock.patch: nptl: Avoid fork handler lock for
  async-signal-safe fork (BZ #24161)
- pthread-join-probe.patch: nptl: Fix invalid Systemtap probe in
  pthread_join (BZ #24211)
- riscv-clone-unwind.patch: RISC-V: Fix elfutils testsuite unwind failures
  (BZ #24040)

OBS-URL: https://build.opensuse.org/request/show/677136
OBS-URL: https://build.opensuse.org/package/show/Base:System/glibc?expand=0&rev=518
This commit is contained in:
Andreas Schwab 2019-02-18 13:35:23 +00:00 committed by Git OBS Bridge
parent add9e7bf61
commit afe7a231ef
8 changed files with 1146 additions and 2 deletions

View File

@ -0,0 +1,74 @@
2019-02-05 Florian Weimer <fweimer@redhat.com>
[BZ #24164]
arm: Use "nr" constraint for Systemtap probes, to avoid the
compiler using memory operands for constants, due to the "o"
alternative in the default "nor" constraint.
* include/stap-probe.h [USE_STAP_PROBE]: Include
<stap-probe-machine.h>
* sysdeps/generic/stap-probe-machine.h: New file.
* sysdeps/arm/stap-probe-machine.h: Likewise.
Index: glibc-2.29/include/stap-probe.h
===================================================================
--- glibc-2.29.orig/include/stap-probe.h
+++ glibc-2.29/include/stap-probe.h
@@ -21,6 +21,7 @@
#ifdef USE_STAP_PROBE
+# include <stap-probe-machine.h>
# include <sys/sdt.h>
/* Our code uses one macro LIBC_PROBE (name, n, arg1, ..., argn).
Index: glibc-2.29/sysdeps/arm/stap-probe-machine.h
===================================================================
--- /dev/null
+++ glibc-2.29/sysdeps/arm/stap-probe-machine.h
@@ -0,0 +1,22 @@
+/* Macros for customizing Systemtap <sys/sdt.h>. Arm version.
+ Copyright (C) 2019 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
+ <http://www.gnu.org/licenses/>. */
+
+/* The default "nor" constraint produces unparseable memory references
+ for constants. Omit the problematic "o" constraint. See bug 24164
+ and GCC PR 89146. */
+#define STAP_SDT_ARG_CONSTRAINT nr
Index: glibc-2.29/sysdeps/generic/stap-probe-machine.h
===================================================================
--- /dev/null
+++ glibc-2.29/sysdeps/generic/stap-probe-machine.h
@@ -0,0 +1,19 @@
+/* Macros for customizing Systemtap <sys/sdt.h>. Generic version.
+ Copyright (C) 2019 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
+ <http://www.gnu.org/licenses/>. */
+
+/* By default, there are no customizations. */

91
fork-handler-lock.patch Normal file
View File

@ -0,0 +1,91 @@
2019-02-08 Florian Weimer <fweimer@redhat.com>
[BZ #24161]
* sysdeps/nptl/fork.h (__run_fork_handlers): Add multiple_threads
argument.
* nptl/register-atfork.c (__run_fork_handlers): Only perform
locking if the new do_locking argument is true.
* sysdeps/nptl/fork.c (__libc_fork): Pass multiple_threads to
__run_fork_handlers.
Index: glibc-2.29/nptl/register-atfork.c
===================================================================
--- glibc-2.29.orig/nptl/register-atfork.c
+++ glibc-2.29/nptl/register-atfork.c
@@ -107,13 +107,14 @@ __unregister_atfork (void *dso_handle)
}
void
-__run_fork_handlers (enum __run_fork_handler_type who)
+__run_fork_handlers (enum __run_fork_handler_type who, _Bool do_locking)
{
struct fork_handler *runp;
if (who == atfork_run_prepare)
{
- lll_lock (atfork_lock, LLL_PRIVATE);
+ if (do_locking)
+ lll_lock (atfork_lock, LLL_PRIVATE);
size_t sl = fork_handler_list_size (&fork_handlers);
for (size_t i = sl; i > 0; i--)
{
@@ -133,7 +134,8 @@ __run_fork_handlers (enum __run_fork_han
else if (who == atfork_run_parent && runp->parent_handler)
runp->parent_handler ();
}
- lll_unlock (atfork_lock, LLL_PRIVATE);
+ if (do_locking)
+ lll_unlock (atfork_lock, LLL_PRIVATE);
}
}
Index: glibc-2.29/sysdeps/nptl/fork.c
===================================================================
--- glibc-2.29.orig/sysdeps/nptl/fork.c
+++ glibc-2.29/sysdeps/nptl/fork.c
@@ -55,7 +55,7 @@ __libc_fork (void)
but our current fork implementation is not. */
bool multiple_threads = THREAD_GETMEM (THREAD_SELF, header.multiple_threads);
- __run_fork_handlers (atfork_run_prepare);
+ __run_fork_handlers (atfork_run_prepare, multiple_threads);
/* If we are not running multiple threads, we do not have to
preserve lock state. If fork runs from a signal handler, only
@@ -134,7 +134,7 @@ __libc_fork (void)
__rtld_lock_initialize (GL(dl_load_lock));
/* Run the handlers registered for the child. */
- __run_fork_handlers (atfork_run_child);
+ __run_fork_handlers (atfork_run_child, multiple_threads);
}
else
{
@@ -149,7 +149,7 @@ __libc_fork (void)
}
/* Run the handlers registered for the parent. */
- __run_fork_handlers (atfork_run_parent);
+ __run_fork_handlers (atfork_run_parent, multiple_threads);
}
return pid;
Index: glibc-2.29/sysdeps/nptl/fork.h
===================================================================
--- glibc-2.29.orig/sysdeps/nptl/fork.h
+++ glibc-2.29/sysdeps/nptl/fork.h
@@ -52,9 +52,11 @@ enum __run_fork_handler_type
- atfork_run_child: run all the CHILD_HANDLER and unlocks the internal
lock.
- atfork_run_parent: run all the PARENT_HANDLER and unlocks the internal
- lock. */
-extern void __run_fork_handlers (enum __run_fork_handler_type who)
- attribute_hidden;
+ lock.
+
+ Perform locking only if DO_LOCKING. */
+extern void __run_fork_handlers (enum __run_fork_handler_type who,
+ _Bool do_locking) attribute_hidden;
/* C library side function to register new fork handlers. */
extern int __register_atfork (void (*__prepare) (void),

View File

@ -1,3 +1,19 @@
-------------------------------------------------------------------
Mon Feb 18 09:28:08 UTC 2019 - schwab@suse.de
- pthread-rwlock-trylock-stalls.patch: nptl: Fix pthread_rwlock_try*lock
stalls (BZ #23844)
- arm-systemtap-probe-constraint.patch: arm: Use "nr" constraint for
Systemtap probes (BZ #24164)
- pthread-mutex-barrier.patch: Add compiler barriers around modifications
of the robust mutex list for pthread_mutex_trylock (BZ #24180)
- fork-handler-lock.patch: nptl: Avoid fork handler lock for
async-signal-safe fork (BZ #24161)
- pthread-join-probe.patch: nptl: Fix invalid Systemtap probe in
pthread_join (BZ #24211)
- riscv-clone-unwind.patch: RISC-V: Fix elfutils testsuite unwind failures
(BZ #24040)
-------------------------------------------------------------------
Fri Feb 1 10:34:39 UTC 2019 - schwab@suse.de

View File

@ -270,6 +270,18 @@ Patch306: glibc-fix-double-loopback.diff
###
# Patches from upstream
###
# PATCH-FIX-UPSTREAM nptl: Fix pthread_rwlock_try*lock stalls (BZ #23844)
Patch1000: pthread-rwlock-trylock-stalls.patch
# PATCH-FIX-UPSTREAM arm: Use "nr" constraint for Systemtap probes (BZ #24164)
Patch1001: arm-systemtap-probe-constraint.patch
# PATCH-FIX-UPSTREAM Add compiler barriers around modifications of the robust mutex list for pthread_mutex_trylock (BZ #24180)
Patch1002: pthread-mutex-barrier.patch
# PATCH-FIX-UPSTREAM nptl: Avoid fork handler lock for async-signal-safe fork (BZ #24161)
Patch1003: fork-handler-lock.patch
# PATCH-FIX-UPSTREAM nptl: Fix invalid Systemtap probe in pthread_join (BZ #24211)
Patch1004: pthread-join-probe.patch
# PATCH-FIX-UPSTREAM RISC-V: Fix elfutils testsuite unwind failures (BZ #24040)
Patch1005: riscv-clone-unwind.patch
###
# Patches awaiting upstream approval
@ -479,6 +491,13 @@ makedb: A program to create a database for nss
%patch304 -p1
%patch306 -p1
%patch1000 -p1
%patch1001 -p1
%patch1002 -p1
%patch1003 -p1
%patch1004 -p1
%patch1005 -p1
%patch2000 -p1
%patch2004 -p1
%patch2005 -p1
@ -850,9 +869,9 @@ cc-base/elf/ldconfig -vn $destdir
# this will not work if we generate them in parallel.
# thus we need to run fdupes on /usr/lib/locale/
# Still, on my system this is a speed advantage:
# non-parallel build for install-locale-files: 9:34mins
# non-parallel build for install-locales: 9:34mins
# parallel build with fdupes: 7:08mins
make %{?_smp_mflags} install_root=%{buildroot} localedata/install-locale-files
make %{?_smp_mflags} install_root=%{buildroot} localedata/install-locales
# Avoid hardlinks across subpackages
mv %{buildroot}/usr/lib/locale/{en_US,C}.utf8 .
%fdupes %{buildroot}/usr/lib/locale

36
pthread-join-probe.patch Normal file
View File

@ -0,0 +1,36 @@
2019-02-15 Florian Weimer <fweimer@redhat.com>
[BZ #24211]
* nptl/pthread_join_common.c (__pthread_timedjoin_ex): Do not read
pd->result after the thread descriptor has been freed.
Index: glibc-2.29/nptl/pthread_join_common.c
===================================================================
--- glibc-2.29.orig/nptl/pthread_join_common.c
+++ glibc-2.29/nptl/pthread_join_common.c
@@ -86,6 +86,7 @@ __pthread_timedjoin_ex (pthread_t thread
pthread_cleanup_pop (0);
}
+ void *pd_result = pd->result;
if (__glibc_likely (result == 0))
{
/* We mark the thread as terminated and as joined. */
@@ -93,7 +94,7 @@ __pthread_timedjoin_ex (pthread_t thread
/* Store the return value if the caller is interested. */
if (thread_return != NULL)
- *thread_return = pd->result;
+ *thread_return = pd_result;
/* Free the TCB. */
__free_tcb (pd);
@@ -101,7 +102,7 @@ __pthread_timedjoin_ex (pthread_t thread
else
pd->joinid = NULL;
- LIBC_PROBE (pthread_join_ret, 3, threadid, result, pd->result);
+ LIBC_PROBE (pthread_join_ret, 3, threadid, result, pd_result);
return result;
}

173
pthread-mutex-barrier.patch Normal file
View File

@ -0,0 +1,173 @@
2019-02-07 Stefan Liebler <stli@linux.ibm.com>
[BZ #24180]
* nptl/pthread_mutex_trylock.c (__pthread_mutex_trylock):
Add compiler barriers and comments.
Index: glibc-2.29/nptl/pthread_mutex_trylock.c
===================================================================
--- glibc-2.29.orig/nptl/pthread_mutex_trylock.c
+++ glibc-2.29/nptl/pthread_mutex_trylock.c
@@ -94,6 +94,9 @@ __pthread_mutex_trylock (pthread_mutex_t
case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP:
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
&mutex->__data.__list.__next);
+ /* We need to set op_pending before starting the operation. Also
+ see comments at ENQUEUE_MUTEX. */
+ __asm ("" ::: "memory");
oldval = mutex->__data.__lock;
do
@@ -119,7 +122,12 @@ __pthread_mutex_trylock (pthread_mutex_t
/* But it is inconsistent unless marked otherwise. */
mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
+ /* We must not enqueue the mutex before we have acquired it.
+ Also see comments at ENQUEUE_MUTEX. */
+ __asm ("" ::: "memory");
ENQUEUE_MUTEX (mutex);
+ /* We need to clear op_pending after we enqueue the mutex. */
+ __asm ("" ::: "memory");
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
/* Note that we deliberately exist here. If we fall
@@ -135,6 +143,8 @@ __pthread_mutex_trylock (pthread_mutex_t
int kind = PTHREAD_MUTEX_TYPE (mutex);
if (kind == PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP)
{
+ /* We do not need to ensure ordering wrt another memory
+ access. Also see comments at ENQUEUE_MUTEX. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
NULL);
return EDEADLK;
@@ -142,6 +152,8 @@ __pthread_mutex_trylock (pthread_mutex_t
if (kind == PTHREAD_MUTEX_ROBUST_RECURSIVE_NP)
{
+ /* We do not need to ensure ordering wrt another memory
+ access. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
NULL);
@@ -160,6 +172,9 @@ __pthread_mutex_trylock (pthread_mutex_t
id, 0);
if (oldval != 0 && (oldval & FUTEX_OWNER_DIED) == 0)
{
+ /* We haven't acquired the lock as it is already acquired by
+ another owner. We do not need to ensure ordering wrt another
+ memory access. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
return EBUSY;
@@ -173,13 +188,20 @@ __pthread_mutex_trylock (pthread_mutex_t
if (oldval == id)
lll_unlock (mutex->__data.__lock,
PTHREAD_ROBUST_MUTEX_PSHARED (mutex));
+ /* FIXME This violates the mutex destruction requirements. See
+ __pthread_mutex_unlock_full. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
return ENOTRECOVERABLE;
}
}
while ((oldval & FUTEX_OWNER_DIED) != 0);
+ /* We must not enqueue the mutex before we have acquired it.
+ Also see comments at ENQUEUE_MUTEX. */
+ __asm ("" ::: "memory");
ENQUEUE_MUTEX (mutex);
+ /* We need to clear op_pending after we enqueue the mutex. */
+ __asm ("" ::: "memory");
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
mutex->__data.__owner = id;
@@ -211,10 +233,15 @@ __pthread_mutex_trylock (pthread_mutex_t
}
if (robust)
- /* Note: robust PI futexes are signaled by setting bit 0. */
- THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
- (void *) (((uintptr_t) &mutex->__data.__list.__next)
- | 1));
+ {
+ /* Note: robust PI futexes are signaled by setting bit 0. */
+ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
+ (void *) (((uintptr_t) &mutex->__data.__list.__next)
+ | 1));
+ /* We need to set op_pending before starting the operation. Also
+ see comments at ENQUEUE_MUTEX. */
+ __asm ("" ::: "memory");
+ }
oldval = mutex->__data.__lock;
@@ -223,12 +250,16 @@ __pthread_mutex_trylock (pthread_mutex_t
{
if (kind == PTHREAD_MUTEX_ERRORCHECK_NP)
{
+ /* We do not need to ensure ordering wrt another memory
+ access. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
return EDEADLK;
}
if (kind == PTHREAD_MUTEX_RECURSIVE_NP)
{
+ /* We do not need to ensure ordering wrt another memory
+ access. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
/* Just bump the counter. */
@@ -250,6 +281,9 @@ __pthread_mutex_trylock (pthread_mutex_t
{
if ((oldval & FUTEX_OWNER_DIED) == 0)
{
+ /* We haven't acquired the lock as it is already acquired by
+ another owner. We do not need to ensure ordering wrt another
+ memory access. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
return EBUSY;
@@ -270,6 +304,9 @@ __pthread_mutex_trylock (pthread_mutex_t
if (INTERNAL_SYSCALL_ERROR_P (e, __err)
&& INTERNAL_SYSCALL_ERRNO (e, __err) == EWOULDBLOCK)
{
+ /* The kernel has not yet finished the mutex owner death.
+ We do not need to ensure ordering wrt another memory
+ access. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
return EBUSY;
@@ -287,7 +324,12 @@ __pthread_mutex_trylock (pthread_mutex_t
/* But it is inconsistent unless marked otherwise. */
mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT;
+ /* We must not enqueue the mutex before we have acquired it.
+ Also see comments at ENQUEUE_MUTEX. */
+ __asm ("" ::: "memory");
ENQUEUE_MUTEX (mutex);
+ /* We need to clear op_pending after we enqueue the mutex. */
+ __asm ("" ::: "memory");
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
/* Note that we deliberately exit here. If we fall
@@ -310,13 +352,20 @@ __pthread_mutex_trylock (pthread_mutex_t
PTHREAD_ROBUST_MUTEX_PSHARED (mutex)),
0, 0);
+ /* To the kernel, this will be visible after the kernel has
+ acquired the mutex in the syscall. */
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
return ENOTRECOVERABLE;
}
if (robust)
{
+ /* We must not enqueue the mutex before we have acquired it.
+ Also see comments at ENQUEUE_MUTEX. */
+ __asm ("" ::: "memory");
ENQUEUE_MUTEX_PI (mutex);
+ /* We need to clear op_pending after we enqueue the mutex. */
+ __asm ("" ::: "memory");
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL);
}

View File

@ -0,0 +1,616 @@
2019-01-31 Carlos O'Donell <carlos@redhat.com>
Torvald Riegel <triegel@redhat.com>
Rik Prohaska <prohaska7@gmail.com>
[BZ# 23844]
* nptl/Makefile (tests): Add tst-rwlock-tryrdlock-stall, and
tst-rwlock-trywrlock-stall.
* nptl/pthread_rwlock_tryrdlock.c (__pthread_rwlock_tryrdlock):
Wake waiters if PTHREAD_RWLOCK_FUTEX_USED is set.
* nptl/pthread_rwlock_trywrlock.c (__pthread_rwlock_trywrlock):
Set __wrphase_fute to 1 only if we started the write phase.
* nptl/tst-rwlock-tryrdlock-stall.c: New file.
* nptl/tst-rwlock-trywrlock-stall.c: New file.
* support/Makefile (libsupport-routines): Add xpthread_rwlock_destroy.
* support/xpthread_rwlock_destroy.c: New file.
* support/xthread.h: Declare xpthread_rwlock_destroy.
Index: glibc-2.29/nptl/Makefile
===================================================================
--- glibc-2.29.orig/nptl/Makefile
+++ glibc-2.29/nptl/Makefile
@@ -319,7 +319,8 @@ tests = tst-attr1 tst-attr2 tst-attr3 ts
tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \
tst-cnd-timedwait tst-thrd-detach tst-mtx-basic tst-thrd-sleep \
tst-mtx-recursive tst-tss-basic tst-call-once tst-mtx-timedlock \
- tst-rwlock-pwn
+ tst-rwlock-pwn \
+ tst-rwlock-tryrdlock-stall tst-rwlock-trywrlock-stall
tests-internal := tst-rwlock19 tst-rwlock20 \
tst-sem11 tst-sem12 tst-sem13 \
Index: glibc-2.29/nptl/pthread_rwlock_tryrdlock.c
===================================================================
--- glibc-2.29.orig/nptl/pthread_rwlock_tryrdlock.c
+++ glibc-2.29/nptl/pthread_rwlock_tryrdlock.c
@@ -94,15 +94,22 @@ __pthread_rwlock_tryrdlock (pthread_rwlo
/* Same as in __pthread_rwlock_rdlock_full:
We started the read phase, so we are also responsible for
updating the write-phase futex. Relaxed MO is sufficient.
- Note that there can be no other reader that we have to wake
- because all other readers will see the read phase started by us
- (or they will try to start it themselves); if a writer started
- the read phase, we cannot have started it. Furthermore, we
- cannot discard a PTHREAD_RWLOCK_FUTEX_USED flag because we will
- overwrite the value set by the most recent writer (or the readers
- before it in case of explicit hand-over) and we know that there
- are no waiting readers. */
- atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 0);
+ We have to do the same steps as a writer would when handing over the
+ read phase to use because other readers cannot distinguish between
+ us and the writer.
+ Note that __pthread_rwlock_tryrdlock callers will not have to be
+ woken up because they will either see the read phase started by us
+ or they will try to start it themselves; however, callers of
+ __pthread_rwlock_rdlock_full just increase the reader count and then
+ check what state the lock is in, so they cannot distinguish between
+ us and a writer that acquired and released the lock in the
+ meantime. */
+ if ((atomic_exchange_relaxed (&rwlock->__data.__wrphase_futex, 0)
+ & PTHREAD_RWLOCK_FUTEX_USED) != 0)
+ {
+ int private = __pthread_rwlock_get_private (rwlock);
+ futex_wake (&rwlock->__data.__wrphase_futex, INT_MAX, private);
+ }
}
return 0;
Index: glibc-2.29/nptl/pthread_rwlock_trywrlock.c
===================================================================
--- glibc-2.29.orig/nptl/pthread_rwlock_trywrlock.c
+++ glibc-2.29/nptl/pthread_rwlock_trywrlock.c
@@ -46,8 +46,15 @@ __pthread_rwlock_trywrlock (pthread_rwlo
&rwlock->__data.__readers, &r,
r | PTHREAD_RWLOCK_WRPHASE | PTHREAD_RWLOCK_WRLOCKED))
{
+ /* We have become the primary writer and we cannot have shared
+ the PTHREAD_RWLOCK_FUTEX_USED flag with someone else, so we
+ can simply enable blocking (see full wrlock code). */
atomic_store_relaxed (&rwlock->__data.__writers_futex, 1);
- atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1);
+ /* If we started a write phase, we need to enable readers to
+ wait. If we did not, we must not change it because other threads
+ may have set the PTHREAD_RWLOCK_FUTEX_USED in the meantime. */
+ if ((r & PTHREAD_RWLOCK_WRPHASE) == 0)
+ atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1);
atomic_store_relaxed (&rwlock->__data.__cur_writer,
THREAD_GETMEM (THREAD_SELF, tid));
return 0;
Index: glibc-2.29/nptl/tst-rwlock-tryrdlock-stall.c
===================================================================
--- /dev/null
+++ glibc-2.29/nptl/tst-rwlock-tryrdlock-stall.c
@@ -0,0 +1,355 @@
+/* Bug 23844: Test for pthread_rwlock_tryrdlock stalls.
+ Copyright (C) 2019 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
+ <http://www.gnu.org/licenses/>. */
+
+/* For a full analysis see comment:
+ https://sourceware.org/bugzilla/show_bug.cgi?id=23844#c14
+
+ Provided here for reference:
+
+ --- Analysis of pthread_rwlock_tryrdlock() stall ---
+ A read lock begins to execute.
+
+ In __pthread_rwlock_rdlock_full:
+
+ We can attempt a read lock, but find that the lock is
+ in a write phase (PTHREAD_RWLOCK_WRPHASE, or WP-bit
+ is set), and the lock is held by a primary writer
+ (PTHREAD_RWLOCK_WRLOCKED is set). In this case we must
+ wait for explicit hand over from the writer to us or
+ one of the other waiters. The read lock threads are
+ about to execute:
+
+ 341 r = (atomic_fetch_add_acquire (&rwlock->__data.__readers,
+ 342 (1 << PTHREAD_RWLOCK_READER_SHIFT))
+ 343 + (1 << PTHREAD_RWLOCK_READER_SHIFT));
+
+ An unlock beings to execute.
+
+ Then in __pthread_rwlock_wrunlock:
+
+ 547 unsigned int r = atomic_load_relaxed (&rwlock->__data.__readers);
+ ...
+ 549 while (!atomic_compare_exchange_weak_release
+ 550 (&rwlock->__data.__readers, &r,
+ 551 ((r ^ PTHREAD_RWLOCK_WRLOCKED)
+ 552 ^ ((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0 ? 0
+ 553 : PTHREAD_RWLOCK_WRPHASE))))
+ 554 {
+ ...
+ 556 }
+
+ We clear PTHREAD_RWLOCK_WRLOCKED, and if there are
+ no readers so we leave the lock in PTHRAD_RWLOCK_WRPHASE.
+
+ Back in the read lock.
+
+ The read lock adjusts __readres as above.
+
+ 383 while ((r & PTHREAD_RWLOCK_WRPHASE) != 0
+ 384 && (r & PTHREAD_RWLOCK_WRLOCKED) == 0)
+ 385 {
+ ...
+ 390 if (atomic_compare_exchange_weak_acquire (&rwlock->__data.__readers, &r,
+ 391 r ^ PTHREAD_RWLOCK_WRPHASE))
+ 392 {
+
+ And then attemps to start the read phase.
+
+ Assume there happens to be a tryrdlock at this point, noting
+ that PTHREAD_RWLOCK_WRLOCKED is clear, and PTHREAD_RWLOCK_WRPHASE
+ is 1. So the try lock attemps to start the read phase.
+
+ In __pthread_rwlock_tryrdlock:
+
+ 44 if ((r & PTHREAD_RWLOCK_WRPHASE) == 0)
+ 45 {
+ ...
+ 49 if (((r & PTHREAD_RWLOCK_WRLOCKED) != 0)
+ 50 && (rwlock->__data.__flags
+ 51 == PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP))
+ 52 return EBUSY;
+ 53 rnew = r + (1 << PTHREAD_RWLOCK_READER_SHIFT);
+ 54 }
+ ...
+ 89 while (!atomic_compare_exchange_weak_acquire (&rwlock->__data.__readers,
+ 90 &r, rnew));
+
+ And succeeds.
+
+ Back in the write unlock:
+
+ 557 if ((r >> PTHREAD_RWLOCK_READER_SHIFT) != 0)
+ 558 {
+ ...
+ 563 if ((atomic_exchange_relaxed (&rwlock->__data.__wrphase_futex, 0)
+ 564 & PTHREAD_RWLOCK_FUTEX_USED) != 0)
+ 565 futex_wake (&rwlock->__data.__wrphase_futex, INT_MAX, private);
+ 566 }
+
+ We note that PTHREAD_RWLOCK_FUTEX_USED is non-zero
+ and don't wake anyone. This is OK because we handed
+ over to the trylock. It will be the trylock's responsibility
+ to wake any waiters.
+
+ Back in the read lock:
+
+ The read lock fails to install PTHRAD_REWLOCK_WRPHASE as 0 because
+ the __readers value was adjusted by the trylock, and so it falls through
+ to waiting on the lock for explicit handover from either a new writer
+ or a new reader.
+
+ 448 int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
+ 449 1 | PTHREAD_RWLOCK_FUTEX_USED,
+ 450 abstime, private);
+
+ We use PTHREAD_RWLOCK_FUTEX_USED to indicate the futex
+ is in use.
+
+ At this point we have readers waiting on the read lock
+ to unlock. The wrlock is done. The trylock is finishing
+ the installation of the read phase.
+
+ 92 if ((r & PTHREAD_RWLOCK_WRPHASE) != 0)
+ 93 {
+ ...
+ 105 atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 0);
+ 106 }
+
+ The trylock does note that we were the one that
+ installed the read phase, but the comments are not
+ correct, the execution ordering above shows that
+ readers might indeed be waiting, and they are.
+
+ The atomic_store_relaxed throws away PTHREAD_RWLOCK_FUTEX_USED,
+ and the waiting reader is never worken becuase as noted
+ above it is conditional on the futex being used.
+
+ The solution is for the trylock thread to inspect
+ PTHREAD_RWLOCK_FUTEX_USED and wake the waiting readers.
+
+ --- Analysis of pthread_rwlock_trywrlock() stall ---
+
+ A write lock begins to execute, takes the write lock,
+ and then releases the lock...
+
+ In pthread_rwlock_wrunlock():
+
+ 547 unsigned int r = atomic_load_relaxed (&rwlock->__data.__readers);
+ ...
+ 549 while (!atomic_compare_exchange_weak_release
+ 550 (&rwlock->__data.__readers, &r,
+ 551 ((r ^ PTHREAD_RWLOCK_WRLOCKED)
+ 552 ^ ((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0 ? 0
+ 553 : PTHREAD_RWLOCK_WRPHASE))))
+ 554 {
+ ...
+ 556 }
+
+ ... leaving it in the write phase with zero readers
+ (the case where we leave the write phase in place
+ during a write unlock).
+
+ A write trylock begins to execute.
+
+ In __pthread_rwlock_trywrlock:
+
+ 40 while (((r & PTHREAD_RWLOCK_WRLOCKED) == 0)
+ 41 && (((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0)
+ 42 || (prefer_writer && ((r & PTHREAD_RWLOCK_WRPHASE) != 0))))
+ 43 {
+
+ The lock is not locked.
+
+ There are no readers.
+
+ 45 if (atomic_compare_exchange_weak_acquire (
+ 46 &rwlock->__data.__readers, &r,
+ 47 r | PTHREAD_RWLOCK_WRPHASE | PTHREAD_RWLOCK_WRLOCKED))
+
+ We atomically install the write phase and we take the
+ exclusive write lock.
+
+ 48 {
+ 49 atomic_store_relaxed (&rwlock->__data.__writers_futex, 1);
+
+ We get this far.
+
+ A reader lock begins to execute.
+
+ In pthread_rwlock_rdlock:
+
+ 437 for (;;)
+ 438 {
+ 439 while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex))
+ 440 | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED))
+ 441 {
+ 442 int private = __pthread_rwlock_get_private (rwlock);
+ 443 if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0)
+ 444 && (!atomic_compare_exchange_weak_relaxed
+ 445 (&rwlock->__data.__wrphase_futex,
+ 446 &wpf, wpf | PTHREAD_RWLOCK_FUTEX_USED)))
+ 447 continue;
+ 448 int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
+ 449 1 | PTHREAD_RWLOCK_FUTEX_USED,
+ 450 abstime, private);
+
+ We are in a write phase, so the while() on line 439 is true.
+
+ The value of wpf does not have PTHREAD_RWLOCK_FUTEX_USED set
+ since this is the first reader to lock.
+
+ The atomic operation sets wpf with PTHREAD_RELOCK_FUTEX_USED
+ on the expectation that this reader will be woken during
+ the handoff.
+
+ Back in pthread_rwlock_trywrlock:
+
+ 50 atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1);
+ 51 atomic_store_relaxed (&rwlock->__data.__cur_writer,
+ 52 THREAD_GETMEM (THREAD_SELF, tid));
+ 53 return 0;
+ 54 }
+ ...
+ 57 }
+
+ We write 1 to __wrphase_futex discarding PTHREAD_RWLOCK_FUTEX_USED,
+ and so in the unlock we will not awaken the waiting reader.
+
+ The solution to this is to realize that if we did not start the write
+ phase we need not write 1 or any other value to __wrphase_futex.
+ This ensures that any readers (which saw __wrphase_futex != 0) can
+ set PTHREAD_RWLOCK_FUTEX_USED and this can be used at unlock to
+ wake them.
+
+ If we installed the write phase then all other readers are looping
+ here:
+
+ In __pthread_rwlock_rdlock_full:
+
+ 437 for (;;)
+ 438 {
+ 439 while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex))
+ 440 | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED))
+ 441 {
+ ...
+ 508 }
+
+ waiting for the write phase to be installed or removed before they
+ can begin waiting on __wrphase_futex (part of the algorithm), or
+ taking a concurrent read lock, and thus we can safely write 1 to
+ __wrphase_futex.
+
+ If we did not install the write phase then the readers may already
+ be waiting on the futex, the original writer wrote 1 to __wrphase_futex
+ as part of starting the write phase, and we cannot also write 1
+ without loosing the PTHREAD_RWLOCK_FUTEX_USED bit.
+
+ ---
+
+ Summary for the pthread_rwlock_tryrdlock() stall:
+
+ The stall is caused by pthread_rwlock_tryrdlock failing to check
+ that PTHREAD_RWLOCK_FUTEX_USED is set in the __wrphase_futex futex
+ and then waking the futex.
+
+ The fix for bug 23844 ensures that waiters on __wrphase_futex are
+ correctly woken. Before the fix the test stalls as readers can
+ wait forever on __wrphase_futex. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <support/xthread.h>
+#include <errno.h>
+
+/* We need only one lock to reproduce the issue. We will need multiple
+ threads to get the exact case where we have a read, try, and unlock
+ all interleaving to produce the case where the readers are waiting
+ and the try fails to wake them. */
+pthread_rwlock_t onelock;
+
+/* The number of threads is arbitrary but empirically chosen to have
+ enough threads that we see the condition where waiting readers are
+ not woken by a successful tryrdlock. */
+#define NTHREADS 32
+
+_Atomic int do_exit;
+
+void *
+run_loop (void *arg)
+{
+ int i = 0, ret;
+ while (!do_exit)
+ {
+ /* Arbitrarily choose if we are the writer or reader. Choose a
+ high enough ratio of readers to writers to make it likely
+ that readers block (and eventually are susceptable to
+ stalling).
+
+ If we are a writer, take the write lock, and then unlock.
+ If we are a reader, try the lock, then lock, then unlock. */
+ if ((i % 8) != 0)
+ xpthread_rwlock_wrlock (&onelock);
+ else
+ {
+ if ((ret = pthread_rwlock_tryrdlock (&onelock)) != 0)
+ {
+ if (ret == EBUSY)
+ xpthread_rwlock_rdlock (&onelock);
+ else
+ exit (EXIT_FAILURE);
+ }
+ }
+ /* Thread does some work and then unlocks. */
+ xpthread_rwlock_unlock (&onelock);
+ i++;
+ }
+ return NULL;
+}
+
+int
+do_test (void)
+{
+ int i;
+ pthread_t tids[NTHREADS];
+ xpthread_rwlock_init (&onelock, NULL);
+ for (i = 0; i < NTHREADS; i++)
+ tids[i] = xpthread_create (NULL, run_loop, NULL);
+ /* Run for some amount of time. Empirically speaking exercising
+ the stall via pthread_rwlock_tryrdlock is much harder, and on
+ a 3.5GHz 4 core x86_64 VM system it takes somewhere around
+ 20-200s to stall, approaching 100% stall past 200s. We can't
+ wait that long for a regression test so we just test for 20s,
+ and expect the stall to happen with a 5-10% chance (enough for
+ developers to see). */
+ sleep (20);
+ /* Then exit. */
+ printf ("INFO: Exiting...\n");
+ do_exit = 1;
+ /* If any readers stalled then we will timeout waiting for them. */
+ for (i = 0; i < NTHREADS; i++)
+ xpthread_join (tids[i]);
+ printf ("INFO: Done.\n");
+ xpthread_rwlock_destroy (&onelock);
+ printf ("PASS: No pthread_rwlock_tryrdlock stalls detected.\n");
+ return 0;
+}
+
+#define TIMEOUT 30
+#include <support/test-driver.c>
Index: glibc-2.29/nptl/tst-rwlock-trywrlock-stall.c
===================================================================
--- /dev/null
+++ glibc-2.29/nptl/tst-rwlock-trywrlock-stall.c
@@ -0,0 +1,108 @@
+/* Bug 23844: Test for pthread_rwlock_trywrlock stalls.
+ Copyright (C) 2019 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
+ <http://www.gnu.org/licenses/>. */
+
+/* For a full analysis see comments in tst-rwlock-tryrdlock-stall.c.
+
+ Summary for the pthread_rwlock_trywrlock() stall:
+
+ The stall is caused by pthread_rwlock_trywrlock setting
+ __wrphase_futex futex to 1 and loosing the
+ PTHREAD_RWLOCK_FUTEX_USED bit.
+
+ The fix for bug 23844 ensures that waiters on __wrphase_futex are
+ correctly woken. Before the fix the test stalls as readers can
+ wait forever on __wrphase_futex. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <support/xthread.h>
+#include <errno.h>
+
+/* We need only one lock to reproduce the issue. We will need multiple
+ threads to get the exact case where we have a read, try, and unlock
+ all interleaving to produce the case where the readers are waiting
+ and the try clears the PTHREAD_RWLOCK_FUTEX_USED bit and a
+ subsequent unlock fails to wake them. */
+pthread_rwlock_t onelock;
+
+/* The number of threads is arbitrary but empirically chosen to have
+ enough threads that we see the condition where waiting readers are
+ not woken by a successful unlock. */
+#define NTHREADS 32
+
+_Atomic int do_exit;
+
+void *
+run_loop (void *arg)
+{
+ int i = 0, ret;
+ while (!do_exit)
+ {
+ /* Arbitrarily choose if we are the writer or reader. Choose a
+ high enough ratio of readers to writers to make it likely
+ that readers block (and eventually are susceptable to
+ stalling).
+
+ If we are a writer, take the write lock, and then unlock.
+ If we are a reader, try the lock, then lock, then unlock. */
+ if ((i % 8) != 0)
+ {
+ if ((ret = pthread_rwlock_trywrlock (&onelock)) != 0)
+ {
+ if (ret == EBUSY)
+ xpthread_rwlock_wrlock (&onelock);
+ else
+ exit (EXIT_FAILURE);
+ }
+ }
+ else
+ xpthread_rwlock_rdlock (&onelock);
+ /* Thread does some work and then unlocks. */
+ xpthread_rwlock_unlock (&onelock);
+ i++;
+ }
+ return NULL;
+}
+
+int
+do_test (void)
+{
+ int i;
+ pthread_t tids[NTHREADS];
+ xpthread_rwlock_init (&onelock, NULL);
+ for (i = 0; i < NTHREADS; i++)
+ tids[i] = xpthread_create (NULL, run_loop, NULL);
+ /* Run for some amount of time. The pthread_rwlock_tryrwlock stall
+ is very easy to trigger and happens in seconds under the test
+ conditions. */
+ sleep (10);
+ /* Then exit. */
+ printf ("INFO: Exiting...\n");
+ do_exit = 1;
+ /* If any readers stalled then we will timeout waiting for them. */
+ for (i = 0; i < NTHREADS; i++)
+ xpthread_join (tids[i]);
+ printf ("INFO: Done.\n");
+ xpthread_rwlock_destroy (&onelock);
+ printf ("PASS: No pthread_rwlock_tryrwlock stalls detected.\n");
+ return 0;
+}
+
+#include <support/test-driver.c>
Index: glibc-2.29/support/Makefile
===================================================================
--- glibc-2.29.orig/support/Makefile
+++ glibc-2.29/support/Makefile
@@ -129,6 +129,7 @@ libsupport-routines = \
xpthread_mutexattr_settype \
xpthread_once \
xpthread_rwlock_init \
+ xpthread_rwlock_destroy \
xpthread_rwlock_rdlock \
xpthread_rwlock_unlock \
xpthread_rwlock_wrlock \
Index: glibc-2.29/support/xpthread_rwlock_destroy.c
===================================================================
--- /dev/null
+++ glibc-2.29/support/xpthread_rwlock_destroy.c
@@ -0,0 +1,26 @@
+/* pthread_rwlock_destroy with error checking.
+ Copyright (C) 2019 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <support/xthread.h>
+
+void
+xpthread_rwlock_destroy (pthread_rwlock_t *rwlock)
+{
+ xpthread_check_return ("pthread_rwlock_destroy",
+ pthread_rwlock_destroy (rwlock));
+}
Index: glibc-2.29/support/xthread.h
===================================================================
--- glibc-2.29.orig/support/xthread.h
+++ glibc-2.29/support/xthread.h
@@ -84,6 +84,7 @@ void xpthread_rwlockattr_setkind_np (pth
void xpthread_rwlock_wrlock (pthread_rwlock_t *rwlock);
void xpthread_rwlock_rdlock (pthread_rwlock_t *rwlock);
void xpthread_rwlock_unlock (pthread_rwlock_t *rwlock);
+void xpthread_rwlock_destroy (pthread_rwlock_t *rwlock);
__END_DECLS

119
riscv-clone-unwind.patch Normal file
View File

@ -0,0 +1,119 @@
2019-01-13 Jim Wilson <jimw@sifive.com>
[BZ #24040]
* elf/Makefile (CFLAGS-tst-unwind-main.c): Add -DUSE_PTHREADS=0.
* elf/tst-unwind-main.c: If USE_PTHEADS, include pthread.h and error.h
(func): New.
(main): If USE_PTHREADS, call pthread_create to run func. Otherwise
call func directly.
* nptl/Makefile (tests): Add tst-unwind-thread.
(CFLAGS-tst-unwind-thread.c): Define.
* nptl/tst-unwind-thread.c: New file.
* sysdeps/unix/sysv/linux/riscv/clone.S (__thread_start): Mark ra
as undefined.
Index: glibc-2.29/elf/Makefile
===================================================================
--- glibc-2.29.orig/elf/Makefile
+++ glibc-2.29/elf/Makefile
@@ -1497,4 +1497,4 @@ $(objpfx)tst-big-note: $(objpfx)tst-big-
$(objpfx)tst-unwind-ctor: $(objpfx)tst-unwind-ctor-lib.so
-CFLAGS-tst-unwind-main.c += -funwind-tables
+CFLAGS-tst-unwind-main.c += -funwind-tables -DUSE_PTHREADS=0
Index: glibc-2.29/elf/tst-unwind-main.c
===================================================================
--- glibc-2.29.orig/elf/tst-unwind-main.c
+++ glibc-2.29/elf/tst-unwind-main.c
@@ -20,19 +20,41 @@
#include <unistd.h>
#include <support/test-driver.h>
+#if USE_PTHREADS
+# include <pthread.h>
+# include <error.h>
+#endif
+
static _Unwind_Reason_Code
callback (struct _Unwind_Context *ctx, void *arg)
{
return _URC_NO_REASON;
}
-int
-main (void)
+static void *
+func (void *a)
{
/* Arrange for this test to be killed if _Unwind_Backtrace runs into an
endless loop. We cannot use the test driver because the complete
call chain needs to be compiled with -funwind-tables so that
- _Unwind_Backtrace is able to reach _start. */
+ _Unwind_Backtrace is able to reach the start routine. */
alarm (DEFAULT_TIMEOUT);
_Unwind_Backtrace (callback, 0);
+ return a;
+}
+
+int
+main (void)
+{
+#if USE_PTHREADS
+ pthread_t thr;
+ int rc = pthread_create (&thr, NULL, &func, NULL);
+ if (rc)
+ error (1, rc, "pthread_create");
+ rc = pthread_join (thr, NULL);
+ if (rc)
+ error (1, rc, "pthread_join");
+#else
+ func (NULL);
+#endif
}
Index: glibc-2.29/nptl/Makefile
===================================================================
--- glibc-2.29.orig/nptl/Makefile
+++ glibc-2.29/nptl/Makefile
@@ -320,7 +320,8 @@ tests = tst-attr1 tst-attr2 tst-attr3 ts
tst-cnd-timedwait tst-thrd-detach tst-mtx-basic tst-thrd-sleep \
tst-mtx-recursive tst-tss-basic tst-call-once tst-mtx-timedlock \
tst-rwlock-pwn \
- tst-rwlock-tryrdlock-stall tst-rwlock-trywrlock-stall
+ tst-rwlock-tryrdlock-stall tst-rwlock-trywrlock-stall \
+ tst-unwind-thread
tests-internal := tst-rwlock19 tst-rwlock20 \
tst-sem11 tst-sem12 tst-sem13 \
@@ -710,6 +711,8 @@ $(objpfx)tst-audit-threads: $(objpfx)tst
$(objpfx)tst-audit-threads.out: $(objpfx)tst-audit-threads-mod1.so
tst-audit-threads-ENV = LD_AUDIT=$(objpfx)tst-audit-threads-mod1.so
+CFLAGS-tst-unwind-thread.c += -funwind-tables
+
# The tests here better do not run in parallel
ifneq ($(filter %tests,$(MAKECMDGOALS)),)
.NOTPARALLEL:
Index: glibc-2.29/nptl/tst-unwind-thread.c
===================================================================
--- /dev/null
+++ glibc-2.29/nptl/tst-unwind-thread.c
@@ -0,0 +1,2 @@
+#define USE_PTHREADS 1
+#include "../elf/tst-unwind-main.c"
Index: glibc-2.29/sysdeps/unix/sysv/linux/riscv/clone.S
===================================================================
--- glibc-2.29.orig/sysdeps/unix/sysv/linux/riscv/clone.S
+++ glibc-2.29/sysdeps/unix/sysv/linux/riscv/clone.S
@@ -69,6 +69,11 @@ L (error):
ENTRY (__thread_start)
L (thread_start):
+ /* Terminate call stack by noting ra is undefined. Use a dummy
+ .cfi_label to force starting the FDE. */
+ .cfi_label .Ldummy
+ cfi_undefined (ra)
+
/* Restore the arg for user's function. */
REG_L a1,0(sp) /* Function pointer. */
REG_L a0,SZREG(sp) /* Argument pointer. */