FreeBSD ZFS
The Zettabyte File System
|
A re-entrant read reader/writer lock (aka "rrwlock"). More...
Go to the source code of this file.
Data Structures | |
struct | rrw_node |
Typedefs | |
typedef struct rrw_node | rrw_node_t |
Functions | |
static rrw_node_t * | rrn_find (rrwlock_t *rrl) |
static void | rrn_add (rrwlock_t *rrl) |
Add a node to the head of the singly linked list. | |
static boolean_t | rrn_find_and_remove (rrwlock_t *rrl) |
If a node is found for 'rrl', then remove the node from this thread's list and return TRUE; otherwise return FALSE. | |
void | rrw_init (rrwlock_t *rrl) |
void | rrw_destroy (rrwlock_t *rrl) |
static void | rrw_enter_read (rrwlock_t *rrl, void *tag) |
static void | rrw_enter_write (rrwlock_t *rrl) |
void | rrw_enter (rrwlock_t *rrl, krw_t rw, void *tag) |
void | rrw_exit (rrwlock_t *rrl, void *tag) |
boolean_t | rrw_held (rrwlock_t *rrl, krw_t rw) |
Variables | |
uint_t | rrw_tsd_key |
global key for TSD |
A re-entrant read reader/writer lock (aka "rrwlock").
This is a normal reader/writer lock with the additional feature of allowing threads who have already obtained a read lock to re-enter another read lock (re-entrant read) - even if there are waiting writers.
Callers who have not obtained a read lock give waiting writers priority.
The rrwlock_t lock does not allow re-entrant writers, nor does it allow a re-entrant mix of reads and writes (that is, it does not allow a caller who has already obtained a read lock to be able to then grab a write lock without first dropping all read locks, and vice versa).
The rrwlock_t uses tsd (thread specific data) to keep a list of nodes (rrw_node_t), where each node keeps track of which specific lock (rrw_node_t::rn_rrl) the thread has grabbed. Since re-entering should be rare, a thread that grabs multiple reads on the same rrwlock_t will store multiple rrw_node_ts of the same 'rrn_rrl'. Nodes on the tsd list can represent a different rrwlock_t. This allows a thread to enter multiple and unique rrwlock_ts for read locks at the same time.
Since using tsd exposes some overhead, the rrwlock_t only needs to keep tsd data when writers are waiting. If no writers are waiting, then a reader just bumps the anonymous read count (rr_anon_rcount) - no tsd is needed. Once a writer attempts to grab the lock, readers then keep tsd data and bump the linked readers count (rr_linked_rcount).
If there are waiting writers and there are anonymous readers, then a reader doesn't know if it is a re-entrant lock. But since it may be one, we allow the read to proceed (otherwise it could deadlock). Since once waiting writers are active, readers no longer bump the anonymous count, the anonymous readers will eventually flush themselves out. At this point, readers will be able to tell if they are a re-entrant lock (have a rrw_node_t entry for the lock) or not. If they are a re-entrant lock, then we must let the proceed. If they are not, then the reader blocks for the waiting writers. Hence, we do not starve writers.
Definition in file rrwlock.c.
typedef struct rrw_node rrw_node_t |
static void rrn_add | ( | rrwlock_t * | rrl | ) | [static] |
static rrw_node_t* rrn_find | ( | rrwlock_t * | rrl | ) | [static] |
static boolean_t rrn_find_and_remove | ( | rrwlock_t * | rrl | ) | [static] |
void rrw_enter | ( | rrwlock_t * | rrl, |
krw_t | rw, | ||
void * | tag | ||
) |
[in] | tag | Used in reference count tracking. The value used in rrw_enter() must also be used any corresponding rrw_exit()s. |
static void rrw_enter_read | ( | rrwlock_t * | rrl, |
void * | tag | ||
) | [static] |
void rrw_exit | ( | rrwlock_t * | rrl, |
void * | tag | ||
) |
[in] | tag | Used in reference count tracking. The value used in rrw_exit() must match that used by its corresponding rrw_enter(). |
uint_t rrw_tsd_key |