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)
This commit is contained in:
fincs 2020-07-01 00:17:08 +02:00
parent 19fd446ac5
commit 9a707b2269
No known key found for this signature in database
GPG Key ID: 62C7609ADA219C60

View File

@ -43,6 +43,7 @@ void LightLock_Lock(LightLock* lock)
{ {
// Read the current lock state // Read the current lock state
val = __ldrex(lock); val = __ldrex(lock);
if (val == 0) val = 1; // 0 is an invalid state - treat it as 1 (unlocked)
bAlreadyLocked = val < 0; bAlreadyLocked = val < 0;
// Calculate the desired next state of the lock // Calculate the desired next state of the lock
@ -76,6 +77,8 @@ void LightLock_Lock(LightLock* lock)
} }
} while (__strex(lock, val)); } while (__strex(lock, val));
} }
__dmb();
} }
int LightLock_TryLock(LightLock* lock) int LightLock_TryLock(LightLock* lock)
@ -84,17 +87,22 @@ int LightLock_TryLock(LightLock* lock)
do do
{ {
val = __ldrex(lock); val = __ldrex(lock);
if (val == 0) val = 1; // 0 is an invalid state - treat it as 1 (unlocked)
if (val < 0) if (val < 0)
{ {
__clrex(); __clrex();
return 1; // Failure return 1; // Failure
} }
} while (__strex(lock, -val)); } while (__strex(lock, -val));
__dmb();
return 0; // Success return 0; // Success
} }
void LightLock_Unlock(LightLock* lock) void LightLock_Unlock(LightLock* lock)
{ {
__dmb();
s32 val; s32 val;
do do
val = -__ldrex(lock); val = -__ldrex(lock);
@ -154,6 +162,7 @@ static inline void LightEvent_SetState(LightEvent* event, int state)
static inline int LightEvent_TryReset(LightEvent* event) static inline int LightEvent_TryReset(LightEvent* event)
{ {
__dmb();
do do
{ {
if (__ldrex(&event->state)) if (__ldrex(&event->state))
@ -162,6 +171,7 @@ static inline int LightEvent_TryReset(LightEvent* event)
return 0; return 0;
} }
} while (__strex(&event->state, -1)); } while (__strex(&event->state, -1));
__dmb();
return 1; return 1;
} }
@ -179,7 +189,11 @@ void LightEvent_Clear(LightEvent* event)
LightEvent_SetState(event, -2); LightEvent_SetState(event, -2);
LightLock_Unlock(&event->lock); LightLock_Unlock(&event->lock);
} else if (event->state == 0) } else if (event->state == 0)
{
__dmb();
LightEvent_SetState(event, -1); LightEvent_SetState(event, -1);
__dmb();
}
} }
void LightEvent_Pulse(LightEvent* event) void LightEvent_Pulse(LightEvent* event)
@ -196,6 +210,7 @@ void LightEvent_Signal(LightEvent* event)
{ {
if (event->state == -1) if (event->state == -1)
{ {
__dmb();
LightEvent_SetState(event, 0); LightEvent_SetState(event, 0);
syncArbitrateAddress(&event->state, ARBITRATION_SIGNAL, 1); syncArbitrateAddress(&event->state, ARBITRATION_SIGNAL, 1);
} else if (event->state == -2) } 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 (__strexh((u16 *)&semaphore->num_threads_acq, num_threads_acq - 1));
} }
} while (__strex(&semaphore->current_count, old_count - count)); } while (__strex(&semaphore->current_count, old_count - count));
__dmb();
} }
int LightSemaphore_TryAcquire(LightSemaphore* semaphore, s32 count) int LightSemaphore_TryAcquire(LightSemaphore* semaphore, s32 count)
@ -281,11 +298,14 @@ int LightSemaphore_TryAcquire(LightSemaphore* semaphore, s32 count)
} }
} while (__strex(&semaphore->current_count, old_count - count)); } while (__strex(&semaphore->current_count, old_count - count));
__dmb();
return 0; // success return 0; // success
} }
void LightSemaphore_Release(LightSemaphore* semaphore, s32 count) void LightSemaphore_Release(LightSemaphore* semaphore, s32 count)
{ {
__dmb();
s32 old_count, new_count; s32 old_count, new_count;
do do
{ {