1 /* $OpenBSD: rwlock.h,v 1.32 2025/01/29 15:10:09 mpi 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 }; 70 71 #define RWLOCK_LO_FLAGS(flags) \ 72 ((ISSET(flags, RWL_DUPOK) ? LO_DUPOK : 0) | \ 73 (ISSET(flags, RWL_NOWITNESS) ? 0 : LO_WITNESS) | \ 74 (ISSET(flags, RWL_IS_VNODE) ? LO_IS_VNODE : 0) | \ 75 LO_INITIALIZED | LO_SLEEPABLE | LO_UPGRADABLE | \ 76 (LO_CLASS_RWLOCK << LO_CLASSSHIFT)) 77 78 #define RRWLOCK_LO_FLAGS(flags) \ 79 ((ISSET(flags, RWL_DUPOK) ? LO_DUPOK : 0) | \ 80 (ISSET(flags, RWL_NOWITNESS) ? 0 : LO_WITNESS) | \ 81 (ISSET(flags, RWL_IS_VNODE) ? LO_IS_VNODE : 0) | \ 82 LO_INITIALIZED | LO_RECURSABLE | LO_SLEEPABLE | LO_UPGRADABLE | \ 83 (LO_CLASS_RRWLOCK << LO_CLASSSHIFT)) 84 85 #define RWLOCK_LO_INITIALIZER(name, flags) \ 86 { .lo_type = &(const struct lock_type){ .lt_name = name }, \ 87 .lo_name = (name), \ 88 .lo_flags = RWLOCK_LO_FLAGS(flags) } 89 90 #define RWL_DUPOK 0x01 91 #define RWL_NOWITNESS 0x02 92 #define RWL_IS_VNODE 0x04 93 94 #ifdef WITNESS 95 #define RWLOCK_INITIALIZER(name) \ 96 { 0, 0, 0, name, .rwl_lock_obj = RWLOCK_LO_INITIALIZER(name, 0) } 97 #else 98 #define RWLOCK_INITIALIZER(name) \ 99 { 0, 0, 0, name } 100 #endif 101 102 #define RWLOCK_WRLOCK 0x04UL 103 #define RWLOCK_MASK 0x07UL 104 105 #define RWLOCK_OWNER(rwl) ((struct proc *)((rwl)->rwl_owner & ~RWLOCK_MASK)) 106 107 #define RWLOCK_READER_SHIFT 3UL 108 #define RWLOCK_READ_INCR (1UL << RWLOCK_READER_SHIFT) 109 110 #define RW_WRITE 0x0001UL /* exclusive lock */ 111 #define RW_READ 0x0002UL /* shared lock */ 112 #define RW_DOWNGRADE 0x0004UL /* downgrade exclusive to shared */ 113 #define RW_UPGRADE 0x0005UL 114 #define RW_OPMASK 0x0007UL 115 116 #define RW_INTR 0x0010UL /* interruptible sleep */ 117 #define RW_SLEEPFAIL 0x0020UL /* fail if we slept for the lock */ 118 #define RW_NOSLEEP 0x0040UL /* don't wait for the lock */ 119 #define RW_RECURSEFAIL 0x0080UL /* Fail on recursion for RRW locks. */ 120 #define RW_DUPOK 0x0100UL /* Permit duplicate lock */ 121 122 /* 123 * for rw_status() and rrw_status() only: exclusive lock held by 124 * some other thread 125 */ 126 #define RW_WRITE_OTHER 0x0100UL 127 128 /* recursive rwlocks; */ 129 struct rrwlock { 130 struct rwlock rrwl_lock; 131 uint32_t rrwl_wcnt; /* # writers. */ 132 }; 133 134 #ifdef _KERNEL 135 136 void _rw_init_flags(struct rwlock *, const char *, int, 137 const struct lock_type *); 138 139 #ifdef WITNESS 140 #define rw_init_flags(rwl, name, flags) do { \ 141 static const struct lock_type __lock_type = { .lt_name = #rwl };\ 142 _rw_init_flags(rwl, name, flags, &__lock_type); \ 143 } while (0) 144 #define rw_init(rwl, name) rw_init_flags(rwl, name, 0) 145 #else /* WITNESS */ 146 #define rw_init_flags(rwl, name, flags) \ 147 _rw_init_flags(rwl, name, flags, NULL) 148 #define rw_init(rwl, name) _rw_init_flags(rwl, name, 0, NULL) 149 #endif /* WITNESS */ 150 151 void rw_enter_read(struct rwlock *); 152 void rw_enter_write(struct rwlock *); 153 void rw_exit_read(struct rwlock *); 154 void rw_exit_write(struct rwlock *); 155 156 #ifdef DIAGNOSTIC 157 void rw_assert_wrlock(struct rwlock *); 158 void rw_assert_rdlock(struct rwlock *); 159 void rw_assert_anylock(struct rwlock *); 160 void rw_assert_unlocked(struct rwlock *); 161 #else 162 #define rw_assert_wrlock(rwl) ((void)0) 163 #define rw_assert_rdlock(rwl) ((void)0) 164 #define rw_assert_anylock(rwl) ((void)0) 165 #define rw_assert_unlocked(rwl) ((void)0) 166 #endif 167 168 int rw_enter(struct rwlock *, int); 169 void rw_exit(struct rwlock *); 170 int rw_status(struct rwlock *); 171 172 static inline int 173 rw_read_held(struct rwlock *rwl) 174 { 175 return (rw_status(rwl) == RW_READ); 176 } 177 178 static inline int 179 rw_write_held(struct rwlock *rwl) 180 { 181 return (rw_status(rwl) == RW_WRITE); 182 } 183 184 static inline int 185 rw_lock_held(struct rwlock *rwl) 186 { 187 int status; 188 189 status = rw_status(rwl); 190 191 return (status == RW_READ || status == RW_WRITE); 192 } 193 194 195 void _rrw_init_flags(struct rrwlock *, const char *, int, 196 const struct lock_type *); 197 int rrw_enter(struct rrwlock *, int); 198 void rrw_exit(struct rrwlock *); 199 int rrw_status(struct rrwlock *); 200 201 #ifdef WITNESS 202 #define rrw_init_flags(rrwl, name, flags) do { \ 203 static const struct lock_type __lock_type = { .lt_name = #rrwl };\ 204 _rrw_init_flags(rrwl, name, flags, &__lock_type); \ 205 } while (0) 206 #define rrw_init(rrwl, name) rrw_init_flags(rrwl, name, 0) 207 #else /* WITNESS */ 208 #define rrw_init_flags(rrwl, name, flags) \ 209 _rrw_init_flags(rrwl, name, 0, NULL) 210 #define rrw_init(rrwl, name) _rrw_init_flags(rrwl, name, 0, NULL) 211 #endif /* WITNESS */ 212 213 214 /* 215 * Allocated, reference-counted rwlocks 216 */ 217 218 #ifdef WITNESS 219 #define rw_obj_alloc_flags(rwl, name, flags) do { \ 220 static struct lock_type __lock_type = { .lt_name = #rwl }; \ 221 _rw_obj_alloc_flags(rwl, name, flags, &__lock_type); \ 222 } while (0) 223 #else 224 #define rw_obj_alloc_flags(rwl, name, flags) \ 225 _rw_obj_alloc_flags(rwl, name, flags, NULL) 226 #endif 227 #define rw_obj_alloc(rwl, name) rw_obj_alloc_flags(rwl, name, 0) 228 229 void rw_obj_init(void); 230 void _rw_obj_alloc_flags(struct rwlock **, const char *, int, 231 struct lock_type *); 232 void rw_obj_hold(struct rwlock *); 233 int rw_obj_free(struct rwlock *); 234 235 #endif /* _KERNEL */ 236 237 #endif /* _SYS_RWLOCK_H */ 238