1 /*
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/spinlock.h>
11 #include <lk/compiler.h>
12
13 __BEGIN_CDECLS
14
15 /* interrupts should already be disabled */
spin_lock(spin_lock_t * lock)16 static inline void spin_lock(spin_lock_t *lock) {
17 arch_spin_lock(lock);
18 }
19
20 /* Returns 0 on success, non-0 on failure */
spin_trylock(spin_lock_t * lock)21 static inline int spin_trylock(spin_lock_t *lock) {
22 return arch_spin_trylock(lock);
23 }
24
25 /* interrupts should already be disabled */
spin_unlock(spin_lock_t * lock)26 static inline void spin_unlock(spin_lock_t *lock) {
27 arch_spin_unlock(lock);
28 }
29
spin_lock_init(spin_lock_t * lock)30 static inline void spin_lock_init(spin_lock_t *lock) {
31 arch_spin_lock_init(lock);
32 }
33
spin_lock_held(spin_lock_t * lock)34 static inline bool spin_lock_held(spin_lock_t *lock) {
35 return arch_spin_lock_held(lock);
36 }
37
38 /* spin lock irq save flags: */
39
40 /* Possible future flags:
41 * SPIN_LOCK_FLAG_PMR_MASK = 0x000000ff
42 * SPIN_LOCK_FLAG_PREEMPTION = 0x00000100
43 * SPIN_LOCK_FLAG_SET_PMR = 0x00000200
44 */
45
46 /* Generic flags */
47 #define SPIN_LOCK_FLAG_INTERRUPTS ARCH_DEFAULT_SPIN_LOCK_FLAG_INTERRUPTS
48
49 /* 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)50 static inline void spin_lock_save(
51 spin_lock_t *lock,
52 spin_lock_saved_state_t *statep,
53 spin_lock_save_flags_t flags) {
54 arch_interrupt_save(statep, flags);
55 spin_lock(lock);
56 }
57
58 /* 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)59 static inline void spin_unlock_restore(
60 spin_lock_t *lock,
61 spin_lock_saved_state_t old_state,
62 spin_lock_save_flags_t flags) {
63 spin_unlock(lock);
64 arch_interrupt_restore(old_state, flags);
65 }
66
67 /* hand(ier) routines */
68 #define spin_lock_irqsave(lock, statep) spin_lock_save(lock, &(statep), SPIN_LOCK_FLAG_INTERRUPTS)
69 #define spin_unlock_irqrestore(lock, statep) spin_unlock_restore(lock, statep, SPIN_LOCK_FLAG_INTERRUPTS)
70
71 __END_CDECLS
72
73 #ifdef __cplusplus
74
75 #include <lk/cpp.h>
76 #include <assert.h>
77
78 // C++ wrapper around a C spinlock_t
79 class SpinLock {
80 public:
81 constexpr SpinLock() = default;
~SpinLock()82 ~SpinLock() { DEBUG_ASSERT(!is_held()); }
83
lock()84 void lock() { spin_lock(&lock_); }
trylock()85 int trylock() { return spin_trylock(&lock_); }
unlock()86 void unlock() { spin_unlock(&lock_); }
is_held()87 bool is_held() { return spin_lock_held(&lock_); }
88
lock_irqsave(spin_lock_saved_state_t * state)89 void lock_irqsave(spin_lock_saved_state_t *state) {
90 spin_lock_save(&lock_, state, SPIN_LOCK_FLAG_INTERRUPTS);
91 }
92
unlock_irqrestore(spin_lock_saved_state_t state)93 void unlock_irqrestore(spin_lock_saved_state_t state) {
94 spin_unlock_restore(&lock_, state, SPIN_LOCK_FLAG_INTERRUPTS);
95 }
96
97 // suppress default constructors
98 DISALLOW_COPY_ASSIGN_AND_MOVE(SpinLock);
99
100 private:
101 spin_lock_t lock_ = SPIN_LOCK_INITIAL_VALUE;
102
103 // friend classes to get to the inner lock
104 friend class AutoSpinLock;
105 friend class AutoSpinLockNoIrqSave;
106 };
107
108 // RAII wrappers for a spinlock, with and without IRQ Save
109 class AutoSpinLock {
110 public:
AutoSpinLock(spin_lock_t * lock)111 explicit AutoSpinLock(spin_lock_t *lock) : lock_(lock) { spin_lock_irqsave(lock_, state_); }
AutoSpinLock(SpinLock * lock)112 explicit AutoSpinLock(SpinLock *lock) : AutoSpinLock(&lock->lock_) {}
~AutoSpinLock()113 ~AutoSpinLock() { release(); }
114
release()115 void release() {
116 if (likely(lock_)) {
117 spin_unlock_irqrestore(lock_, state_);
118 lock_ = nullptr;
119 }
120 }
121
122 // suppress default constructors
123 DISALLOW_COPY_ASSIGN_AND_MOVE(AutoSpinLock);
124
125 private:
126 spin_lock_t *lock_;
127 spin_lock_saved_state_t state_;
128 };
129
130 class AutoSpinLockNoIrqSave {
131 public:
AutoSpinLockNoIrqSave(spin_lock_t * lock)132 explicit AutoSpinLockNoIrqSave(spin_lock_t *lock) : lock_(lock) { spin_lock(lock_); }
AutoSpinLockNoIrqSave(SpinLock * lock)133 explicit AutoSpinLockNoIrqSave(SpinLock *lock) : AutoSpinLockNoIrqSave(&lock->lock_) {}
~AutoSpinLockNoIrqSave()134 ~AutoSpinLockNoIrqSave() { release(); }
135
release()136 void release() {
137 if (likely(lock_)) {
138 spin_unlock(lock_);
139 lock_ = nullptr;
140 }
141 }
142
143 // suppress default constructors
144 DISALLOW_COPY_ASSIGN_AND_MOVE(AutoSpinLockNoIrqSave);
145
146 private:
147 spin_lock_t *lock_;
148 };
149
150 #endif // __cplusplus
151