Add lightweight synchronization primitives

This commit is contained in:
fincs 2015-09-30 00:07:42 +02:00
parent 4603b972fa
commit 95f63f280d
3 changed files with 114 additions and 0 deletions

View File

@ -12,6 +12,7 @@ extern "C" {
#include <3ds/linear.h> #include <3ds/linear.h>
#include <3ds/vram.h> #include <3ds/vram.h>
#include <3ds/os.h> #include <3ds/os.h>
#include <3ds/synchronization.h>
#include <3ds/gfx.h> #include <3ds/gfx.h>
#include <3ds/console.h> #include <3ds/console.h>
#include <3ds/util/utf.h> #include <3ds/util/utf.h>

View 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);

View 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);
}
}