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
12class SpinLocker;
13struct 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
71should_inline bool spinlock_is_locked(const spinlock_t *lock)
72{
73 return lock->flag;
74}
75
76typedef 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
87should_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
101should_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
114should_inline bool recursive_spinlock_is_locked(recursive_spinlock_t *lock)
115{
116 return lock->lock.flag;
117}
118
119class [[nodiscard("don't discard")]] SpinUnlocker
120{
121 public:
122 explicit SpinUnlocker(spinlock_t *lock) : m_lock(lock)
123 {
124 spinlock_release(m_lock);
125 }
126
127 SpinUnlocker(const SpinUnlocker &) = delete;
128 SpinUnlocker &operator=(const SpinUnlocker &) = delete;
129 SpinUnlocker(SpinUnlocker &&) = delete;
130 SpinUnlocker &operator=(SpinUnlocker &&) = delete;
131
132 void discard()
133 {
134 m_lock = nullptr;
135 }
136
137 ~SpinUnlocker()
138 {
139 if (m_lock)
140 spinlock_acquire(m_lock);
141 }
142
143 private:
144 spinlock_t *m_lock;
145};
146
147class [[nodiscard("don't discard")]] SpinLocker
148{
149 public:
150 explicit SpinLocker(spinlock_t *lock) : m_lock(lock)
151 {
152 spinlock_acquire(m_lock);
153 }
154
155 SpinLocker(const SpinLocker &) = delete;
156 SpinLocker &operator=(const SpinLocker &) = delete;
157 SpinLocker(SpinLocker &&) = delete;
158 SpinLocker &operator=(SpinLocker &&) = delete;
159
160 void discard()
161 {
162 m_lock = nullptr;
163 }
164
165 ~SpinLocker()
166 {
167 if (m_lock)
168 spinlock_release(m_lock);
169 }
170
171 SpinUnlocker UnlockTemporarily()
172 {
173 return SpinUnlocker(m_lock);
174 }
175
176 private:
177 spinlock_t *m_lock;
178};
179
180inline SpinLocker spinlock_t::lock()
181{
182 return SpinLocker(this);
183}
184