Add CondVar implementation
This commit is contained in:
parent
ef6289f977
commit
4a9c547d8b
@ -12,6 +12,9 @@ typedef _LOCK_T LightLock;
|
||||
/// A recursive lock.
|
||||
typedef _LOCK_RECURSIVE_T RecursiveLock;
|
||||
|
||||
/// A condition variable.
|
||||
typedef s32 CondVar;
|
||||
|
||||
/// A light event.
|
||||
typedef struct
|
||||
{
|
||||
@ -217,6 +220,53 @@ int RecursiveLock_TryLock(RecursiveLock* lock);
|
||||
*/
|
||||
void RecursiveLock_Unlock(RecursiveLock* lock);
|
||||
|
||||
/**
|
||||
* @brief Initializes a condition variable.
|
||||
* @param cv Pointer to the condition variable.
|
||||
*/
|
||||
void CondVar_Init(CondVar* cv);
|
||||
|
||||
/**
|
||||
* @brief Waits on a condition variable.
|
||||
* @param cv Pointer to the condition variable.
|
||||
* @param lock Pointer to the lock to atomically unlock/relock during the wait.
|
||||
*/
|
||||
void CondVar_Wait(CondVar* cv, LightLock* lock);
|
||||
|
||||
/**
|
||||
* @brief Waits on a condition variable with a timeout.
|
||||
* @param cv Pointer to the condition variable.
|
||||
* @param lock Pointer to the lock to atomically unlock/relock during the wait.
|
||||
* @param timeout_ns Timeout in nanoseconds.
|
||||
* @return Zero on success, non-zero on failure.
|
||||
*/
|
||||
int CondVar_WaitTimeout(CondVar* cv, LightLock* lock, s64 timeout_ns);
|
||||
|
||||
/**
|
||||
* @brief Wakes up threads waiting on a condition variable.
|
||||
* @param cv Pointer to the condition variable.
|
||||
* @param num_threads Maximum number of threads to wake up (or \ref ARBITRATION_SIGNAL_ALL to wake them all).
|
||||
*/
|
||||
void CondVar_WakeUp(CondVar* cv, s32 num_threads);
|
||||
|
||||
/**
|
||||
* @brief Wakes up a single thread waiting on a condition variable.
|
||||
* @param cv Pointer to the condition variable.
|
||||
*/
|
||||
static inline void CondVar_Signal(CondVar* cv)
|
||||
{
|
||||
CondVar_WakeUp(cv, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wakes up all threads waiting on a condition variable.
|
||||
* @param cv Pointer to the condition variable.
|
||||
*/
|
||||
static inline void CondVar_Broadcast(CondVar* cv)
|
||||
{
|
||||
CondVar_WakeUp(cv, ARBITRATION_SIGNAL_ALL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes a light event.
|
||||
* @param event Pointer to the event.
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <string.h>
|
||||
#include <3ds/types.h>
|
||||
#include <3ds/svc.h>
|
||||
#include <3ds/result.h>
|
||||
#include <3ds/synchronization.h>
|
||||
|
||||
static Handle arbiter;
|
||||
@ -153,6 +154,74 @@ void RecursiveLock_Unlock(RecursiveLock* lock)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void CondVar_BeginWait(CondVar* cv, LightLock* lock)
|
||||
{
|
||||
s32 val;
|
||||
do
|
||||
val = __ldrex(cv) - 1;
|
||||
while (!__strex(cv, val));
|
||||
LightLock_Unlock(lock);
|
||||
}
|
||||
|
||||
static inline bool CondVar_EndWait(CondVar* cv, s32 num_threads)
|
||||
{
|
||||
bool hasWaiters;
|
||||
s32 val;
|
||||
|
||||
do {
|
||||
val = __ldrex(cv);
|
||||
hasWaiters = val < 0;
|
||||
if (hasWaiters)
|
||||
{
|
||||
if (num_threads < 0)
|
||||
val = 0;
|
||||
else if (val <= -num_threads)
|
||||
val += num_threads;
|
||||
else
|
||||
val = 0;
|
||||
}
|
||||
} while (!__strex(cv, val));
|
||||
|
||||
return hasWaiters;
|
||||
}
|
||||
|
||||
void CondVar_Init(CondVar* cv)
|
||||
{
|
||||
*cv = 0;
|
||||
}
|
||||
|
||||
void CondVar_Wait(CondVar* cv, LightLock* lock)
|
||||
{
|
||||
CondVar_BeginWait(cv, lock);
|
||||
syncArbitrateAddress(cv, ARBITRATION_WAIT_IF_LESS_THAN, 0);
|
||||
LightLock_Lock(lock);
|
||||
}
|
||||
|
||||
int CondVar_WaitTimeout(CondVar* cv, LightLock* lock, s64 timeout_ns)
|
||||
{
|
||||
CondVar_BeginWait(cv, lock);
|
||||
|
||||
bool timedOut = false;
|
||||
Result rc = syncArbitrateAddressWithTimeout(cv, ARBITRATION_WAIT_IF_LESS_THAN_TIMEOUT, 0, timeout_ns);
|
||||
if (R_DESCRIPTION(rc) == RD_TIMEOUT)
|
||||
{
|
||||
timedOut = CondVar_EndWait(cv, 1);
|
||||
__dmb();
|
||||
}
|
||||
|
||||
LightLock_Lock(lock);
|
||||
return timedOut;
|
||||
}
|
||||
|
||||
void CondVar_WakeUp(CondVar* cv, s32 num_threads)
|
||||
{
|
||||
__dmb();
|
||||
if (CondVar_EndWait(cv, num_threads))
|
||||
syncArbitrateAddress(cv, ARBITRATION_SIGNAL, num_threads);
|
||||
else
|
||||
__dmb();
|
||||
}
|
||||
|
||||
static inline void LightEvent_SetState(LightEvent* event, int state)
|
||||
{
|
||||
do
|
||||
|
Loading…
Reference in New Issue
Block a user