rwlock.h revision 155042
10SN/A/*-
2157SN/A * Copyright (c) 2006 John Baldwin <jhb@FreeBSD.org>
30SN/A * All rights reserved.
40SN/A *
50SN/A * Redistribution and use in source and binary forms, with or without
60SN/A * modification, are permitted provided that the following conditions
7157SN/A * are met:
80SN/A * 1. Redistributions of source code must retain the above copyright
9157SN/A *    notice, this list of conditions and the following disclaimer.
100SN/A * 2. Redistributions in binary form must reproduce the above copyright
110SN/A *    notice, this list of conditions and the following disclaimer in the
120SN/A *    documentation and/or other materials provided with the distribution.
130SN/A * 3. Neither the name of the author nor the names of any co-contributors
140SN/A *    may be used to endorse or promote products derived from this software
150SN/A *    without specific prior written permission.
160SN/A *
170SN/A * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
180SN/A * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
190SN/A * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
200SN/A * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21157SN/A * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22157SN/A * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23157SN/A * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
240SN/A * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
250SN/A * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
260SN/A * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
270SN/A * SUCH DAMAGE.
280SN/A *
290SN/A * $FreeBSD: head/sys/sys/rwlock.h 155042 2006-01-30 11:43:53Z glebius $
300SN/A */
310SN/A
320SN/A#ifndef _SYS_RWLOCK_H_
330SN/A#define _SYS_RWLOCK_H_
340SN/A
350SN/A#include <sys/_lock.h>
360SN/A#include <sys/_rwlock.h>
370SN/A
380SN/A#ifdef _KERNEL
390SN/A#include <machine/atomic.h>
400SN/A#endif
410SN/A
420SN/A/*
430SN/A * The rw_lock field consists of several fields.  The low bit indicates
440SN/A * if the lock is locked with a read (shared) or write (exclusive) lock.
450SN/A * A value of 0 indicates a write lock, and a value of 1 indicates a read
460SN/A * lock.  Bit 1 is a boolean indicating if there are any threads waiting
470SN/A * for a read lock.  Bit 2 is a boolean indicating if there are any threads
480SN/A * waiting for a write lock.  The rest of the variable's definition is
490SN/A * dependent on the value of the first bit.  For a write lock, it is a
500SN/A * pointer to the thread holding the lock, similar to the mtx_lock field of
510SN/A * mutexes.  For read locks, it is a count of read locks that are held.
520SN/A *
530SN/A * When the lock is not locked by any thread, it is encoded as a read lock
540SN/A * with zero waiters.
550SN/A *
560SN/A * A note about memory barriers.  Write locks need to use the same memory
570SN/A * barriers as mutexes: _acq when acquiring a write lock and _rel when
580SN/A * releasing a write lock.  Read locks also need to use an _acq barrier when
590SN/A * acquiring a read lock.  However, since read locks do not update any
600SN/A * locked data (modulo bugs of course), no memory barrier is needed to when
610SN/A * releasing a read lock.
620SN/A */
630SN/A
640SN/A#define	RW_LOCK_READ		0x01
650SN/A#define	RW_LOCK_READ_WAITERS	0x02
660SN/A#define	RW_LOCK_WRITE_WAITERS	0x04
670SN/A#define	RW_LOCK_FLAGMASK						\
680SN/A	(RW_LOCK_READ | RW_LOCK_READ_WAITERS | RW_LOCK_WRITE_WAITERS)
690SN/A
700SN/A#define	RW_OWNER(x)		((x) & ~RW_LOCK_FLAGMASK)
710SN/A#define	RW_READERS_SHIFT	3
720SN/A#define	RW_READERS(x)		(RW_OWNER((x)) >> RW_READERS_SHIFT)
730SN/A#define	RW_READERS_LOCK(x)	((x) << RW_READERS_SHIFT | RW_LOCK_READ)
740SN/A#define	RW_ONE_READER		(1 << RW_READERS_SHIFT)
750SN/A
760SN/A#define	RW_UNLOCKED		RW_READERS_LOCK(0)
770SN/A
780SN/A#ifdef _KERNEL
790SN/A
800SN/A/* Very simple operations on rw_lock. */
810SN/A
820SN/A/* Try to obtain a write lock once. */
830SN/A#define	_rw_write_lock(rw, tid)						\
840SN/A	atomic_cmpset_acq_ptr(&(rw)->rw_lock, RW_UNLOCKED, (tid))
850SN/A
860SN/A/* Release a write lock quickly if there are no waiters. */
870SN/A#define	_rw_write_unlock(rw, tid)					\
880SN/A	atomic_cmpset_rel_ptr(&(rw)->rw_lock, (tid), RW_UNLOCKED)
890SN/A
900SN/A/*
910SN/A * Full lock operations that are suitable to be inlined in non-debug
920SN/A * kernels.  If the lock cannot be acquired or released trivially then
930SN/A * the work is deferred to another function.
940SN/A */
950SN/A
960SN/A/* Acquire a write lock. */
970SN/A#define	__rw_wlock(rw, tid, file, line) do {				\
980SN/A	uintptr_t _tid = (uintptr_t)(tid);				\
990SN/A									\
1000SN/A	if (!_rw_write_lock((rw), _tid))				\
1010SN/A		_rw_wlock_hard((rw), _tid, (file), (line));		\
1020SN/A} while (0)
1030SN/A
1040SN/A/* Release a write lock. */
1050SN/A#define	__rw_wunlock(rw, tid, file, line) do {				\
1060SN/A	uintptr_t _tid = (uintptr_t)(tid);				\
1070SN/A									\
1080SN/A	if (!_rw_write_unlock((rw), _tid))				\
1090SN/A		_rw_wunlock_hard((rw), _tid, (file), (line));		\
1100SN/A} while (0)
1110SN/A
1120SN/A/*
1130SN/A * Function prototypes.  Routines that start with _ are not part of the
1140SN/A * external API and should not be called directly.  Wrapper macros should
1150SN/A * be used instead.
1160SN/A */
1170SN/A
1180SN/Avoid	rw_init(struct rwlock *rw, const char *name);
1190SN/Avoid	rw_destroy(struct rwlock *rw);
1200SN/Avoid	rw_sysinit(void *arg);
1210SN/Avoid	_rw_wlock(struct rwlock *rw, const char *file, int line);
1220SN/Avoid	_rw_wunlock(struct rwlock *rw, const char *file, int line);
1230SN/Avoid	_rw_rlock(struct rwlock *rw, const char *file, int line);
1240SN/Avoid	_rw_runlock(struct rwlock *rw, const char *file, int line);
1250SN/Avoid	_rw_wlock_hard(struct rwlock *rw, uintptr_t tid, const char *file,
1260SN/A	    int line);
1270SN/Avoid	_rw_wunlock_hard(struct rwlock *rw, uintptr_t tid, const char *file,
1280SN/A	    int line);
1290SN/A#if defined(INVARIANTS) || defined(INVARIANT_SUPPORT)
1300SN/Avoid	_rw_assert(struct rwlock *rw, int what, const char *file, int line);
1310SN/A#endif
1320SN/A
1330SN/A/*
1340SN/A * Public interface for lock operations.
1350SN/A *
1360SN/A * XXX: Missing try and upgrade/downgrade.
1370SN/A */
1380SN/A
1390SN/A#ifndef LOCK_DEBUG
1400SN/A#error LOCK_DEBUG not defined, include <sys/lock.h> before <sys/rwlock.h>
1410SN/A#endif
1420SN/A#if LOCK_DEBUG > 0 || defined(RWLOCK_NOINLINE)
1430SN/A#define	rw_wlock(rw)		_rw_wlock((rw), LOCK_FILE, LOCK_LINE)
1440SN/A#define	rw_wunlock(rw)		_rw_wunlock((rw), LOCK_FILE, LOCK_LINE)
1450SN/A#else
1460SN/A#define	rw_wlock(rw)							\
1470SN/A	__rw_wlock((rw), curthread, LOCK_FILE, LOCK_LINE)
1480SN/A#define	rw_wunlock(rw)							\
1490SN/A	__rw_wunlock((rw), curthread, LOCK_FILE, LOCK_LINE)
1500SN/A#endif
151#define	rw_rlock(rw)		_rw_rlock((rw), LOCK_FILE, LOCK_LINE)
152#define	rw_runlock(rw)		_rw_runlock((rw), LOCK_FILE, LOCK_LINE)
153
154#define	rw_initialized(rw)	lock_initalized(&(rw)->rw_object)
155
156struct rw_args {
157	struct rwlock	*ra_rw;
158	const char 	*ra_desc;
159};
160
161#define	RW_SYSINIT(name, rw, desc)					\
162	static struct rw_args name##_args = {				\
163		(rw),							\
164		(desc),							\
165	};								\
166	SYSINIT(name##_rw_sysinit, SI_SUB_LOCK, SI_ORDER_MIDDLE,	\
167	    rw_sysinit, &name##_args);					\
168	SYSUNINIT(name##_mtx_sysuninit, SI_SUB_LOCK, SI_ORDER_MIDDLE,	\
169	    rw_destroy, (rw))
170
171/*
172 * The INVARIANTS-enabled rw_assert() functionality.
173 *
174 * The constants need to be defined for INVARIANT_SUPPORT infrastructure
175 * support as _rw_assert() itself uses them and the latter implies that
176 * _rw_assert() must build.
177 */
178#if defined(INVARIANTS) || defined(INVARIANT_SUPPORT)
179#define	RA_LOCKED		LA_LOCKED
180#define	RA_RLOCKED		LA_SLOCKED
181#define	RA_WLOCKED		LA_XLOCKED
182#define	RA_UNLOCKED		LA_UNLOCKED
183#endif
184
185#ifdef INVARIANTS
186#define	rw_assert(rw, what)	_rw_assert((rw), (what), LOCK_FILE, LOCK_LINE)
187#else
188#define	rw_assert(rw, what)
189#endif
190
191#endif /* _KERNEL */
192#endif /* !_SYS_RWLOCK_H_ */
193