1 // Copyright 2016 The Fuchsia Authors
2 // Copyright (c) 2014 Travis Geiselbrecht
3 //
4 // Use of this source code is governed by a MIT-style
5 // license that can be found in the LICENSE file or at
6 // https://opensource.org/licenses/MIT
7
8 #pragma once
9
10 #include <arch/arch_ops.h>
11 #include <arch/spinlock.h>
12 #include <zircon/compiler.h>
13 #include <zircon/thread_annotations.h>
14
15 __BEGIN_CDECLS
16
17 /* returns true if |lock| is held by the current CPU;
18 * interrupts should be disabled before calling */
spin_lock_held(spin_lock_t * lock)19 static inline bool spin_lock_held(spin_lock_t* lock) {
20 return arch_spin_lock_held(lock);
21 }
22
23 // interrupts should already be disabled
spin_lock(spin_lock_t * lock)24 static inline void spin_lock(spin_lock_t* lock) TA_ACQ(lock) {
25 DEBUG_ASSERT(arch_ints_disabled());
26 DEBUG_ASSERT(!spin_lock_held(lock));
27 arch_spin_lock(lock);
28 }
29
30 // Returns 0 on success, non-0 on failure
spin_trylock(spin_lock_t * lock)31 static inline int spin_trylock(spin_lock_t* lock) TA_TRY_ACQ(false, lock) {
32 return arch_spin_trylock(lock);
33 }
34
35 // interrupts should already be disabled
spin_unlock(spin_lock_t * lock)36 static inline void spin_unlock(spin_lock_t* lock) TA_REL(lock) {
37 arch_spin_unlock(lock);
38 }
39
spin_lock_init(spin_lock_t * lock)40 static inline void spin_lock_init(spin_lock_t* lock) {
41 arch_spin_lock_init(lock);
42 }
43
44 // which cpu currently holds the spin lock
45 // returns UINT_MAX if not held
spin_lock_holder_cpu(spin_lock_t * lock)46 static inline uint spin_lock_holder_cpu(spin_lock_t* lock) {
47 return arch_spin_lock_holder_cpu(lock);
48 }
49
50 // spin lock irq save flags:
51
52 // Possible future flags:
53 // SPIN_LOCK_FLAG_PMR_MASK = 0x000000ff
54 // SPIN_LOCK_FLAG_PREEMPTION = 0x00000100
55 // SPIN_LOCK_FLAG_SET_PMR = 0x00000200
56
57 // Generic flags
58 #define SPIN_LOCK_FLAG_INTERRUPTS ARCH_DEFAULT_SPIN_LOCK_FLAG_INTERRUPTS
59
60 // same as spin lock, but save disable and save interrupt state first
spin_lock_save(spin_lock_t * lock,spin_lock_saved_state_t * statep,spin_lock_save_flags_t flags)61 static inline void spin_lock_save(spin_lock_t* lock, spin_lock_saved_state_t* statep,
62 spin_lock_save_flags_t flags) TA_ACQ(lock) {
63 arch_interrupt_save(statep, flags);
64 spin_lock(lock);
65 }
66
67 // restore interrupt state before unlocking
spin_unlock_restore(spin_lock_t * lock,spin_lock_saved_state_t old_state,spin_lock_save_flags_t flags)68 static inline void spin_unlock_restore(spin_lock_t* lock, spin_lock_saved_state_t old_state,
69 spin_lock_save_flags_t flags) TA_REL(lock) {
70 spin_unlock(lock);
71 arch_interrupt_restore(old_state, flags);
72 }
73
74 // hand(ier) routines
75 #define spin_lock_irqsave(lock, statep) spin_lock_save(lock, &(statep), SPIN_LOCK_FLAG_INTERRUPTS)
76 #define spin_unlock_irqrestore(lock, statep) spin_unlock_restore(lock, statep, SPIN_LOCK_FLAG_INTERRUPTS)
77
78 __END_CDECLS
79
80 #ifdef __cplusplus
81
82 #include <lockdep/lock_policy.h>
83 #include <lockdep/lock_traits.h>
84
85 class TA_CAP("mutex") SpinLock {
86 public:
SpinLock()87 SpinLock() { spin_lock_init(&spinlock_); }
Acquire()88 void Acquire() TA_ACQ() { spin_lock(&spinlock_); }
TryAcquire()89 bool TryAcquire() TA_TRY_ACQ(false) { return spin_trylock(&spinlock_); }
Release()90 void Release() TA_REL() { spin_unlock(&spinlock_); }
IsHeld()91 bool IsHeld() { return spin_lock_held(&spinlock_); }
92
93 void AcquireIrqSave(spin_lock_saved_state_t& state,
94 spin_lock_save_flags_t flags = SPIN_LOCK_FLAG_INTERRUPTS)
TA_ACQ()95 TA_ACQ() {
96 spin_lock_save(&spinlock_, &state, flags);
97 }
98
99 void ReleaseIrqRestore(spin_lock_saved_state_t state,
100 spin_lock_save_flags_t flags = SPIN_LOCK_FLAG_INTERRUPTS)
TA_REL()101 TA_REL() {
102 spin_unlock_restore(&spinlock_, state, flags);
103 }
104
GetInternal()105 spin_lock_t* GetInternal() TA_RET_CAP(spinlock_) { return &spinlock_; }
106
107 // suppress default constructors
108 SpinLock(const SpinLock& am) = delete;
109 SpinLock& operator=(const SpinLock& am) = delete;
110 SpinLock(SpinLock&& c) = delete;
111 SpinLock& operator=(SpinLock&& c) = delete;
112
113 private:
114 spin_lock_t spinlock_;
115 };
116
117 // Declares a SpinLock member of the struct or class |containing_type|
118 // with instrumentation for runtime lock validation.
119 //
120 // Example usage:
121 //
122 // struct MyType {
123 // DECLARE_SPINLOCK(MyType) lock;
124 // };
125 //
126 #define DECLARE_SPINLOCK(containing_type) \
127 LOCK_DEP_INSTRUMENT(containing_type, SpinLock)
128
129 // Declares a singleton SpinLock with the name |name|.
130 //
131 // Example usage:
132 //
133 // DECLARE_SINGLETON_SPINLOCK(MyGlobalLock [, LockFlags]);
134 //
135 #define DECLARE_SINGLETON_SPINLOCK(name, ...) \
136 LOCK_DEP_SINGLETON_LOCK(name, SpinLock, ##__VA_ARGS__)
137
138 //
139 // Configure lockdep flags and wrappers for SpinLock.
140 //
141
142 // Configure lockdep to check irq-safety rules for SpinLock.
143 LOCK_DEP_TRAITS(SpinLock, lockdep::LockFlagsIrqSafe);
144
145 // Configure lockdep to check irq-safety rules for spin_lock_t.
146 LOCK_DEP_TRAITS(spin_lock_t, lockdep::LockFlagsIrqSafe);
147
148 // Option tag for acquiring a SpinLock WITHOUT saving irq state.
149 struct NoIrqSave {};
150
151 // Option tag for acquiring a SpinLock WITH saving irq state.
152 struct IrqSave {};
153
154 // Option tag for try-acquiring a SpinLock WITHOUT saving irq state.
155 struct TryLockNoIrqSave {};
156
157 // Base type for spinlock policies that do not save irq state.
158 template <typename LockType>
159 struct NoIrqSavePolicy;
160
161 // Lock policy for acquiring a SpinLock WITHOUT saving irq state.
162 template <>
163 struct NoIrqSavePolicy<SpinLock> {
164 // No extra state required when not saving irq state.
165 struct State {};
166
167 static bool Acquire(SpinLock* lock, State*) TA_ACQ(lock) {
168 lock->Acquire();
169 return true;
170 }
171 static void Release(SpinLock* lock, State*) TA_REL(lock) {
172 lock->Release();
173 }
174 };
175
176 // Configure Guard<SpinLock, NoIrqSave> to use the above policy to acquire and
177 // release a SpinLock.
178 LOCK_DEP_POLICY_OPTION(SpinLock, NoIrqSave, NoIrqSavePolicy<SpinLock>);
179
180 // Lock policy for acquiring a SpinLock WITHOUT saving irq state.
181 template <>
182 struct NoIrqSavePolicy<spin_lock_t> {
183 // No extra state required when not saving irq state.
184 struct State {};
185
186 static bool Acquire(spin_lock_t* lock, State*) TA_ACQ(lock) {
187 spin_lock(lock);
188 return true;
189 }
190 static void Release(spin_lock_t* lock, State*) TA_REL(lock) {
191 spin_unlock(lock);
192 }
193 };
194
195 // Configure Guard<spin_lock_t, NoIrqSave> to use the above policy to acquire and
196 // release a spin_lock_t.
197 LOCK_DEP_POLICY_OPTION(spin_lock_t, NoIrqSave, NoIrqSavePolicy<spin_lock_t>);
198
199 // Base type for spinlock policies that save irq state.
200 template <typename LockType>
201 struct IrqSavePolicy;
202
203 // Lock policy for acquiring a SpinLock WITH saving irq state.
204 template <>
205 struct IrqSavePolicy<SpinLock> {
206 // State and flags required to save irq state.
207 struct State {
208 // This constructor receives the extra arguments passed to Guard when
209 // locking an instrumented SpinLock like this:
210 //
211 // Guard<SpinLock, IrqSave> guard{&a_spin_lock, |flags|};
212 //
213 // The extra argument to Guard is optional because this constructor has
214 // a default value.
215 State(spin_lock_save_flags_t flags = SPIN_LOCK_FLAG_INTERRUPTS)
216 : flags{flags} {}
217
218 spin_lock_save_flags_t flags;
219 spin_lock_saved_state_t state;
220 };
221
222 static bool Acquire(SpinLock* lock, State* state) TA_ACQ(lock) {
223 lock->AcquireIrqSave(state->state, state->flags);
224 return true;
225 }
226 static void Release(SpinLock* lock, State* state) TA_REL(lock) {
227 lock->ReleaseIrqRestore(state->state, state->flags);
228 }
229 };
230
231 // Configure Guard<SpinLock, IrqSave> to use the above policy to acquire and
232 // release a SpinLock.
233 LOCK_DEP_POLICY_OPTION(SpinLock, IrqSave, IrqSavePolicy<SpinLock>);
234
235 // Lock policy for acquiring a spin_lock_t WITH saving irq state.
236 template <>
237 struct IrqSavePolicy<spin_lock_t> {
238 // State and flags required to save irq state.
239 struct State {
240 // This constructor receives the extra arguments passed to Guard when
241 // locking an instrumented spin_lock_t like this:
242 //
243 // Guard<spin_lock_t, IrqSave> guard{&a_spin_lock, |flags|};
244 //
245 // The extra argument to Guard is optional because this constructor has
246 // a default value.
247 State(spin_lock_save_flags_t flags = SPIN_LOCK_FLAG_INTERRUPTS)
248 : flags{flags} {}
249
250 spin_lock_save_flags_t flags;
251 spin_lock_saved_state_t state;
252 };
253
254 static bool Acquire(spin_lock_t* lock, State* state) TA_ACQ(lock) {
255 spin_lock_save(lock, &state->state, state->flags);
256 return true;
257 }
258 static void Release(spin_lock_t* lock, State* state) TA_REL(lock) {
259 spin_unlock_restore(lock, state->state, state->flags);
260 }
261 };
262
263 // Configure Guard<SpinLock, IrqSave> to use the above policy to acquire and
264 // release a SpinLock.
265 LOCK_DEP_POLICY_OPTION(spin_lock_t, IrqSave, IrqSavePolicy<spin_lock_t>);
266
267 // Base type for spinlock policies that try-acquire without saving irq state.
268 template <typename LockType>
269 struct TryLockNoIrqSavePolicy;
270
271 // Lock policy for try-acquiring a SpinLock WITHOUT saving irq state.
272 template <>
273 struct TryLockNoIrqSavePolicy<SpinLock> {
274 // No extra state required when not saving irq state.
275 struct State {};
276
277 static bool Acquire(SpinLock* lock, State*) TA_TRY_ACQ(true, lock) {
278 const bool failed = lock->TryAcquire();
279 return !failed; // Guard uses true to indicate success.
280 }
281 static void Release(SpinLock* lock, State*) TA_REL(lock) {
282 lock->Release();
283 }
284 };
285
286 // Configure Guard<SpinLock, TryLockNoIrqSave> to use the above policy to
287 // acquire and release a SpinLock.
288 LOCK_DEP_POLICY_OPTION(SpinLock, TryLockNoIrqSave,
289 TryLockNoIrqSavePolicy<SpinLock>);
290
291 // Lock policy for try-acquiring a spin_lock_t WITHOUT saving irq state.
292 template <>
293 struct TryLockNoIrqSavePolicy<spin_lock_t> {
294 // No extra state required when not saving irq state.
295 struct State {};
296
297 static bool Acquire(spin_lock_t* lock, State*) TA_TRY_ACQ(true, lock) {
298 const bool failed = spin_trylock(lock);
299 return !failed; // Guard uses true to indicate success.
300 }
301 static void Release(spin_lock_t* lock, State*) TA_REL(lock) {
302 spin_unlock(lock);
303 }
304 };
305
306 // Configure Guard<spin_lock_t, TryLockNoIrqSave> to use the above policy to
307 // acquire and release a spin_lock_t.
308 LOCK_DEP_POLICY_OPTION(spin_lock_t, TryLockNoIrqSave,
309 TryLockNoIrqSavePolicy<spin_lock_t>);
310
311 #endif // ifdef __cplusplus
312