Reader/writer locks allow shared access to protected data by multiple threads,
or exclusive access by a single thread.
The threads with shared access are known as
readers
since they only read the protected data.
A thread with exclusive access is known as a
writer
since it can modify protected data.
Although reader/writer locks look very similar to
sx(9)
locks, their usage pattern is different.
Reader/writer locks can be treated as mutexes (see
mutex(9))
with shared/exclusive semantics.
Unlike
sx(9),
an
can be locked while holding a non-spin mutex, and an
cannot be held while sleeping.
The
locks have priority propagation like mutexes, but priority
can be propagated only to an exclusive holder.
This limitation comes from the fact that shared owners
are anonymous.
Another important property is that shared holders of
can recurse,
and exclusive locks can be made recursive selectively.
Macros and Functions
Fn rw_init struct rwlock *rw const char *name
Initialize structure located at
Fa rw
as reader/writer lock, described by name
Fa name .
The description is used solely for debugging purposes.
This function must be called before any other operations
on the lock.
Fn rw_init_flags struct rwlock *rw const char *name int opts
Initialize the rw lock just like the
rw_init ();
function, but specifying a set of optional flags to alter the
behaviour of
Fa rw ,
through the
Fa opts
argument.
It contains one or more of the following flags:
RW_DUPOK
Witness should not log messages about duplicate locks being acquired.
Do not log any operations for this lock via
ktr(4).
RW_RECURSE
Allow threads to recursively acquire exclusive locks for
Fa rw .
Fn rw_rlock struct rwlock *rw
Lock
Fa rw
as a reader.
If any thread holds this lock exclusively, the current thread blocks,
and its priority is propagated to the exclusive holder.
The
rw_rlock ();
function can be called when the thread has already acquired reader
access on
Fa rw .
This is called
``recursing on a lock''
Fn rw_wlock struct rwlock *rw
Lock
Fa rw
as a writer.
If there are any shared owners of the lock, the current thread blocks.
The
rw_wlock ();
function can be called recursively only if
Fa rw
has been initialized with the
RW_RECURSE
option enabled.
Fn rw_try_rlock struct rwlock *rw
Try to lock
Fa rw
as a reader.
This function will return true if the operation succeeds, otherwise 0
will be returned.
Fn rw_try_wlock struct rwlock *rw
Try to lock
Fa rw
as a writer.
This function will return true if the operation succeeds, otherwise 0
will be returned.
Fn rw_runlock struct rwlock *rw
This function releases a shared lock previously acquired by
rw_rlock (.);
Fn rw_wunlock struct rwlock *rw
This function releases an exclusive lock previously acquired by
rw_wlock (.);
Fn 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
Fa rw .
This will only succeed if the current thread holds the only shared lock on
Fa 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.
Fn rw_downgrade struct rwlock *rw
Convert an exclusive lock into a single shared lock.
The current thread must hold an exclusive lock of
Fa rw .
Fn rw_sleep void *chan struct rwlock *rw int priority const char *wmesg int timo
Atomically release
Fa rw
while waiting for an event.
For more details on the parameters to this function,
see
sleep(9).
Fn rw_initialized struct rwlock *rw
This function returns non-zero if
Fa rw
has been initialized, and zero otherwise.
Fn rw_destroy struct rwlock *rw
This functions destroys a lock previously initialized with
rw_init (.);
The
Fa rw
lock must be unlocked.
Fn rw_wowned struct rwlock *rw
This function returns a non-zero value if the current thread owns an
exclusive lock on
Fa rw .
Fn rw_assert struct rwlock *rw int what
This function allows assertions specified in
Fa what
to be made about
Fa rw .
If the assertions are not true and the kernel is compiled
with
options INVARIANTS
and
options INVARIANT_SUPPORT
the kernel will panic.
Currently the following assertions are supported:
RA_LOCKED
Assert that current thread holds either a shared or exclusive lock
of
Fa rw .
RA_RLOCKED
Assert that current thread holds a shared lock of
Fa rw .
RA_WLOCKED
Assert that current thread holds an exclusive lock of
Fa rw .
RA_UNLOCKED
Assert that current thread holds neither a shared nor exclusive lock of
Fa rw .
An -nosplit
The
facility was written by
An John Baldwin .
This manual page was written by
An Gleb Smirnoff .
BUGS
If
WITNESS
is not included in the kernel,
then it is impossible to assert that the current thread does or does not
hold a read lock.
#include <the>
non- WITNESS
case, the
RA_LOCKED
and
RA_RLOCKED
assertions merely check that some thread holds a read lock.
Reader/writer is a bit of an awkward name.
An
can also be called a
``Robert Watson''
lock if desired.