From 9c1c847388d1dea787b2b2a205630336d095d194 Mon Sep 17 00:00:00 2001 From: fincs Date: Fri, 12 Jun 2020 20:40:47 +0200 Subject: [PATCH] Introduce syncArbitrateAddress/WithTimeout (replaces __sync_get_arbiter) --- libctru/include/3ds/svc.h | 11 +-------- libctru/include/3ds/synchronization.h | 32 ++++++++++++++++++++++++--- libctru/source/services/gspgpu.c | 6 ++--- libctru/source/synchronization.c | 29 ++++++++++++++---------- 4 files changed, 49 insertions(+), 29 deletions(-) diff --git a/libctru/include/3ds/svc.h b/libctru/include/3ds/svc.h index 95200e7..bb061ea 100644 --- a/libctru/include/3ds/svc.h +++ b/libctru/include/3ds/svc.h @@ -915,16 +915,7 @@ Result svcCreateAddressArbiter(Handle *arbiter); * @param addr A pointer to a s32 value. * @param type Type of action to be performed by the arbiter * @param value Number of threads to signal if using @ref ARBITRATION_SIGNAL, or the value used for comparison. - * - * This will perform an arbitration based on #type. The comparisons are done between #value and the value at the address #addr. - * - * @code - * s32 val=0; - * // Does *nothing* since val >= 0 - * svcCreateAddressArbiter(arbiter,&val,ARBITRATION_WAIT_IF_LESS_THAN,0,0); - * // Thread will wait for a signal or wake up after 10000000 nanoseconds because val < 1. - * svcCreateAddressArbiter(arbiter,&val,ARBITRATION_WAIT_IF_LESS_THAN_TIMEOUT,1,10000000ULL); - * @endcode + * @warning Please use \ref syncArbitrateAddress or \ref syncArbitrateAddressWithTimeout instead. */ Result svcArbitrateAddress(Handle arbiter, u32 addr, ArbitrationType type, s32 value, s64 nanoseconds); diff --git a/libctru/include/3ds/synchronization.h b/libctru/include/3ds/synchronization.h index 551884a..fdf52f8 100644 --- a/libctru/include/3ds/synchronization.h +++ b/libctru/include/3ds/synchronization.h @@ -126,10 +126,36 @@ static inline bool __strexb(u8* addr, u8 val) #define AtomicSwap(ptr, value) __atomic_exchange_n((u32*)(ptr), (value), __ATOMIC_SEQ_CST) /** - * @brief Retrieves the synchronization subsystem's address arbiter handle. - * @return The synchronization subsystem's address arbiter handle. + * @brief Function used to implement user-mode synchronization primitives. + * @param addr Pointer to a signed 32-bit value whose address will be used to identify waiting threads. + * @param type Type of action to be performed by the arbiter + * @param value Number of threads to signal if using @ref ARBITRATION_SIGNAL, or the value used for comparison. + * + * This will perform an arbitration based on #type. The comparisons are done between #value and the value at the address #addr. + * + * @code + * s32 val=0; + * // Does *nothing* since val >= 0 + * syncArbitrateAddress(&val,ARBITRATION_WAIT_IF_LESS_THAN,0); + * @endcode */ -Handle __sync_get_arbiter(void); +Result syncArbitrateAddress(s32* addr, ArbitrationType type, s32 value); + +/** + * @brief Function used to implement user-mode synchronization primitives (with timeout). + * @param addr Pointer to a signed 32-bit value whose address will be used to identify waiting threads. + * @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) + * @param value Number of threads to signal if using @ref ARBITRATION_SIGNAL, or the value used for comparison. + * + * This will perform an arbitration based on #type. The comparisons are done between #value and the value at the address #addr. + * + * @code + * s32 val=0; + * // Thread will wait for a signal or wake up after 10000000 nanoseconds because val < 1. + * syncArbitrateAddressWithTimeout(&val,ARBITRATION_WAIT_IF_LESS_THAN_TIMEOUT,1,10000000LL); + * @endcode + */ +Result syncArbitrateAddressWithTimeout(s32* addr, ArbitrationType type, s32 value, s64 timeout_ns); /** * @brief Initializes a light lock. diff --git a/libctru/source/services/gspgpu.c b/libctru/source/services/gspgpu.c index f169ba4..7e42894 100644 --- a/libctru/source/services/gspgpu.c +++ b/libctru/source/services/gspgpu.c @@ -28,8 +28,6 @@ static vu8* gspEventData; static void gspEventThreadMain(void *arg); -Handle __sync_get_arbiter(void); - Result gspInit(void) { Result res=0; @@ -103,7 +101,7 @@ GSPGPU_Event gspWaitForAnyEvent(void) } } while (__strex(&gspLastEvent, -1)); if (x < 0) - svcArbitrateAddress(__sync_get_arbiter(), (u32)&gspLastEvent, ARBITRATION_WAIT_IF_LESS_THAN, 0, 0); + syncArbitrateAddress(&gspLastEvent, ARBITRATION_WAIT_IF_LESS_THAN, 0); } while (x < 0); return (GSPGPU_Event)x; } @@ -177,7 +175,7 @@ void gspEventThreadMain(void *arg) do __ldrex(&gspLastEvent); while (__strex(&gspLastEvent, curEvt)); - svcArbitrateAddress(__sync_get_arbiter(), (u32)&gspLastEvent, ARBITRATION_SIGNAL, 1, 0); + syncArbitrateAddress(&gspLastEvent, ARBITRATION_SIGNAL, 1); gspEventCounts[curEvt]++; } } diff --git a/libctru/source/synchronization.c b/libctru/source/synchronization.c index fa3f8bc..9750bfc 100644 --- a/libctru/source/synchronization.c +++ b/libctru/source/synchronization.c @@ -16,9 +16,14 @@ void __sync_fini(void) svcCloseHandle(arbiter); } -Handle __sync_get_arbiter(void) +Result syncArbitrateAddress(s32* addr, ArbitrationType type, s32 value) { - return arbiter; + return svcArbitrateAddress(arbiter, (u32)addr, type, value, 0); +} + +Result syncArbitrateAddressWithTimeout(s32* addr, ArbitrationType type, s32 value, s64 timeout_ns) +{ + return svcArbitrateAddress(arbiter, (u32)addr, type, value, timeout_ns); } void LightLock_Init(LightLock* lock) @@ -51,7 +56,7 @@ void LightLock_Lock(LightLock* lock) while (bAlreadyLocked) { // Wait for the lock holder thread to wake us up - svcArbitrateAddress(arbiter, (u32)lock, ARBITRATION_WAIT_IF_LESS_THAN, 0, 0); + syncArbitrateAddress(lock, ARBITRATION_WAIT_IF_LESS_THAN, 0); // Try to lock again do @@ -97,7 +102,7 @@ void LightLock_Unlock(LightLock* lock) if (val > 1) // Wake up exactly one thread - svcArbitrateAddress(arbiter, (u32)lock, ARBITRATION_SIGNAL, 1, 0); + syncArbitrateAddress(lock, ARBITRATION_SIGNAL, 1); } void RecursiveLock_Init(RecursiveLock* lock) @@ -180,9 +185,9 @@ void LightEvent_Clear(LightEvent* event) void LightEvent_Pulse(LightEvent* event) { if (event->state == -2) - svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_SIGNAL, -1, 0); + syncArbitrateAddress(&event->state, ARBITRATION_SIGNAL, -1); else if (event->state == -1) - svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_SIGNAL, 1, 0); + syncArbitrateAddress(&event->state, ARBITRATION_SIGNAL, 1); else LightEvent_Clear(event); } @@ -192,12 +197,12 @@ void LightEvent_Signal(LightEvent* event) if (event->state == -1) { LightEvent_SetState(event, 0); - svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_SIGNAL, 1, 0); + syncArbitrateAddress(&event->state, ARBITRATION_SIGNAL, 1); } else if (event->state == -2) { LightLock_Lock(&event->lock); LightEvent_SetState(event, 1); - svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_SIGNAL, -1, 0); + syncArbitrateAddress(&event->state, ARBITRATION_SIGNAL, -1); LightLock_Unlock(&event->lock); } } @@ -215,7 +220,7 @@ void LightEvent_Wait(LightEvent* event) { if (event->state == -2) { - svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_WAIT_IF_LESS_THAN, 0, 0); + syncArbitrateAddress(&event->state, ARBITRATION_WAIT_IF_LESS_THAN, 0); return; } if (event->state != -1) @@ -225,7 +230,7 @@ void LightEvent_Wait(LightEvent* event) if (event->state == 0 && LightEvent_TryReset(event)) return; } - svcArbitrateAddress(arbiter, (u32)event, ARBITRATION_WAIT_IF_LESS_THAN, 0, 0); + syncArbitrateAddress(&event->state, ARBITRATION_WAIT_IF_LESS_THAN, 0); } } @@ -254,7 +259,7 @@ void LightSemaphore_Acquire(LightSemaphore* semaphore, s32 count) num_threads_acq = (s16)__ldrexh((u16 *)&semaphore->num_threads_acq); while (__strexh((u16 *)&semaphore->num_threads_acq, num_threads_acq + 1)); - svcArbitrateAddress(arbiter, (u32)semaphore, ARBITRATION_WAIT_IF_LESS_THAN, count, 0); + syncArbitrateAddress(&semaphore->current_count, ARBITRATION_WAIT_IF_LESS_THAN, count); do num_threads_acq = (s16)__ldrexh((u16 *)&semaphore->num_threads_acq); @@ -275,5 +280,5 @@ void LightSemaphore_Release(LightSemaphore* semaphore, s32 count) } while (__strex(&semaphore->current_count, new_count)); if(old_count <= 0 || semaphore->num_threads_acq > 0) - svcArbitrateAddress(arbiter, (u32)semaphore, ARBITRATION_SIGNAL, count, 0); + syncArbitrateAddress(&semaphore->current_count, ARBITRATION_SIGNAL, count); }