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__))
115_When_(
return ==
true, _Acquires_shared_lock_(*l))
116 _When_(timeout ==
timeForever, _Acquires_shared_lock_(*l)) _When_(
127_When_(
return ==
true, _Acquires_exclusive_lock_(*l))
128 _When_(timeout ==
timeForever, _Acquires_exclusive_lock_(*l)) _When_(
141 _Acquires_shared_lock_(
144 uint32 state = atomicLoad(uint32, &l->state, Relaxed);
146 if (RWLOCK_WRITERS(state) == 0) {
150 if (atomicCompareExchange(uint32,
154 state + RWLOCK_READ_ADD,
157 aspinRecordUncontended(&l->aspin);
174 _Acquires_exclusive_lock_(
177 uint32 state = atomicLoad(uint32, &l->state, Relaxed);
179 if (RWLOCK_WRITERS(state) == 0 && RWLOCK_READERS(state) == 0) {
183 if (atomicCompareExchange(uint32,
187 state + RWLOCK_WRITE_ADD,
190 aspinRecordUncontended(&l->aspin);
207 relFatalError(
"Failed to acquire read lock (too many waiting readers?)");
215#define withReadLock(l) blkWrap (rwlockAcquireRead(l), rwlockReleaseRead(l))
222#define withWriteLock(l) blkWrap (rwlockAcquireWrite(l), rwlockReleaseWrite(l))
225#define _logFmtRwlockArgComp2(level, fmt, nargs, args) \
226 _logFmt_##level(LOG_##level, LogDefault, fmt, nargs, args)
227#define _logFmtRwlockArgComp(level, fmt, ...) \
228 _logFmtRwlockArgComp2(level, fmt, count_macro_args(__VA_ARGS__), (stvar[]) { __VA_ARGS__ })
229_Acquires_shared_lock_(*l)
230 _meta_inline
bool rwlockLogAndAcquireRead(_Inout_
RWLock* l,
const char* name,
231 const char* filename,
int line)
233 _logFmtRwlockArgComp(CX_LOCK_DEBUG,
234 _S"Locking rwlock ${string} for READ at ${string}:${int}",
235 stvar(
string, (
string)name),
236 stvar(
string, (
string)filename),
241#define rwlockAcquireRead(l) rwlockLogAndAcquireRead(l, #l, __FILE__, __LINE__)
252 relFatalError(
"Failed to acquire write lock (too many waiting writers?)");
256_Acquires_exclusive_lock_(*l)
257 _meta_inline
bool rwlockLogAndAcquireWrite(_Inout_
RWLock* l,
const char* name,
258 const char* filename,
int line)
260 _logFmtRwlockArgComp(CX_LOCK_DEBUG,
261 _S"Locking rwlock ${string} for WRITE at ${string}:${int}",
262 stvar(
string, (
string)name),
263 stvar(
string, (
string)filename),
268#define rwlockAcquireWrite(l) rwlockLogAndAcquireWrite(l, #l, __FILE__, __LINE__)
279 devAssert(RWLOCK_READERS(atomicLoad(uint32, &l->state, Relaxed)) > 0);
280 uint32 oldstate = atomicFetchSub(uint32, &l->state, RWLOCK_READ_ADD, Release);
283 if (RWLOCK_READERS(oldstate) == 1 && RWLOCK_WRITERS(oldstate) > 0) {
284 devVerify(atomicFetchAdd(int32, &l->wftx.val, 1, Relaxed) == 0);
292_Releases_shared_lock_(*l)
293 _meta_inline
bool rwlockLogAndReleaseRead(_Inout_
RWLock* l,
const char* name,
294 const char* filename,
int line)
296 _logFmtRwlockArgComp(CX_LOCK_DEBUG,
297 _S"Releasing rwlock ${string} for READ at ${string}:${int}",
298 stvar(
string, (
string)name),
299 stvar(
string, (
string)filename),
304#define rwlockReleaseRead(l) rwlockLogAndReleaseRead(l, #l, __FILE__, __LINE__)
315_Releases_exclusive_lock_(*l)
316 _meta_inline
bool rwlockLogAndReleaseWrite(_Inout_
RWLock* l,
const char* name,
317 const char* filename,
int line)
319 _logFmtRwlockArgComp(CX_LOCK_DEBUG,
320 _S"Releasing rwlock ${string} for WRITE at ${string}:${int}",
321 stvar(
string, (
string)name),
322 stvar(
string, (
string)filename),
327#define rwlockReleaseWrite(l) rwlockLogAndReleaseWrite(l, #l, __FILE__, __LINE__)
337_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 from a string literal.
#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.