68#define RWLOCK_READER_MAX 4095
70#define RWLOCK_READWAIT_MAX 2047
72#define RWLOCK_WRITER_MAX 511
74#define RWLOCK_READER_MASK (0x00000fff)
75#define RWLOCK_READWAIT_MASK (0x007ff000)
76#define RWLOCK_WRITER_MASK (0xff800000)
77#define RWLOCK_READERS(state) ((state) & RWLOCK_READER_MASK)
78#define RWLOCK_READWAIT(state) (((state) & RWLOCK_READWAIT_MASK) >> 12)
79#define RWLOCK_WRITERS(state) (((state) & RWLOCK_WRITER_MASK) >> 23)
80#define RWLOCK_READ_ADD 0x00000001
81#define RWLOCK_READWAIT_ADD 0x00001000
82#define RWLOCK_WRITE_ADD 0x00800000
96void _rwlockInit(_Out_
RWLock* l, uint32 flags);
105#define rwlockInit(l, ...) _rwlockInit(l, opt_flags(__VA_ARGS__))
135 uint32 state = atomicLoad(uint32, &l->state, Relaxed);
137 if (RWLOCK_WRITERS(state) == 0) {
141 if (atomicCompareExchange(uint32,
145 state + RWLOCK_READ_ADD,
148 aspinRecordUncontended(&l->aspin);
165 uint32 state = atomicLoad(uint32, &l->state, Relaxed);
167 if (RWLOCK_WRITERS(state) == 0 && RWLOCK_READERS(state) == 0) {
171 if (atomicCompareExchange(uint32,
175 state + RWLOCK_WRITE_ADD,
178 aspinRecordUncontended(&l->aspin);
195 relFatalError(
"Failed to acquire read lock (too many waiting readers?)");
203#define withReadLock(l) blkWrap (rwlockAcquireRead(l), rwlockReleaseRead(l))
210#define withWriteLock(l) blkWrap (rwlockAcquireWrite(l), rwlockReleaseWrite(l))
214#define _logFmtRwlockArgComp(level, fmt, ...) \
215 _logFmtArgs(level, LogDefault, LOG_SiteAlways, 0, fmt, __VA_ARGS__)
216_Acquires_shared_lock_(*l)
217 static bool rwlockLogAndAcquireRead(_Inout_
RWLock* l,
const char* name,
218 const char* filename,
int line)
220 _logFmtRwlockArgComp(CX_LOCK_DEBUG,
221 _S"Locking rwlock ${string} for READ at ${string}:${int}",
222 stvar(
string, (
string)name),
223 stvar(
string, (
string)filename),
229#define rwlockAcquireRead(l) rwlockLogAndAcquireRead(l, #l, __FILE__, __LINE__)
240 relFatalError(
"Failed to acquire write lock (too many waiting writers?)");
244_Acquires_exclusive_lock_(*l)
245 static bool rwlockLogAndAcquireWrite(_Inout_
RWLock* l,
const char* name,
246 const char* filename,
int line)
248 _logFmtRwlockArgComp(CX_LOCK_DEBUG,
249 _S"Locking rwlock ${string} for WRITE at ${string}:${int}",
250 stvar(
string, (
string)name),
251 stvar(
string, (
string)filename),
257#define rwlockAcquireWrite(l) rwlockLogAndAcquireWrite(l, #l, __FILE__, __LINE__)
268 devAssert(RWLOCK_READERS(atomicLoad(uint32, &l->state, Relaxed)) > 0);
269 uint32 oldstate = atomicFetchSub(uint32, &l->state, RWLOCK_READ_ADD, Release);
272 if (RWLOCK_READERS(oldstate) == 1 && RWLOCK_WRITERS(oldstate) > 0) {
273 devVerify(atomicFetchAdd(int32, &l->wftx.val, 1, Relaxed) == 0);
281_Releases_shared_lock_(*l)
282 static bool rwlockLogAndReleaseRead(_Inout_
RWLock* l,
const char* name,
283 const char* filename,
int line)
285 _logFmtRwlockArgComp(CX_LOCK_DEBUG,
286 _S"Releasing rwlock ${string} for READ at ${string}:${int}",
287 stvar(
string, (
string)name),
288 stvar(
string, (
string)filename),
293#define rwlockReleaseRead(l) rwlockLogAndReleaseRead(l, #l, __FILE__, __LINE__)
304_Releases_exclusive_lock_(*l)
305 static bool rwlockLogAndReleaseWrite(_Inout_
RWLock* l,
const char* name,
306 const char* filename,
int line)
308 _logFmtRwlockArgComp(CX_LOCK_DEBUG,
309 _S"Releasing rwlock ${string} for WRITE at ${string}:${int}",
310 stvar(
string, (
string)name),
311 stvar(
string, (
string)filename),
316#define rwlockReleaseWrite(l) rwlockLogAndReleaseWrite(l, #l, __FILE__, __LINE__)
326_Releases_exclusive_lock_(*l)
Compiler and platform detection macros.
Block wrapping macros for automatic resource management.
#define relFatalError(msg)
#define _S
Creates a static ASCII string literal (STR_LEN0, runtime strlen). Prefer _SL() on hot paths when targ...
#define stvar(typen, val)
bool rwlockReleaseWrite(RWLock *l)
void rwlockAcquireWrite(RWLock *l)
bool rwlockTryAcquireReadTimeout(RWLock *l, int64 timeout)
bool rwlockTryAcquireWriteTimeout(RWLock *l, int64 timeout)
bool rwlockTryAcquireWrite(RWLock *l)
bool rwlockReleaseRead(RWLock *l)
void rwlockDestroy(RWLock *l)
bool rwlockDowngradeWrite(RWLock *l)
bool rwlockTryAcquireRead(RWLock *l)
RWLOCK_Flags
Reader-writer lock initialization flags.
#define RWLOCK_WRITER_MAX
Maximum number of writers (active + pending)
void rwlockAcquireRead(RWLock *l)
#define RWLOCK_READER_MAX
Maximum number of concurrent readers.
@ RWLOCK_NoSpin
Disable adaptive spinning, use kernel futex immediately.
#define timeForever
Maximum representable time value (approximately year 294,276 CE)
atomic(uint32) state
Packed lock state (readers, waiting readers, writers)
Futex rftx
Futex for reader wait queue.
AdaptiveSpin aspin
Adaptive spin state.
Futex wftx
Futex for writer wait queue.