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
9struct 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
19void mutex_simple_init_chk_full(struct mutex_simple *m,
20 const struct lock_chk_class *class,
21 enum lock_chk_flags flags);
22void mutex_simple_set_chk_flags(struct mutex_simple *m,
23 enum lock_chk_flags flags);
24void mutex_simple_reinit_chk(struct mutex_simple *m,
25 const struct lock_chk_class *class,
26 enum lock_chk_flags flags);
27void mutex_simple_lock_full(struct mutex_simple *m,
28 const struct lock_chk_site *site)
29 TSA_ACQUIRES(m) TSA_MAY_SLEEP;
30
31void mutex_simple_unlock_full(struct mutex_simple *m,
32 const struct lock_chk_site *site) TSA_RELEASES(m);
33
34void 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
39bool mutex_simple_locked(struct mutex_simple *m);
40struct thread *mutex_simple_get_owner(struct mutex_simple *m);
41
42void mutex_simple_assert_held_full(struct mutex_simple *m,
43 const struct lock_chk_site *site)
44 TSA_ASSERT_CAPABILITY(m);
45
46void 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
117static inline cc_always_inline cc_unused void
118mutex_simple_guard_exit(struct mutex_simple **m) TSA_NO_ANALYSIS {
119 if (*m)
120 mutex_simple_unlock(*m);
121}
122
123static inline cc_always_inline cc_unused void
124mutex_simple_guard_assume(struct mutex_simple *m) TSA_ASSERT_CAPABILITY(m) {
125 cc_ignore(m);
126}
127
128static inline cc_always_inline cc_unused struct mutex_simple *
129mutex_simple_guard_enter(struct mutex_simple *m) TSA_MAY_SLEEP TSA_NO_ANALYSIS {
130 mutex_simple_lock(m);
131 return m;
132}
133
134static inline cc_always_inline cc_unused struct mutex_simple *
135mutex_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