Add lightweight synchronization primitives
This commit is contained in:
parent
4603b972fa
commit
95f63f280d
@ -12,6 +12,7 @@ extern "C" {
|
||||
#include <3ds/linear.h>
|
||||
#include <3ds/vram.h>
|
||||
#include <3ds/os.h>
|
||||
#include <3ds/synchronization.h>
|
||||
#include <3ds/gfx.h>
|
||||
#include <3ds/console.h>
|
||||
#include <3ds/util/utf.h>
|
||||
|
18
libctru/include/3ds/synchronization.h
Normal file
18
libctru/include/3ds/synchronization.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
typedef s32 LightLock;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LightLock lock;
|
||||
u32 thread_tag;
|
||||
u32 counter;
|
||||
} RecursiveLock;
|
||||
|
||||
void LightLock_Init(LightLock* lock);
|
||||
void LightLock_Lock(LightLock* lock);
|
||||
void LightLock_Unlock(LightLock* lock);
|
||||
|
||||
void RecursiveLock_Init(RecursiveLock* lock);
|
||||
void RecursiveLock_Lock(RecursiveLock* lock);
|
||||
void RecursiveLock_Unlock(RecursiveLock* lock);
|
95
libctru/source/synchronization.c
Normal file
95
libctru/source/synchronization.c
Normal file
@ -0,0 +1,95 @@
|
||||
#include <string.h>
|
||||
#include <3ds/types.h>
|
||||
#include <3ds/svc.h>
|
||||
#include <3ds/synchronization.h>
|
||||
|
||||
static Handle arbiter;
|
||||
|
||||
Result __sync_init(void)
|
||||
{
|
||||
return svcCreateAddressArbiter(&arbiter);
|
||||
}
|
||||
|
||||
void __sync_fini(void)
|
||||
{
|
||||
if (arbiter)
|
||||
svcCloseHandle(arbiter);
|
||||
}
|
||||
|
||||
static inline void __clrex(void)
|
||||
{
|
||||
__asm__ __volatile__("clrex");
|
||||
}
|
||||
|
||||
static inline s32 __ldrex(s32* addr)
|
||||
{
|
||||
s32 val;
|
||||
__asm__ __volatile__("ldrex %[val], [%[addr]]" : [val] "=r" (val) : [addr] "r" (addr));
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline bool __strex(s32* addr, s32 val)
|
||||
{
|
||||
bool res;
|
||||
__asm__ __volatile__("strex %[res], %[val], [%[addr]]" : [res] "=&r" (res) : [val] "r" (val), [addr] "r" (addr));
|
||||
return res;
|
||||
}
|
||||
|
||||
void LightLock_Init(LightLock* lock)
|
||||
{
|
||||
do
|
||||
__ldrex(lock);
|
||||
while (__strex(lock, 1));
|
||||
}
|
||||
|
||||
void LightLock_Lock(LightLock* lock)
|
||||
{
|
||||
s32 val;
|
||||
_begin:
|
||||
do
|
||||
{
|
||||
val = __ldrex(lock);
|
||||
if (val < 0)
|
||||
{
|
||||
__clrex();
|
||||
svcArbitrateAddress(arbiter, (u32)lock, ARBITRATION_WAIT_IF_LESS_THAN, 0, 0);
|
||||
goto _begin; // Try locking again
|
||||
}
|
||||
} while (__strex(lock, -val));
|
||||
}
|
||||
|
||||
void LightLock_Unlock(LightLock* lock)
|
||||
{
|
||||
s32 val;
|
||||
do
|
||||
val = -__ldrex(lock);
|
||||
while (__strex(lock, val));
|
||||
svcArbitrateAddress(arbiter, (u32)lock, ARBITRATION_SIGNAL, 1, 0);
|
||||
}
|
||||
|
||||
void RecursiveLock_Init(RecursiveLock* lock)
|
||||
{
|
||||
LightLock_Init(&lock->lock);
|
||||
lock->thread_tag = 0;
|
||||
lock->counter = 0;
|
||||
}
|
||||
|
||||
void RecursiveLock_Lock(RecursiveLock* lock)
|
||||
{
|
||||
u32 tag = (u32)getThreadLocalStorage();
|
||||
if (lock->thread_tag != tag)
|
||||
{
|
||||
LightLock_Lock(&lock->lock);
|
||||
lock->thread_tag = tag;
|
||||
}
|
||||
lock->counter ++;
|
||||
}
|
||||
|
||||
void RecursiveLock_Unlock(RecursiveLock* lock)
|
||||
{
|
||||
if (!--lock->counter)
|
||||
{
|
||||
lock->thread_tag = 0;
|
||||
LightLock_Unlock(&lock->lock);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user