thr_umtx.h revision 197445
1144518Sdavidxu/*-
2144518Sdavidxu * Copyright (c) 2005 David Xu <davidxu@freebsd.org>
3144518Sdavidxu * All rights reserved.
4144518Sdavidxu *
5144518Sdavidxu * Redistribution and use in source and binary forms, with or without
6144518Sdavidxu * modification, are permitted provided that the following conditions
7144518Sdavidxu * are met:
8144518Sdavidxu * 1. Redistributions of source code must retain the above copyright
9144518Sdavidxu *    notice, this list of conditions and the following disclaimer.
10144518Sdavidxu * 2. Redistributions in binary form must reproduce the above copyright
11144518Sdavidxu *    notice, this list of conditions and the following disclaimer in the
12144518Sdavidxu *    documentation and/or other materials provided with the distribution.
13144518Sdavidxu *
14144518Sdavidxu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15144518Sdavidxu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16144518Sdavidxu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17144518Sdavidxu * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18144518Sdavidxu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19144518Sdavidxu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20144518Sdavidxu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21144518Sdavidxu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22144518Sdavidxu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23144518Sdavidxu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24144518Sdavidxu * SUCH DAMAGE.
25144518Sdavidxu *
26144518Sdavidxu * $FreeBSD: head/lib/libthr/thread/thr_umtx.h 197445 2009-09-23 21:38:57Z attilio $
27144518Sdavidxu */
28144518Sdavidxu
29144518Sdavidxu#ifndef _THR_FBSD_UMTX_H_
30144518Sdavidxu#define _THR_FBSD_UMTX_H_
31144518Sdavidxu
32162061Sdavidxu#include <strings.h>
33144518Sdavidxu#include <sys/umtx.h>
34144518Sdavidxu
35173801Sdavidxu#define DEFAULT_UMUTEX	{0,0, {0,0},{0,0,0,0}}
36162061Sdavidxu
37179970Sdavidxuint __thr_umutex_lock(struct umutex *mtx, uint32_t id) __hidden;
38179970Sdavidxuint __thr_umutex_timedlock(struct umutex *mtx, uint32_t id,
39161680Sdavidxu	const struct timespec *timeout) __hidden;
40179970Sdavidxuint __thr_umutex_unlock(struct umutex *mtx, uint32_t id) __hidden;
41163334Sdavidxuint __thr_umutex_trylock(struct umutex *mtx) __hidden;
42161680Sdavidxuint __thr_umutex_set_ceiling(struct umutex *mtx, uint32_t ceiling,
43161680Sdavidxu	uint32_t *oldceiling) __hidden;
44161680Sdavidxu
45163334Sdavidxuvoid _thr_umutex_init(struct umutex *mtx) __hidden;
46173801Sdavidxuint _thr_umtx_wait(volatile long *mtx, long exp,
47162061Sdavidxu	const struct timespec *timeout) __hidden;
48173801Sdavidxuint _thr_umtx_wait_uint(volatile u_int *mtx, u_int exp,
49178647Sdavidxu	const struct timespec *timeout, int shared) __hidden;
50178647Sdavidxuint _thr_umtx_wake(volatile void *mtx, int count, int shared) __hidden;
51164877Sdavidxuint _thr_ucond_wait(struct ucond *cv, struct umutex *m,
52164902Sdavidxu        const struct timespec *timeout, int check_unpaking) __hidden;
53164902Sdavidxuvoid _thr_ucond_init(struct ucond *cv) __hidden;
54164902Sdavidxuint _thr_ucond_signal(struct ucond *cv) __hidden;
55164902Sdavidxuint _thr_ucond_broadcast(struct ucond *cv) __hidden;
56162061Sdavidxu
57177850Sdavidxuint __thr_rwlock_rdlock(struct urwlock *rwlock, int flags, struct timespec *tsp) __hidden;
58177850Sdavidxuint __thr_rwlock_wrlock(struct urwlock *rwlock, struct timespec *tsp) __hidden;
59177850Sdavidxuint __thr_rwlock_unlock(struct urwlock *rwlock) __hidden;
60177850Sdavidxu
61144518Sdavidxustatic inline int
62161680Sdavidxu_thr_umutex_trylock(struct umutex *mtx, uint32_t id)
63161680Sdavidxu{
64161680Sdavidxu    if (atomic_cmpset_acq_32(&mtx->m_owner, UMUTEX_UNOWNED, id))
65161680Sdavidxu	return (0);
66161680Sdavidxu    if ((mtx->m_flags & UMUTEX_PRIO_PROTECT) == 0)
67161680Sdavidxu    	return (EBUSY);
68163334Sdavidxu    return (__thr_umutex_trylock(mtx));
69161680Sdavidxu}
70161680Sdavidxu
71161680Sdavidxustatic inline int
72165206Sdavidxu_thr_umutex_trylock2(struct umutex *mtx, uint32_t id)
73165206Sdavidxu{
74179970Sdavidxu    if (atomic_cmpset_acq_32(&mtx->m_owner, UMUTEX_UNOWNED, id) != 0)
75165206Sdavidxu	return (0);
76179970Sdavidxu    if ((uint32_t)mtx->m_owner == UMUTEX_CONTESTED &&
77179970Sdavidxu        __predict_true((mtx->m_flags & (UMUTEX_PRIO_PROTECT | UMUTEX_PRIO_INHERIT)) == 0))
78179970Sdavidxu    	if (atomic_cmpset_acq_32(&mtx->m_owner, UMUTEX_CONTESTED, id | UMUTEX_CONTESTED))
79179970Sdavidxu		return (0);
80165206Sdavidxu    return (EBUSY);
81165206Sdavidxu}
82165206Sdavidxu
83165206Sdavidxustatic inline int
84161680Sdavidxu_thr_umutex_lock(struct umutex *mtx, uint32_t id)
85161680Sdavidxu{
86179970Sdavidxu    if (_thr_umutex_trylock2(mtx, id) == 0)
87161680Sdavidxu	return (0);
88179970Sdavidxu    return (__thr_umutex_lock(mtx, id));
89161680Sdavidxu}
90161680Sdavidxu
91161680Sdavidxustatic inline int
92161680Sdavidxu_thr_umutex_timedlock(struct umutex *mtx, uint32_t id,
93161680Sdavidxu	const struct timespec *timeout)
94161680Sdavidxu{
95179970Sdavidxu    if (_thr_umutex_trylock2(mtx, id) == 0)
96161680Sdavidxu	return (0);
97179970Sdavidxu    return (__thr_umutex_timedlock(mtx, id, timeout));
98161680Sdavidxu}
99161680Sdavidxu
100161680Sdavidxustatic inline int
101161680Sdavidxu_thr_umutex_unlock(struct umutex *mtx, uint32_t id)
102161680Sdavidxu{
103161680Sdavidxu    if (atomic_cmpset_rel_32(&mtx->m_owner, id, UMUTEX_UNOWNED))
104161680Sdavidxu	return (0);
105179970Sdavidxu    return (__thr_umutex_unlock(mtx, id));
106161680Sdavidxu}
107161680Sdavidxu
108177850Sdavidxustatic inline int
109177850Sdavidxu_thr_rwlock_tryrdlock(struct urwlock *rwlock, int flags)
110177850Sdavidxu{
111177850Sdavidxu	int32_t state;
112177850Sdavidxu	int32_t wrflags;
113177850Sdavidxu
114177850Sdavidxu	if (flags & URWLOCK_PREFER_READER || rwlock->rw_flags & URWLOCK_PREFER_READER)
115177850Sdavidxu		wrflags = URWLOCK_WRITE_OWNER;
116177850Sdavidxu	else
117177850Sdavidxu		wrflags = URWLOCK_WRITE_OWNER | URWLOCK_WRITE_WAITERS;
118177850Sdavidxu	state = rwlock->rw_state;
119177850Sdavidxu	while (!(state & wrflags)) {
120177850Sdavidxu		if (__predict_false(URWLOCK_READER_COUNT(state) == URWLOCK_MAX_READERS))
121177850Sdavidxu			return (EAGAIN);
122177850Sdavidxu		if (atomic_cmpset_acq_32(&rwlock->rw_state, state, state + 1))
123177850Sdavidxu			return (0);
124177850Sdavidxu		state = rwlock->rw_state;
125177850Sdavidxu	}
126177850Sdavidxu
127177850Sdavidxu	return (EBUSY);
128177850Sdavidxu}
129177850Sdavidxu
130177850Sdavidxustatic inline int
131177850Sdavidxu_thr_rwlock_trywrlock(struct urwlock *rwlock)
132177850Sdavidxu{
133177850Sdavidxu	int32_t state;
134177850Sdavidxu
135177850Sdavidxu	state = rwlock->rw_state;
136177850Sdavidxu	while (!(state & URWLOCK_WRITE_OWNER) && URWLOCK_READER_COUNT(state) == 0) {
137177850Sdavidxu		if (atomic_cmpset_acq_32(&rwlock->rw_state, state, state | URWLOCK_WRITE_OWNER))
138177850Sdavidxu			return (0);
139177850Sdavidxu		state = rwlock->rw_state;
140177850Sdavidxu	}
141177850Sdavidxu
142177850Sdavidxu	return (EBUSY);
143177850Sdavidxu}
144177850Sdavidxu
145177850Sdavidxustatic inline int
146177850Sdavidxu_thr_rwlock_rdlock(struct urwlock *rwlock, int flags, struct timespec *tsp)
147177850Sdavidxu{
148177850Sdavidxu	if (_thr_rwlock_tryrdlock(rwlock, flags) == 0)
149177850Sdavidxu		return (0);
150177850Sdavidxu	return (__thr_rwlock_rdlock(rwlock, flags, tsp));
151177850Sdavidxu}
152177850Sdavidxu
153177850Sdavidxustatic inline int
154177850Sdavidxu_thr_rwlock_wrlock(struct urwlock *rwlock, struct timespec *tsp)
155177850Sdavidxu{
156177850Sdavidxu	if (_thr_rwlock_trywrlock(rwlock) == 0)
157177850Sdavidxu		return (0);
158177850Sdavidxu	return (__thr_rwlock_wrlock(rwlock, tsp));
159177850Sdavidxu}
160177850Sdavidxu
161177850Sdavidxustatic inline int
162177850Sdavidxu_thr_rwlock_unlock(struct urwlock *rwlock)
163177850Sdavidxu{
164177850Sdavidxu	int32_t state;
165177850Sdavidxu
166177850Sdavidxu	state = rwlock->rw_state;
167177850Sdavidxu	if (state & URWLOCK_WRITE_OWNER) {
168177850Sdavidxu		if (atomic_cmpset_rel_32(&rwlock->rw_state, URWLOCK_WRITE_OWNER, 0))
169177850Sdavidxu			return (0);
170177850Sdavidxu	} else {
171177850Sdavidxu		for (;;) {
172177850Sdavidxu			if (__predict_false(URWLOCK_READER_COUNT(state) == 0))
173177850Sdavidxu				return (EPERM);
174197445Sattilio			if (!((state & (URWLOCK_WRITE_WAITERS |
175197445Sattilio			    URWLOCK_READ_WAITERS)) &&
176197445Sattilio			    URWLOCK_READER_COUNT(state) == 1)) {
177197445Sattilio				if (atomic_cmpset_rel_32(&rwlock->rw_state,
178197445Sattilio				    state, state-1))
179177850Sdavidxu					return (0);
180177850Sdavidxu				state = rwlock->rw_state;
181177850Sdavidxu			} else {
182177850Sdavidxu				break;
183177850Sdavidxu			}
184177850Sdavidxu		}
185177850Sdavidxu    	}
186177850Sdavidxu    	return (__thr_rwlock_unlock(rwlock));
187177850Sdavidxu}
188144518Sdavidxu#endif
189