Index: thread/thr_private.h =================================================================== RCS file: /home/ncvs/src/lib/libthr/thread/thr_private.h,v retrieving revision 1.86 diff -u -u -r1.86 thr_private.h --- thread/thr_private.h 31 Mar 2008 02:55:49 -0000 1.86 +++ thread/thr_private.h 1 Apr 2008 02:07:22 -0000 @@ -272,12 +272,7 @@ }; struct pthread_rwlock { - pthread_mutex_t lock; /* monitor lock */ - pthread_cond_t read_signal; - pthread_cond_t write_signal; - volatile int32_t state; - int blocked_writers; - int blocked_readers; + struct urwlock lock; struct pthread *owner; }; Index: thread/thr_rwlock.c =================================================================== RCS file: /home/ncvs/src/lib/libthr/thread/thr_rwlock.c,v retrieving revision 1.12 diff -u -u -r1.12 thr_rwlock.c --- thread/thr_rwlock.c 1 Apr 2008 00:21:49 -0000 1.12 +++ thread/thr_rwlock.c 1 Apr 2008 02:07:22 -0000 @@ -32,15 +32,10 @@ #include "namespace.h" #include +#include #include "un-namespace.h" #include "thr_private.h" -#define RWLOCK_WRITE_OWNER 0x80000000U -#define RWLOCK_WRITE_WAITERS 0x40000000U -#define RWLOCK_READ_WAITERS 0x20000000U -#define RWLOCK_MAX_READERS 0x1fffffffU -#define RWLOCK_READER_COUNT(c) ((c) & RWLOCK_MAX_READERS) - __weak_reference(_pthread_rwlock_destroy, pthread_rwlock_destroy); __weak_reference(_pthread_rwlock_init, pthread_rwlock_init); __weak_reference(_pthread_rwlock_rdlock, pthread_rwlock_rdlock); @@ -59,44 +54,12 @@ rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr __unused) { pthread_rwlock_t prwlock; - int ret; - - /* allocate rwlock object */ - prwlock = (pthread_rwlock_t)malloc(sizeof(struct pthread_rwlock)); + prwlock = (pthread_rwlock_t)calloc(1, sizeof(struct pthread_rwlock)); if (prwlock == NULL) return (ENOMEM); - - /* initialize the lock */ - if ((ret = _pthread_mutex_init(&prwlock->lock, NULL)) != 0) - free(prwlock); - else { - /* initialize the read condition signal */ - ret = _pthread_cond_init(&prwlock->read_signal, NULL); - - if (ret != 0) { - _pthread_mutex_destroy(&prwlock->lock); - free(prwlock); - } else { - /* initialize the write condition signal */ - ret = _pthread_cond_init(&prwlock->write_signal, NULL); - - if (ret != 0) { - _pthread_cond_destroy(&prwlock->read_signal); - _pthread_mutex_destroy(&prwlock->lock); - free(prwlock); - } else { - /* success */ - prwlock->state = 0; - prwlock->blocked_readers = 0; - prwlock->blocked_writers = 0; - prwlock->owner = NULL; - *rwlock = prwlock; - } - } - } - - return (ret); + *rwlock = prwlock; + return (0); } int @@ -112,11 +75,7 @@ prwlock = *rwlock; *rwlock = NULL; - _pthread_mutex_destroy(&prwlock->lock); - _pthread_cond_destroy(&prwlock->read_signal); - _pthread_cond_destroy(&prwlock->write_signal); free(prwlock); - ret = 0; } return (ret); @@ -146,37 +105,13 @@ return (rwlock_init(rwlock, attr)); } -static inline int -rwlock_tryrdlock(struct pthread_rwlock *prwlock, int prefer_reader) -{ - int32_t state; - int32_t wrflags; - - if (prefer_reader) - wrflags = RWLOCK_WRITE_OWNER; - else - wrflags = RWLOCK_WRITE_OWNER | RWLOCK_WRITE_WAITERS; - state = prwlock->state; - while (!(state & wrflags)) { - if (__predict_false(RWLOCK_READER_COUNT(state) == RWLOCK_MAX_READERS)) - return (EAGAIN); - if (atomic_cmpset_acq_32(&prwlock->state, state, state + 1)) - return (0); - CPU_SPINWAIT; - state = prwlock->state; - } - - return (EBUSY); -} - static int rwlock_rdlock_common(pthread_rwlock_t *rwlock, const struct timespec *abstime) { struct pthread *curthread = _get_curthread(); - const int prefer_read = curthread->rdlock_count > 0; pthread_rwlock_t prwlock; - int ret, wrflags, old; - int32_t state; + struct timespec ts, ts2, *tsp; + int ret, flags; if (__predict_false(rwlock == NULL)) return (EINVAL); @@ -195,19 +130,17 @@ * POSIX said the validity of the abstimeout parameter need * not be checked if the lock can be immediately acquired. */ - ret = rwlock_tryrdlock(prwlock, prefer_read); + ret = _thr_rwlock_tryrdlock(&prwlock->lock); if (ret == 0) { curthread->rdlock_count++; return (ret); } - if (__predict_false(ret == EAGAIN)) - return (ret); if (__predict_false(abstime && (abstime->tv_nsec >= 1000000000 || abstime->tv_nsec < 0))) return (EINVAL); - if (prefer_read) { + if (curthread->rdlock_count > 0) { /* * To avoid having to track all the rdlocks held by * a thread or all of the threads that hold a rdlock, @@ -221,49 +154,32 @@ * deadlock. I hope the reader can follow that logic ;-) */ - wrflags = RWLOCK_WRITE_OWNER; + flags = URWLOCK_PREFER_READER; } else - wrflags = RWLOCK_WRITE_OWNER | RWLOCK_WRITE_WAITERS; + flags = 0; - /* reset to zero */ - ret = 0; for (;;) { - _pthread_mutex_lock(&prwlock->lock); - state = prwlock->state; - /* set read contention bit */ - while ((state & wrflags) && !(state & RWLOCK_READ_WAITERS)) { - if (atomic_cmpset_acq_32(&prwlock->state, state, state | RWLOCK_READ_WAITERS)) - break; - CPU_SPINWAIT; - state = prwlock->state; - } - - atomic_add_32(&prwlock->blocked_readers, 1); - if (state & wrflags) { - ret = _pthread_cond_wait_unlocked(&prwlock->read_signal, &prwlock->lock, abstime); - old = atomic_fetchadd_32(&prwlock->blocked_readers, -1); - if (old == 1) - _pthread_mutex_lock(&prwlock->lock); - else - goto try_it; - } else { - atomic_subtract_32(&prwlock->blocked_readers, 1); - } + if (abstime) { + clock_gettime(CLOCK_REALTIME, &ts); + TIMESPEC_SUB(&ts2, abstime, &ts); + if (ts2.tv_sec < 0 || + (ts2.tv_sec == 0 && ts2.tv_nsec <= 0)) + return (ETIMEDOUT); + tsp = &ts2; + } else + tsp = NULL; + + /* goto kernel and lock it */ + ret = __thr_rwlock_rdlock(&prwlock->lock, flags, tsp); + if (ret != EINTR) + break; - if (prwlock->blocked_readers == 0) - atomic_clear_32(&prwlock->state, RWLOCK_READ_WAITERS); - _pthread_mutex_unlock(&prwlock->lock); - -try_it: - /* try to lock it again. */ - if (rwlock_tryrdlock(prwlock, prefer_read) == 0) { + /* if interrupted, try to lock it in userland again. */ + ret = _thr_rwlock_tryrdlock(&prwlock->lock); + if (ret == 0) { curthread->rdlock_count++; - ret = 0; break; } - - if (ret) - break; } return (ret); } @@ -301,27 +217,12 @@ prwlock = *rwlock; } - ret = rwlock_tryrdlock(prwlock, curthread->rdlock_count > 0); + ret = _thr_rwlock_tryrdlock(&prwlock->lock); if (ret == 0) curthread->rdlock_count++; return (ret); } -static inline int -rwlock_trywrlock(struct pthread_rwlock *prwlock) -{ - int32_t state; - - state = prwlock->state; - while (!(state & RWLOCK_WRITE_OWNER) && RWLOCK_READER_COUNT(state) == 0) { - if (atomic_cmpset_acq_32(&prwlock->state, state, state | RWLOCK_WRITE_OWNER)) - return (0); - CPU_SPINWAIT; - state = prwlock->state; - } - return (EBUSY); -} - int _pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock) { @@ -342,19 +243,49 @@ prwlock = *rwlock; } - ret = rwlock_trywrlock(prwlock); + ret = _thr_rwlock_trywrlock(&prwlock->lock); if (ret == 0) prwlock->owner = curthread; return (ret); } +int +_pthread_rwlock_unlock (pthread_rwlock_t *rwlock) +{ + struct pthread *curthread = _get_curthread(); + pthread_rwlock_t prwlock; + int ret; + int32_t state; + + if (__predict_false(rwlock == NULL)) + return (EINVAL); + + prwlock = *rwlock; + + if (__predict_false(prwlock == NULL)) + return (EINVAL); + + state = prwlock->lock.rw_state; + if (state & URWLOCK_WRITE_OWNER) { + if (__predict_false(prwlock->owner != curthread)) + return (EPERM); + prwlock->owner = NULL; + } + + ret = _thr_rwlock_unlock(&prwlock->lock); + if (ret == 0 && (state & URWLOCK_WRITE_OWNER) == 0) + curthread->rdlock_count--; + + return (ret); +} + static int rwlock_wrlock_common (pthread_rwlock_t *rwlock, const struct timespec *abstime) { struct pthread *curthread = _get_curthread(); pthread_rwlock_t prwlock; + struct timespec ts, ts2, *tsp; int ret; - int32_t state; if (__predict_false(rwlock == NULL)) return (EINVAL); @@ -375,7 +306,7 @@ */ /* try to lock it in userland */ - ret = rwlock_trywrlock(prwlock); + ret = _thr_rwlock_trywrlock(&prwlock->lock); if (ret == 0) { prwlock->owner = curthread; return (ret); @@ -385,46 +316,28 @@ (abstime->tv_nsec >= 1000000000 || abstime->tv_nsec < 0))) return (EINVAL); - /* reset to zero */ - ret = 0; - for (;;) { - _pthread_mutex_lock(&prwlock->lock); - state = prwlock->state; - while (((state & RWLOCK_WRITE_OWNER) || RWLOCK_READER_COUNT(state) != 0) && - (state & RWLOCK_WRITE_WAITERS) == 0) { - if (atomic_cmpset_acq_32(&prwlock->state, state, state | RWLOCK_WRITE_WAITERS)) - break; - CPU_SPINWAIT; - state = prwlock->state; - } - - prwlock->blocked_writers++; - - while ((state & RWLOCK_WRITE_OWNER) || RWLOCK_READER_COUNT(state) != 0) { - if (abstime == NULL) - ret = _pthread_cond_wait(&prwlock->write_signal, &prwlock->lock); - else - ret = _pthread_cond_timedwait(&prwlock->write_signal, &prwlock->lock, abstime); - - if (ret) - break; - state = prwlock->state; - } - - prwlock->blocked_writers--; - if (prwlock->blocked_writers == 0) - atomic_clear_32(&prwlock->state, RWLOCK_WRITE_WAITERS); - _pthread_mutex_unlock(&prwlock->lock); + if (abstime != NULL) { + clock_gettime(CLOCK_REALTIME, &ts); + TIMESPEC_SUB(&ts2, abstime, &ts); + if (ts2.tv_sec < 0 || + (ts2.tv_sec == 0 && ts2.tv_nsec <= 0)) + return (ETIMEDOUT); + tsp = &ts2; + } else + tsp = NULL; + + /* goto kernel and lock it */ + ret = __thr_rwlock_wrlock(&prwlock->lock, tsp); + if (ret != EINTR) + break; - if (rwlock_trywrlock(prwlock) == 0) { + /* if interrupted, try to lock it in userland again. */ + ret = _thr_rwlock_trywrlock(&prwlock->lock); + if (ret == 0) { prwlock->owner = curthread; - ret = 0; break; } - - if (ret) - break; } return (ret); } @@ -441,62 +354,3 @@ { return (rwlock_wrlock_common (rwlock, abstime)); } - -int -_pthread_rwlock_unlock (pthread_rwlock_t *rwlock) -{ - struct pthread *curthread = _get_curthread(); - pthread_rwlock_t prwlock; - int32_t state; - - if (__predict_false(rwlock == NULL)) - return (EINVAL); - - prwlock = *rwlock; - - if (__predict_false(prwlock == NULL)) - return (EINVAL); - - state = prwlock->state; - - if (state & RWLOCK_WRITE_OWNER) { - if (__predict_false(prwlock->owner != curthread)) - return (EPERM); - prwlock->owner = NULL; - while (!atomic_cmpset_rel_32(&prwlock->state, state, state & ~RWLOCK_WRITE_OWNER)) { - CPU_SPINWAIT; - state = prwlock->state; - } - } else if (RWLOCK_READER_COUNT(state) != 0) { - while (!atomic_cmpset_rel_32(&prwlock->state, state, state - 1)) { - CPU_SPINWAIT; - state = prwlock->state; - if (RWLOCK_READER_COUNT(state) == 0) - return (EPERM); - } - curthread->rdlock_count--; - } else { - return (EPERM); - } - -#if 0 - if (state & RWLOCK_WRITE_WAITERS) { - _pthread_mutex_lock(&prwlock->lock); - _pthread_cond_signal(&prwlock->write_signal); - _pthread_mutex_unlock(&prwlock->lock); - } else if (state & RWLOCK_READ_WAITERS) { - _pthread_mutex_lock(&prwlock->lock); - _pthread_cond_broadcast(&prwlock->read_signal); - _pthread_mutex_unlock(&prwlock->lock); - } -#endif - - if (state & RWLOCK_WRITE_WAITERS) { - _pthread_mutex_lock(&prwlock->lock); - _pthread_cond_broadcast_unlock(&prwlock->write_signal, &prwlock->lock, 0); - } else if (state & RWLOCK_READ_WAITERS) { - _pthread_mutex_lock(&prwlock->lock); - _pthread_cond_broadcast_unlock(&prwlock->write_signal, &prwlock->lock, 1); - } - return (0); -}