summaryrefslogtreecommitdiff
path: root/nptl/sysdeps/unix/sysv/linux/rtld-lowlevel.h
diff options
context:
space:
mode:
Diffstat (limited to 'nptl/sysdeps/unix/sysv/linux/rtld-lowlevel.h')
-rw-r--r--nptl/sysdeps/unix/sysv/linux/rtld-lowlevel.h115
1 files changed, 112 insertions, 3 deletions
diff --git a/nptl/sysdeps/unix/sysv/linux/rtld-lowlevel.h b/nptl/sysdeps/unix/sysv/linux/rtld-lowlevel.h
index 1aeff8fb39..6b3d3682da 100644
--- a/nptl/sysdeps/unix/sysv/linux/rtld-lowlevel.h
+++ b/nptl/sysdeps/unix/sysv/linux/rtld-lowlevel.h
@@ -1,5 +1,5 @@
/* Defintions for lowlevel handling in ld.so.
- Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+ Copyright (C) 2006 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
@@ -24,6 +24,115 @@
#include <lowlevellock.h>
+/* Special multi-reader lock used in ld.so. */
+#define __RTLD_MRLOCK_WRITER 1
+#define __RTLD_MRLOCK_RWAIT 2
+#define __RTLD_MRLOCK_WWAIT 4
+#define __RTLD_MRLOCK_RBITS \
+ ~(__RTLD_MRLOCK_WRITER | __RTLD_MRLOCK_RWAIT | __RTLD_MRLOCK_WWAIT)
+#define __RTLD_MRLOCK_INC 8
+#define __RTLD_MRLOCK_TRIES 5
+
+
+typedef int __rtld_mrlock_t;
+
+
+#define __rtld_mrlock_define(CLASS,NAME) \
+ CLASS __rtld_mrlock_t NAME;
+
+
+#define _RTLD_MRLOCK_INITIALIZER 0
+#define __rtld_mrlock_initialize(NAME) \
+ (void) ((NAME) = 0)
+
+
+#define __rtld_mrlock_lock(lock) \
+ do { \
+ __label__ out; \
+ while (1) \
+ { \
+ int oldval; \
+ for (int tries = 0; tries < __RTLD_MRLOCK_TRIES; ++tries) \
+ { \
+ oldval = lock; \
+ while (__builtin_expect ((oldval \
+ & (__RTLD_MRLOCK_WRITER \
+ | __RTLD_MRLOCK_WWAIT)) \
+ == 0, 1)) \
+ { \
+ int newval = ((oldval & __RTLD_MRLOCK_RBITS) \
+ + __RTLD_MRLOCK_INC); \
+ int ret = atomic_compare_and_exchange_val_acq (&(lock), \
+ newval, \
+ oldval); \
+ if (__builtin_expect (ret == oldval, 1)) \
+ goto out; \
+ oldval = ret; \
+ } \
+ atomic_delay (); \
+ } \
+ if ((oldval & __RTLD_MRLOCK_RWAIT) == 0) \
+ { \
+ atomic_or (&(lock), __RTLD_MRLOCK_RWAIT); \
+ oldval |= __RTLD_MRLOCK_RWAIT; \
+ } \
+ lll_futex_wait (lock, oldval); \
+ } \
+ out:; \
+ } while (0)
+
+
+#define __rtld_mrlock_unlock(lock) \
+ do { \
+ int oldval = atomic_exchange_and_add (&(lock), -__RTLD_MRLOCK_INC); \
+ if (__builtin_expect ((oldval \
+ & (__RTLD_MRLOCK_RBITS | __RTLD_MRLOCK_WWAIT)) \
+ == (__RTLD_MRLOCK_INC | __RTLD_MRLOCK_WWAIT), 0)) \
+ /* We have to wake all threads since there might be some queued \
+ readers already. */ \
+ lll_futex_wake (&(lock), 0x7fffffff); \
+ } while (0)
+
+
+/* There can only ever be one thread trying to get the exclusive lock. */
+#define __rtld_mrlock_change(lock) \
+ do { \
+ __label__ out; \
+ while (1) \
+ { \
+ int oldval; \
+ for (int tries = 0; tries < __RTLD_MRLOCK_TRIES; ++tries) \
+ { \
+ oldval = lock; \
+ while (__builtin_expect ((oldval & __RTLD_MRLOCK_RBITS) == 0, 1)) \
+ { \
+ int newval = ((oldval & __RTLD_MRLOCK_RWAIT) \
+ + __RTLD_MRLOCK_WRITER); \
+ int ret = atomic_compare_and_exchange_val_acq (&(lock), \
+ newval, \
+ oldval); \
+ if (__builtin_expect (ret == oldval, 1)) \
+ goto out; \
+ oldval = ret; \
+ } \
+ atomic_delay (); \
+ } \
+ atomic_or (&(lock), __RTLD_MRLOCK_WWAIT); \
+ oldval |= __RTLD_MRLOCK_WWAIT; \
+ lll_futex_wait (lock, oldval); \
+ } \
+ out:; \
+ } while (0)
+
+
+#define __rtld_mrlock_done(lock) \
+ do { \
+ int oldval = atomic_exchange_and_add (&(lock), -__RTLD_MRLOCK_WRITER); \
+ if (__builtin_expect ((oldval & __RTLD_MRLOCK_RWAIT) != 0, 0)) \
+ lll_futex_wake (&(lock), 0x7fffffff); \
+ } while (0)
+
+
/* Function to wait for variable become zero. Used in ld.so for
reference counters. */
#define __rtld_waitzero(word) \
@@ -33,12 +142,12 @@
int val = word; \
if (val == 0) \
break; \
- lll_private_futex_wait (&(word), val); \
+ lll_futex_wait (&(word), val); \
} \
} while (0)
#define __rtld_notify(word) \
- lll_private_futex_wake (&(word), 1)
+ lll_futex_wake (&(word), 1)
#endif