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")]] 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
157inline SpinLocker spinlock_t::lock()
158{
159 return SpinLocker(this);
160}
161