| 1 | /* @title: Reader writer lock */ |
| 2 | #pragma once |
| 3 | #include <stdatomic.h> |
| 4 | #include <stddef.h> |
| 5 | #include <stdint.h> |
| 6 | #include <thread/thread_types.h> |
| 7 | |
| 8 | /* rwlock: pointer sized shared reader writer lock |
| 9 | * |
| 10 | * note: the writer bit leads to two separate |
| 11 | * possible encodings for the rest of the bits in the lock word. |
| 12 | * |
| 13 | * ┌─────────────────────────┐ |
| 14 | * Bits │ .... .... .... 3..0 │ |
| 15 | * Use when w = 1 │ %%%% %%%% %%%% %ppw │ |
| 16 | * Use when w = 0 │ RRRR RRRR RRRW appw │ |
| 17 | * └─────────────────────────┘ |
| 18 | * |
| 19 | * |
| 20 | * w - writer bit -> a writer holds the lock |
| 21 | * a - waiter bit -> threads are waiting on the lock |
| 22 | * W - writer want -> a writer wants the lock |
| 23 | * R - reader count -> used to store the number of readers |
| 24 | * p - prio. ceil. -> boosts threads to this ceiling |
| 25 | * |
| 26 | * %%%% - pointer to owner thread |
| 27 | * |
| 28 | */ |
| 29 | struct rwlock { |
| 30 | _Atomic(uintptr_t) lock_word; |
| 31 | }; |
| 32 | |
| 33 | enum rwlock_acquire_type { |
| 34 | RWLOCK_ACQUIRE_READ = 0, |
| 35 | RWLOCK_ACQUIRE_WRITE = 1, |
| 36 | }; |
| 37 | |
| 38 | void rwlock_lock(struct rwlock *lock, enum rwlock_acquire_type type); |
| 39 | void rwlock_unlock(struct rwlock *lock); |
| 40 | void rwlock_init(struct rwlock *lock, enum thread_prio_class ceiling); |
| 41 | bool rwlock_held(struct rwlock *lock, enum rwlock_acquire_type type); |
| 42 | |
| 43 | #define RWLOCK_ASSERT_HELD(lock, type) \ |
| 44 | kassert(rwlock_held((lock), (type)), "rwlock not held") |
| 45 | #define RWLOCK_ASSERT_READ(lock) RWLOCK_ASSERT_HELD((lock), RWLOCK_ACQUIRE_READ) |
| 46 | #define RWLOCK_ASSERT_WRITE(lock) \ |
| 47 | RWLOCK_ASSERT_HELD((lock), RWLOCK_ACQUIRE_WRITE) |
| 48 | |
| 49 | #define RWLOCK_PRIO_CEIL_SHIFT (1) |
| 50 | #define RWLOCK_INIT(ceil) {((ceil) << RWLOCK_PRIO_CEIL_SHIFT)} |
| 51 | |
| 52 | static inline void rwlock_read_lock(struct rwlock *lock) { |
| 53 | rwlock_lock(lock, type: RWLOCK_ACQUIRE_READ); |
| 54 | } |
| 55 | |
| 56 | static inline void rwlock_write_lock(struct rwlock *lock) { |
| 57 | rwlock_lock(lock, type: RWLOCK_ACQUIRE_WRITE); |
| 58 | } |
| 59 | |