thr_umtx.h revision 232209
1240116Smarcel/*- 2240116Smarcel * Copyright (c) 2005 David Xu <davidxu@freebsd.org> 3240116Smarcel * All rights reserved. 4240116Smarcel * 5240116Smarcel * Redistribution and use in source and binary forms, with or without 6240116Smarcel * modification, are permitted provided that the following conditions 7240116Smarcel * are met: 8240116Smarcel * 1. Redistributions of source code must retain the above copyright 9240116Smarcel * notice, this list of conditions and the following disclaimer. 10240116Smarcel * 2. Redistributions in binary form must reproduce the above copyright 11240116Smarcel * notice, this list of conditions and the following disclaimer in the 12240116Smarcel * documentation and/or other materials provided with the distribution. 13240116Smarcel * 14240116Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15240116Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16240116Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17240116Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18240116Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19240116Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20240116Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21240116Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22240116Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23240116Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24240116Smarcel * SUCH DAMAGE. 25240116Smarcel * 26275988Sngie * $FreeBSD: head/lib/libthr/thread/thr_umtx.h 232209 2012-02-27 13:38:52Z davidxu $ 27275988Sngie */ 28240116Smarcel 29240116Smarcel#ifndef _THR_FBSD_UMTX_H_ 30240116Smarcel#define _THR_FBSD_UMTX_H_ 31240116Smarcel 32240116Smarcel#include <strings.h> 33240116Smarcel#include <sys/umtx.h> 34240116Smarcel 35240116Smarcel#define DEFAULT_UMUTEX {0,0,{0,0},{0,0,0,0}} 36240116Smarcel#define DEFAULT_URWLOCK {0,0,0,0,{0,0,0,0}} 37240116Smarcel 38240116Smarcelint __thr_umutex_lock(struct umutex *mtx, uint32_t id) __hidden; 39240116Smarcelint __thr_umutex_lock_spin(struct umutex *mtx, uint32_t id) __hidden; 40240116Smarcelint __thr_umutex_timedlock(struct umutex *mtx, uint32_t id, 41275988Sngie const struct timespec *timeout) __hidden; 42240116Smarcelint __thr_umutex_unlock(struct umutex *mtx, uint32_t id) __hidden; 43240116Smarcelint __thr_umutex_trylock(struct umutex *mtx) __hidden; 44240116Smarcelint __thr_umutex_set_ceiling(struct umutex *mtx, uint32_t ceiling, 45240116Smarcel uint32_t *oldceiling) __hidden; 46240116Smarcel 47240116Smarcelvoid _thr_umutex_init(struct umutex *mtx) __hidden; 48240116Smarcelvoid _thr_urwlock_init(struct urwlock *rwl) __hidden; 49240116Smarcel 50240116Smarcelint _thr_umtx_wait(volatile long *mtx, long exp, 51240116Smarcel const struct timespec *timeout) __hidden; 52240116Smarcelint _thr_umtx_wait_uint(volatile u_int *mtx, u_int exp, 53240116Smarcel const struct timespec *timeout, int shared) __hidden; 54240116Smarcelint _thr_umtx_timedwait_uint(volatile u_int *mtx, u_int exp, int clockid, 55240116Smarcel const struct timespec *timeout, int shared) __hidden; 56240116Smarcelint _thr_umtx_wake(volatile void *mtx, int count, int shared) __hidden; 57240116Smarcelint _thr_ucond_wait(struct ucond *cv, struct umutex *m, 58240116Smarcel const struct timespec *timeout, int check_unpaking) __hidden; 59240116Smarcelvoid _thr_ucond_init(struct ucond *cv) __hidden; 60240116Smarcelint _thr_ucond_signal(struct ucond *cv) __hidden; 61240116Smarcelint _thr_ucond_broadcast(struct ucond *cv) __hidden; 62240116Smarcel 63240116Smarcelint __thr_rwlock_rdlock(struct urwlock *rwlock, int flags, 64240116Smarcel const struct timespec *tsp) __hidden; 65240116Smarcelint __thr_rwlock_wrlock(struct urwlock *rwlock, 66240116Smarcel const struct timespec *tsp) __hidden; 67240116Smarcelint __thr_rwlock_unlock(struct urwlock *rwlock) __hidden; 68240116Smarcel 69240116Smarcel/* Internal used only */ 70240116Smarcelvoid _thr_rwl_rdlock(struct urwlock *rwlock) __hidden; 71240116Smarcelvoid _thr_rwl_wrlock(struct urwlock *rwlock) __hidden; 72240116Smarcelvoid _thr_rwl_unlock(struct urwlock *rwlock) __hidden; 73240116Smarcel 74240116Smarcelstatic inline int 75240116Smarcel_thr_umutex_trylock(struct umutex *mtx, uint32_t id) 76240116Smarcel{ 77240116Smarcel if (atomic_cmpset_acq_32(&mtx->m_owner, UMUTEX_UNOWNED, id)) 78240116Smarcel return (0); 79240116Smarcel if ((mtx->m_flags & UMUTEX_PRIO_PROTECT) == 0) 80240116Smarcel return (EBUSY); 81240116Smarcel return (__thr_umutex_trylock(mtx)); 82240116Smarcel} 83240116Smarcel 84240116Smarcelstatic inline int 85240116Smarcel_thr_umutex_trylock2(struct umutex *mtx, uint32_t id) 86240116Smarcel{ 87240116Smarcel if (atomic_cmpset_acq_32(&mtx->m_owner, UMUTEX_UNOWNED, id) != 0) 88240116Smarcel return (0); 89240116Smarcel if ((uint32_t)mtx->m_owner == UMUTEX_CONTESTED && 90240116Smarcel __predict_true((mtx->m_flags & (UMUTEX_PRIO_PROTECT | UMUTEX_PRIO_INHERIT)) == 0)) 91240116Smarcel if (atomic_cmpset_acq_32(&mtx->m_owner, UMUTEX_CONTESTED, id | UMUTEX_CONTESTED)) 92240116Smarcel return (0); 93240116Smarcel return (EBUSY); 94240116Smarcel} 95240116Smarcel 96240116Smarcelstatic inline int 97240116Smarcel_thr_umutex_lock(struct umutex *mtx, uint32_t id) 98240116Smarcel{ 99240116Smarcel if (_thr_umutex_trylock2(mtx, id) == 0) 100240116Smarcel return (0); 101240116Smarcel return (__thr_umutex_lock(mtx, id)); 102240116Smarcel} 103240116Smarcel 104240116Smarcelstatic inline int 105240116Smarcel_thr_umutex_lock_spin(struct umutex *mtx, uint32_t id) 106240116Smarcel{ 107240116Smarcel if (_thr_umutex_trylock2(mtx, id) == 0) 108240116Smarcel return (0); 109240116Smarcel return (__thr_umutex_lock_spin(mtx, id)); 110240116Smarcel} 111240116Smarcel 112240116Smarcelstatic inline int 113240116Smarcel_thr_umutex_timedlock(struct umutex *mtx, uint32_t id, 114240116Smarcel const struct timespec *timeout) 115240116Smarcel{ 116240116Smarcel if (_thr_umutex_trylock2(mtx, id) == 0) 117240116Smarcel return (0); 118240116Smarcel return (__thr_umutex_timedlock(mtx, id, timeout)); 119240116Smarcel} 120240116Smarcel 121240116Smarcelstatic inline int 122240116Smarcel_thr_umutex_unlock(struct umutex *mtx, uint32_t id) 123240116Smarcel{ 124240116Smarcel if (atomic_cmpset_rel_32(&mtx->m_owner, id, UMUTEX_UNOWNED)) 125240116Smarcel return (0); 126240116Smarcel return (__thr_umutex_unlock(mtx, id)); 127240116Smarcel} 128240116Smarcel 129240116Smarcelstatic inline int 130240116Smarcel_thr_rwlock_tryrdlock(struct urwlock *rwlock, int flags) 131240116Smarcel{ 132240116Smarcel int32_t state; 133240116Smarcel int32_t wrflags; 134240116Smarcel 135240116Smarcel if (flags & URWLOCK_PREFER_READER || rwlock->rw_flags & URWLOCK_PREFER_READER) 136240116Smarcel wrflags = URWLOCK_WRITE_OWNER; 137240116Smarcel else 138240116Smarcel wrflags = URWLOCK_WRITE_OWNER | URWLOCK_WRITE_WAITERS; 139240116Smarcel state = rwlock->rw_state; 140240116Smarcel while (!(state & wrflags)) { 141240116Smarcel if (__predict_false(URWLOCK_READER_COUNT(state) == URWLOCK_MAX_READERS)) 142240116Smarcel return (EAGAIN); 143240116Smarcel if (atomic_cmpset_acq_32(&rwlock->rw_state, state, state + 1)) 144240116Smarcel return (0); 145240116Smarcel state = rwlock->rw_state; 146240116Smarcel } 147240116Smarcel 148240116Smarcel return (EBUSY); 149240116Smarcel} 150240116Smarcel 151240116Smarcelstatic inline int 152240116Smarcel_thr_rwlock_trywrlock(struct urwlock *rwlock) 153240116Smarcel{ 154240116Smarcel int32_t state; 155240116Smarcel 156240116Smarcel state = rwlock->rw_state; 157240116Smarcel while (!(state & URWLOCK_WRITE_OWNER) && URWLOCK_READER_COUNT(state) == 0) { 158240116Smarcel if (atomic_cmpset_acq_32(&rwlock->rw_state, state, state | URWLOCK_WRITE_OWNER)) 159240116Smarcel return (0); 160240116Smarcel state = rwlock->rw_state; 161240116Smarcel } 162240116Smarcel 163240116Smarcel return (EBUSY); 164240116Smarcel} 165240116Smarcel 166240116Smarcelstatic inline int 167240116Smarcel_thr_rwlock_rdlock(struct urwlock *rwlock, int flags, struct timespec *tsp) 168240116Smarcel{ 169240116Smarcel if (_thr_rwlock_tryrdlock(rwlock, flags) == 0) 170240116Smarcel return (0); 171240116Smarcel return (__thr_rwlock_rdlock(rwlock, flags, tsp)); 172240116Smarcel} 173240116Smarcel 174240116Smarcelstatic inline int 175240116Smarcel_thr_rwlock_wrlock(struct urwlock *rwlock, struct timespec *tsp) 176240116Smarcel{ 177240116Smarcel if (_thr_rwlock_trywrlock(rwlock) == 0) 178240116Smarcel return (0); 179240116Smarcel return (__thr_rwlock_wrlock(rwlock, tsp)); 180240116Smarcel} 181240116Smarcel 182240116Smarcelstatic inline int 183240116Smarcel_thr_rwlock_unlock(struct urwlock *rwlock) 184240116Smarcel{ 185240116Smarcel int32_t state; 186240116Smarcel 187240116Smarcel state = rwlock->rw_state; 188240116Smarcel if (state & URWLOCK_WRITE_OWNER) { 189240116Smarcel if (atomic_cmpset_rel_32(&rwlock->rw_state, URWLOCK_WRITE_OWNER, 0)) 190240116Smarcel return (0); 191240116Smarcel } else { 192240116Smarcel for (;;) { 193240116Smarcel if (__predict_false(URWLOCK_READER_COUNT(state) == 0)) 194240116Smarcel return (EPERM); 195240116Smarcel if (!((state & (URWLOCK_WRITE_WAITERS | 196240116Smarcel URWLOCK_READ_WAITERS)) && 197240116Smarcel URWLOCK_READER_COUNT(state) == 1)) { 198240116Smarcel if (atomic_cmpset_rel_32(&rwlock->rw_state, 199240116Smarcel state, state-1)) 200240116Smarcel return (0); 201240116Smarcel state = rwlock->rw_state; 202240116Smarcel } else { 203240116Smarcel break; 204240116Smarcel } 205240116Smarcel } 206240116Smarcel } 207240116Smarcel return (__thr_rwlock_unlock(rwlock)); 208240116Smarcel} 209240116Smarcel#endif 210240116Smarcel