diff options
Diffstat (limited to 'lib/libthr')
-rw-r--r-- | lib/libthr/thread/thr_private.h | 2 | ||||
-rw-r--r-- | lib/libthr/thread/thr_umtx.h | 21 |
2 files changed, 18 insertions, 5 deletions
diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h index 4b9219d..87af318 100644 --- a/lib/libthr/thread/thr_private.h +++ b/lib/libthr/thread/thr_private.h @@ -834,8 +834,6 @@ ssize_t __sys_write(int, const void *, size_t); void __sys_exit(int); #endif -int _umtx_op_err(void *, int op, u_long, void *, void *) __hidden; - static inline int _thr_isthreaded(void) { diff --git a/lib/libthr/thread/thr_umtx.h b/lib/libthr/thread/thr_umtx.h index 61a74a8..d74cc81 100644 --- a/lib/libthr/thread/thr_umtx.h +++ b/lib/libthr/thread/thr_umtx.h @@ -35,6 +35,7 @@ #define DEFAULT_UMUTEX {0,0,{0,0},{0,0,0,0}} #define DEFAULT_URWLOCK {0,0,0,0,{0,0,0,0}} +int _umtx_op_err(void *, int op, u_long, void *, void *) __hidden; int __thr_umutex_lock(struct umutex *mtx, uint32_t id) __hidden; int __thr_umutex_lock_spin(struct umutex *mtx, uint32_t id) __hidden; int __thr_umutex_timedlock(struct umutex *mtx, uint32_t id, @@ -121,9 +122,23 @@ _thr_umutex_timedlock(struct umutex *mtx, uint32_t id, 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, id)); + uint32_t flags = mtx->m_flags; + + if ((flags & (UMUTEX_PRIO_PROTECT | UMUTEX_PRIO_INHERIT)) == 0) { + uint32_t owner; + do { + owner = mtx->m_owner; + if (__predict_false((owner & ~UMUTEX_CONTESTED) != id)) + return (EPERM); + } while (__predict_false(!atomic_cmpset_rel_32(&mtx->m_owner, + owner, UMUTEX_UNOWNED))); + if ((owner & UMUTEX_CONTESTED)) + (void)_umtx_op_err(mtx, UMTX_OP_MUTEX_WAKE2, flags, 0, 0); + return (0); + } + if (atomic_cmpset_rel_32(&mtx->m_owner, id, UMUTEX_UNOWNED)) + return (0); + return (__thr_umutex_unlock(mtx, id)); } static inline int |