1 | // SPDX-License-Identifier: GPL-3.0-or-later |
---|---|
2 | |
3 | #pragma once |
4 | |
5 | #include "mos/platform/platform_defs.hpp" |
6 | |
7 | #include <mos/mos_global.h> |
8 | #include <mos/types.hpp> |
9 | |
10 | #define barrier() MOS_PLATFORM_MEMORY_BARRIER() |
11 | |
12 | class SpinLocker; |
13 | struct spinlock_t |
14 | { |
15 | bool flag = false; |
16 | #if MOS_DEBUG_FEATURE(spinlock) |
17 | const char *file = nullptr; |
18 | int line = 0; |
19 | #endif |
20 | |
21 | SpinLocker lock(); |
22 | }; |
23 | |
24 | #define spinlock_init(lock) \ |
25 | do \ |
26 | { \ |
27 | (lock)->flag = 0; \ |
28 | } while (0) |
29 | |
30 | // clang-format off |
31 | #define SPINLOCK_INIT { 0 } |
32 | // clang-format on |
33 | |
34 | #define _spinlock_real_acquire(lock) \ |
35 | do \ |
36 | { \ |
37 | barrier(); \ |
38 | while (__atomic_test_and_set(&(lock)->flag, __ATOMIC_ACQUIRE)) \ |
39 | ; \ |
40 | } while (0) |
41 | |
42 | #define _spinlock_real_release(lock) \ |
43 | do \ |
44 | { \ |
45 | __atomic_clear(&(lock)->flag, __ATOMIC_RELEASE); \ |
46 | } while (0) |
47 | |
48 | #if MOS_DEBUG_FEATURE(spinlock) |
49 | #define spinlock_acquire(lock) \ |
50 | do \ |
51 | { \ |
52 | _spinlock_real_acquire(lock); \ |
53 | (lock)->file = __FILE__; \ |
54 | (lock)->line = __LINE__; \ |
55 | } while (0) |
56 | #define spinlock_release(lock) \ |
57 | do \ |
58 | { \ |
59 | (lock)->file = NULL; \ |
60 | (lock)->line = 0; \ |
61 | _spinlock_real_release(lock); \ |
62 | } while (0) |
63 | #else |
64 | #define spinlock_acquire(lock) _spinlock_real_acquire(lock) |
65 | #define spinlock_release(lock) _spinlock_real_release(lock) |
66 | #endif |
67 | |
68 | #define spinlock_acquire_nodebug(lock) _spinlock_real_acquire(lock) |
69 | #define spinlock_release_nodebug(lock) _spinlock_real_release(lock) |
70 | |
71 | should_inline bool spinlock_is_locked(const spinlock_t *lock) |
72 | { |
73 | return lock->flag; |
74 | } |
75 | |
76 | typedef struct |
77 | { |
78 | spinlock_t lock; |
79 | void *owner; |
80 | size_t count; |
81 | } recursive_spinlock_t; |
82 | |
83 | // clang-format off |
84 | #define RECURSIVE_SPINLOCK_INIT { SPINLOCK_INIT, NULL, 0 } |
85 | // clang-format on |
86 | |
87 | should_inline void recursive_spinlock_acquire(recursive_spinlock_t *lock, void *owner) |
88 | { |
89 | if (lock->owner == owner) |
90 | { |
91 | lock->count++; |
92 | } |
93 | else |
94 | { |
95 | spinlock_acquire(&lock->lock); |
96 | lock->owner = owner; |
97 | lock->count = 1; |
98 | } |
99 | } |
100 | |
101 | should_inline void recursive_spinlock_release(recursive_spinlock_t *lock, void *owner) |
102 | { |
103 | if (lock->owner == owner) |
104 | { |
105 | lock->count--; |
106 | if (lock->count == 0) |
107 | { |
108 | lock->owner = NULL; |
109 | spinlock_release(&lock->lock); |
110 | } |
111 | } |
112 | } |
113 | |
114 | should_inline bool recursive_spinlock_is_locked(recursive_spinlock_t *lock) |
115 | { |
116 | return lock->lock.flag; |
117 | } |
118 | |
119 | class [[nodiscard("don't discard")]] SpinLocker |
120 | { |
121 | public: |
122 | SpinLocker(spinlock_t *lock) : m_lock(lock) |
123 | { |
124 | spinlock_acquire(m_lock); |
125 | } |
126 | |
127 | SpinLocker(const SpinLocker &) = delete; |
128 | SpinLocker &operator=(const SpinLocker &) = delete; |
129 | |
130 | // move constructor |
131 | SpinLocker(SpinLocker &&other) : m_lock(other.m_lock) |
132 | { |
133 | other.m_lock = nullptr; |
134 | } |
135 | |
136 | // move assignment |
137 | SpinLocker &operator=(SpinLocker &&other) |
138 | { |
139 | if (this != &other) |
140 | { |
141 | m_lock = other.m_lock; |
142 | other.m_lock = nullptr; |
143 | } |
144 | return *this; |
145 | } |
146 | |
147 | ~SpinLocker() |
148 | { |
149 | if (m_lock) |
150 | spinlock_release(m_lock); |
151 | } |
152 | |
153 | private: |
154 | spinlock_t *m_lock; |
155 | }; |
156 | |
157 | inline SpinLocker spinlock_t::lock() |
158 | { |
159 | return SpinLocker(this); |
160 | } |
161 |