diff options
Diffstat (limited to 'lib/libthr')
-rw-r--r-- | lib/libthr/thread/thr_spec.c | 12 | ||||
-rw-r--r-- | lib/libthr/thread/thr_umtx.h | 7 |
2 files changed, 16 insertions, 3 deletions
diff --git a/lib/libthr/thread/thr_spec.c b/lib/libthr/thread/thr_spec.c index 06d1287..0740d6b 100644 --- a/lib/libthr/thread/thr_spec.c +++ b/lib/libthr/thread/thr_spec.c @@ -131,9 +131,19 @@ _thread_cleanupspecific(void) curthread->specific[key].data = NULL; curthread->specific_data_count--; } + else if (curthread->specific[key].data != NULL) { + /* + * This can happen if the key is deleted via + * pthread_key_delete without first setting the value + * to NULL in all threads. POSIX says that the + * destructor is not invoked in this case. + */ + curthread->specific[key].data = NULL; + curthread->specific_data_count--; + } /* - * If there is a destructore, call it + * If there is a destructor, call it * with the key table entry unlocked: */ if (destructor != NULL) { diff --git a/lib/libthr/thread/thr_umtx.h b/lib/libthr/thread/thr_umtx.h index 41b5f96..a6e462e 100644 --- a/lib/libthr/thread/thr_umtx.h +++ b/lib/libthr/thread/thr_umtx.h @@ -171,8 +171,11 @@ _thr_rwlock_unlock(struct urwlock *rwlock) for (;;) { if (__predict_false(URWLOCK_READER_COUNT(state) == 0)) return (EPERM); - if (!((state & URWLOCK_WRITE_WAITERS) && URWLOCK_READER_COUNT(state) == 1)) { - if (atomic_cmpset_rel_32(&rwlock->rw_state, state, state-1)) + if (!((state & (URWLOCK_WRITE_WAITERS | + URWLOCK_READ_WAITERS)) && + URWLOCK_READER_COUNT(state) == 1)) { + if (atomic_cmpset_rel_32(&rwlock->rw_state, + state, state-1)) return (0); state = rwlock->rw_state; } else { |