RWLOCK(9)
β¨ RWLOCK β the kernel reader/writer lock, bestie edition β¨
okay so picture this: you're in the kernel, multiple threads wanna touch the same data, and you need β¨rulesβ¨. That's rwlock, from the Kernel Developer's Manual (section 9). Sit down, grab a π, let's get into it.
πΈ 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 β it's giving 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 one single thread have it all to themselves. Exclusive. Main character energy π.
The threads with shared access are called readers, because all they do is read the protected data. No touching, just looking π. A thread with exclusive access is called a writer, because it's the one who actually gets to modify the protected data.
ngl, reader/writer locks look super similar to sx(9) locks, but the usage pattern is a whole different vibe. Reader/writer locks can be treated like mutexes (see 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 π΄
Also, rwlock locks have priority propagation like mutexes do, but priority can only be propagated to writers. Why? Because readers are anonymous β no names, no identity, we can't propagate to them fr fr. Another important property: readers can always recurse, and exclusive locks can be made recursive selectively. Periodt.
π Macros and Functions π
rw_init(struct rwlock *rw, const char *name)β Initialize the structure hanging out atrwas a reader/writer lock, described byname. That description is solely for debugging purposes, bestie, don't read into it. You must call this before doing literally anything else to the lock.rw_init_flags(struct rwlock *rw, const char *name, int opts)β Initialize the rw lock exactly likerw_init()does, but you get to pass a set of optional flags throughoptsto alter howrwbehaves. It contains one or more of these flags:RW_DUPOKβ Witness should not log messages about duplicate locks being acquired.RW_NOPROFILEβ Do not profile this lock.RW_NOWITNESSβ Instructwitness(4)to ignore this lock. πRW_QUIETβ Do not log any operations for this lock viaktr(4).RW_RECURSEβ Allow threads to recursively acquire exclusive locks forrw.RW_NEWβ If the kernel has been compiled with optionINVARIANTS,rw_init_flags()will assert that therwhas not been initialized multiple times without intervening calls torw_destroy()β unless this option is specified.
rw_rlock(struct rwlock *rw)β Lockrwas a reader. If any thread holds this lock exclusively, your current thread blocks, and its priority gets propagated to the exclusive holder. And here's the cute part:rw_rlock()can be called when the thread has already acquired reader access onrw. That's called "recursing on a lock" π«.rw_wlock(struct rwlock *rw)β Lockrwas a writer. If there are any shared owners of the lock, the current thread blocks.rw_wlock()can only be called recursively ifrwwas initialized with theRW_RECURSEoption enabled. No sneaky recursion otherwise π«.rw_try_rlock(struct rwlock *rw)β Try to lockrwas a reader. Returns true if it worked, otherwise0comes back. No blocking, just vibes.rw_try_wlock(struct rwlock *rw)β Try to lockrwas a writer. Returns true if it worked, otherwise0comes back.rw_runlock(struct rwlock *rw)β Releases a shared lock previously acquired byrw_rlock().rw_wunlock(struct rwlock *rw)β Releases an exclusive lock previously acquired byrw_wlock().rw_unlock(struct rwlock *rw)β Releases a shared lock previously acquired byrw_rlock()OR an exclusive lock previously acquired byrw_wlock(). It's flexible like that π .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 ofrw. This only succeeds if the current thread holds the only shared lock onrw, and it only holds a single shared lock. If it works,rw_try_upgrade()returns a non-zero value and the current thread now holds an exclusive lock π. If it fails,rw_try_upgrade()returns zero and the current thread still holds a shared lock. Whomp whomp.rw_downgrade(struct rwlock *rw)β Convert an exclusive lock into a single shared lock. The current thread must hold an exclusive lock ofrw.rw_sleep(void *chan, struct rwlock *rw, int priority, const char *wmesg, int timo)β Atomically releaserwwhile waiting for an event. For all the deets on the parameters here, go readsleep(9).rw_initialized(const struct rwlock *rw)β Returns non-zero ifrwhas been initialized, and zero otherwise. A little vibe check β .rw_destroy(struct rwlock *rw)β Destroys a lock previously initialized withrw_init(). Therwlock must be unlocked. Do not skip this, I'm serious π.rw_wowned(const struct rwlock *rw)β Returns a non-zero value if the current thread owns an exclusive lock onrw.rw_assert(const struct rwlock *rw, int what)β Lets assertions specified inwhatbe made aboutrw. If the assertions aren't true AND the kernel was compiled withoptions INVARIANTSandoptions INVARIANT_SUPPORT, the kernel will panic π. Currently these base assertions are supported:RA_LOCKEDβ Assert that current thread holds either a shared or exclusive lock ofrw.RA_RLOCKEDβ Assert that current thread holds a shared lock ofrw.RA_WLOCKEDβ Assert that current thread holds an exclusive lock ofrw.RA_UNLOCKEDβ Assert that current thread holds neither a shared nor exclusive lock ofrw.
In addition, one of these optional flags may be specified alongside RA_LOCKED, RA_RLOCKED, or RA_WLOCKED:
RA_RECURSEDβ Assert that the current thread holds a recursive lock ofrw.RA_NOTRECURSEDβ Assert that the current thread does not hold a recursive lock ofrw.
π¦ SEE ALSO π¦
locking(9), mutex(9), panic(9), sema(9), sx(9)
β HISTORY β
These functions appeared in FreeBSD 7.0. Vintage β¨.
π AUTHORS π
The rwlock facility was written by John Baldwin. This manual page was written by Gleb Smirnoff. Absolute legends, both of them π«Ά.
π BUGS π
- A kernel without
WITNESScannot assert whether the current thread does or does not hold a read lock.RA_LOCKEDandRA_RLOCKEDcan only assert that any thread holds a read lock. They cannot ensure that the current thread holds a read lock. Further,RA_UNLOCKEDcan only assert that the current thread does not hold a write lock. So like... it's giving approximate, not exact, iykyk π. - "Reader/writer" is a bit of an awkward name, lowkey. An
rwlockcan also be called a "Robert Watson" lock if desired. No cap, that's in the manual π.
Debian build, dated November 11, 2017, RWLOCK(9) β that's the whole page bestie, go lock something (responsibly) π
π¦ where this page comes from
- debian bookworm: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- debian trixie: freebsd-manpages 12.2-2 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu jammy: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu noble: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu questing: freebsd-manpages 12.2-2
- ubuntu resolute: freebsd-manpages 12.2-2build1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu stonking: freebsd-manpages 12.2-2build1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- Copyright (c) 2006 Gleb Smirnoff <glebius@FreeBSD.org>
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms