diff options
Diffstat (limited to 'nptl/sysdeps/unix/sysv/linux/rtld-lowlevel.h')
-rw-r--r-- | nptl/sysdeps/unix/sysv/linux/rtld-lowlevel.h | 115 |
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 |