[PATCH 3/3] nptl: Only initialize robust list at mutex usage
Adhemerval Zanella
adhemerval.zanella@linaro.org
Tue Jul 29 18:21:29 GMT 2025
The robust mutex kernel initialization is always performed at process
startup and thread creation, even when the process does not use any
robust mutexes. This patch moves the set_robust_issue syscall to
either when a robust process is initialized or used, saving the
syscall issue for processes that do not use robust mutexes.
The field futex_offset is used as a sentinel to indicate whether the
struct pthread list is already initialized. This also allows to move
the __nptl_set_robust_list_avail from ld.so to libc.so, since there is
no need to initialize it at pthread startup.
Checked on x86_64-linux-gnu and aarch64-linux-gnu.
---
nptl/Makefile | 1 +
nptl/Versions | 1 -
nptl/allocatestack.c | 9 +-------
nptl/descr.h | 32 ++++++++++++++++++++++++++++
nptl/nptl_robust_setup.c | 38 ++++++++++++++++++++++++++++++++++
nptl/pthread_create.c | 8 -------
nptl/pthread_mutex_init.c | 2 +-
nptl/pthread_mutex_lock.c | 2 ++
nptl/pthread_mutex_timedlock.c | 2 ++
nptl/pthread_mutex_trylock.c | 2 ++
sysdeps/nptl/dl-tls_init_tp.c | 17 +--------------
sysdeps/nptl/pthreadP.h | 6 ++----
12 files changed, 82 insertions(+), 38 deletions(-)
create mode 100644 nptl/nptl_robust_setup.c
diff --git a/nptl/Makefile b/nptl/Makefile
index e6481d5694..f0864c7054 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -55,6 +55,7 @@ routines = \
nptl_deallocate_tsd \
nptl_free_tcb \
nptl_nthreads \
+ nptl_robust_setup \
nptl_setxid \
nptlfreeres \
old_pthread_cond_broadcast \
diff --git a/nptl/Versions b/nptl/Versions
index ef55376dd9..019bc132fe 100644
--- a/nptl/Versions
+++ b/nptl/Versions
@@ -533,6 +533,5 @@ libpthread {
ld {
GLIBC_PRIVATE {
__nptl_initial_report_events;
- __nptl_set_robust_list_avail;
}
}
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
index 800ca89720..a3c7b75eb9 100644
--- a/nptl/allocatestack.c
+++ b/nptl/allocatestack.c
@@ -611,14 +611,7 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
/* The robust mutex lists also need to be initialized
unconditionally because the cleanup for the previous stack owner
might have happened in the kernel. */
- pd->robust_head.futex_offset = (offsetof (pthread_mutex_t, __data.__lock)
- - offsetof (pthread_mutex_t,
- __data.__list.__next));
- pd->robust_head.list_op_pending = NULL;
-#if __PTHREAD_MUTEX_HAVE_PREV
- pd->robust_prev = &pd->robust_head;
-#endif
- pd->robust_head.list = &pd->robust_head;
+ robust_list_init (pd);
/* We place the thread descriptor at the end of the stack. */
*pdp = pd;
diff --git a/nptl/descr.h b/nptl/descr.h
index ada6867a19..7961d28944 100644
--- a/nptl/descr.h
+++ b/nptl/descr.h
@@ -454,6 +454,38 @@ cancel_enabled_and_canceled_and_async (int value)
== (CANCELTYPE_BITMASK | CANCELED_BITMASK);
}
+static inline void
+robust_list_init (struct pthread *pd)
+{
+ pd->robust_head.list_op_pending = NULL;
+#if __PTHREAD_MUTEX_HAVE_PREV
+ pd->robust_prev = &pd->robust_head;
+#endif
+ pd->robust_head.list = &pd->robust_head;
+ pd->robust_head.futex_offset = 0;
+}
+
+extern bool __nptl_robust_setup (struct robust_list_head *robust_head)
+ attribute_hidden;
+
+static inline bool
+robust_list_setup (struct pthread *pd)
+{
+ /* The current thread was already initialized. */
+ if (pd->robust_head.futex_offset != 0)
+ return true;
+
+ if (__nptl_robust_setup (&pd->robust_head))
+ {
+ pd->robust_head.futex_offset = (offsetof (pthread_mutex_t, __data.__lock)
+ - offsetof (pthread_mutex_t,
+ __data.__list.__next));
+ return true;
+ }
+
+ return false;
+}
+
/* This yields the pointer that TLS support code calls the thread pointer. */
#if TLS_TCB_AT_TP
# define TLS_TPADJ(pd) (pd)
diff --git a/nptl/nptl_robust_setup.c b/nptl/nptl_robust_setup.c
new file mode 100644
index 0000000000..cf72677c63
--- /dev/null
+++ b/nptl/nptl_robust_setup.c
@@ -0,0 +1,38 @@
+/* Linux robust mutext setup.
+ 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 <descr.h>
+#include <atomic.h>
+#include <pthreadP.h>
+
+int __nptl_set_robust_list_avail = 1;
+
+bool
+__nptl_robust_setup (struct robust_list_head *robust_head)
+{
+ if (atomic_load_relaxed (&__nptl_set_robust_list_avail))
+ {
+ int res = INTERNAL_SYSCALL_CALL (set_robust_list, robust_head,
+ sizeof (struct robust_list_head));
+ if (!INTERNAL_SYSCALL_ERROR_P (res))
+ return true;
+
+ atomic_store_relaxed (&__nptl_set_robust_list_avail, 0);
+ }
+ return false;
+}
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
index 04b8f27b99..4bf1ff56de 100644
--- a/nptl/pthread_create.c
+++ b/nptl/pthread_create.c
@@ -380,14 +380,6 @@ start_thread (void *arg)
__libc_fatal ("Fatal glibc error: rseq registration failed\n");
}
- if (__nptl_set_robust_list_avail)
- {
- /* This call should never fail because the initial call in init.c
- succeeded. */
- INTERNAL_SYSCALL_CALL (set_robust_list, &pd->robust_head,
- sizeof (struct robust_list_head));
- }
-
/* This is where the try/finally block should be created. For
compilers without that support we do use setjmp. */
struct pthread_unwind_buf unwind_buf;
diff --git a/nptl/pthread_mutex_init.c b/nptl/pthread_mutex_init.c
index 35b55576c4..85a1371afd 100644
--- a/nptl/pthread_mutex_init.c
+++ b/nptl/pthread_mutex_init.c
@@ -94,7 +94,7 @@ ___pthread_mutex_init (pthread_mutex_t *mutex,
if ((imutexattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_ROBUST) != 0)
{
if ((imutexattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_PSHARED) != 0
- && !__nptl_set_robust_list_avail)
+ && !robust_list_setup (THREAD_SELF))
return ENOTSUP;
mutex_kind |= PTHREAD_MUTEX_ROBUST_NORMAL_NP;
}
diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c
index 604941c9dd..8e435147bc 100644
--- a/nptl/pthread_mutex_lock.c
+++ b/nptl/pthread_mutex_lock.c
@@ -201,6 +201,7 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex)
case PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP:
case PTHREAD_MUTEX_ROBUST_NORMAL_NP:
case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP:
+ robust_list_setup (THREAD_SELF);
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
&mutex->__data.__list.__next);
/* We need to set op_pending before starting the operation. Also
@@ -385,6 +386,7 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex)
if (robust)
{
+ robust_list_setup (THREAD_SELF);
/* 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)
diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c
index 138cdcc985..387597f7d9 100644
--- a/nptl/pthread_mutex_timedlock.c
+++ b/nptl/pthread_mutex_timedlock.c
@@ -125,6 +125,7 @@ __pthread_mutex_clocklock_common (pthread_mutex_t *mutex,
case PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP:
case PTHREAD_MUTEX_ROBUST_NORMAL_NP:
case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP:
+ robust_list_setup (THREAD_SELF);
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
&mutex->__data.__list.__next);
/* We need to set op_pending before starting the operation. Also
@@ -309,6 +310,7 @@ __pthread_mutex_clocklock_common (pthread_mutex_t *mutex,
if (robust)
{
+ robust_list_setup (THREAD_SELF);
/* 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)
diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c
index dbb8fcc754..d9ae14b636 100644
--- a/nptl/pthread_mutex_trylock.c
+++ b/nptl/pthread_mutex_trylock.c
@@ -84,6 +84,7 @@ ___pthread_mutex_trylock (pthread_mutex_t *mutex)
case PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP:
case PTHREAD_MUTEX_ROBUST_NORMAL_NP:
case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP:
+ robust_list_setup (THREAD_SELF);
THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,
&mutex->__data.__list.__next);
/* We need to set op_pending before starting the operation. Also
@@ -226,6 +227,7 @@ ___pthread_mutex_trylock (pthread_mutex_t *mutex)
if (robust)
{
+ robust_list_setup (THREAD_SELF);
/* 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)
diff --git a/sysdeps/nptl/dl-tls_init_tp.c b/sysdeps/nptl/dl-tls_init_tp.c
index 8bf3c7f14b..d42d9203ce 100644
--- a/sysdeps/nptl/dl-tls_init_tp.c
+++ b/sysdeps/nptl/dl-tls_init_tp.c
@@ -28,9 +28,6 @@
#define TUNABLE_NAMESPACE pthread
#include <dl-tunables.h>
-bool __nptl_set_robust_list_avail;
-rtld_hidden_data_def (__nptl_set_robust_list_avail)
-
bool __nptl_initial_report_events;
rtld_hidden_def (__nptl_initial_report_events)
@@ -81,19 +78,7 @@ __tls_init_tp (void)
THREAD_SETMEM (pd, report_events, __nptl_initial_report_events);
/* Initialize the robust mutex data. */
- {
-#if __PTHREAD_MUTEX_HAVE_PREV
- pd->robust_prev = &pd->robust_head;
-#endif
- pd->robust_head.list = &pd->robust_head;
- pd->robust_head.futex_offset = (offsetof (pthread_mutex_t, __data.__lock)
- - offsetof (pthread_mutex_t,
- __data.__list.__next));
- int res = INTERNAL_SYSCALL_CALL (set_robust_list, &pd->robust_head,
- sizeof (struct robust_list_head));
- if (!INTERNAL_SYSCALL_ERROR_P (res))
- __nptl_set_robust_list_avail = true;
- }
+ robust_list_init (pd);
{
/* If the registration fails or is disabled by tunable, the public
diff --git a/sysdeps/nptl/pthreadP.h b/sysdeps/nptl/pthreadP.h
index 0822a437da..f404b791fd 100644
--- a/sysdeps/nptl/pthreadP.h
+++ b/sysdeps/nptl/pthreadP.h
@@ -210,10 +210,8 @@ libc_hidden_proto (__pthread_keys)
extern unsigned int __nptl_nthreads;
libc_hidden_proto (__nptl_nthreads)
-/* True if the set_robust_list system call works. Initialized in
- __tls_init_tp. */
-extern bool __nptl_set_robust_list_avail;
-rtld_hidden_proto (__nptl_set_robust_list_avail)
+/* Set if the set_robust_list system call works. */
+extern int __nptl_set_robust_list_avail attribute_hidden;
/* Thread Priority Protection. */
extern int __sched_fifo_min_prio;
--
2.43.0
More information about the Libc-alpha
mailing list