Skip to content

Reader writer lock

include/sync/rwlock.h View source View on GitHub

rwlock: 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

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
void rwlock_set_chk_flags(
    struct rwlock *lock,
    enum lock_chk_flags flags
)
source
void rwlock_reinit_chk(
    struct rwlock *lock,
    enum thread_prio_class ceiling,
    const struct lock_chk_class *class,
    enum lock_chk_flags flags
)
source
bool rwlock_locked(struct rwlock *lock, enum rwlock_acquire_type type)
source
void rwlock_assert_not_held_full(
    struct rwlock *lock,
    const struct lock_chk_site *site
)
source
void rwlock_guard_exit(struct rwlock **lock)
source
void rwlock_guard_assume(struct rwlock *lock)
source
struct rwlock * rw_read_guard_enter(struct rwlock *lock)
source
struct rwlock * rw_write_guard_enter(struct rwlock *lock)
source
struct lock_chk_lock chk
source
#define RWLOCK_ASSERT_HELD(lock, type)
source
Expansion
#define RWLOCK_ASSERT_HELD(lock, type) \
    rwlock_assert_held_full((lock), (type), LOCK_CHK_SITE_HERE())
#define RWLOCK_ASSERT_READ(lock)
source
Expansion
#define RWLOCK_ASSERT_READ(lock) RWLOCK_ASSERT_HELD((lock), RWLOCK_READ)
#define RWLOCK_ASSERT_WRITE(lock)
source
Expansion
#define RWLOCK_ASSERT_WRITE(lock) RWLOCK_ASSERT_HELD((lock), RWLOCK_WRITE)
#define RWLOCK_ASSERT_NOT_HELD(lock)
source
#define RWLOCK_PRIO_CEIL_SHIFT 1
source
#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_)), \
    })
#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_))
#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)
#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), \
    })
#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)
#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)
#define RWLOCK_INIT(ceil_)
source
Expansion
#define RWLOCK_INIT(ceil_) RWLOCK_INIT_CHK((ceil_), NULL, LOCK_CHKD_FULL)
#define RWLOCK_DEFINE(id, ceil_)
source
Expansion
#define RWLOCK_DEFINE(id, ceil_) struct rwlock id = RWLOCK_INIT(ceil_)
#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_))
#define rwlock_init_2(lock_, ceil_)
source
Expansion
#define rwlock_init_2(lock_, ceil_) rwlock_init_3(lock_, ceil_, LOCK_CHKD_FULL)
#define rwlock_init_3(lock_, ceil_, flags_)
source
Expansion
#define rwlock_init_3(lock_, ceil_, flags_) \
    rwlock_init_auto_internal((lock_), (ceil_), (flags_))
#define rwlock_init(...)
source
Expansion
#define rwlock_init(...) PP_CALL(rwlock_init, __VA_ARGS__)
#define rw_lock(lock_, type_)
source
Expansion
#define rw_lock(lock_, type_) \
    rw_lock_full((lock_), (type_), LOCK_SUBCLASS_PRIMARY, LOCK_CHK_SITE_HERE())
#define rw_read_lock(lock_)
source
#define rw_write_lock(lock_)
source
#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())
#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())
#define rw_unlock(lock_)
source
Expansion
#define rw_unlock(lock_) rw_unlock_full((lock_), LOCK_CHK_SITE_HERE())
#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_))
#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_))