[PATCH RESEND 2/3] sysdeps: add rtld_rwlock_recursive

Caleb Sander Mateos csander@purestorage.com
Tue Sep 23 19:27:03 GMT 2025


A subsequent commit will want to use a reader-writer lock in the runtime
dynamic loader. Currently, only a full mutual exclusion lock is defined
for rtld, rtld_lock_recursive. Add rtld_rwlock_*_recursive macros
providing an similar interface except with "lock" split into "rdlock"
and "wrlock":
- __rtld_rwlock_define_recursive() to declare a rwlock
- __rtld_rwlock_define_initialized_recursive() to define and initialize
  a rwlock
- __rtld_rwlock_rdlock_recursive() to lock a rwlock for reading (shared)
- __rtld_rwlock_wrlock_recursive() to lock a rwlock for writing
  (exclusive)
- __rtld_rwlock_unlock_recursive() to unlock a rwlock locked for either
  reading or writing

In sysdeps/nptl/libc-lockP.h and sysdeps/nptl/dl-mutex.c, map the rdlock,
wrlock, and unlock macros to the corresponding pthread_rwlock functions.
Initialize the pthread_rwlock with the PTHREAD_RWLOCK_PREFER_READER_NP
lock kind in the define_initialized macro to allow the rwlock to be
locked recursively for reading.

Define the rtld_rwlock macros as aliases for the corresponding rtld_lock
macros in sysdeps/mach/libc-lock.h, analogous to the libc_rwlock macros.

Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
---
 sysdeps/generic/ldsodefs.h    |  3 +++
 sysdeps/generic/libc-lock.h   |  5 +++++
 sysdeps/mach/libc-lock.h      |  7 +++++++
 sysdeps/nptl/dl-mutex.c       | 24 ++++++++++++++++++++++++
 sysdeps/nptl/dl-tls_init_tp.c |  9 +++++++++
 sysdeps/nptl/libc-lockP.h     | 26 ++++++++++++++++++++++++++
 6 files changed, 74 insertions(+)

diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 31e9a6b600..f36e64ddba 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -1457,10 +1457,13 @@ _dl_audit_objclose (struct link_map *l)
    no-op dummy implementation early.  Similar
    to GL (dl_rtld_lock_recursive) and GL (dl_rtld_unlock_recursive)
    in !PTHREAD_IN_LIBC builds.  */
 extern int (*___rtld_mutex_lock) (pthread_mutex_t *) attribute_hidden;
 extern int (*___rtld_mutex_unlock) (pthread_mutex_t *lock) attribute_hidden;
+extern int (*___rtld_rwlock_rdlock) (pthread_rwlock_t *) attribute_hidden;
+extern int (*___rtld_rwlock_wrlock) (pthread_rwlock_t *) attribute_hidden;
+extern int (*___rtld_rwlock_unlock) (pthread_rwlock_t *) attribute_hidden;
 
 /* Called after libc has been loaded, but before RELRO is activated.
    Used to initialize the function pointers to the actual
    implementations.  */
 void __rtld_mutex_init (void) attribute_hidden;
diff --git a/sysdeps/generic/libc-lock.h b/sysdeps/generic/libc-lock.h
index fafaf8c932..a7b0ee6c88 100644
--- a/sysdeps/generic/libc-lock.h
+++ b/sysdeps/generic/libc-lock.h
@@ -28,20 +28,22 @@
    begins with a `*'), because its storage size will not be known outside
    of libc.  */
 #define __libc_lock_define(CLASS,NAME)
 #define __libc_lock_define_recursive(CLASS,NAME)
 #define __rtld_lock_define_recursive(CLASS,NAME)
+#define __rtld_rwlock_define_recursive(CLASS,NAME)
 #define __libc_rwlock_define(CLASS,NAME)
 
 /* Define an initialized lock variable NAME with storage class CLASS.  */
 #define __libc_lock_define_initialized(CLASS,NAME)
 #define __libc_rwlock_define_initialized(CLASS,NAME)
 
 /* Define an initialized recursive lock variable NAME with storage
    class CLASS.  */
 #define __libc_lock_define_initialized_recursive(CLASS,NAME)
 #define __rtld_lock_define_initialized_recursive(CLASS,NAME)
+#define __rtld_rwlock_define_initialized_recursive(CLASS,NAME)
 
 /* Initialize the named lock variable, leaving it in a consistent, unlocked
    state.  */
 #define __libc_lock_init(NAME)
 #define __rtld_lock_initialize(NAME)
@@ -65,10 +67,12 @@
 #define __libc_rwlock_wrlock(NAME)
 
 /* Lock the recursive named lock variable.  */
 #define __libc_lock_lock_recursive(NAME)
 #define __rtld_lock_lock_recursive(NAME)
+#define __rtld_rwlock_rdlock_recursive(NAME)
+#define __rtld_rwlock_wrlock_recursive(NAME)
 
 /* Try to lock the named lock variable.  */
 #define __libc_lock_trylock(NAME) 0
 #define __libc_rwlock_tryrdlock(NAME) 0
 #define __libc_rwlock_trywrlock(NAME) 0
@@ -81,10 +85,11 @@
 #define __libc_rwlock_unlock(NAME)
 
 /* Unlock the recursive named lock variable.  */
 #define __libc_lock_unlock_recursive(NAME)
 #define __rtld_lock_unlock_recursive(NAME)
+#define __rtld_rwlock_unlock_recursive(NAME)
 
 
 /* Define once control variable.  */
 #define __libc_once_define(CLASS, NAME) CLASS int NAME = 0
 
diff --git a/sysdeps/mach/libc-lock.h b/sysdeps/mach/libc-lock.h
index fd590f1551..d02269039b 100644
--- a/sysdeps/mach/libc-lock.h
+++ b/sysdeps/mach/libc-lock.h
@@ -150,10 +150,17 @@ typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t;
 #define __libc_rwlock_rdlock		__libc_lock_lock
 #define __libc_rwlock_wrlock		__libc_lock_lock
 #define __libc_rwlock_tryrdlock		__libc_lock_trylock
 #define __libc_rwlock_trywrlock		__libc_lock_trylock
 #define __libc_rwlock_unlock		__libc_lock_unlock
+#define __rtld_rwlock_define_recursive __rtld_lock_define_recursive
+#define _RTLD_RWLOCK_RECURSIVE_INITIALIZER _RTLD_LOCK_RECURSIVE_INITIALIZER
+#define __rtld_rwlock_define_initialized_recursive \
+  __rtld_lock_define_initialized_recursive
+#define __rtld_rwlock_rdlock_recursive __rtld_lock_lock_recursive
+#define __rtld_rwlock_wrlock_recursive __rtld_lock_lock_recursive
+#define __rtld_rwlock_unlock_recursive __rtld_lock_unlock_recursive
 
 struct __libc_cleanup_frame
 {
   void (*__fct) (void *);
   void *__argp;
diff --git a/sysdeps/nptl/dl-mutex.c b/sysdeps/nptl/dl-mutex.c
index 1e324e19bb..f5371326b2 100644
--- a/sysdeps/nptl/dl-mutex.c
+++ b/sysdeps/nptl/dl-mutex.c
@@ -22,10 +22,13 @@
 #include <first-versions.h>
 #include <ldsodefs.h>
 
 __typeof (pthread_mutex_lock) *___rtld_mutex_lock attribute_relro;
 __typeof (pthread_mutex_unlock) *___rtld_mutex_unlock attribute_relro;
+__typeof (pthread_rwlock_rdlock) *___rtld_rwlock_rdlock attribute_relro;
+__typeof (pthread_rwlock_wrlock) *___rtld_rwlock_wrlock attribute_relro;
+__typeof (pthread_rwlock_unlock) *___rtld_rwlock_unlock attribute_relro;
 
 void
 __rtld_mutex_init (void)
 {
   /* There is an implicit assumption here that the lock counters are
@@ -48,6 +51,27 @@ __rtld_mutex_init (void)
                            0x7dd7aaaa, /* dl_new_hash output.  */
                            FIRST_VERSION_libc_pthread_mutex_unlock_STRING,
                            FIRST_VERSION_libc_pthread_mutex_unlock_HASH);
   assert (sym != NULL);
   ___rtld_mutex_unlock = DL_SYMBOL_ADDRESS (libc_map, sym);
+
+  sym = _dl_lookup_direct (libc_map, "pthread_rwlock_rdlock",
+                           0x1534d41c, /* dl_new_hash output.  */
+                           FIRST_VERSION_libc_pthread_rwlock_rdlock_STRING,
+                           FIRST_VERSION_libc_pthread_rwlock_rdlock_HASH);
+  assert (sym != NULL);
+  ___rtld_rwlock_rdlock = DL_SYMBOL_ADDRESS (libc_map, sym);
+
+  sym = _dl_lookup_direct (libc_map, "pthread_rwlock_wrlock",
+                           0x21dbf64f, /* dl_new_hash output.  */
+                           FIRST_VERSION_libc_pthread_rwlock_wrlock_STRING,
+                           FIRST_VERSION_libc_pthread_rwlock_wrlock_HASH);
+  assert (sym != NULL);
+  ___rtld_rwlock_wrlock = DL_SYMBOL_ADDRESS (libc_map, sym);
+
+  sym = _dl_lookup_direct (libc_map, "pthread_rwlock_unlock",
+                           0x1ce94309, /* dl_new_hash output.  */
+                           FIRST_VERSION_libc_pthread_rwlock_unlock_STRING,
+                           FIRST_VERSION_libc_pthread_rwlock_unlock_HASH);
+  assert (sym != NULL);
+  ___rtld_rwlock_unlock = DL_SYMBOL_ADDRESS (libc_map, sym);
 }
diff --git a/sysdeps/nptl/dl-tls_init_tp.c b/sysdeps/nptl/dl-tls_init_tp.c
index 47566dce4f..5c97983302 100644
--- a/sysdeps/nptl/dl-tls_init_tp.c
+++ b/sysdeps/nptl/dl-tls_init_tp.c
@@ -41,10 +41,16 @@ rtld_hidden_def (__nptl_initial_report_events)
 static int
 rtld_mutex_dummy (pthread_mutex_t *lock)
 {
   return 0;
 }
+
+static int
+rtld_rwlock_dummy (pthread_rwlock_t *lock)
+{
+  return 0;
+}
 #endif
 
 const unsigned int __rseq_flags;
 
 size_t _rseq_align attribute_hidden;
@@ -59,10 +65,13 @@ __tls_pre_init_tp (void)
   INIT_LIST_HEAD (&GL (dl_stack_cache));
 
 #ifdef SHARED
   ___rtld_mutex_lock = rtld_mutex_dummy;
   ___rtld_mutex_unlock = rtld_mutex_dummy;
+  ___rtld_rwlock_rdlock = rtld_rwlock_dummy;
+  ___rtld_rwlock_wrlock = rtld_rwlock_dummy;
+  ___rtld_rwlock_unlock = rtld_rwlock_dummy;
 #endif
 }
 
 void
 __tls_init_tp (void)
diff --git a/sysdeps/nptl/libc-lockP.h b/sysdeps/nptl/libc-lockP.h
index 1be3dd1ec1..904482be83 100644
--- a/sysdeps/nptl/libc-lockP.h
+++ b/sysdeps/nptl/libc-lockP.h
@@ -36,10 +36,11 @@
 
 /* Mutex type.  */
 typedef int __libc_lock_t __LIBC_LOCK_ALIGNMENT;
 typedef struct { pthread_mutex_t mutex; } __rtld_lock_recursive_t;
 typedef pthread_rwlock_t __libc_rwlock_t;
+typedef struct { pthread_rwlock_t rwlock; } __rtld_rwlock_recursive_t;
 
 /* Define a lock variable NAME with storage class CLASS.  The lock must be
    initialized with __libc_lock_init before it can be used (or define it
    with __libc_lock_define_initialized, below).  Use `extern' for CLASS to
    declare a lock defined in another module.  In public structure
@@ -50,10 +51,12 @@ typedef pthread_rwlock_t __libc_rwlock_t;
   CLASS __libc_lock_t NAME;
 #define __libc_rwlock_define(CLASS,NAME) \
   CLASS __libc_rwlock_t NAME;
 #define __rtld_lock_define_recursive(CLASS,NAME) \
   CLASS __rtld_lock_recursive_t NAME;
+#define __rtld_rwlock_define_recursive(CLASS,NAME) \
+  CLASS __rtld_rwlock_recursive_t NAME;
 
 /* Define an initialized lock variable NAME with storage class CLASS.
 
    For the C library we take a deeper look at the initializer.  For
    this implementation all fields are initialized to zero.  Therefore
@@ -71,10 +74,15 @@ _Static_assert (LLL_LOCK_INITIALIZER == 0, "LLL_LOCK_INITIALIZER != 0");
 #define __rtld_lock_define_initialized_recursive(CLASS,NAME) \
   CLASS __rtld_lock_recursive_t NAME = _RTLD_LOCK_RECURSIVE_INITIALIZER;
 #define _RTLD_LOCK_RECURSIVE_INITIALIZER \
   {PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP}
 
+#define __rtld_rwlock_define_initialized_recursive(CLASS,NAME) \
+  CLASS __rtld_rwlock_recursive_t NAME = _RTLD_RWLOCK_RECURSIVE_INITIALIZER;
+#define _RTLD_RWLOCK_RECURSIVE_INITIALIZER \
+  {PTHREAD_RWLOCK_INITIALIZER}
+
 #define __rtld_lock_initialize(NAME) \
   (void) ((NAME) = (__rtld_lock_recursive_t) _RTLD_LOCK_RECURSIVE_INITIALIZER)
 
 /* If we check for a weakly referenced symbol and then perform a
    normal jump to it te code generated for some platforms in case of
@@ -124,16 +132,34 @@ _Static_assert (LLL_LOCK_INITIALIZER == 0, "LLL_LOCK_INITIALIZER != 0");
 # define __rtld_lock_lock_recursive(NAME) \
   ___rtld_mutex_lock (&(NAME).mutex)
 
 # define __rtld_lock_unlock_recursive(NAME) \
   ___rtld_mutex_unlock (&(NAME).mutex)
+
+# define __rtld_rwlock_rdlock_recursive(NAME) \
+  ___rtld_rwlock_rdlock (&(NAME).rwlock)
+
+# define __rtld_rwlock_wrlock_recursive(NAME) \
+  ___rtld_rwlock_wrlock (&(NAME).rwlock)
+
+# define __rtld_rwlock_unlock_recursive(NAME) \
+  ___rtld_rwlock_unlock (&(NAME).rwlock)
 #else /* Not in the dynamic loader.  */
 # define __rtld_lock_lock_recursive(NAME) \
   __pthread_mutex_lock (&(NAME).mutex)
 
 # define __rtld_lock_unlock_recursive(NAME) \
   __pthread_mutex_unlock (&(NAME).mutex)
+
+# define __rtld_rwlock_rdlock_recursive(NAME) \
+  __pthread_rwlock_rdlock (&(NAME).rwlock)
+
+# define __rtld_rwlock_wrlock_recursive(NAME) \
+  __pthread_rwlock_wrlock (&(NAME).rwlock)
+
+# define __rtld_rwlock_unlock_recursive(NAME) \
+  __pthread_rwlock_unlock (&(NAME).rwlock)
 #endif
 
 /* Define once control variable.  */
 #if PTHREAD_ONCE_INIT == 0
 /* Special case for static variables where we can avoid the initialization
-- 
2.43.0



More information about the Libc-alpha mailing list