From 9a707b2269ed4f24de716818c3587eff9eb667d5 Mon Sep 17 00:00:00 2001 From: fincs Date: Wed, 1 Jul 2020 00:17:08 +0200 Subject: [PATCH] Improve safety of usermode synchronization primitives, see details: - Added data memory barriers where required to ensure intercore safety - Changed LightLock to handle 0 during locking instead of silently failing (this means trivially initialized/zerofilled LightLocks are now supported) --- libctru/source/synchronization.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/libctru/source/synchronization.c b/libctru/source/synchronization.c index 14b4f2e..7e343bf 100644 --- a/libctru/source/synchronization.c +++ b/libctru/source/synchronization.c @@ -43,6 +43,7 @@ void LightLock_Lock(LightLock* lock) { // Read the current lock state val = __ldrex(lock); + if (val == 0) val = 1; // 0 is an invalid state - treat it as 1 (unlocked) bAlreadyLocked = val < 0; // Calculate the desired next state of the lock @@ -76,6 +77,8 @@ void LightLock_Lock(LightLock* lock) } } while (__strex(lock, val)); } + + __dmb(); } int LightLock_TryLock(LightLock* lock) @@ -84,17 +87,22 @@ int LightLock_TryLock(LightLock* lock) do { val = __ldrex(lock); + if (val == 0) val = 1; // 0 is an invalid state - treat it as 1 (unlocked) if (val < 0) { __clrex(); return 1; // Failure } } while (__strex(lock, -val)); + + __dmb(); return 0; // Success } void LightLock_Unlock(LightLock* lock) { + __dmb(); + s32 val; do val = -__ldrex(lock); @@ -154,6 +162,7 @@ static inline void LightEvent_SetState(LightEvent* event, int state) static inline int LightEvent_TryReset(LightEvent* event) { + __dmb(); do { if (__ldrex(&event->state)) @@ -162,6 +171,7 @@ static inline int LightEvent_TryReset(LightEvent* event) return 0; } } while (__strex(&event->state, -1)); + __dmb(); return 1; } @@ -179,7 +189,11 @@ void LightEvent_Clear(LightEvent* event) LightEvent_SetState(event, -2); LightLock_Unlock(&event->lock); } else if (event->state == 0) + { + __dmb(); LightEvent_SetState(event, -1); + __dmb(); + } } void LightEvent_Pulse(LightEvent* event) @@ -196,6 +210,7 @@ void LightEvent_Signal(LightEvent* event) { if (event->state == -1) { + __dmb(); LightEvent_SetState(event, 0); syncArbitrateAddress(&event->state, ARBITRATION_SIGNAL, 1); } else if (event->state == -2) @@ -266,6 +281,8 @@ void LightSemaphore_Acquire(LightSemaphore* semaphore, s32 count) while (__strexh((u16 *)&semaphore->num_threads_acq, num_threads_acq - 1)); } } while (__strex(&semaphore->current_count, old_count - count)); + + __dmb(); } int LightSemaphore_TryAcquire(LightSemaphore* semaphore, s32 count) @@ -280,12 +297,15 @@ int LightSemaphore_TryAcquire(LightSemaphore* semaphore, s32 count) return 1; // failure } } while (__strex(&semaphore->current_count, old_count - count)); - + + __dmb(); return 0; // success } void LightSemaphore_Release(LightSemaphore* semaphore, s32 count) { + __dmb(); + s32 old_count, new_count; do {