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