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/queue.h>
7
8struct mutex_simple {
9 struct thread *owner;
10 struct thread_queue waiters;
11 struct spinlock lock;
12
13#ifdef DEBUG_LOCK_CHK
14 struct lock_chk_lock chk;
15#endif /* DEBUG_LOCK_CHK */
16};
17
18void mutex_simple_init_chk_internal(struct mutex_simple *m,
19 const struct lock_chk_class *class,
20 enum lock_chk_flags flags);
21void mutex_simple_set_chk_flags(struct mutex_simple *m,
22 enum lock_chk_flags flags);
23void mutex_simple_reinit_chk(struct mutex_simple *m,
24 const struct lock_chk_class *class,
25 enum lock_chk_flags flags);
26void mutex_simple_lock_internal(struct mutex_simple *m,
27 const struct lock_chk_site *site);
28void mutex_simple_unlock_internal(struct mutex_simple *m,
29 const struct lock_chk_site *site);
30void mutex_simple_lock_subclass_internal(struct mutex_simple *m,
31 uint8_t subclass,
32 const struct lock_chk_site *site);
33bool mutex_simple_locked(struct mutex_simple *m);
34struct thread *mutex_simple_get_owner(struct mutex_simple *m);
35void mutex_simple_assert_held_internal(struct mutex_simple *m,
36 const struct lock_chk_site *site);
37void mutex_simple_assert_not_held_internal(struct mutex_simple *m,
38 const struct lock_chk_site *site);
39
40#ifdef DEBUG_LOCK_CHK
41
42#define MUTEX_SIMPLE_INIT_CHK(id_, class_, flags_) \
43 ((struct mutex_simple) { \
44 .owner = NULL, \
45 .waiters = \
46 { \
47 .list = LIST_HEAD_INIT((id_).waiters.list), \
48 .lock = SPINLOCK_INIT_CHK(NULL, LOCK_UNCHKD), \
49 }, \
50 .lock = SPINLOCK_INIT_CHK(NULL, LOCK_UNCHKD), \
51 .chk = LOCK_CHK_LOCK_VALUE_INIT((class_), (flags_)), \
52 })
53
54#define mutex_simple_init_chk(mtx_, class_, flags_) \
55 mutex_simple_init_chk_internal((mtx_), (class_), (flags_))
56#define mutex_simple_init_auto_internal(mtx_, flags_) \
57 do { \
58 static const struct lock_chk_class __auto_class = { \
59 .name = #mtx_, \
60 .file = __RELFILE__, \
61 .line = __LINE__, \
62 }; \
63 mutex_simple_init_chk_internal((mtx_), &__auto_class, (flags_)); \
64 } while (0)
65
66#else /* !defined(DEBUG_LOCK_CHK) */
67
68#define MUTEX_SIMPLE_INIT_CHK(id_, class_, flags_) \
69 ((struct mutex_simple) { \
70 .owner = NULL, \
71 .waiters = \
72 { \
73 .list = LIST_HEAD_INIT((id_).waiters.list), \
74 .lock = SPINLOCK_INIT_CHK(NULL, LOCK_UNCHKD), \
75 }, \
76 .lock = SPINLOCK_INIT_CHK(NULL, LOCK_UNCHKD), \
77 })
78
79#define mutex_simple_init_chk(mtx_, class_, flags_) \
80 mutex_simple_init_chk_internal((mtx_), NULL, LOCK_UNCHKD)
81#define mutex_simple_init_auto_internal(mtx_, flags_) \
82 mutex_simple_init_chk_internal((mtx_), NULL, LOCK_UNCHKD)
83
84#endif /* DEBUG_LOCK_CHK */
85
86#define MUTEX_SIMPLE_INIT(id_) \
87 MUTEX_SIMPLE_INIT_CHK((id_), NULL, LOCK_CHKD_FULL)
88#define MUTEX_SIMPLE_DEFINE(id) struct mutex_simple id = MUTEX_SIMPLE_INIT(id)
89#define MUTEX_SIMPLE_DEFINE_CHK(id, class_, flags_) \
90 struct mutex_simple id = MUTEX_SIMPLE_INIT_CHK((id), (class_), (flags_))
91
92#define mutex_simple_init_1(mtx_) \
93 mutex_simple_init_auto_internal((mtx_), LOCK_CHKD_FULL)
94#define mutex_simple_init_2(mtx_, flags_) \
95 mutex_simple_init_auto_internal((mtx_), (flags_))
96#define mutex_simple_init(...) \
97 _DISPATCH(mutex_simple_init, PP_NARG(__VA_ARGS__))(__VA_ARGS__)
98
99#define mutex_simple_lock(m_) \
100 mutex_simple_lock_internal((m_), LOCK_CHK_SITE_HERE())
101#define mutex_simple_unlock(m_) \
102 mutex_simple_unlock_internal((m_), LOCK_CHK_SITE_HERE())
103#define mutex_simple_lock_subclass(m_, subclass_) \
104 mutex_simple_lock_subclass_internal((m_), (subclass_), LOCK_CHK_SITE_HERE())
105
106#define MUTEX_SIMPLE_ASSERT_HELD(m) \
107 mutex_simple_assert_held_internal((m), LOCK_CHK_SITE_HERE())
108#define MUTEX_SIMPLE_ASSERT_NOT_HELD(m) \
109 mutex_simple_assert_not_held_internal((m), LOCK_CHK_SITE_HERE())
110