RWLOCK(9)
π RWLOCK(9) β the kernel reader/writer lock page, bestie edition π
Okay so this is the kernel developer's manual page for rwlock and its whole friend group (rw_init, rw_wlock, rw_try_upgrade, the SYSINIT macros, all of them) β FreeBSD kernel reader/writer locks. Buckle up, it's giving synchronization but make it fashion β¨
πΈ NAME πΈ
rwlock, rw_init, rw_init_flags, rw_destroy, rw_rlock, rw_wlock, rw_runlock, rw_wunlock, rw_unlock, rw_try_rlock, rw_try_upgrade, rw_try_wlock, rw_downgrade, rw_sleep, rw_initialized, rw_wowned, rw_assert, RW_SYSINIT, RW_SYSINIT_FLAGS β kernel reader/writer lock π
β¨ SYNOPSIS β¨
#include <sys/param.h>
#include <sys/lock.h>
#include <sys/rwlock.h>
void
rw_init(struct rwlock *rw, const char *name);
void
rw_init_flags(struct rwlock *rw, const char *name, int opts);
void
rw_destroy(struct rwlock *rw);
void
rw_rlock(struct rwlock *rw);
void
rw_wlock(struct rwlock *rw);
int
rw_try_rlock(struct rwlock *rw);
int
rw_try_wlock(struct rwlock *rw);
void
rw_runlock(struct rwlock *rw);
void
rw_wunlock(struct rwlock *rw);
void
rw_unlock(struct rwlock *rw);
int
rw_try_upgrade(struct rwlock *rw);
void
rw_downgrade(struct rwlock *rw);
int
rw_sleep(void *chan, struct rwlock *rw, int priority, const char *wmesg,
int timo);
int
rw_initialized(const struct rwlock *rw);
int
rw_wowned(const struct rwlock *rw);
options INVARIANTS
options INVARIANT_SUPPORT
void
rw_assert(const struct rwlock *rw, int what);
#include <sys/kernel.h>
RW_SYSINIT(name, struct rwlock *rw, const char *desc);
RW_SYSINIT_FLAGS(name, struct rwlock *rw, const char *desc, int flags);
π¦ DESCRIPTION π¦
So reader/writer locks let multiple threads share access to protected data, or let a single thread have exclusive access. The shared-access girlies are called readers, because all they do is read the protected data (iconic, low-effort). A thread with exclusive access is called a writer, because it actually modifies the protected data (main character energy, but make it dangerous).
Okay so yes, reader/writer locks look very similar to sx(9) locks, but the usage pattern is a whole different vibe. Reader/writer locks can be treated as mutexes (peep mutex(9)) with shared/exclusive semantics. But unlike sx(9):
- an
rwlockcan be locked while holding a non-spin mutex β - an
rwlockcannot be held while sleeping β
The rwlock locks have priority propagation like mutexes do, but priority can only be propagated to writers. Why? Because readers are anonymous, bestie β can't propagate to a girl with no name π. Another important property: readers can always recurse, and exclusive locks can be made recursive selectively (iykyk).
π§ Macros and Functions π§
rw_init(struct rwlock *rw, const char *name)β Initializes the structure located at rw as a reader/writer lock, described by name name. The description is used solely for debugging purposes, so it's just a little name tag π·οΈ. This function must be called before any other operations on the lock. No cap.rw_init_flags(struct rwlock *rw, const char *name, int opts)β Initializes the rw lock just like therw_init()function, but you also get to specify a set of optional flags to alter the behaviour of rw, through the opts argument. It contains one or more of these bad boys:RW_DUPOKβ Witness should not log messages about duplicate locks being acquired. Shhh π€«RW_NOPROFILEβ Do not profile this lock. Not everything is about the metrics, periodt.RW_NOWITNESSβ Instructwitness(4)to ignore this lock. Witness? Never heard of her πRW_QUIETβ Do not log any operations for this lock viaktr(4).RW_RECURSEβ Allow threads to recursively acquire exclusive locks for rw.RW_NEWβ If the kernel has been compiled with optionINVARIANTS,rw_init_flags()will assert that the rw has not been initialized multiple times without intervening calls torw_destroy()β unless this option is specified. So it's the "yes I know what I'm doing" flag π
rw_rlock(struct rwlock *rw)β Lock rw as a reader. If any thread holds this lock exclusively, the current thread blocks, and its priority is propagated to the exclusive holder. And here's the cute part:rw_rlock()can be called when the thread has already acquired reader access on rw. That's called "recursing on a lock" πrw_wlock(struct rwlock *rw)β Lock rw as a writer. If there are any shared owners of the lock, the current thread blocks. Therw_wlock()function can be called recursively only if rw has been initialized with theRW_RECURSEoption enabled. Read the fine print or perish, bestie π«Άrw_try_rlock(struct rwlock *rw)β Try to lock rw as a reader. This function will return true if the operation succeeds, otherwise0will be returned. It's giving "shoot your shot, no hard feelings" π―rw_try_wlock(struct rwlock *rw)β Try to lock rw as a writer. This function will return true if the operation succeeds, otherwise0will be returned. Same energy, exclusive edition πrw_runlock(struct rwlock *rw)β This function releases a shared lock previously acquired byrw_rlock(). Bye bestie πrw_wunlock(struct rwlock *rw)β This function releases an exclusive lock previously acquired byrw_wlock().rw_unlock(struct rwlock *rw)β This function releases a shared lock previously acquired byrw_rlock()or an exclusive lock previously acquired byrw_wlock(). One function, two vibes β¨rw_try_upgrade(struct rwlock *rw)β Attempt to upgrade a single shared lock to an exclusive lock. The current thread must hold a shared lock of rw. This will only succeed if the current thread holds the only shared lock on rw, and it only holds a single shared lock. If the attempt succeeds,rw_try_upgrade()will return a non-zero value, and the current thread will hold an exclusive lock π₯ If the attempt fails,rw_try_upgrade()will return zero, and the current thread will still hold a shared lock. Glow-up attempted, honestly.rw_downgrade(struct rwlock *rw)β Convert an exclusive lock into a single shared lock. The current thread must hold an exclusive lock of rw. Character development arc πrw_sleep(void *chan, struct rwlock *rw, int priority, const char *wmesg, int timo)β Atomically release rw while waiting for an event. For more details on the parameters to this function, seesleep(9). Like, all of them. Go look. πrw_initialized(const struct rwlock *rw)β This function returns non-zero if rw has been initialized, and zero otherwise. Vibe check: is she real or not?rw_destroy(struct rwlock *rw)β This function destroys a lock previously initialized withrw_init(). The rw lock must be unlocked. Do not come for her while she's working π€rw_wowned(const struct rwlock *rw)β This function returns a non-zero value if the current thread owns an exclusive lock on rw. Yes ma'am, that's mine πrw_assert(const struct rwlock *rw, int what)β This function allows assertions specified in what to be made about rw. If the assertions are not true and the kernel is compiled withoptions INVARIANTSandoptions INVARIANT_SUPPORT, the kernel will panic. Like, hard panic. So, you know, be right π
Currently the following base assertions are supported:
RA_LOCKEDβ Assert that current thread holds either a shared or exclusive lock of rw.RA_RLOCKEDβ Assert that current thread holds a shared lock of rw.RA_WLOCKEDβ Assert that current thread holds an exclusive lock of rw.RA_UNLOCKEDβ Assert that current thread holds neither a shared nor exclusive lock of rw.
In addition, one of the following optional flags may be specified with RA_LOCKED, RA_RLOCKED, or RA_WLOCKED:
RA_RECURSEDβ Assert that the current thread holds a recursive lock of rw.RA_NOTRECURSEDβ Assert that the current thread does not hold a recursive lock of rw.
π SEE ALSO π
locking(9), mutex(9), panic(9), sema(9), sx(9) β the whole friend group, go say hi π«Ά
π HISTORY π
These functions appeared in FreeBSD 7.0. Ancient history, but make it slay.
π AUTHORS π
The rwlock facility was written by John Baldwin. This manual page was written by Gleb Smirnoff. Legends, both of them π
π BUGS π
So here's the tea, and it's messy:
A kernel without WITNESS cannot assert whether the current thread does or does not hold a read lock. RA_LOCKED and RA_RLOCKED can only assert that any thread holds a read lock. They cannot ensure that the current thread holds a read lock. Further, RA_UNLOCKED can only assert that the current thread does not hold a write lock. So like... approximately correct. Lowkey a vibe, highkey a caveat π
Also: "Reader/writer" is a bit of an awkward name, ngl. An rwlock can also be called a "Robert Watson" lock if desired. That's not a bug, that's just cute π
β¨ and that's the page! β¨
Sign-off time, bestie: this one's from the Debian package, dated November 11, 2017 β RWLOCK(9), out. Go forth and lock responsibly π¦π
π¦ where this page comes from
- freebsd 14.5: base 14.5
- freebsd 15.1: base 15.1
- nixpkgs unstable: source
- Copyright (c) 2006 Gleb Smirnoff <glebius@FreeBSD.org>
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms