summaryrefslogtreecommitdiffstats
path: root/libexec/rtld-elf/rtld_lock.c
diff options
context:
space:
mode:
Diffstat (limited to 'libexec/rtld-elf/rtld_lock.c')
-rw-r--r--libexec/rtld-elf/rtld_lock.c102
1 files changed, 77 insertions, 25 deletions
diff --git a/libexec/rtld-elf/rtld_lock.c b/libexec/rtld-elf/rtld_lock.c
index c5e582e..e76a4da 100644
--- a/libexec/rtld-elf/rtld_lock.c
+++ b/libexec/rtld-elf/rtld_lock.c
@@ -43,7 +43,6 @@
*/
#include <sys/param.h>
-
#include <signal.h>
#include <stdlib.h>
#include <time.h>
@@ -183,44 +182,88 @@ rtld_lock_t rtld_bind_lock = &rtld_locks[0];
rtld_lock_t rtld_libc_lock = &rtld_locks[1];
rtld_lock_t rtld_phdr_lock = &rtld_locks[2];
-int
-rlock_acquire(rtld_lock_t lock)
+#define print_ebp(str) do {register long ebp asm("ebp"); printf("%s 0x%0lx\n", str, ebp);} while (0)
+
+void
+rlock_acquire(rtld_lock_t lock, RtldLockState *lockstate)
{
+
+ if (lockstate == NULL)
+ return;
+
if (thread_mask_set(lock->mask) & lock->mask) {
- dbg("rlock_acquire: recursed");
- return (0);
+ dbg("rlock_acquire: recursed");
+ lockstate->lockstate = RTLD_LOCK_UNLOCKED;
+ return;
}
lockinfo.rlock_acquire(lock->handle);
- return (1);
+ lockstate->lockstate = RTLD_LOCK_RLOCKED;
}
-int
-wlock_acquire(rtld_lock_t lock)
+void
+wlock_acquire(rtld_lock_t lock, RtldLockState *lockstate)
{
+
+ if (lockstate == NULL)
+ return;
+
if (thread_mask_set(lock->mask) & lock->mask) {
- dbg("wlock_acquire: recursed");
- return (0);
+ dbg("wlock_acquire: recursed");
+ lockstate->lockstate = RTLD_LOCK_UNLOCKED;
+ return;
}
lockinfo.wlock_acquire(lock->handle);
- return (1);
+ lockstate->lockstate = RTLD_LOCK_WLOCKED;
}
void
-rlock_release(rtld_lock_t lock, int locked)
+lock_release(rtld_lock_t lock, RtldLockState *lockstate)
{
- if (locked == 0)
- return;
- thread_mask_clear(lock->mask);
- lockinfo.lock_release(lock->handle);
+
+ if (lockstate == NULL)
+ return;
+
+ switch (lockstate->lockstate) {
+ case RTLD_LOCK_UNLOCKED:
+ break;
+ case RTLD_LOCK_RLOCKED:
+ case RTLD_LOCK_WLOCKED:
+ thread_mask_clear(lock->mask);
+ lockinfo.lock_release(lock->handle);
+ break;
+ default:
+ assert(0);
+ }
}
void
-wlock_release(rtld_lock_t lock, int locked)
+lock_upgrade(rtld_lock_t lock, RtldLockState *lockstate)
{
- if (locked == 0)
- return;
- thread_mask_clear(lock->mask);
- lockinfo.lock_release(lock->handle);
+
+ if (lockstate == NULL)
+ return;
+
+ lock_release(lock, lockstate);
+ wlock_acquire(lock, lockstate);
+}
+
+void
+lock_restart_for_upgrade(RtldLockState *lockstate)
+{
+
+ if (lockstate == NULL)
+ return;
+
+ switch (lockstate->lockstate) {
+ case RTLD_LOCK_UNLOCKED:
+ case RTLD_LOCK_WLOCKED:
+ break;
+ case RTLD_LOCK_RLOCKED:
+ longjmp(lockstate->env, 1);
+ break;
+ default:
+ assert(0);
+ }
}
void
@@ -322,15 +365,24 @@ _rtld_thread_init(struct RtldLockInfo *pli)
void
_rtld_atfork_pre(int *locks)
{
+ RtldLockState ls[2];
+
+ wlock_acquire(rtld_phdr_lock, &ls[0]);
+ rlock_acquire(rtld_bind_lock, &ls[1]);
- locks[2] = wlock_acquire(rtld_phdr_lock);
- locks[0] = rlock_acquire(rtld_bind_lock);
+ /* XXXKIB: I am really sorry for this. */
+ locks[0] = ls[1].lockstate;
+ locks[2] = ls[0].lockstate;
}
void
_rtld_atfork_post(int *locks)
{
+ RtldLockState ls[2];
- rlock_release(rtld_bind_lock, locks[0]);
- wlock_release(rtld_phdr_lock, locks[2]);
+ bzero(ls, sizeof(ls));
+ ls[0].lockstate = locks[2];
+ ls[1].lockstate = locks[0];
+ lock_release(rtld_bind_lock, &ls[1]);
+ lock_release(rtld_phdr_lock, &ls[0]);
}
OpenPOWER on IntegriCloud