RWLOCK(9)

RWLOCK(9) | Kernel Developer's Manual | RWLOCK(9)

# NAME

`rw`, `rw_init`, `rw_destroy`, `rw_enter`, `rw_exit`, `rw_tryenter`, `rw_tryupgrade`, `rw_downgrade`, `rw_read_held`, `rw_write_held`, `rw_lock_held`, `rw_lock_op` —
reader / writer lock primitives

# SYNOPSIS

`#include <sys/rwlock.h>`

void
`rw_init`(krwlock_t *rw);

void
`rw_destroy`(krwlock_t *rw);

void
`rw_enter`(krwlock_t *rw, const krw_t op);

void
`rw_exit`(krwlock_t *rw);

int
`rw_tryenter`(krwlock_t *rw, const krw_t op);

int
`rw_tryupgrade`(krwlock_t *rw);

void
`rw_downgrade`(krwlock_t *rw);

int
`rw_read_held`(krwlock_t *rw);

int
`rw_write_held`(krwlock_t *rw);

int
`rw_lock_held`(krwlock_t *rw);

krw_t
`rw_lock_op`(krwlock_t *rw);

`options DIAGNOSTIC`
`options LOCKDEBUG`

# DESCRIPTION

Reader / writer locks (RW locks) are used in the kernel to synchronize access to an object among LWPs (lightweight processes) and soft interrupt handlers.

In addition to the capabilities provided by mutexes, RW locks distinguish between read (shared) and write (exclusive) access.

RW locks are in one of three distinct states at any given time:

`Unlocked`
  The lock is not held.
`Read locked`
  The lock holders intend to read the protected object. Multiple callers may hold a RW lock with “read intent” simultaneously.
`Write locked`
  The lock holder intends to update the protected object. Only one caller may hold a RW lock with “write intent”.

The krwlock_t type provides storage for the RW lock object. This should be treated as an opaque object and not examined directly by consumers.

Note that these interfaces must not be used from a hardware interrupt handler.

# OPTIONS AND MACROS

`options DIAGNOSTIC`

  Kernels compiled with the `DIAGNOSTIC` option perform basic sanity checks on RW lock operations.

`options LOCKDEBUG`

  Kernels compiled with the `LOCKDEBUG` option perform potentially CPU intensive sanity checks on RW lock operations.

# FUNCTIONS

`rw_init`(rw)

  Initialize a lock for use. No other operations can be performed on the lock until it has been initialized.

`rw_destroy`(rw)

  Release resources used by a lock. The lock may not be used after it has been destroyed.

`rw_enter`(rw, op)

  If `RW_READER` is specified as the argument to op, acquire a read lock. The caller may block and will not return until the hold is acquired. Callers must not recursively acquire read locks.

  If `RW_WRITER` is specified, acquire a write lock. If the lock is already held, the caller will block and not return until the hold is acquired.

  RW locks and other types of locks must always be acquired in a consistent order with respect to each other. Otherwise, the potential for system deadlock exists.

`rw_exit`(rw)

  Release a lock. The lock must have been previously acquired by the caller.

`rw_tryenter`(rw, op)

  Try to acquire a lock, but do not block if the lock is already held. If the lock is acquired successfully, return non-zero. Otherwise, return zero.

  Valid arguments to op are `RW_READER` or `RW_WRITER`.

`rw_tryupgrade`(rw)

  Try to upgrade a lock from one read hold to a write hold. If the lock is upgraded successfully, returns non-zero. Otherwise, returns zero.

`rw_downgrade`(rw)

  Downgrade a lock from a write hold to a read hold.

`rw_write_held`(rw)

  Return non-zero if write lock is held by current lwp. Otherwise, return zero.

`rw_read_held`(rw)

  Returns non-zero if read lock is held by any lwp. Otherwise, return zero.

`rw_lock_held`(rw)

  Returns non-zero if either read or write lock is held by any lwp. Otherwise, return zero.

  `rw_write_held`(), `rw_read_held`(), and `rw_lock_held`() should not generally be used to make locking decisions at run time: they are provided for diagnostic purposes, for example making assertions.

  Negative assertions (lock not held) should not be made due to atomicity issues, excepting `rw_write_held`(), which can safely be used to assert that a write lock is NOT held by the current LWP.

`rw_lock_op`(rw)

  For a lock that is known to be held by the calling LWP, return either `RW_READER` or `RW_WRITER` to denote the type of hold. This is useful when dropping and later re-acquiring a lock, if the type of hold is not already known.

# PERFORMANCE CONSIDERATIONS

RW locks are subject to high cache contention on multiprocessor systems, and scale poorly when the write:read ratio is not strongly in favour of readers. Ideally, RW locks should only be used in settings when the following three conditions are met:

- The data object(s) protected by the RW lock are read much more frequently than written.
- The read-side hold time for the RW lock is long (in the order of thousands of processor clock cycles).
- Strong synchronization semantics are required: there is no scope for lockless, lazy or optimistic synchronization.

Generally speaking, it is better to organise code paths and/or data flows such that fewer and weaker synchronization points are required to ensure correct operation.

# CODE REFERENCES

The core of the RW lock implementation is in sys/kern/kern_rwlock.c.

The header file sys/sys/rwlock.h describes the public interface, and interfaces that machine-dependent code must provide to support RW locks.

# SEE ALSO

membar_ops(3), lockstat(8), condvar(9), mutex(9)

Jim Mauro and Richard McDougall, Solaris Internals: Core Kernel Architecture, Prentice Hall, 2001, ISBN 0-13-022496-0.

# HISTORY

The RW lock primitives first appeared in NetBSD 5.0.

February 22, 2020 | NetBSD 10.1