--- lib/libthr/thread/thr_rtld.c.orig 2011-01-23 09:17:50.657791000 +0900 +++ lib/libthr/thread/thr_rtld.c 2012-04-12 02:48:05.091322596 +0900 @@ -52,6 +52,10 @@ static void _thr_rtld_wlock_acquire(void struct rtld_lock { struct urwlock lock; + struct pthread * volatile owner; + int nested; + int count_rw; /* total rlock-within-wlock incidents */ + int count_ww; /* total wlock-within-wlock incidents */ char _pad[CACHE_LINE_SIZE - sizeof(struct urwlock)]; }; @@ -106,6 +110,15 @@ _thr_rtld_lock_destroy(void *lock) errno = errsave; \ } +#define HANDLE_NESTED_ACQ(statfield) { \ + if ((l->lock.rw_state & URWLOCK_WRITE_OWNER) != 0 && \ + l->owner == curthread) { \ + l->nested++; \ + l->statfield++; \ + return; \ + } \ + } + static void _thr_rtld_rlock_acquire(void *lock) { @@ -117,6 +130,7 @@ _thr_rtld_rlock_acquire(void *lock) SAVE_ERRNO(); l = (struct rtld_lock *)lock; + HANDLE_NESTED_ACQ(count_rw); THR_CRITICAL_ENTER(curthread); while (_thr_rwlock_rdlock(&l->lock, 0, NULL) != 0) ; @@ -135,9 +149,11 @@ _thr_rtld_wlock_acquire(void *lock) SAVE_ERRNO(); l = (struct rtld_lock *)lock; + HANDLE_NESTED_ACQ(count_ww); THR_CRITICAL_ENTER(curthread); while (_thr_rwlock_wrlock(&l->lock, NULL) != 0) ; + l->owner = curthread; RESTORE_ERRNO(); } @@ -154,6 +170,14 @@ _thr_rtld_lock_release(void *lock) l = (struct rtld_lock *)lock; state = l->lock.rw_state; + if ((state & URWLOCK_WRITE_OWNER) != 0) { + if (l->nested == 0) + l->owner = NULL; + else { + l->nested--; + return; + } + } if (_thr_rwlock_unlock(&l->lock) == 0) { if ((state & URWLOCK_WRITE_OWNER) == 0) curthread->rdlock_count--;