1/* @title: Mutex */
2#pragma once
3#include <stdbool.h>
4#include <stdint.h>
5#include <sync/lock_chk_types.h>
6
7/* mutex: pointer sized mutex
8 *
9 * ┌─────────────────────────┐
10 * Bits │ .... .... .... 3..0 │
11 * Use │ %%%% %%%% %%%% %rrh │
12 * └─────────────────────────┘
13 *
14 * h - "held" - is the lock held?
15 *
16 * r - reserved for future use
17 *
18 * %%%% - pointer to owner thread
19 *
20 */
21
22struct mutex {
23 _Atomic(uintptr_t) lock_word;
24
25#ifdef DEBUG_LOCK_CHK
26 struct lock_chk_lock chk;
27#endif /* DEBUG_LOCK_CHK */
28};
29
30void mutex_init_chk_internal(struct mutex *mtx,
31 const struct lock_chk_class *class,
32 enum lock_chk_flags flags);
33void mutex_set_chk_flags(struct mutex *mtx, enum lock_chk_flags flags);
34void mutex_reinit_chk(struct mutex *mtx, const struct lock_chk_class *class,
35 enum lock_chk_flags flags);
36void mutex_unlock_internal(struct mutex *mutex,
37 const struct lock_chk_site *site);
38void mutex_lock_internal(struct mutex *mutex, const struct lock_chk_site *site);
39void mutex_lock_subclass_internal(struct mutex *mutex, uint8_t subclass,
40 const struct lock_chk_site *site);
41bool mutex_locked(struct mutex *mtx);
42struct thread *mutex_get_owner(struct mutex *mtx);
43void mutex_assert_held_internal(struct mutex *mtx,
44 const struct lock_chk_site *site);
45void mutex_assert_not_held_internal(struct mutex *mtx,
46 const struct lock_chk_site *site);
47
48#ifdef DEBUG_LOCK_CHK
49
50#define MUTEX_INIT_CHK(class_, flags_) \
51 ((struct mutex) { \
52 .lock_word = ATOMIC_VAR_INIT(0), \
53 .chk = LOCK_CHK_LOCK_VALUE_INIT((class_), (flags_)), \
54 })
55
56#define mutex_init_chk(mtx_, class_, flags_) \
57 mutex_init_chk_internal((mtx_), (class_), (flags_))
58#define mutex_init_auto_internal(mtx_, flags_) \
59 do { \
60 static const struct lock_chk_class __auto_class = { \
61 .name = #mtx_, \
62 .file = __RELFILE__, \
63 .line = __LINE__, \
64 }; \
65 mutex_init_chk_internal((mtx_), &__auto_class, (flags_)); \
66 } while (0)
67
68#else /* !defined(DEBUG_LOCK_CHK) */
69
70#define MUTEX_INIT_CHK(class_, flags_) \
71 ((struct mutex) {.lock_word = ATOMIC_VAR_INIT(0)})
72
73#define mutex_init_chk(mtx_, class_, flags_) \
74 mutex_init_chk_internal((mtx_), NULL, LOCK_UNCHKD)
75#define mutex_init_auto_internal(mtx_, flags_) \
76 mutex_init_chk_internal((mtx_), NULL, LOCK_UNCHKD)
77
78#endif /* DEBUG_LOCK_CHK */
79
80#define MUTEX_INIT MUTEX_INIT_CHK(NULL, LOCK_CHKD_FULL)
81#define MUTEX_DEFINE(id) struct mutex id = MUTEX_INIT
82#define MUTEX_DEFINE_CHK(id, class_, flags_) \
83 struct mutex id = MUTEX_INIT_CHK((class_), (flags_))
84
85#define mutex_init_1(mtx_) mutex_init_auto_internal((mtx_), LOCK_CHKD_FULL)
86#define mutex_init_2(mtx_, flags_) mutex_init_auto_internal((mtx_), (flags_))
87#define mutex_init(...) _DISPATCH(mutex_init, PP_NARG(__VA_ARGS__))(__VA_ARGS__)
88
89#define mutex_lock(mutex_) mutex_lock_internal((mutex_), LOCK_CHK_SITE_HERE())
90#define mutex_lock_subclass(mutex_, subclass_) \
91 mutex_lock_subclass_internal((mutex_), (subclass_), LOCK_CHK_SITE_HERE())
92#define mutex_unlock(mutex_) \
93 mutex_unlock_internal((mutex_), LOCK_CHK_SITE_HERE())
94
95#define MUTEX_ASSERT_HELD(m) \
96 mutex_assert_held_internal((m), LOCK_CHK_SITE_HERE())
97#define MUTEX_ASSERT_NOT_HELD(m) \
98 mutex_assert_not_held_internal((m), LOCK_CHK_SITE_HERE())
99