| 1 | /* @title: Simple Mutex */ |
| 2 | #pragma once |
| 3 | #include <stdbool.h> |
| 4 | #include <sync/lock_chk_types.h> |
| 5 | #include <sync/spinlock.h> |
| 6 | #include <thread/wait.h> |
| 7 | #include <tsa.h> |
| 8 | |
| 9 | struct TSA_CAPABILITY("mutex" ) mutex_simple { |
| 10 | struct thread *owner; |
| 11 | struct thread_wait_header waiters; |
| 12 | struct spinlock lock; |
| 13 | |
| 14 | #ifdef DEBUG_LOCK_CHK |
| 15 | struct lock_chk_lock chk; |
| 16 | #endif /* DEBUG_LOCK_CHK */ |
| 17 | }; |
| 18 | |
| 19 | void mutex_simple_init_chk_full(struct mutex_simple *m, |
| 20 | const struct lock_chk_class *class, |
| 21 | enum lock_chk_flags flags); |
| 22 | void mutex_simple_set_chk_flags(struct mutex_simple *m, |
| 23 | enum lock_chk_flags flags); |
| 24 | void mutex_simple_reinit_chk(struct mutex_simple *m, |
| 25 | const struct lock_chk_class *class, |
| 26 | enum lock_chk_flags flags); |
| 27 | void mutex_simple_lock_full(struct mutex_simple *m, |
| 28 | const struct lock_chk_site *site) |
| 29 | TSA_ACQUIRES(m) TSA_MAY_SLEEP; |
| 30 | |
| 31 | void mutex_simple_unlock_full(struct mutex_simple *m, |
| 32 | const struct lock_chk_site *site) TSA_RELEASES(m); |
| 33 | |
| 34 | void mutex_simple_lock_subclass_full(struct mutex_simple *m, |
| 35 | enum lock_subclass subclass, |
| 36 | const struct lock_chk_site *site) |
| 37 | TSA_ACQUIRES(m) TSA_MAY_SLEEP; |
| 38 | |
| 39 | bool mutex_simple_locked(struct mutex_simple *m); |
| 40 | struct thread *mutex_simple_get_owner(struct mutex_simple *m); |
| 41 | |
| 42 | void mutex_simple_assert_held_full(struct mutex_simple *m, |
| 43 | const struct lock_chk_site *site) |
| 44 | TSA_ASSERT_CAPABILITY(m); |
| 45 | |
| 46 | void mutex_simple_assert_not_held_full(struct mutex_simple *m, |
| 47 | const struct lock_chk_site *site); |
| 48 | |
| 49 | #ifdef DEBUG_LOCK_CHK |
| 50 | |
| 51 | #define MUTEX_SIMPLE_INIT_CHK(id_, class_, flags_) \ |
| 52 | ((struct mutex_simple) { \ |
| 53 | .owner = NULL, \ |
| 54 | .waiters = \ |
| 55 | { \ |
| 56 | .waiters = LIST_HEAD_INIT((id_).waiters.waiters), \ |
| 57 | .lock = SPINLOCK_INIT_CHK(NULL, LOCK_UNCHKD), \ |
| 58 | }, \ |
| 59 | .lock = SPINLOCK_INIT_CHK(NULL, LOCK_UNCHKD), \ |
| 60 | .chk = LOCK_CHK_LOCK_VALUE_INIT((class_), (flags_)), \ |
| 61 | }) |
| 62 | |
| 63 | #define mutex_simple_init_chk(mtx_, class_, flags_) \ |
| 64 | mutex_simple_init_chk_full((mtx_), (class_), (flags_)) |
| 65 | #define mutex_simple_init_auto_internal(mtx_, flags_) \ |
| 66 | do { \ |
| 67 | static const struct lock_chk_class __auto_class = { \ |
| 68 | .name = #mtx_, \ |
| 69 | .file = __RELFILE__, \ |
| 70 | .line = __LINE__, \ |
| 71 | }; \ |
| 72 | mutex_simple_init_chk_full((mtx_), &__auto_class, (flags_)); \ |
| 73 | } while (0) |
| 74 | |
| 75 | #else /* !defined(DEBUG_LOCK_CHK) */ |
| 76 | |
| 77 | #define MUTEX_SIMPLE_INIT_CHK(id_, class_, flags_) \ |
| 78 | ((struct mutex_simple) { \ |
| 79 | .owner = NULL, \ |
| 80 | .waiters = \ |
| 81 | { \ |
| 82 | .waiters = LIST_HEAD_INIT((id_).waiters.waiters), \ |
| 83 | .lock = SPINLOCK_INIT_CHK(NULL, LOCK_UNCHKD), \ |
| 84 | }, \ |
| 85 | .lock = SPINLOCK_INIT_CHK(NULL, LOCK_UNCHKD), \ |
| 86 | }) |
| 87 | |
| 88 | #define mutex_simple_init_chk(mtx_, class_, flags_) \ |
| 89 | mutex_simple_init_chk_full((mtx_), NULL, LOCK_UNCHKD) |
| 90 | #define mutex_simple_init_auto_internal(mtx_, flags_) \ |
| 91 | mutex_simple_init_chk_full((mtx_), NULL, LOCK_UNCHKD) |
| 92 | |
| 93 | #endif /* DEBUG_LOCK_CHK */ |
| 94 | |
| 95 | #define MUTEX_SIMPLE_INIT(id_) \ |
| 96 | MUTEX_SIMPLE_INIT_CHK((id_), NULL, LOCK_CHKD_FULL) |
| 97 | #define MUTEX_SIMPLE_DEFINE(id) struct mutex_simple id = MUTEX_SIMPLE_INIT(id) |
| 98 | #define MUTEX_SIMPLE_DEFINE_CHK(id, class_, flags_) \ |
| 99 | struct mutex_simple id = MUTEX_SIMPLE_INIT_CHK((id), (class_), (flags_)) |
| 100 | |
| 101 | #define mutex_simple_init_1(mtx_) mutex_simple_init_2(mtx_, LOCK_CHKD_FULL) |
| 102 | #define mutex_simple_init_2(mtx_, flags_) \ |
| 103 | mutex_simple_init_auto_internal((mtx_), (flags_)) |
| 104 | #define mutex_simple_init(...) PP_CALL(mutex_simple_init, __VA_ARGS__) |
| 105 | |
| 106 | #define mutex_simple_lock(m_) mutex_simple_lock_full((m_), LOCK_CHK_SITE_HERE()) |
| 107 | #define mutex_simple_unlock(m_) \ |
| 108 | mutex_simple_unlock_full((m_), LOCK_CHK_SITE_HERE()) |
| 109 | #define mutex_simple_lock_subclass(m_, subclass_) \ |
| 110 | mutex_simple_lock_subclass_full((m_), (subclass_), LOCK_CHK_SITE_HERE()) |
| 111 | |
| 112 | #define MUTEX_SIMPLE_ASSERT_HELD(m) \ |
| 113 | mutex_simple_assert_held_full((m), LOCK_CHK_SITE_HERE()) |
| 114 | #define MUTEX_SIMPLE_ASSERT_NOT_HELD(m) \ |
| 115 | mutex_simple_assert_not_held_full((m), LOCK_CHK_SITE_HERE()) |
| 116 | |
| 117 | static inline cc_always_inline cc_unused void |
| 118 | mutex_simple_guard_exit(struct mutex_simple **m) TSA_NO_ANALYSIS { |
| 119 | if (*m) |
| 120 | mutex_simple_unlock(*m); |
| 121 | } |
| 122 | |
| 123 | static inline cc_always_inline cc_unused void |
| 124 | mutex_simple_guard_assume(struct mutex_simple *m) TSA_ASSERT_CAPABILITY(m) { |
| 125 | cc_ignore(m); |
| 126 | } |
| 127 | |
| 128 | static inline cc_always_inline cc_unused struct mutex_simple * |
| 129 | mutex_simple_guard_enter(struct mutex_simple *m) TSA_MAY_SLEEP TSA_NO_ANALYSIS { |
| 130 | mutex_simple_lock(m); |
| 131 | return m; |
| 132 | } |
| 133 | |
| 134 | static inline cc_always_inline cc_unused struct mutex_simple * |
| 135 | mutex_simple_guard_subclass_enter(struct mutex_simple *m, |
| 136 | enum lock_subclass subclass) |
| 137 | TSA_MAY_SLEEP TSA_NO_ANALYSIS { |
| 138 | mutex_simple_lock_subclass(m, subclass); |
| 139 | return m; |
| 140 | } |
| 141 | |
| 142 | #define mutex_simple_guard(m_) \ |
| 143 | cc_cleanup(mutex_simple_guard_exit) struct mutex_simple *PP_CONCAT( \ |
| 144 | mtx_simple_guard_, __COUNTER__) = \ |
| 145 | (mutex_simple_guard_assume(m_), mutex_simple_guard_enter(m_)) |
| 146 | |
| 147 | #define mutex_simple_guard_subclass(m_, subclass_) \ |
| 148 | cc_cleanup(mutex_simple_guard_exit) struct mutex_simple *PP_CONCAT( \ |
| 149 | mtx_simple_guard_, __COUNTER__) = \ |
| 150 | (mutex_simple_guard_assume(m_), \ |
| 151 | mutex_simple_guard_subclass_enter((m_), (subclass_))) |
| 152 | |