Index: sys/sys/umtx.h =================================================================== RCS file: /home/ncvs/src/sys/sys/umtx.h,v retrieving revision 1.32 diff -u -u -r1.32 umtx.h --- sys/sys/umtx.h 29 Apr 2008 03:48:48 -0000 1.32 +++ sys/sys/umtx.h 5 May 2008 08:40:40 -0000 @@ -52,6 +52,7 @@ #define UMUTEX_ERROR_CHECK 0x0002 /* Error-checking mutex */ #define UMUTEX_PRIO_INHERIT 0x0004 /* Priority inherited mutex */ #define UMUTEX_PRIO_PROTECT 0x0008 /* Priority protect mutex */ +#define UMUTEX_SIMPLE_MUTEX 0x0010 /* Simple userland mutex. */ struct umutex { volatile __lwpid_t m_owner; /* Owner of the mutex */ Index: lib/libthr/thread/thr_mutex.c =================================================================== RCS file: /home/ncvs/src/lib/libthr/thread/thr_mutex.c,v retrieving revision 1.73 diff -u -u -r1.73 thr_mutex.c --- lib/libthr/thread/thr_mutex.c 26 Apr 2008 13:19:07 -0000 1.73 +++ lib/libthr/thread/thr_mutex.c 5 May 2008 08:40:40 -0000 @@ -159,7 +159,7 @@ break; case PTHREAD_PRIO_NONE: pmutex->m_lock.m_owner = UMUTEX_UNOWNED; - pmutex->m_lock.m_flags = 0; + pmutex->m_lock.m_flags = UMUTEX_SIMPLE_MUTEX; } if (pmutex->m_type == PTHREAD_MUTEX_ADAPTIVE_NP) { @@ -263,8 +263,10 @@ * am not worried. */ - TAILQ_FOREACH(m, &curthread->mutexq, m_qe) - m->m_lock.m_owner = TID(curthread); + TAILQ_FOREACH(m, &curthread->mutexq, m_qe) { + if (!(m->m_lock.m_flags & UMUTEX_SIMPLE_MUTEX)) + m->m_lock.m_owner = TID(curthread); + } TAILQ_FOREACH(m, &curthread->pp_mutexq, m_qe) m->m_lock.m_owner = TID(curthread) | UMUTEX_CONTESTED; } @@ -390,7 +392,6 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *mutex, const struct timespec * abstime) { - struct timespec ts, ts2; struct pthread_mutex *m; uint32_t id; int ret; @@ -398,7 +399,7 @@ id = TID(curthread); m = *mutex; - ret = _thr_umutex_trylock2(&m->m_lock, id); + ret = _thr_umutex_trylock(&m->m_lock, id); if (ret == 0) { ENQUEUE_MUTEX(curthread, m); } else if (m->m_owner == curthread) { @@ -443,15 +444,7 @@ abstime->tv_nsec >= 1000000000)) { ret = EINVAL; } else { - clock_gettime(CLOCK_REALTIME, &ts); - TIMESPEC_SUB(&ts2, abstime, &ts); - ret = __thr_umutex_timedlock(&m->m_lock, &ts2); - /* - * Timed out wait is not restarted if - * it was interrupted, not worth to do it. - */ - if (ret == EINTR) - ret = ETIMEDOUT; + ret = __thr_umutex_timedlock(&m->m_lock, abstime); } done: if (ret == 0) Index: lib/libthr/thread/thr_umtx.c =================================================================== RCS file: /home/ncvs/src/lib/libthr/thread/thr_umtx.c,v retrieving revision 1.16 diff -u -u -r1.16 thr_umtx.c --- lib/libthr/thread/thr_umtx.c 29 Apr 2008 03:58:18 -0000 1.16 +++ lib/libthr/thread/thr_umtx.c 5 May 2008 08:40:40 -0000 @@ -39,6 +39,77 @@ } #endif +/* + * lock a simple mutex. + * 0 : free, 1 : locked, 2: locked + contested + */ +int +__thr_umtx_lock(volatile int32_t *mtx) +{ + int32_t v; + int ret = 0; + + /* contested */ + do { + v = *mtx; + if (v == 2 || atomic_cmpset_acq_32(mtx, 1, 2)) + _thr_umtx_wait_uint(mtx, 2, NULL, 0); + } while (!atomic_cmpset_acq_32(mtx, 0, 2)); + + return (ret); +} + +int +__thr_umtx_unlock(volatile int32_t *mtx) +{ + int32_t v; + + for (;;) { + v = *mtx; + if (atomic_cmpset_rel_32(mtx, v, v-1)) { + if (v != 1) { + *mtx = 0; + _thr_umtx_wake(mtx, 1, 0); + } + break; + } + } + + return (0); +} + +int +__thr_umtx_timedlock(volatile int32_t *mtx, const struct timespec *ets) +{ + struct timespec timo, cts; + int32_t v; + int ret = 0; + + clock_gettime(CLOCK_REALTIME, &cts); + TIMESPEC_SUB(&timo, ets, &cts); + + /* contested */ + for (;;) { + v = *mtx; + if (v == 2 || atomic_cmpset_acq_32(mtx, 1, 2)) + ret = _thr_umtx_wait_uint(mtx, 2, &timo, 0); + if (atomic_cmpset_acq_32(mtx, 0, 2)) { + ret = 0; + break; + } + if (ret == ETIMEDOUT) + break; + clock_gettime(CLOCK_REALTIME, &cts); + TIMESPEC_SUB(&timo, ets, &cts); + if (timo.tv_sec < 0 || + (timo.tv_sec == 0 && timo.tv_nsec <= 0)) { + ret = ETIMEDOUT; + break; + } + } + return (ret); +} + void _thr_umutex_init(struct umutex *mtx) { @@ -50,23 +121,46 @@ int __thr_umutex_lock(struct umutex *mtx) { + if (mtx->m_flags & UMUTEX_SIMPLE_MUTEX) + return __thr_umtx_lock(&mtx->m_owner); return _umtx_op_err(mtx, UMTX_OP_MUTEX_LOCK, 0, 0, 0); } int __thr_umutex_timedlock(struct umutex *mtx, - const struct timespec *timeout) + const struct timespec *ets) { - if (timeout && (timeout->tv_sec < 0 || (timeout->tv_sec == 0 && - timeout->tv_nsec <= 0))) - return (ETIMEDOUT); - return _umtx_op_err(mtx, UMTX_OP_MUTEX_LOCK, 0, 0, - __DECONST(void *, timeout)); + struct timespec timo, cts; + int ret; + + if (mtx->m_flags & UMUTEX_SIMPLE_MUTEX) + return __thr_umtx_timedlock(&mtx->m_owner, ets); + + clock_gettime(CLOCK_REALTIME, &cts); + TIMESPEC_SUB(&timo, ets, &cts); + + for (;;) { + ret = _umtx_op_err(mtx, UMTX_OP_MUTEX_LOCK, 0, 0, &timo); + if (ret == 0) + break; + if (ret == ETIMEDOUT) + break; + clock_gettime(CLOCK_REALTIME, &cts); + TIMESPEC_SUB(&timo, ets, &cts); + if (timo.tv_sec < 0 || + (timo.tv_sec == 0 && timo.tv_nsec <= 0)) { + ret = ETIMEDOUT; + break; + } + } + return (ret); } int __thr_umutex_unlock(struct umutex *mtx) { + if (mtx->m_flags & UMUTEX_SIMPLE_MUTEX) + return __thr_umtx_unlock(&mtx->m_owner); return _umtx_op_err(mtx, UMTX_OP_MUTEX_UNLOCK, 0, 0, 0); } Index: lib/libthr/thread/thr_umtx.h =================================================================== RCS file: /home/ncvs/src/lib/libthr/thread/thr_umtx.h,v retrieving revision 1.13 diff -u -u -r1.13 thr_umtx.h --- lib/libthr/thread/thr_umtx.h 29 Apr 2008 03:58:18 -0000 1.13 +++ lib/libthr/thread/thr_umtx.h 5 May 2008 08:40:40 -0000 @@ -32,7 +32,11 @@ #include #include -#define DEFAULT_UMUTEX {0,0, {0,0},{0,0,0,0}} +#define DEFAULT_UMUTEX {0, 0, {0,0}, {0,0,0,0}} + +int __thr_umtx_lock(volatile int32_t *mtx) __hidden; +int __thr_umtx_unlock(volatile int32_t *mtx) __hidden; +int __thr_umtx_timedlock(volatile int32_t *mtx, const struct timespec *timeout) __hidden; int __thr_umutex_lock(struct umutex *mtx) __hidden; int __thr_umutex_timedlock(struct umutex *mtx, @@ -59,46 +63,89 @@ int __thr_rwlock_unlock(struct urwlock *rwlock) __hidden; static inline int +_thr_umtx_trylock(volatile int32_t *mtx) +{ + if (atomic_cmpset_acq_32(mtx, 0, 1)) + return (0); + return (EBUSY); +} + +static inline int +_thr_umtx_lock(volatile int32_t *mtx) +{ + if (atomic_cmpset_acq_32(mtx, 0, 1)) + return (0); + return (__thr_umtx_lock(mtx)); +} + +static inline int +_thr_umtx_timedlock(volatile int32_t *mtx, + const struct timespec *timeout) +{ + if (atomic_cmpset_acq_32(mtx, 0, 1)) + return (0); + return (__thr_umtx_timedlock(mtx, timeout)); +} + +static inline int +_thr_umtx_unlock(volatile int32_t *mtx) +{ + if (atomic_cmpset_rel_32(mtx, 1, 0)) + return (0); + return __thr_umtx_unlock(mtx); +} + +static inline int _thr_umutex_trylock(struct umutex *mtx, uint32_t id) { - if (atomic_cmpset_acq_32(&mtx->m_owner, UMUTEX_UNOWNED, id)) - return (0); - if ((mtx->m_flags & UMUTEX_PRIO_PROTECT) == 0) - return (EBUSY); - return (__thr_umutex_trylock(mtx)); + if (mtx->m_flags & UMUTEX_SIMPLE_MUTEX) + return _thr_umtx_trylock(&mtx->m_owner); + if (atomic_cmpset_acq_32(&mtx->m_owner, UMUTEX_UNOWNED, id)) + return (0); + if ((mtx->m_flags & UMUTEX_PRIO_PROTECT) == 0) + return (EBUSY); + return (__thr_umutex_trylock(mtx)); } static inline int _thr_umutex_trylock2(struct umutex *mtx, uint32_t id) { - if (atomic_cmpset_acq_32(&mtx->m_owner, UMUTEX_UNOWNED, id)) - return (0); - return (EBUSY); + if (mtx->m_flags & UMUTEX_SIMPLE_MUTEX) + return _thr_umtx_trylock(&mtx->m_owner); + if (atomic_cmpset_acq_32(&mtx->m_owner, UMUTEX_UNOWNED, id)) + return (0); + return (EBUSY); } static inline int _thr_umutex_lock(struct umutex *mtx, uint32_t id) { - if (atomic_cmpset_acq_32(&mtx->m_owner, UMUTEX_UNOWNED, id)) - return (0); - return (__thr_umutex_lock(mtx)); + if (mtx->m_flags & UMUTEX_SIMPLE_MUTEX) + return _thr_umtx_lock(&mtx->m_owner); + if (atomic_cmpset_acq_32(&mtx->m_owner, UMUTEX_UNOWNED, id)) + return (0); + return (__thr_umutex_lock(mtx)); } static inline int _thr_umutex_timedlock(struct umutex *mtx, uint32_t id, const struct timespec *timeout) { - if (atomic_cmpset_acq_32(&mtx->m_owner, UMUTEX_UNOWNED, id)) - return (0); - return (__thr_umutex_timedlock(mtx, timeout)); + if (mtx->m_flags & UMUTEX_SIMPLE_MUTEX) + return _thr_umtx_trylock(&mtx->m_owner); + if (atomic_cmpset_acq_32(&mtx->m_owner, UMUTEX_UNOWNED, id)) + return (0); + return (__thr_umutex_timedlock(mtx, timeout)); } static inline int _thr_umutex_unlock(struct umutex *mtx, uint32_t id) { - if (atomic_cmpset_rel_32(&mtx->m_owner, id, UMUTEX_UNOWNED)) - return (0); - return (__thr_umutex_unlock(mtx)); + if (mtx->m_flags & UMUTEX_SIMPLE_MUTEX) + return _thr_umtx_unlock(&mtx->m_owner); + if (atomic_cmpset_rel_32(&mtx->m_owner, id, UMUTEX_UNOWNED)) + return (0); + return (__thr_umutex_unlock(mtx)); } static inline int