15e53a4f9SPedro F. Giffuni /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
35e53a4f9SPedro F. Giffuni *
4a091d823SDavid Xu * Copyright (c) 2005 David Xu <davidxu@freebsd.org>
5a091d823SDavid Xu * All rights reserved.
6a091d823SDavid Xu *
7a091d823SDavid Xu * Redistribution and use in source and binary forms, with or without
8a091d823SDavid Xu * modification, are permitted provided that the following conditions
9a091d823SDavid Xu * are met:
10a091d823SDavid Xu * 1. Redistributions of source code must retain the above copyright
11a091d823SDavid Xu * notice unmodified, this list of conditions, and the following
12a091d823SDavid Xu * disclaimer.
13a091d823SDavid Xu * 2. Redistributions in binary form must reproduce the above copyright
14a091d823SDavid Xu * notice, this list of conditions and the following disclaimer in the
15a091d823SDavid Xu * documentation and/or other materials provided with the distribution.
16a091d823SDavid Xu *
17a091d823SDavid Xu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18a091d823SDavid Xu * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19a091d823SDavid Xu * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20a091d823SDavid Xu * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21a091d823SDavid Xu * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22a091d823SDavid Xu * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23a091d823SDavid Xu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24a091d823SDavid Xu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25a091d823SDavid Xu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26a091d823SDavid Xu * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27a091d823SDavid Xu */
28a091d823SDavid Xu
29a091d823SDavid Xu #include "thr_private.h"
30a091d823SDavid Xu #include "thr_umtx.h"
31a091d823SDavid Xu
328042f26dSDavid Xu void
_thr_umutex_init(struct umutex * mtx)338042f26dSDavid Xu _thr_umutex_init(struct umutex *mtx)
348042f26dSDavid Xu {
358e402f34SEric van Gyzen static const struct umutex default_mtx = DEFAULT_UMUTEX;
368042f26dSDavid Xu
378042f26dSDavid Xu *mtx = default_mtx;
388042f26dSDavid Xu }
398042f26dSDavid Xu
40ada33a6eSDavid Xu void
_thr_urwlock_init(struct urwlock * rwl)41ada33a6eSDavid Xu _thr_urwlock_init(struct urwlock *rwl)
42ada33a6eSDavid Xu {
438e402f34SEric van Gyzen static const struct urwlock default_rwl = DEFAULT_URWLOCK;
448e402f34SEric van Gyzen
45ada33a6eSDavid Xu *rwl = default_rwl;
46ada33a6eSDavid Xu }
47ada33a6eSDavid Xu
48a091d823SDavid Xu int
__thr_umutex_lock(struct umutex * mtx,uint32_t id)497de1ecefSDavid Xu __thr_umutex_lock(struct umutex *mtx, uint32_t id)
50cf13ecdaSDavid Xu {
517de1ecefSDavid Xu uint32_t owner;
527de1ecefSDavid Xu
532a339d9eSKonstantin Belousov if ((mtx->m_flags & (UMUTEX_PRIO_PROTECT | UMUTEX_PRIO_INHERIT)) != 0)
542a339d9eSKonstantin Belousov return (_umtx_op_err(mtx, UMTX_OP_MUTEX_LOCK, 0, 0, 0));
557de1ecefSDavid Xu
562a339d9eSKonstantin Belousov for (;;) {
577de1ecefSDavid Xu owner = mtx->m_owner;
587de1ecefSDavid Xu if ((owner & ~UMUTEX_CONTESTED) == 0 &&
597de1ecefSDavid Xu atomic_cmpset_acq_32(&mtx->m_owner, owner, id | owner))
607de1ecefSDavid Xu return (0);
612a339d9eSKonstantin Belousov if (owner == UMUTEX_RB_OWNERDEAD &&
622a339d9eSKonstantin Belousov atomic_cmpset_acq_32(&mtx->m_owner, owner,
632a339d9eSKonstantin Belousov id | UMUTEX_CONTESTED))
642a339d9eSKonstantin Belousov return (EOWNERDEAD);
652a339d9eSKonstantin Belousov if (owner == UMUTEX_RB_NOTRECOV)
662a339d9eSKonstantin Belousov return (ENOTRECOVERABLE);
677de1ecefSDavid Xu
682a339d9eSKonstantin Belousov /* wait in kernel */
692a339d9eSKonstantin Belousov _umtx_op_err(mtx, UMTX_OP_MUTEX_WAIT, 0, 0, 0);
702a339d9eSKonstantin Belousov }
71cf13ecdaSDavid Xu }
72cf13ecdaSDavid Xu
73d1078b0bSDavid Xu #define SPINLOOPS 1000
74d1078b0bSDavid Xu
75d1078b0bSDavid Xu int
__thr_umutex_lock_spin(struct umutex * mtx,uint32_t id)76d1078b0bSDavid Xu __thr_umutex_lock_spin(struct umutex *mtx, uint32_t id)
77d1078b0bSDavid Xu {
78d1078b0bSDavid Xu uint32_t owner;
792a339d9eSKonstantin Belousov int count;
80d1078b0bSDavid Xu
81d1078b0bSDavid Xu if (!_thr_is_smp)
822a339d9eSKonstantin Belousov return (__thr_umutex_lock(mtx, id));
832a339d9eSKonstantin Belousov if ((mtx->m_flags & (UMUTEX_PRIO_PROTECT | UMUTEX_PRIO_INHERIT)) != 0)
842a339d9eSKonstantin Belousov return (_umtx_op_err(mtx, UMTX_OP_MUTEX_LOCK, 0, 0, 0));
85d1078b0bSDavid Xu
86d1078b0bSDavid Xu for (;;) {
872a339d9eSKonstantin Belousov count = SPINLOOPS;
88d1078b0bSDavid Xu while (count--) {
89d1078b0bSDavid Xu owner = mtx->m_owner;
902a339d9eSKonstantin Belousov if ((owner & ~UMUTEX_CONTESTED) == 0 &&
912a339d9eSKonstantin Belousov atomic_cmpset_acq_32(&mtx->m_owner, owner,
922a339d9eSKonstantin Belousov id | owner))
93d1078b0bSDavid Xu return (0);
942a339d9eSKonstantin Belousov if (__predict_false(owner == UMUTEX_RB_OWNERDEAD) &&
952a339d9eSKonstantin Belousov atomic_cmpset_acq_32(&mtx->m_owner, owner,
962a339d9eSKonstantin Belousov id | UMUTEX_CONTESTED))
972a339d9eSKonstantin Belousov return (EOWNERDEAD);
982a339d9eSKonstantin Belousov if (__predict_false(owner == UMUTEX_RB_NOTRECOV))
992a339d9eSKonstantin Belousov return (ENOTRECOVERABLE);
100d1078b0bSDavid Xu CPU_SPINWAIT;
101d1078b0bSDavid Xu }
102d1078b0bSDavid Xu
103d1078b0bSDavid Xu /* wait in kernel */
104d1078b0bSDavid Xu _umtx_op_err(mtx, UMTX_OP_MUTEX_WAIT, 0, 0, 0);
105d1078b0bSDavid Xu }
106d1078b0bSDavid Xu }
107d1078b0bSDavid Xu
108cf13ecdaSDavid Xu int
__thr_umutex_timedlock(struct umutex * mtx,uint32_t id,const struct timespec * abstime)1097de1ecefSDavid Xu __thr_umutex_timedlock(struct umutex *mtx, uint32_t id,
110df1f1baeSDavid Xu const struct timespec *abstime)
111cf13ecdaSDavid Xu {
112df1f1baeSDavid Xu struct _umtx_time *tm_p, timeout;
113df1f1baeSDavid Xu size_t tm_size;
1147de1ecefSDavid Xu uint32_t owner;
1157de1ecefSDavid Xu int ret;
1167de1ecefSDavid Xu
117df1f1baeSDavid Xu if (abstime == NULL) {
118df1f1baeSDavid Xu tm_p = NULL;
119df1f1baeSDavid Xu tm_size = 0;
120df1f1baeSDavid Xu } else {
121df1f1baeSDavid Xu timeout._clockid = CLOCK_REALTIME;
122df1f1baeSDavid Xu timeout._flags = UMTX_ABSTIME;
123df1f1baeSDavid Xu timeout._timeout = *abstime;
124df1f1baeSDavid Xu tm_p = &timeout;
125df1f1baeSDavid Xu tm_size = sizeof(timeout);
126df1f1baeSDavid Xu }
1277de1ecefSDavid Xu
1287de1ecefSDavid Xu for (;;) {
1292a339d9eSKonstantin Belousov if ((mtx->m_flags & (UMUTEX_PRIO_PROTECT |
1302a339d9eSKonstantin Belousov UMUTEX_PRIO_INHERIT)) == 0) {
1312a339d9eSKonstantin Belousov /* try to lock it */
1322a339d9eSKonstantin Belousov owner = mtx->m_owner;
1332a339d9eSKonstantin Belousov if ((owner & ~UMUTEX_CONTESTED) == 0 &&
1342a339d9eSKonstantin Belousov atomic_cmpset_acq_32(&mtx->m_owner, owner,
1352a339d9eSKonstantin Belousov id | owner))
1362a339d9eSKonstantin Belousov return (0);
1372a339d9eSKonstantin Belousov if (__predict_false(owner == UMUTEX_RB_OWNERDEAD) &&
1382a339d9eSKonstantin Belousov atomic_cmpset_acq_32(&mtx->m_owner, owner,
1392a339d9eSKonstantin Belousov id | UMUTEX_CONTESTED))
1402a339d9eSKonstantin Belousov return (EOWNERDEAD);
1412a339d9eSKonstantin Belousov if (__predict_false(owner == UMUTEX_RB_NOTRECOV))
1422a339d9eSKonstantin Belousov return (ENOTRECOVERABLE);
1437de1ecefSDavid Xu /* wait in kernel */
144df1f1baeSDavid Xu ret = _umtx_op_err(mtx, UMTX_OP_MUTEX_WAIT, 0,
145df1f1baeSDavid Xu (void *)tm_size, __DECONST(void *, tm_p));
1467de1ecefSDavid Xu } else {
147df1f1baeSDavid Xu ret = _umtx_op_err(mtx, UMTX_OP_MUTEX_LOCK, 0,
148df1f1baeSDavid Xu (void *)tm_size, __DECONST(void *, tm_p));
1492a339d9eSKonstantin Belousov if (ret == 0 || ret == EOWNERDEAD ||
1502a339d9eSKonstantin Belousov ret == ENOTRECOVERABLE)
1517de1ecefSDavid Xu break;
1527de1ecefSDavid Xu }
1537de1ecefSDavid Xu if (ret == ETIMEDOUT)
1547de1ecefSDavid Xu break;
1557de1ecefSDavid Xu }
1567de1ecefSDavid Xu return (ret);
157cf13ecdaSDavid Xu }
158cf13ecdaSDavid Xu
159cf13ecdaSDavid Xu int
__thr_umutex_unlock(struct umutex * mtx)160d2335a57SEric van Gyzen __thr_umutex_unlock(struct umutex *mtx)
161cf13ecdaSDavid Xu {
1622a339d9eSKonstantin Belousov
1632a339d9eSKonstantin Belousov return (_umtx_op_err(mtx, UMTX_OP_MUTEX_UNLOCK, 0, 0, 0));
164cf13ecdaSDavid Xu }
165cf13ecdaSDavid Xu
166cf13ecdaSDavid Xu int
__thr_umutex_trylock(struct umutex * mtx)1678042f26dSDavid Xu __thr_umutex_trylock(struct umutex *mtx)
168cf13ecdaSDavid Xu {
1692a339d9eSKonstantin Belousov
1702a339d9eSKonstantin Belousov return (_umtx_op_err(mtx, UMTX_OP_MUTEX_TRYLOCK, 0, 0, 0));
171cf13ecdaSDavid Xu }
172cf13ecdaSDavid Xu
173cf13ecdaSDavid Xu int
__thr_umutex_set_ceiling(struct umutex * mtx,uint32_t ceiling,uint32_t * oldceiling)174cf13ecdaSDavid Xu __thr_umutex_set_ceiling(struct umutex *mtx, uint32_t ceiling,
175cf13ecdaSDavid Xu uint32_t *oldceiling)
176cf13ecdaSDavid Xu {
1772a339d9eSKonstantin Belousov
1782a339d9eSKonstantin Belousov return (_umtx_op_err(mtx, UMTX_OP_SET_CEILING, ceiling, oldceiling, 0));
179cf13ecdaSDavid Xu }
180cf13ecdaSDavid Xu
181cf13ecdaSDavid Xu int
_thr_umtx_wait(volatile long * mtx,long id,const struct timespec * timeout)1826fdfcacbSDavid Xu _thr_umtx_wait(volatile long *mtx, long id, const struct timespec *timeout)
183a091d823SDavid Xu {
1842a339d9eSKonstantin Belousov
185a091d823SDavid Xu if (timeout && (timeout->tv_sec < 0 || (timeout->tv_sec == 0 &&
186a091d823SDavid Xu timeout->tv_nsec <= 0)))
187a091d823SDavid Xu return (ETIMEDOUT);
1882a339d9eSKonstantin Belousov return (_umtx_op_err(__DEVOLATILE(void *, mtx), UMTX_OP_WAIT, id, 0,
1892a339d9eSKonstantin Belousov __DECONST(void*, timeout)));
190a091d823SDavid Xu }
191a091d823SDavid Xu
192a091d823SDavid Xu int
_thr_umtx_wait_uint(volatile u_int * mtx,u_int id,const struct timespec * timeout,int shared)1932a339d9eSKonstantin Belousov _thr_umtx_wait_uint(volatile u_int *mtx, u_int id,
1942a339d9eSKonstantin Belousov const struct timespec *timeout, int shared)
1956fdfcacbSDavid Xu {
1962a339d9eSKonstantin Belousov
1976fdfcacbSDavid Xu if (timeout && (timeout->tv_sec < 0 || (timeout->tv_sec == 0 &&
1986fdfcacbSDavid Xu timeout->tv_nsec <= 0)))
1996fdfcacbSDavid Xu return (ETIMEDOUT);
2002a339d9eSKonstantin Belousov return (_umtx_op_err(__DEVOLATILE(void *, mtx), shared ?
2012a339d9eSKonstantin Belousov UMTX_OP_WAIT_UINT : UMTX_OP_WAIT_UINT_PRIVATE, id, 0,
2022a339d9eSKonstantin Belousov __DECONST(void*, timeout)));
2036fdfcacbSDavid Xu }
2046fdfcacbSDavid Xu
2056fdfcacbSDavid Xu int
_thr_umtx_timedwait_uint(volatile u_int * mtx,u_int id,int clockid,const struct timespec * abstime,int shared)206d1078b0bSDavid Xu _thr_umtx_timedwait_uint(volatile u_int *mtx, u_int id, int clockid,
207d1078b0bSDavid Xu const struct timespec *abstime, int shared)
208d1078b0bSDavid Xu {
209df1f1baeSDavid Xu struct _umtx_time *tm_p, timeout;
210df1f1baeSDavid Xu size_t tm_size;
211df1f1baeSDavid Xu
212df1f1baeSDavid Xu if (abstime == NULL) {
213df1f1baeSDavid Xu tm_p = NULL;
214df1f1baeSDavid Xu tm_size = 0;
215df1f1baeSDavid Xu } else {
21681cd726aSDavid Xu timeout._clockid = clockid;
217df1f1baeSDavid Xu timeout._flags = UMTX_ABSTIME;
218df1f1baeSDavid Xu timeout._timeout = *abstime;
219df1f1baeSDavid Xu tm_p = &timeout;
220df1f1baeSDavid Xu tm_size = sizeof(timeout);
221df1f1baeSDavid Xu }
222df1f1baeSDavid Xu
2232a339d9eSKonstantin Belousov return (_umtx_op_err(__DEVOLATILE(void *, mtx), shared ?
2242a339d9eSKonstantin Belousov UMTX_OP_WAIT_UINT : UMTX_OP_WAIT_UINT_PRIVATE, id,
2252a339d9eSKonstantin Belousov (void *)tm_size, __DECONST(void *, tm_p)));
226d1078b0bSDavid Xu }
227d1078b0bSDavid Xu
228d1078b0bSDavid Xu int
_thr_umtx_wake(volatile void * mtx,int nr_wakeup,int shared)2298d6a11a0SDavid Xu _thr_umtx_wake(volatile void *mtx, int nr_wakeup, int shared)
230a091d823SDavid Xu {
2312a339d9eSKonstantin Belousov
2322a339d9eSKonstantin Belousov return (_umtx_op_err(__DEVOLATILE(void *, mtx), shared ?
2332a339d9eSKonstantin Belousov UMTX_OP_WAKE : UMTX_OP_WAKE_PRIVATE, nr_wakeup, 0, 0));
234a091d823SDavid Xu }
2352bd2c907SDavid Xu
236670b44d6SDavid Xu void
_thr_ucond_init(struct ucond * cv)237670b44d6SDavid Xu _thr_ucond_init(struct ucond *cv)
238670b44d6SDavid Xu {
2392a339d9eSKonstantin Belousov
240670b44d6SDavid Xu bzero(cv, sizeof(struct ucond));
241670b44d6SDavid Xu }
242670b44d6SDavid Xu
2432bd2c907SDavid Xu int
_thr_ucond_wait(struct ucond * cv,struct umutex * m,const struct timespec * timeout,int flags)2442bd2c907SDavid Xu _thr_ucond_wait(struct ucond *cv, struct umutex *m,
2457859df8eSDavid Xu const struct timespec *timeout, int flags)
2462bd2c907SDavid Xu {
2472a339d9eSKonstantin Belousov struct pthread *curthread;
2482a339d9eSKonstantin Belousov
2492bd2c907SDavid Xu if (timeout && (timeout->tv_sec < 0 || (timeout->tv_sec == 0 &&
2502bd2c907SDavid Xu timeout->tv_nsec <= 0))) {
2512a339d9eSKonstantin Belousov curthread = _get_curthread();
2527de1ecefSDavid Xu _thr_umutex_unlock(m, TID(curthread));
2532bd2c907SDavid Xu return (ETIMEDOUT);
2542bd2c907SDavid Xu }
2552a339d9eSKonstantin Belousov return (_umtx_op_err(cv, UMTX_OP_CV_WAIT, flags, m,
2562a339d9eSKonstantin Belousov __DECONST(void*, timeout)));
2572bd2c907SDavid Xu }
2582bd2c907SDavid Xu
2592bd2c907SDavid Xu int
_thr_ucond_signal(struct ucond * cv)2602bd2c907SDavid Xu _thr_ucond_signal(struct ucond *cv)
2612bd2c907SDavid Xu {
2622a339d9eSKonstantin Belousov
263347126a2SDavid Xu if (!cv->c_has_waiters)
264347126a2SDavid Xu return (0);
2652a339d9eSKonstantin Belousov return (_umtx_op_err(cv, UMTX_OP_CV_SIGNAL, 0, NULL, NULL));
2662bd2c907SDavid Xu }
2672bd2c907SDavid Xu
2682bd2c907SDavid Xu int
_thr_ucond_broadcast(struct ucond * cv)2692bd2c907SDavid Xu _thr_ucond_broadcast(struct ucond *cv)
2702bd2c907SDavid Xu {
2712a339d9eSKonstantin Belousov
272347126a2SDavid Xu if (!cv->c_has_waiters)
273347126a2SDavid Xu return (0);
2742a339d9eSKonstantin Belousov return (_umtx_op_err(cv, UMTX_OP_CV_BROADCAST, 0, NULL, NULL));
2752bd2c907SDavid Xu }
2768bf1a48cSDavid Xu
2778bf1a48cSDavid Xu int
__thr_rwlock_rdlock(struct urwlock * rwlock,int flags,const struct timespec * tsp)27824c20949SDavid Xu __thr_rwlock_rdlock(struct urwlock *rwlock, int flags,
27924c20949SDavid Xu const struct timespec *tsp)
2808bf1a48cSDavid Xu {
28124c20949SDavid Xu struct _umtx_time timeout, *tm_p;
28224c20949SDavid Xu size_t tm_size;
28324c20949SDavid Xu
28424c20949SDavid Xu if (tsp == NULL) {
28524c20949SDavid Xu tm_p = NULL;
28624c20949SDavid Xu tm_size = 0;
28724c20949SDavid Xu } else {
28824c20949SDavid Xu timeout._timeout = *tsp;
28924c20949SDavid Xu timeout._flags = UMTX_ABSTIME;
29024c20949SDavid Xu timeout._clockid = CLOCK_REALTIME;
29124c20949SDavid Xu tm_p = &timeout;
29224c20949SDavid Xu tm_size = sizeof(timeout);
29324c20949SDavid Xu }
2942a339d9eSKonstantin Belousov return (_umtx_op_err(rwlock, UMTX_OP_RW_RDLOCK, flags,
2952a339d9eSKonstantin Belousov (void *)tm_size, tm_p));
2968bf1a48cSDavid Xu }
2978bf1a48cSDavid Xu
2988bf1a48cSDavid Xu int
__thr_rwlock_wrlock(struct urwlock * rwlock,const struct timespec * tsp)29924c20949SDavid Xu __thr_rwlock_wrlock(struct urwlock *rwlock, const struct timespec *tsp)
3008bf1a48cSDavid Xu {
30124c20949SDavid Xu struct _umtx_time timeout, *tm_p;
30224c20949SDavid Xu size_t tm_size;
30324c20949SDavid Xu
30424c20949SDavid Xu if (tsp == NULL) {
30524c20949SDavid Xu tm_p = NULL;
30624c20949SDavid Xu tm_size = 0;
30724c20949SDavid Xu } else {
30824c20949SDavid Xu timeout._timeout = *tsp;
30924c20949SDavid Xu timeout._flags = UMTX_ABSTIME;
31024c20949SDavid Xu timeout._clockid = CLOCK_REALTIME;
31124c20949SDavid Xu tm_p = &timeout;
31224c20949SDavid Xu tm_size = sizeof(timeout);
31324c20949SDavid Xu }
3142a339d9eSKonstantin Belousov return (_umtx_op_err(rwlock, UMTX_OP_RW_WRLOCK, 0, (void *)tm_size,
3152a339d9eSKonstantin Belousov tm_p));
3168bf1a48cSDavid Xu }
3178bf1a48cSDavid Xu
3188bf1a48cSDavid Xu int
__thr_rwlock_unlock(struct urwlock * rwlock)3198bf1a48cSDavid Xu __thr_rwlock_unlock(struct urwlock *rwlock)
3208bf1a48cSDavid Xu {
3212a339d9eSKonstantin Belousov
3222a339d9eSKonstantin Belousov return (_umtx_op_err(rwlock, UMTX_OP_RW_UNLOCK, 0, NULL, NULL));
3238bf1a48cSDavid Xu }
32402c3c858SDavid Xu
32502c3c858SDavid Xu void
_thr_rwl_rdlock(struct urwlock * rwlock)32602c3c858SDavid Xu _thr_rwl_rdlock(struct urwlock *rwlock)
32702c3c858SDavid Xu {
32802c3c858SDavid Xu int ret;
32902c3c858SDavid Xu
33002c3c858SDavid Xu for (;;) {
33102c3c858SDavid Xu if (_thr_rwlock_tryrdlock(rwlock, URWLOCK_PREFER_READER) == 0)
33202c3c858SDavid Xu return;
33302c3c858SDavid Xu ret = __thr_rwlock_rdlock(rwlock, URWLOCK_PREFER_READER, NULL);
33402c3c858SDavid Xu if (ret == 0)
33502c3c858SDavid Xu return;
33602c3c858SDavid Xu if (ret != EINTR)
33702c3c858SDavid Xu PANIC("rdlock error");
33802c3c858SDavid Xu }
33902c3c858SDavid Xu }
34002c3c858SDavid Xu
34102c3c858SDavid Xu void
_thr_rwl_wrlock(struct urwlock * rwlock)34202c3c858SDavid Xu _thr_rwl_wrlock(struct urwlock *rwlock)
34302c3c858SDavid Xu {
34402c3c858SDavid Xu int ret;
34502c3c858SDavid Xu
34602c3c858SDavid Xu for (;;) {
34702c3c858SDavid Xu if (_thr_rwlock_trywrlock(rwlock) == 0)
34802c3c858SDavid Xu return;
34902c3c858SDavid Xu ret = __thr_rwlock_wrlock(rwlock, NULL);
35002c3c858SDavid Xu if (ret == 0)
35102c3c858SDavid Xu return;
35202c3c858SDavid Xu if (ret != EINTR)
35302c3c858SDavid Xu PANIC("wrlock error");
35402c3c858SDavid Xu }
35502c3c858SDavid Xu }
35602c3c858SDavid Xu
35702c3c858SDavid Xu void
_thr_rwl_unlock(struct urwlock * rwlock)35802c3c858SDavid Xu _thr_rwl_unlock(struct urwlock *rwlock)
35902c3c858SDavid Xu {
3602a339d9eSKonstantin Belousov
36102c3c858SDavid Xu if (_thr_rwlock_unlock(rwlock))
36202c3c858SDavid Xu PANIC("unlock error");
36302c3c858SDavid Xu }
364