libctru v2.6.2
Loading...
Searching...
No Matches
synchronization.h
Go to the documentation of this file.
1/**
2 * @file synchronization.h
3 * @brief Provides synchronization locks.
4 */
5#pragma once
6#include <sys/lock.h>
7#include <3ds/svc.h>
8
9/// A light lock.
10typedef _LOCK_T LightLock;
11
12/// A recursive lock.
13typedef _LOCK_RECURSIVE_T RecursiveLock;
14
15/// A condition variable.
16typedef s32 CondVar;
17
18/// A light event.
19typedef struct
20{
21 s32 state; ///< State of the event: -2=cleared sticky, -1=cleared oneshot, 0=signaled oneshot, 1=signaled sticky
22 LightLock lock; ///< Lock used for sticky timer operation
24
25/// A light semaphore.
26typedef struct
27{
28 s32 current_count; ///< The current release count of the semaphore
29 s16 num_threads_acq; ///< Number of threads concurrently acquiring the semaphore
30 s16 max_count; ///< The maximum release count of the semaphore
32
33/// Performs a Data Synchronization Barrier operation.
34static inline void __dsb(void)
35{
36 __asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 4" :: [val] "r" (0) : "memory");
37}
38
39/// Performs a Data Memory Barrier operation.
40static inline void __dmb(void)
41{
42 __asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 5" :: [val] "r" (0) : "memory");
43}
44
45/// Performs an Instruction Synchronization Barrier (officially "flush prefetch buffer") operation.
46static inline void __isb(void)
47{
48 __asm__ __volatile__("mcr p15, 0, %[val], c7, c5, 4" :: [val] "r" (0) : "memory");
49}
50
51/// Performs a clrex operation.
52static inline void __clrex(void)
53{
54 __asm__ __volatile__("clrex" ::: "memory");
55}
56
57/**
58 * @brief Performs a ldrex operation.
59 * @param addr Address to perform the operation on.
60 * @return The resulting value.
61 */
62static inline s32 __ldrex(s32* addr)
63{
64 s32 val;
65 __asm__ __volatile__("ldrex %[val], %[addr]" : [val] "=r" (val) : [addr] "Q" (*addr));
66 return val;
67}
68
69/**
70 * @brief Performs a strex operation.
71 * @param addr Address to perform the operation on.
72 * @param val Value to store.
73 * @return Whether the operation was successful.
74 */
75static inline bool __strex(s32* addr, s32 val)
76{
77 bool res;
78 __asm__ __volatile__("strex %[res], %[val], %[addr]" : [res] "=&r" (res) : [val] "r" (val), [addr] "Q" (*addr));
79 return res;
80}
81
82/**
83 * @brief Performs a ldrexh operation.
84 * @param addr Address to perform the operation on.
85 * @return The resulting value.
86 */
87static inline u16 __ldrexh(u16* addr)
88{
89 u16 val;
90 __asm__ __volatile__("ldrexh %[val], %[addr]" : [val] "=r" (val) : [addr] "Q" (*addr));
91 return val;
92}
93
94/**
95 * @brief Performs a strexh operation.
96 * @param addr Address to perform the operation on.
97 * @param val Value to store.
98 * @return Whether the operation was successful.
99 */
100static inline bool __strexh(u16* addr, u16 val)
101{
102 bool res;
103 __asm__ __volatile__("strexh %[res], %[val], %[addr]" : [res] "=&r" (res) : [val] "r" (val), [addr] "Q" (*addr));
104 return res;
105}
106
107/**
108 * @brief Performs a ldrexb operation.
109 * @param addr Address to perform the operation on.
110 * @return The resulting value.
111 */
112static inline u8 __ldrexb(u8* addr)
113{
114 u8 val;
115 __asm__ __volatile__("ldrexb %[val], %[addr]" : [val] "=r" (val) : [addr] "Q" (*addr));
116 return val;
117}
118
119/**
120 * @brief Performs a strexb operation.
121 * @param addr Address to perform the operation on.
122 * @param val Value to store.
123 * @return Whether the operation was successful.
124 */
125static inline bool __strexb(u8* addr, u8 val)
126{
127 bool res;
128 __asm__ __volatile__("strexb %[res], %[val], %[addr]" : [res] "=&r" (res) : [val] "r" (val), [addr] "Q" (*addr));
129 return res;
130}
131
132/// Performs an atomic pre-increment operation.
133#define AtomicIncrement(ptr) __atomic_add_fetch((u32*)(ptr), 1, __ATOMIC_SEQ_CST)
134/// Performs an atomic pre-decrement operation.
135#define AtomicDecrement(ptr) __atomic_sub_fetch((u32*)(ptr), 1, __ATOMIC_SEQ_CST)
136/// Performs an atomic post-increment operation.
137#define AtomicPostIncrement(ptr) __atomic_fetch_add((u32*)(ptr), 1, __ATOMIC_SEQ_CST)
138/// Performs an atomic post-decrement operation.
139#define AtomicPostDecrement(ptr) __atomic_fetch_sub((u32*)(ptr), 1, __ATOMIC_SEQ_CST)
140/// Performs an atomic swap operation.
141#define AtomicSwap(ptr, value) __atomic_exchange_n((u32*)(ptr), (value), __ATOMIC_SEQ_CST)
142
143/**
144 * @brief Function used to implement user-mode synchronization primitives.
145 * @param addr Pointer to a signed 32-bit value whose address will be used to identify waiting threads.
146 * @param type Type of action to be performed by the arbiter
147 * @param value Number of threads to signal if using @ref ARBITRATION_SIGNAL, or the value used for comparison.
148 *
149 * This will perform an arbitration based on #type. The comparisons are done between #value and the value at the address #addr.
150 *
151 * @code
152 * s32 val=0;
153 * // Does *nothing* since val >= 0
154 * syncArbitrateAddress(&val,ARBITRATION_WAIT_IF_LESS_THAN,0);
155 * @endcode
156 *
157 * @note Usage of this function entails an implicit Data Memory Barrier (dmb).
158 */
160
161/**
162 * @brief Function used to implement user-mode synchronization primitives (with timeout).
163 * @param addr Pointer to a signed 32-bit value whose address will be used to identify waiting threads.
164 * @param type Type of action to be performed by the arbiter (must use \ref ARBITRATION_WAIT_IF_LESS_THAN_TIMEOUT or \ref ARBITRATION_DECREMENT_AND_WAIT_IF_LESS_THAN_TIMEOUT)
165 * @param value Number of threads to signal if using @ref ARBITRATION_SIGNAL, or the value used for comparison.
166 *
167 * This will perform an arbitration based on #type. The comparisons are done between #value and the value at the address #addr.
168 *
169 * @code
170 * s32 val=0;
171 * // Thread will wait for a signal or wake up after 10000000 nanoseconds because val < 1.
172 * syncArbitrateAddressWithTimeout(&val,ARBITRATION_WAIT_IF_LESS_THAN_TIMEOUT,1,10000000LL);
173 * @endcode
174 *
175 * @note Usage of this function entails an implicit Data Memory Barrier (dmb).
176 */
178
179/**
180 * @brief Initializes a light lock.
181 * @param lock Pointer to the lock.
182 */
184
185/**
186 * @brief Locks a light lock.
187 * @param lock Pointer to the lock.
188 */
190
191/**
192 * @brief Attempts to lock a light lock.
193 * @param lock Pointer to the lock.
194 * @return Zero on success, non-zero on failure.
195 */
197
198/**
199 * @brief Unlocks a light lock.
200 * @param lock Pointer to the lock.
201 */
203
204/**
205 * @brief Initializes a recursive lock.
206 * @param lock Pointer to the lock.
207 */
209
210/**
211 * @brief Locks a recursive lock.
212 * @param lock Pointer to the lock.
213 */
215
216/**
217 * @brief Attempts to lock a recursive lock.
218 * @param lock Pointer to the lock.
219 * @return Zero on success, non-zero on failure.
220 */
222
223/**
224 * @brief Unlocks a recursive lock.
225 * @param lock Pointer to the lock.
226 */
228
229/**
230 * @brief Initializes a condition variable.
231 * @param cv Pointer to the condition variable.
232 */
234
235/**
236 * @brief Waits on a condition variable.
237 * @param cv Pointer to the condition variable.
238 * @param lock Pointer to the lock to atomically unlock/relock during the wait.
239 */
241
242/**
243 * @brief Waits on a condition variable with a timeout.
244 * @param cv Pointer to the condition variable.
245 * @param lock Pointer to the lock to atomically unlock/relock during the wait.
246 * @param timeout_ns Timeout in nanoseconds.
247 * @return Zero on success, non-zero on failure.
248 */
249int CondVar_WaitTimeout(CondVar* cv, LightLock* lock, s64 timeout_ns);
250
251/**
252 * @brief Wakes up threads waiting on a condition variable.
253 * @param cv Pointer to the condition variable.
254 * @param num_threads Maximum number of threads to wake up (or \ref ARBITRATION_SIGNAL_ALL to wake them all).
255 */
256void CondVar_WakeUp(CondVar* cv, s32 num_threads);
257
258/**
259 * @brief Wakes up a single thread waiting on a condition variable.
260 * @param cv Pointer to the condition variable.
261 */
262static inline void CondVar_Signal(CondVar* cv)
263{
264 CondVar_WakeUp(cv, 1);
265}
266
267/**
268 * @brief Wakes up all threads waiting on a condition variable.
269 * @param cv Pointer to the condition variable.
270 */
271static inline void CondVar_Broadcast(CondVar* cv)
272{
274}
275
276/**
277 * @brief Initializes a light event.
278 * @param event Pointer to the event.
279 * @param reset_type Type of reset the event uses (RESET_ONESHOT/RESET_STICKY).
280 */
281void LightEvent_Init(LightEvent* event, ResetType reset_type);
282
283/**
284 * @brief Clears a light event.
285 * @param event Pointer to the event.
286 */
288
289/**
290 * @brief Wakes up threads waiting on a sticky light event without signaling it. If the event had been signaled before, it is cleared instead.
291 * @param event Pointer to the event.
292 */
294
295/**
296 * @brief Signals a light event, waking up threads waiting on it.
297 * @param event Pointer to the event.
298 */
300
301/**
302 * @brief Attempts to wait on a light event.
303 * @param event Pointer to the event.
304 * @return Non-zero if the event was signaled, zero otherwise.
305 */
307
308/**
309 * @brief Waits on a light event.
310 * @param event Pointer to the event.
311 */
313
314/**
315 * @brief Waits on a light event until either the event is signaled or the timeout is reached.
316 * @param event Pointer to the event.
317 * @param timeout_ns Timeout in nanoseconds.
318 * @return Non-zero on timeout, zero otherwise.
319 */
320int LightEvent_WaitTimeout(LightEvent* event, s64 timeout_ns);
321
322/**
323 * @brief Initializes a light semaphore.
324 * @param event Pointer to the semaphore.
325 * @param max_count Initial count of the semaphore.
326 * @param max_count Maximum count of the semaphore.
327 */
328void LightSemaphore_Init(LightSemaphore* semaphore, s16 initial_count, s16 max_count);
329
330/**
331 * @brief Acquires a light semaphore.
332 * @param semaphore Pointer to the semaphore.
333 * @param count Acquire count
334 */
336
337/**
338 * @brief Attempts to acquire a light semaphore.
339 * @param semaphore Pointer to the semaphore.
340 * @param count Acquire count
341 * @return Zero on success, non-zero on failure
342 */
344
345/**
346 * @brief Releases a light semaphore.
347 * @param semaphore Pointer to the semaphore.
348 * @param count Release count
349 */
A light event.
Definition synchronization.h:20
LightLock lock
Lock used for sticky timer operation.
Definition synchronization.h:22
s32 state
State of the event: -2=cleared sticky, -1=cleared oneshot, 0=signaled oneshot, 1=signaled sticky.
Definition synchronization.h:21
A light semaphore.
Definition synchronization.h:27
s32 current_count
The current release count of the semaphore.
Definition synchronization.h:28
s16 num_threads_acq
Number of threads concurrently acquiring the semaphore.
Definition synchronization.h:29
s16 max_count
The maximum release count of the semaphore.
Definition synchronization.h:30
Syscall wrappers.
ArbitrationType
Arbitration modes.
Definition svc.h:88
#define ARBITRATION_SIGNAL_ALL
Special value to signal all the threads.
Definition svc.h:97
ResetType
Reset types (for use with events and timers)
Definition svc.h:105
void LightEvent_Wait(LightEvent *event)
Waits on a light event.
_LOCK_T LightLock
A light lock.
Definition synchronization.h:10
Result syncArbitrateAddress(s32 *addr, ArbitrationType type, s32 value)
Function used to implement user-mode synchronization primitives.
int LightLock_TryLock(LightLock *lock)
Attempts to lock a light lock.
void RecursiveLock_Init(RecursiveLock *lock)
Initializes a recursive lock.
static bool __strexh(u16 *addr, u16 val)
Performs a strexh operation.
Definition synchronization.h:100
void LightEvent_Init(LightEvent *event, ResetType reset_type)
Initializes a light event.
int LightEvent_TryWait(LightEvent *event)
Attempts to wait on a light event.
void LightEvent_Pulse(LightEvent *event)
Wakes up threads waiting on a sticky light event without signaling it.
Result syncArbitrateAddressWithTimeout(s32 *addr, ArbitrationType type, s32 value, s64 timeout_ns)
Function used to implement user-mode synchronization primitives (with timeout).
static void CondVar_Signal(CondVar *cv)
Wakes up a single thread waiting on a condition variable.
Definition synchronization.h:262
static u8 __ldrexb(u8 *addr)
Performs a ldrexb operation.
Definition synchronization.h:112
void LightSemaphore_Release(LightSemaphore *semaphore, s32 count)
Releases a light semaphore.
void CondVar_WakeUp(CondVar *cv, s32 num_threads)
Wakes up threads waiting on a condition variable.
int LightSemaphore_TryAcquire(LightSemaphore *semaphore, s32 count)
Attempts to acquire a light semaphore.
static void __dsb(void)
Performs a Data Synchronization Barrier operation.
Definition synchronization.h:34
void RecursiveLock_Unlock(RecursiveLock *lock)
Unlocks a recursive lock.
void LightEvent_Clear(LightEvent *event)
Clears a light event.
s32 CondVar
A condition variable.
Definition synchronization.h:16
void LightLock_Init(LightLock *lock)
Initializes a light lock.
void LightLock_Unlock(LightLock *lock)
Unlocks a light lock.
int RecursiveLock_TryLock(RecursiveLock *lock)
Attempts to lock a recursive lock.
static void __isb(void)
Performs an Instruction Synchronization Barrier (officially "flush prefetch buffer") operation.
Definition synchronization.h:46
void CondVar_Wait(CondVar *cv, LightLock *lock)
Waits on a condition variable.
static s32 __ldrex(s32 *addr)
Performs a ldrex operation.
Definition synchronization.h:62
int CondVar_WaitTimeout(CondVar *cv, LightLock *lock, s64 timeout_ns)
Waits on a condition variable with a timeout.
int LightEvent_WaitTimeout(LightEvent *event, s64 timeout_ns)
Waits on a light event until either the event is signaled or the timeout is reached.
static void __dmb(void)
Performs a Data Memory Barrier operation.
Definition synchronization.h:40
void CondVar_Init(CondVar *cv)
Initializes a condition variable.
static void CondVar_Broadcast(CondVar *cv)
Wakes up all threads waiting on a condition variable.
Definition synchronization.h:271
static u16 __ldrexh(u16 *addr)
Performs a ldrexh operation.
Definition synchronization.h:87
void LightEvent_Signal(LightEvent *event)
Signals a light event, waking up threads waiting on it.
static bool __strexb(u8 *addr, u8 val)
Performs a strexb operation.
Definition synchronization.h:125
void LightSemaphore_Init(LightSemaphore *semaphore, s16 initial_count, s16 max_count)
Initializes a light semaphore.
void LightSemaphore_Acquire(LightSemaphore *semaphore, s32 count)
Acquires a light semaphore.
_LOCK_RECURSIVE_T RecursiveLock
A recursive lock.
Definition synchronization.h:13
static bool __strex(s32 *addr, s32 val)
Performs a strex operation.
Definition synchronization.h:75
void LightLock_Lock(LightLock *lock)
Locks a light lock.
static void __clrex(void)
Performs a clrex operation.
Definition synchronization.h:52
void RecursiveLock_Lock(RecursiveLock *lock)
Locks a recursive lock.
int64_t s64
64-bit signed integer
Definition types.h:29
uint8_t u8
would be nice if newlib had this already
Definition types.h:21
int16_t s16
16-bit signed integer
Definition types.h:27
s32 Result
Function result.
Definition types.h:42
uint16_t u16
16-bit unsigned integer
Definition types.h:22
int32_t s32
32-bit signed integer
Definition types.h:28