Reader writer lock
include/sync/rwlock.h View source View on GitHubrwlock: pointer sized shared reader writer lock
note: the writer bit leads to two separate possible encodings for the rest of the bits in the lock word.
┌─────────────────────────┐Bits │ .... .... .... 3..0 │Use when w = 1 │ %%%% %%%% %%%% %ppw │Use when w = 0 │ RRRR RRRR RRRW appw │ └─────────────────────────┘w - writer bit -> a writer holds the lock a - waiter bit -> threads are waiting on the lock W - writer want -> a writer wants the lock R - reader count -> used to store the number of readers | | The way the reader count actually works, | though, is that it uses the base priority | of the reader to create multiple separate | counters that are all the same few bits, | so writers have an exact snapshot of | who is reading the lock. |
m - max prio class -> panic if reader > this
%%%% - pointer to owner thread
Functions
Section titled “Functions”rwlock_init_chk_full
Section titled “rwlock_init_chk_full”void rwlock_init_chk_full(
struct rwlock *lock,
enum thread_prio_class ceiling,
const struct lock_chk_class *class,
enum lock_chk_flags flags
) source rwlock_set_chk_flags
Section titled “rwlock_set_chk_flags”void rwlock_set_chk_flags(
struct rwlock *lock,
enum lock_chk_flags flags
) source rwlock_reinit_chk
Section titled “rwlock_reinit_chk”void rwlock_reinit_chk(
struct rwlock *lock,
enum thread_prio_class ceiling,
const struct lock_chk_class *class,
enum lock_chk_flags flags
) source rwlock_locked
Section titled “rwlock_locked”bool rwlock_locked(struct rwlock *lock, enum rwlock_acquire_type type) source rwlock_assert_not_held_full
Section titled “rwlock_assert_not_held_full”void rwlock_assert_not_held_full(
struct rwlock *lock,
const struct lock_chk_site *site
) source rwlock_guard_exit
Section titled “rwlock_guard_exit”rwlock_guard_assume
Section titled “rwlock_guard_assume”rw_read_guard_enter
Section titled “rw_read_guard_enter”rw_write_guard_enter
Section titled “rw_write_guard_enter”Variables
Section titled “Variables”lock_word
Section titled “lock_word”atomic_uintptr_t lock_word source struct lock_chk_lock chk source Macros
Section titled “Macros”RWLOCK_ASSERT_HELD
Section titled “RWLOCK_ASSERT_HELD”#define RWLOCK_ASSERT_HELD(lock, type) source Expansion
#define RWLOCK_ASSERT_HELD(lock, type) \
rwlock_assert_held_full((lock), (type), LOCK_CHK_SITE_HERE()) RWLOCK_ASSERT_READ
Section titled “RWLOCK_ASSERT_READ”#define RWLOCK_ASSERT_READ(lock) source Expansion
#define RWLOCK_ASSERT_READ(lock) RWLOCK_ASSERT_HELD((lock), RWLOCK_READ) RWLOCK_ASSERT_WRITE
Section titled “RWLOCK_ASSERT_WRITE”#define RWLOCK_ASSERT_WRITE(lock) source Expansion
#define RWLOCK_ASSERT_WRITE(lock) RWLOCK_ASSERT_HELD((lock), RWLOCK_WRITE) RWLOCK_ASSERT_NOT_HELD
Section titled “RWLOCK_ASSERT_NOT_HELD”#define RWLOCK_ASSERT_NOT_HELD(lock) source Expansion
#define RWLOCK_ASSERT_NOT_HELD(lock) \
rwlock_assert_not_held_full((lock), LOCK_CHK_SITE_HERE()) RWLOCK_PRIO_CEIL_SHIFT
Section titled “RWLOCK_PRIO_CEIL_SHIFT”#define RWLOCK_PRIO_CEIL_SHIFT 1 source RWLOCK_INIT_CHK
Section titled “RWLOCK_INIT_CHK”#define RWLOCK_INIT_CHK(ceil_, class_, flags_) source Expansion
#define RWLOCK_INIT_CHK(ceil_, class_, flags_) \
((struct rwlock) { \
.lock_word = ATOMIC_VAR_INIT((ceil_) << RWLOCK_PRIO_CEIL_SHIFT), \
.chk = LOCK_CHK_LOCK_VALUE_INIT((class_), (flags_)), \
}) rwlock_init_chk
Section titled “rwlock_init_chk”#define rwlock_init_chk(lock_, ceil_, class_, flags_) source Expansion
#define rwlock_init_chk(lock_, ceil_, class_, flags_) \
rwlock_init_chk_full((lock_), (ceil_), (class_), (flags_)) rwlock_init_auto_internal
Section titled “rwlock_init_auto_internal”#define rwlock_init_auto_internal(lock_, ceil_, flags_) source Expansion
#define rwlock_init_auto_internal(lock_, ceil_, flags_) \
do { \
static const struct lock_chk_class __auto_class = { \
.name = #lock_, \
.file = __RELFILE__, \
.line = __LINE__, \
}; \
rwlock_init_chk_full((lock_), (ceil_), &__auto_class, (flags_)); \
} while (0) RWLOCK_INIT_CHK
Section titled “RWLOCK_INIT_CHK”#define RWLOCK_INIT_CHK(ceil_, class_, flags_) source Expansion
#define RWLOCK_INIT_CHK(ceil_, class_, flags_) \
((struct rwlock) { \
.lock_word = ATOMIC_VAR_INIT((ceil_) << RWLOCK_PRIO_CEIL_SHIFT), \
}) rwlock_init_chk
Section titled “rwlock_init_chk”#define rwlock_init_chk(lock_, ceil_, class_, flags_) source Expansion
#define rwlock_init_chk(lock_, ceil_, class_, flags_) \
rwlock_init_chk_full((lock_), (ceil_), NULL, LOCK_UNCHKD) rwlock_init_auto_internal
Section titled “rwlock_init_auto_internal”#define rwlock_init_auto_internal(lock_, ceil_, flags_) source Expansion
#define rwlock_init_auto_internal(lock_, ceil_, flags_) \
rwlock_init_chk_full((lock_), (ceil_), NULL, LOCK_UNCHKD) RWLOCK_INIT
Section titled “RWLOCK_INIT”#define RWLOCK_INIT(ceil_) source Expansion
#define RWLOCK_INIT(ceil_) RWLOCK_INIT_CHK((ceil_), NULL, LOCK_CHKD_FULL) RWLOCK_DEFINE
Section titled “RWLOCK_DEFINE”#define RWLOCK_DEFINE(id, ceil_) source Expansion
#define RWLOCK_DEFINE(id, ceil_) struct rwlock id = RWLOCK_INIT(ceil_) RWLOCK_DEFINE_CHK
Section titled “RWLOCK_DEFINE_CHK”#define RWLOCK_DEFINE_CHK(id, ceil_, class_, flags_) source Expansion
#define RWLOCK_DEFINE_CHK(id, ceil_, class_, flags_) \
struct rwlock id = RWLOCK_INIT_CHK((ceil_), (class_), (flags_)) rwlock_init_2
Section titled “rwlock_init_2”#define rwlock_init_2(lock_, ceil_) source Expansion
#define rwlock_init_2(lock_, ceil_) rwlock_init_3(lock_, ceil_, LOCK_CHKD_FULL) rwlock_init_3
Section titled “rwlock_init_3”#define rwlock_init_3(lock_, ceil_, flags_) source Expansion
#define rwlock_init_3(lock_, ceil_, flags_) \
rwlock_init_auto_internal((lock_), (ceil_), (flags_)) rwlock_init
Section titled “rwlock_init”#define rwlock_init(...) source Expansion
#define rwlock_init(...) PP_CALL(rwlock_init, __VA_ARGS__) rw_lock
Section titled “rw_lock”#define rw_lock(lock_, type_) source Expansion
#define rw_lock(lock_, type_) \
rw_lock_full((lock_), (type_), LOCK_SUBCLASS_PRIMARY, LOCK_CHK_SITE_HERE()) rw_read_lock
Section titled “rw_read_lock”#define rw_read_lock(lock_) source Expansion
#define rw_read_lock(lock_) \
rw_lock_full((lock_), RWLOCK_READ, LOCK_SUBCLASS_PRIMARY, \
LOCK_CHK_SITE_HERE()) rw_write_lock
Section titled “rw_write_lock”#define rw_write_lock(lock_) source Expansion
#define rw_write_lock(lock_) \
rw_lock_full((lock_), RWLOCK_WRITE, LOCK_SUBCLASS_PRIMARY, \
LOCK_CHK_SITE_HERE()) rw_read_lock_subclass
Section titled “rw_read_lock_subclass”#define rw_read_lock_subclass(lock_, subclass_) source Expansion
#define rw_read_lock_subclass(lock_, subclass_) \
rw_lock_full((lock_), RWLOCK_READ, (subclass_), LOCK_CHK_SITE_HERE()) rw_write_lock_subclass
Section titled “rw_write_lock_subclass”#define rw_write_lock_subclass(lock_, subclass_) source Expansion
#define rw_write_lock_subclass(lock_, subclass_) \
rw_lock_full((lock_), RWLOCK_WRITE, (subclass_), LOCK_CHK_SITE_HERE()) rw_unlock
Section titled “rw_unlock”#define rw_unlock(lock_) source Expansion
#define rw_unlock(lock_) rw_unlock_full((lock_), LOCK_CHK_SITE_HERE()) rw_read_guard
Section titled “rw_read_guard”#define rw_read_guard(lock_) source Expansion
#define rw_read_guard(lock_) \
cc_cleanup(rwlock_guard_exit) struct rwlock *PP_CONCAT(rw_read_guard_, \
__COUNTER__) = \
(rwlock_guard_assume(lock_), rw_read_guard_enter(lock_)) rw_write_guard
Section titled “rw_write_guard”#define rw_write_guard(lock_) source Expansion
#define rw_write_guard(lock_) \
cc_cleanup(rwlock_guard_exit) struct rwlock *PP_CONCAT(rw_write_guard_, \
__COUNTER__) = \
(rwlock_guard_assume(lock_), rw_write_guard_enter(lock_))