thr_umtx.h revision 177850
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 177850 2008-04-02 04:32:31Z davidxu $
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
37163334Sdavidxuint __thr_umutex_lock(struct umutex *mtx) __hidden;
38163334Sdavidxuint __thr_umutex_timedlock(struct umutex *mtx,
39161680Sdavidxu	const struct timespec *timeout) __hidden;
40163334Sdavidxuint __thr_umutex_unlock(struct umutex *mtx) __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,
49173801Sdavidxu	const struct timespec *timeout) __hidden;
50173801Sdavidxuint _thr_umtx_wake(volatile void *mtx, int count) __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{
74165206Sdavidxu    if (atomic_cmpset_acq_32(&mtx->m_owner, UMUTEX_UNOWNED, id))
75165206Sdavidxu	return (0);
76165206Sdavidxu    return (EBUSY);
77165206Sdavidxu}
78165206Sdavidxu
79165206Sdavidxustatic inline int
80161680Sdavidxu_thr_umutex_lock(struct umutex *mtx, uint32_t id)
81161680Sdavidxu{
82161680Sdavidxu    if (atomic_cmpset_acq_32(&mtx->m_owner, UMUTEX_UNOWNED, id))
83161680Sdavidxu	return (0);
84163334Sdavidxu    return (__thr_umutex_lock(mtx));
85161680Sdavidxu}
86161680Sdavidxu
87161680Sdavidxustatic inline int
88161680Sdavidxu_thr_umutex_timedlock(struct umutex *mtx, uint32_t id,
89161680Sdavidxu	const struct timespec *timeout)
90161680Sdavidxu{
91161680Sdavidxu    if (atomic_cmpset_acq_32(&mtx->m_owner, UMUTEX_UNOWNED, id))
92161680Sdavidxu	return (0);
93163334Sdavidxu    return (__thr_umutex_timedlock(mtx, timeout));
94161680Sdavidxu}
95161680Sdavidxu
96161680Sdavidxustatic inline int
97161680Sdavidxu_thr_umutex_unlock(struct umutex *mtx, uint32_t id)
98161680Sdavidxu{
99161680Sdavidxu    if (atomic_cmpset_rel_32(&mtx->m_owner, id, UMUTEX_UNOWNED))
100161680Sdavidxu	return (0);
101163334Sdavidxu    return (__thr_umutex_unlock(mtx));
102161680Sdavidxu}
103161680Sdavidxu
104177850Sdavidxustatic inline int
105177850Sdavidxu_thr_rwlock_tryrdlock(struct urwlock *rwlock, int flags)
106177850Sdavidxu{
107177850Sdavidxu	int32_t state;
108177850Sdavidxu	int32_t wrflags;
109177850Sdavidxu
110177850Sdavidxu	if (flags & URWLOCK_PREFER_READER || rwlock->rw_flags & URWLOCK_PREFER_READER)
111177850Sdavidxu		wrflags = URWLOCK_WRITE_OWNER;
112177850Sdavidxu	else
113177850Sdavidxu		wrflags = URWLOCK_WRITE_OWNER | URWLOCK_WRITE_WAITERS;
114177850Sdavidxu	state = rwlock->rw_state;
115177850Sdavidxu	while (!(state & wrflags)) {
116177850Sdavidxu		if (__predict_false(URWLOCK_READER_COUNT(state) == URWLOCK_MAX_READERS))
117177850Sdavidxu			return (EAGAIN);
118177850Sdavidxu		if (atomic_cmpset_acq_32(&rwlock->rw_state, state, state + 1))
119177850Sdavidxu			return (0);
120177850Sdavidxu		state = rwlock->rw_state;
121177850Sdavidxu	}
122177850Sdavidxu
123177850Sdavidxu	return (EBUSY);
124177850Sdavidxu}
125177850Sdavidxu
126177850Sdavidxustatic inline int
127177850Sdavidxu_thr_rwlock_trywrlock(struct urwlock *rwlock)
128177850Sdavidxu{
129177850Sdavidxu	int32_t state;
130177850Sdavidxu
131177850Sdavidxu	state = rwlock->rw_state;
132177850Sdavidxu	while (!(state & URWLOCK_WRITE_OWNER) && URWLOCK_READER_COUNT(state) == 0) {
133177850Sdavidxu		if (atomic_cmpset_acq_32(&rwlock->rw_state, state, state | URWLOCK_WRITE_OWNER))
134177850Sdavidxu			return (0);
135177850Sdavidxu		state = rwlock->rw_state;
136177850Sdavidxu	}
137177850Sdavidxu
138177850Sdavidxu	return (EBUSY);
139177850Sdavidxu}
140177850Sdavidxu
141177850Sdavidxustatic inline int
142177850Sdavidxu_thr_rwlock_rdlock(struct urwlock *rwlock, int flags, struct timespec *tsp)
143177850Sdavidxu{
144177850Sdavidxu	if (_thr_rwlock_tryrdlock(rwlock, flags) == 0)
145177850Sdavidxu		return (0);
146177850Sdavidxu	return (__thr_rwlock_rdlock(rwlock, flags, tsp));
147177850Sdavidxu}
148177850Sdavidxu
149177850Sdavidxustatic inline int
150177850Sdavidxu_thr_rwlock_wrlock(struct urwlock *rwlock, struct timespec *tsp)
151177850Sdavidxu{
152177850Sdavidxu	if (_thr_rwlock_trywrlock(rwlock) == 0)
153177850Sdavidxu		return (0);
154177850Sdavidxu	return (__thr_rwlock_wrlock(rwlock, tsp));
155177850Sdavidxu}
156177850Sdavidxu
157177850Sdavidxustatic inline int
158177850Sdavidxu_thr_rwlock_unlock(struct urwlock *rwlock)
159177850Sdavidxu{
160177850Sdavidxu	int32_t state;
161177850Sdavidxu
162177850Sdavidxu	state = rwlock->rw_state;
163177850Sdavidxu	if (state & URWLOCK_WRITE_OWNER) {
164177850Sdavidxu		if (atomic_cmpset_rel_32(&rwlock->rw_state, URWLOCK_WRITE_OWNER, 0))
165177850Sdavidxu			return (0);
166177850Sdavidxu	} else {
167177850Sdavidxu		for (;;) {
168177850Sdavidxu			if (__predict_false(URWLOCK_READER_COUNT(state) == 0))
169177850Sdavidxu				return (EPERM);
170177850Sdavidxu			if (!((state & URWLOCK_WRITE_WAITERS) && URWLOCK_READER_COUNT(state) == 1)) {
171177850Sdavidxu				if (atomic_cmpset_rel_32(&rwlock->rw_state, state, state-1))
172177850Sdavidxu					return (0);
173177850Sdavidxu				state = rwlock->rw_state;
174177850Sdavidxu			} else {
175177850Sdavidxu				break;
176177850Sdavidxu			}
177177850Sdavidxu		}
178177850Sdavidxu    	}
179177850Sdavidxu    	return (__thr_rwlock_unlock(rwlock));
180177850Sdavidxu}
181144518Sdavidxu#endif
182