| 1 | /*	$OpenBSD: rwlock.h,v 1.34 2025/07/21 20:36:41 bluhm Exp $	*/ |
| 2 | /* |
| 3 | * Copyright (c) 2002 Artur Grabowski <art@openbsd.org> |
| 4 | * |
| 5 | * Permission to use, copy, modify, and distribute this software for any |
| 6 | * purpose with or without fee is hereby granted, provided that the above |
| 7 | * copyright notice and this permission notice appear in all copies. |
| 8 | * |
| 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| 14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| 15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 16 | */ |
| 17 | |
| 18 | /* |
| 19 | * Multiple readers, single writer lock. |
| 20 | * |
| 21 | * Simplistic implementation modelled after rw locks in Solaris. |
| 22 | * |
| 23 | * The rwl_owner has the following layout: |
| 24 | * [ owner or count of readers | wrlock | wrwant | wait ] |
| 25 | * |
| 26 | * When the WAIT bit is set (bit 0), the lock has waiters sleeping on it. |
| 27 | * When the WRWANT bit is set (bit 1), at least one waiter wants a write lock. |
| 28 | * When the WRLOCK bit is set (bit 2) the lock is currently write-locked. |
| 29 | * |
| 30 | * When write locked, the upper bits contain the struct proc * pointer to |
| 31 | * the writer, otherwise they count the number of readers. |
| 32 | * |
| 33 | * We provide a simple machine independent implementation: |
| 34 | * |
| 35 | * void rw_enter_read(struct rwlock *) |
| 36 | * atomically test for RWLOCK_WRLOCK and if not set, increment the lock |
| 37 | * by RWLOCK_READ_INCR. While RWLOCK_WRLOCK is set, loop into rw_enter_wait. |
| 38 | * |
| 39 | * void rw_enter_write(struct rwlock *); |
| 40 | * atomically test for the lock being 0 (it's not possible to have |
| 41 | * owner/read count unset and waiter bits set) and if 0 set the owner to |
| 42 | * the proc and RWLOCK_WRLOCK. While not zero, loop into rw_enter_wait. |
| 43 | * |
| 44 | * void rw_exit_read(struct rwlock *); |
| 45 | * atomically decrement lock by RWLOCK_READ_INCR and unset RWLOCK_WAIT and |
| 46 | * RWLOCK_WRWANT remembering the old value of lock and if RWLOCK_WAIT was set, |
| 47 | * call rw_exit_waiters with the old contents of the lock. |
| 48 | * |
| 49 | * void rw_exit_write(struct rwlock *); |
| 50 | * atomically swap the contents of the lock with 0 and if RWLOCK_WAIT was |
| 51 | * set, call rw_exit_waiters with the old contents of the lock. |
| 52 | */ |
| 53 | |
| 54 | #ifndef _SYS_RWLOCK_H |
| 55 | #define _SYS_RWLOCK_H |
| 56 | |
| 57 | #include <sys/_lock.h> |
| 58 | |
| 59 | struct proc; |
| 60 | |
| 61 | struct rwlock { |
| 62 | 	volatile unsigned long	 rwl_owner; |
| 63 | 	volatile unsigned int	 rwl_waiters; |
| 64 | 	volatile unsigned int	 rwl_readers; |
| 65 | 	const char		*rwl_name; |
| 66 | #ifdef WITNESS |
| 67 | 	struct lock_object	 rwl_lock_obj; |
| 68 | #endif |
| 69 | 	int			 rwl_traceidx; |
| 70 | }; |
| 71 | |
| 72 | #define RWLOCK_LO_FLAGS(flags) \ |
| 73 | 	((ISSET(flags, RWL_DUPOK) ? LO_DUPOK : 0) |			\ |
| 74 | 	 (ISSET(flags, RWL_NOWITNESS) ? 0 : LO_WITNESS) |		\ |
| 75 | 	 (ISSET(flags, RWL_IS_VNODE) ? LO_IS_VNODE : 0) |		\ |
| 76 | 	 LO_INITIALIZED | LO_SLEEPABLE | LO_UPGRADABLE |		\ |
| 77 | 	 (LO_CLASS_RWLOCK << LO_CLASSSHIFT)) |
| 78 | |
| 79 | #define RRWLOCK_LO_FLAGS(flags) \ |
| 80 | 	((ISSET(flags, RWL_DUPOK) ? LO_DUPOK : 0) |			\ |
| 81 | 	 (ISSET(flags, RWL_NOWITNESS) ? 0 : LO_WITNESS) |		\ |
| 82 | 	 (ISSET(flags, RWL_IS_VNODE) ? LO_IS_VNODE : 0) |		\ |
| 83 | 	 LO_INITIALIZED | LO_RECURSABLE | LO_SLEEPABLE | LO_UPGRADABLE | \ |
| 84 | 	 (LO_CLASS_RRWLOCK << LO_CLASSSHIFT)) |
| 85 | |
| 86 | #define RWLOCK_LO_INITIALIZER(name, flags) \ |
| 87 | 	{ .lo_type = &(const struct lock_type){ .lt_name = name },	\ |
| 88 | 	 .lo_name = (name),						\ |
| 89 | 	 .lo_flags = RWLOCK_LO_FLAGS(flags) } |
| 90 | |
| 91 | #define RWL_DUPOK		0x01 |
| 92 | #define RWL_NOWITNESS		0x02 |
| 93 | #define RWL_IS_VNODE		0x04 |
| 94 | |
| 95 | #ifdef WITNESS |
| 96 | #define RWLOCK_INITIALIZER(name) \ |
| 97 | 	{ 0, 0, 0, name, .rwl_lock_obj = RWLOCK_LO_INITIALIZER(name, 0), 0 } |
| 98 | #define RWLOCK_INITIALIZER_TRACE(name, trace) \ |
| 99 | 	{ 0, 0, 0, name, .rwl_lock_obj = RWLOCK_LO_INITIALIZER(name, 0), trace } |
| 100 | #else |
| 101 | #define RWLOCK_INITIALIZER(name) \ |
| 102 | 	{ 0, 0, 0, name, 0 } |
| 103 | #define RWLOCK_INITIALIZER_TRACE(name, trace) \ |
| 104 | 	{ 0, 0, 0, name, trace } |
| 105 | #endif |
| 106 | |
| 107 | #define RWLOCK_WRLOCK		0x04UL |
| 108 | #define RWLOCK_MASK		0x07UL |
| 109 | |
| 110 | #define RWLOCK_OWNER(rwl)	((struct proc *)((rwl)->rwl_owner & ~RWLOCK_MASK)) |
| 111 | |
| 112 | #define RWLOCK_READER_SHIFT	3UL |
| 113 | #define RWLOCK_READ_INCR	(1UL << RWLOCK_READER_SHIFT) |
| 114 | |
| 115 | #define RW_WRITE		0x0001UL /* exclusive lock */ |
| 116 | #define RW_READ			0x0002UL /* shared lock */ |
| 117 | #define RW_DOWNGRADE		0x0004UL /* downgrade exclusive to shared */ |
| 118 | #define RW_UPGRADE		0x0005UL |
| 119 | #define RW_OPMASK		0x0007UL |
| 120 | |
| 121 | #define RW_INTR			0x0010UL /* interruptible sleep */ |
| 122 | #define RW_NOSLEEP		0x0040UL /* don't wait for the lock */ |
| 123 | #define RW_RECURSEFAIL		0x0080UL /* Fail on recursion for RRW locks. */ |
| 124 | #define RW_DUPOK		0x0100UL /* Permit duplicate lock */ |
| 125 | |
| 126 | /* |
| 127 | * for rw_status() and rrw_status() only: exclusive lock held by |
| 128 | * some other thread |
| 129 | */ |
| 130 | #define RW_WRITE_OTHER		0x0100UL |
| 131 | |
| 132 | /* recursive rwlocks; */ |
| 133 | struct rrwlock { |
| 134 | 	struct rwlock		 rrwl_lock; |
| 135 | 	uint32_t		 rrwl_wcnt; /* # writers. */ |
| 136 | }; |
| 137 | |
| 138 | #ifdef _KERNEL |
| 139 | |
| 140 | void	_rw_init_flags(struct rwlock *, const char *, int, |
| 141 | 	 const struct lock_type *, int); |
| 142 | |
| 143 | #ifdef WITNESS |
| 144 | #define rw_init_flags_trace(rwl, name, flags, trace) do {		\ |
| 145 | 	static const struct lock_type __lock_type = { .lt_name = #rwl };\ |
| 146 | 	_rw_init_flags(rwl, name, flags, &__lock_type, trace);		\ |
| 147 | } while (0) |
| 148 | #define rw_init_flags(rwl, name, flags) do {				\ |
| 149 | 	static const struct lock_type __lock_type = { .lt_name = #rwl };\ |
| 150 | 	_rw_init_flags(rwl, name, flags, &__lock_type, 0);	\ |
| 151 | } while (0) |
| 152 | #define rw_init(rwl, name)		rw_init_flags(rwl, name, 0) |
| 153 | #else /* WITNESS */ |
| 154 | #define rw_init_flags_trace(rwl, name, flags, trace) \ |
| 155 | 				_rw_init_flags(rwl, name, flags, NULL, trace) |
| 156 | #define rw_init_flags(rwl, name, flags) \ |
| 157 | 				_rw_init_flags(rwl, name, flags, NULL, 0) |
| 158 | #define rw_init(rwl, name)	_rw_init_flags(rwl, name, 0, NULL, 0) |
| 159 | #endif /* WITNESS */ |
| 160 | |
| 161 | void	rw_enter_read(struct rwlock *); |
| 162 | void	rw_enter_write(struct rwlock *); |
| 163 | void	rw_exit_read(struct rwlock *); |
| 164 | void	rw_exit_write(struct rwlock *); |
| 165 | |
| 166 | #ifdef DIAGNOSTIC |
| 167 | void	rw_assert_wrlock(struct rwlock *); |
| 168 | void	rw_assert_rdlock(struct rwlock *); |
| 169 | void	rw_assert_anylock(struct rwlock *); |
| 170 | void	rw_assert_unlocked(struct rwlock *); |
| 171 | #else |
| 172 | #define rw_assert_wrlock(rwl)	((void)0) |
| 173 | #define rw_assert_rdlock(rwl)	((void)0) |
| 174 | #define rw_assert_anylock(rwl)	((void)0) |
| 175 | #define rw_assert_unlocked(rwl)	((void)0) |
| 176 | #endif |
| 177 | |
| 178 | int	rw_enter(struct rwlock *, int); |
| 179 | void	rw_exit(struct rwlock *); |
| 180 | int	rw_status(struct rwlock *); |
| 181 | |
| 182 | static inline int |
| 183 | rw_read_held(struct rwlock *rwl) |
| 184 | { |
| 185 | 	return (rw_status(rwl) == RW_READ); |
| 186 | } |
| 187 | |
| 188 | static inline int |
| 189 | rw_write_held(struct rwlock *rwl) |
| 190 | { |
| 191 | 	return (rw_status(rwl) == RW_WRITE); |
| 192 | } |
| 193 | |
| 194 | static inline int |
| 195 | rw_lock_held(struct rwlock *rwl) |
| 196 | { |
| 197 | 	int status; |
| 198 | |
| 199 | 	status = rw_status(rwl); |
| 200 | |
| 201 | 	return (status == RW_READ || status == RW_WRITE); |
| 202 | } |
| 203 | |
| 204 | |
| 205 | void	_rrw_init_flags(struct rrwlock *, const char *, int, |
| 206 | 	 const struct lock_type *); |
| 207 | int	rrw_enter(struct rrwlock *, int); |
| 208 | void	rrw_exit(struct rrwlock *); |
| 209 | int	rrw_status(struct rrwlock *); |
| 210 | |
| 211 | #ifdef WITNESS |
| 212 | #define rrw_init_flags(rrwl, name, flags) do {				\ |
| 213 | 	static const struct lock_type __lock_type = { .lt_name = #rrwl };\ |
| 214 | 	_rrw_init_flags(rrwl, name, flags, &__lock_type);		\ |
| 215 | } while (0) |
| 216 | #define rrw_init(rrwl, name)	rrw_init_flags(rrwl, name, 0) |
| 217 | #else /* WITNESS */ |
| 218 | #define rrw_init_flags(rrwl, name, flags) \ |
| 219 | 				_rrw_init_flags(rrwl, name, 0, NULL) |
| 220 | #define rrw_init(rrwl, name)	_rrw_init_flags(rrwl, name, 0, NULL) |
| 221 | #endif /* WITNESS */ |
| 222 | |
| 223 | |
| 224 | /* |
| 225 | * Allocated, reference-counted rwlocks |
| 226 | */ |
| 227 | |
| 228 | #ifdef WITNESS |
| 229 | #define rw_obj_alloc_flags(rwl, name, flags) do {			\ |
| 230 | 	static struct lock_type __lock_type = { .lt_name = #rwl };	\ |
| 231 | 	_rw_obj_alloc_flags(rwl, name, flags, &__lock_type);		\ |
| 232 | } while (0) |
| 233 | #else |
| 234 | #define rw_obj_alloc_flags(rwl, name, flags) \ |
| 235 | 			_rw_obj_alloc_flags(rwl, name, flags, NULL) |
| 236 | #endif |
| 237 | #define rw_obj_alloc(rwl, name)		rw_obj_alloc_flags(rwl, name, 0) |
| 238 | |
| 239 | void	rw_obj_init(void); |
| 240 | void	_rw_obj_alloc_flags(struct rwlock **, const char *, int, |
| 241 | 		struct lock_type *); |
| 242 | void	rw_obj_hold(struct rwlock *); |
| 243 | int	rw_obj_free(struct rwlock *); |
| 244 | |
| 245 | /* sorted alphabetically, keep in sync with dev/dt/dt_prov_static.c */ |
| 246 | #define DT_RWLOCK_IDX_NETLOCK	1 |
| 247 | #define DT_RWLOCK_IDX_SOLOCK	2 |
| 248 | |
| 249 | #endif /* _KERNEL */ |
| 250 | |
| 251 | #endif /* _SYS_RWLOCK_H */ |