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/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>
|
||||||
|
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