1 |
+ |
/* $MidnightBSD$ */ |
2 |
|
/* |
3 |
|
* Copyright (c) 2005 David Xu <davidxu@freebsd.org> |
4 |
|
* All rights reserved. |
24 |
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
25 |
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 |
|
* |
27 |
< |
* $FreeBSD$ |
27 |
> |
* $FreeBSD: stable/10/lib/libthr/thread/thr_umtx.c 294639 2016-01-23 20:49:52Z vangyzen $ |
28 |
|
* |
29 |
|
*/ |
30 |
|
|
52 |
|
_thr_urwlock_init(struct urwlock *rwl) |
53 |
|
{ |
54 |
|
static const struct urwlock default_rwl = DEFAULT_URWLOCK; |
55 |
+ |
|
56 |
|
*rwl = default_rwl; |
57 |
|
} |
58 |
|
|
111 |
|
|
112 |
|
int |
113 |
|
__thr_umutex_timedlock(struct umutex *mtx, uint32_t id, |
114 |
< |
const struct timespec *ets) |
114 |
> |
const struct timespec *abstime) |
115 |
|
{ |
116 |
< |
struct timespec timo, cts; |
116 |
> |
struct _umtx_time *tm_p, timeout; |
117 |
> |
size_t tm_size; |
118 |
|
uint32_t owner; |
119 |
|
int ret; |
120 |
|
|
121 |
< |
clock_gettime(CLOCK_REALTIME, &cts); |
122 |
< |
TIMESPEC_SUB(&timo, ets, &cts); |
121 |
> |
if (abstime == NULL) { |
122 |
> |
tm_p = NULL; |
123 |
> |
tm_size = 0; |
124 |
> |
} else { |
125 |
> |
timeout._clockid = CLOCK_REALTIME; |
126 |
> |
timeout._flags = UMTX_ABSTIME; |
127 |
> |
timeout._timeout = *abstime; |
128 |
> |
tm_p = &timeout; |
129 |
> |
tm_size = sizeof(timeout); |
130 |
> |
} |
131 |
|
|
121 |
– |
if (timo.tv_sec < 0) |
122 |
– |
return (ETIMEDOUT); |
123 |
– |
|
132 |
|
for (;;) { |
133 |
|
if ((mtx->m_flags & (UMUTEX_PRIO_PROTECT | UMUTEX_PRIO_INHERIT)) == 0) { |
134 |
|
|
135 |
|
/* wait in kernel */ |
136 |
< |
ret = _umtx_op_err(mtx, UMTX_OP_MUTEX_WAIT, 0, 0, &timo); |
136 |
> |
ret = _umtx_op_err(mtx, UMTX_OP_MUTEX_WAIT, 0, |
137 |
> |
(void *)tm_size, __DECONST(void *, tm_p)); |
138 |
|
|
139 |
|
/* now try to lock it */ |
140 |
|
owner = mtx->m_owner; |
142 |
|
atomic_cmpset_acq_32(&mtx->m_owner, owner, id|owner)) |
143 |
|
return (0); |
144 |
|
} else { |
145 |
< |
ret = _umtx_op_err(mtx, UMTX_OP_MUTEX_LOCK, 0, 0, &timo); |
145 |
> |
ret = _umtx_op_err(mtx, UMTX_OP_MUTEX_LOCK, 0, |
146 |
> |
(void *)tm_size, __DECONST(void *, tm_p)); |
147 |
|
if (ret == 0) |
148 |
|
break; |
149 |
|
} |
150 |
|
if (ret == ETIMEDOUT) |
151 |
|
break; |
142 |
– |
clock_gettime(CLOCK_REALTIME, &cts); |
143 |
– |
TIMESPEC_SUB(&timo, ets, &cts); |
144 |
– |
if (timo.tv_sec < 0 || (timo.tv_sec == 0 && timo.tv_nsec == 0)) { |
145 |
– |
ret = ETIMEDOUT; |
146 |
– |
break; |
147 |
– |
} |
152 |
|
} |
153 |
|
return (ret); |
154 |
|
} |
156 |
|
int |
157 |
|
__thr_umutex_unlock(struct umutex *mtx, uint32_t id) |
158 |
|
{ |
155 |
– |
static int wake2_avail = 0; |
156 |
– |
|
157 |
– |
if (__predict_false(wake2_avail == 0)) { |
158 |
– |
struct umutex test = DEFAULT_UMUTEX; |
159 |
– |
|
160 |
– |
if (_umtx_op(&test, UMTX_OP_MUTEX_WAKE2, test.m_flags, 0, 0) == -1) |
161 |
– |
wake2_avail = -1; |
162 |
– |
else |
163 |
– |
wake2_avail = 1; |
164 |
– |
} |
165 |
– |
|
166 |
– |
if (wake2_avail != 1) |
167 |
– |
goto unlock; |
168 |
– |
|
169 |
– |
uint32_t flags = mtx->m_flags; |
170 |
– |
|
171 |
– |
if ((flags & (UMUTEX_PRIO_PROTECT | UMUTEX_PRIO_INHERIT)) == 0) { |
172 |
– |
uint32_t owner; |
173 |
– |
do { |
174 |
– |
owner = mtx->m_owner; |
175 |
– |
if (__predict_false((owner & ~UMUTEX_CONTESTED) != id)) |
176 |
– |
return (EPERM); |
177 |
– |
} while (__predict_false(!atomic_cmpset_rel_32(&mtx->m_owner, |
178 |
– |
owner, UMUTEX_UNOWNED))); |
179 |
– |
if ((owner & UMUTEX_CONTESTED)) |
180 |
– |
(void)_umtx_op_err(mtx, UMTX_OP_MUTEX_WAKE2, flags, 0, 0); |
181 |
– |
return (0); |
182 |
– |
} |
183 |
– |
unlock: |
159 |
|
return _umtx_op_err(mtx, UMTX_OP_MUTEX_UNLOCK, 0, 0, 0); |
160 |
|
} |
161 |
|
|
197 |
|
_thr_umtx_timedwait_uint(volatile u_int *mtx, u_int id, int clockid, |
198 |
|
const struct timespec *abstime, int shared) |
199 |
|
{ |
200 |
< |
struct timespec ts, ts2, *tsp; |
200 |
> |
struct _umtx_time *tm_p, timeout; |
201 |
> |
size_t tm_size; |
202 |
|
|
203 |
< |
if (abstime != NULL) { |
204 |
< |
clock_gettime(clockid, &ts); |
205 |
< |
TIMESPEC_SUB(&ts2, abstime, &ts); |
230 |
< |
if (ts2.tv_sec < 0 || (ts2.tv_sec == 0 && ts2.tv_nsec <= 0)) |
231 |
< |
return (ETIMEDOUT); |
232 |
< |
tsp = &ts2; |
203 |
> |
if (abstime == NULL) { |
204 |
> |
tm_p = NULL; |
205 |
> |
tm_size = 0; |
206 |
|
} else { |
207 |
< |
tsp = NULL; |
207 |
> |
timeout._clockid = clockid; |
208 |
> |
timeout._flags = UMTX_ABSTIME; |
209 |
> |
timeout._timeout = *abstime; |
210 |
> |
tm_p = &timeout; |
211 |
> |
tm_size = sizeof(timeout); |
212 |
|
} |
213 |
+ |
|
214 |
|
return _umtx_op_err(__DEVOLATILE(void *, mtx), |
215 |
< |
shared ? UMTX_OP_WAIT_UINT : UMTX_OP_WAIT_UINT_PRIVATE, id, NULL, |
216 |
< |
tsp); |
215 |
> |
shared ? UMTX_OP_WAIT_UINT : UMTX_OP_WAIT_UINT_PRIVATE, id, |
216 |
> |
(void *)tm_size, __DECONST(void *, tm_p)); |
217 |
|
} |
218 |
|
|
219 |
|
int |
260 |
|
} |
261 |
|
|
262 |
|
int |
263 |
< |
__thr_rwlock_rdlock(struct urwlock *rwlock, int flags, struct timespec *tsp) |
263 |
> |
__thr_rwlock_rdlock(struct urwlock *rwlock, int flags, |
264 |
> |
const struct timespec *tsp) |
265 |
|
{ |
266 |
< |
return _umtx_op_err(rwlock, UMTX_OP_RW_RDLOCK, flags, NULL, tsp); |
266 |
> |
struct _umtx_time timeout, *tm_p; |
267 |
> |
size_t tm_size; |
268 |
> |
|
269 |
> |
if (tsp == NULL) { |
270 |
> |
tm_p = NULL; |
271 |
> |
tm_size = 0; |
272 |
> |
} else { |
273 |
> |
timeout._timeout = *tsp; |
274 |
> |
timeout._flags = UMTX_ABSTIME; |
275 |
> |
timeout._clockid = CLOCK_REALTIME; |
276 |
> |
tm_p = &timeout; |
277 |
> |
tm_size = sizeof(timeout); |
278 |
> |
} |
279 |
> |
return _umtx_op_err(rwlock, UMTX_OP_RW_RDLOCK, flags, (void *)tm_size, tm_p); |
280 |
|
} |
281 |
|
|
282 |
|
int |
283 |
< |
__thr_rwlock_wrlock(struct urwlock *rwlock, struct timespec *tsp) |
283 |
> |
__thr_rwlock_wrlock(struct urwlock *rwlock, const struct timespec *tsp) |
284 |
|
{ |
285 |
< |
return _umtx_op_err(rwlock, UMTX_OP_RW_WRLOCK, 0, NULL, tsp); |
285 |
> |
struct _umtx_time timeout, *tm_p; |
286 |
> |
size_t tm_size; |
287 |
> |
|
288 |
> |
if (tsp == NULL) { |
289 |
> |
tm_p = NULL; |
290 |
> |
tm_size = 0; |
291 |
> |
} else { |
292 |
> |
timeout._timeout = *tsp; |
293 |
> |
timeout._flags = UMTX_ABSTIME; |
294 |
> |
timeout._clockid = CLOCK_REALTIME; |
295 |
> |
tm_p = &timeout; |
296 |
> |
tm_size = sizeof(timeout); |
297 |
> |
} |
298 |
> |
return _umtx_op_err(rwlock, UMTX_OP_RW_WRLOCK, 0, (void *)tm_size, tm_p); |
299 |
|
} |
300 |
|
|
301 |
|
int |