Clean up and optimize LightLock_Lock

This commit is contained in:
fincs 2020-05-04 18:34:13 +02:00
parent fddc517a6b
commit 98664af53c
No known key found for this signature in database
GPG Key ID: 62C7609ADA219C60

View File

@ -31,34 +31,46 @@ void LightLock_Init(LightLock* lock)
void LightLock_Lock(LightLock* lock) void LightLock_Lock(LightLock* lock)
{ {
s32 val; s32 val;
_begin: bool bAlreadyLocked;
// Try to lock, or if that's not possible, increment the number of waiting threads
do do
{ {
// Read the current lock state
val = __ldrex(lock); val = __ldrex(lock);
if (val < 0) bAlreadyLocked = val < 0;
// Calculate the desired next state of the lock
if (!bAlreadyLocked)
val = -val; // transition into locked state
else
--val; // increment the number of waiting threads (which has the sign reversed during locked state)
} while (__strex(lock, val));
// While the lock is held by a different thread:
while (bAlreadyLocked)
{
// Wait for the lock holder thread to wake us up
svcArbitrateAddress(arbiter, (u32)lock, ARBITRATION_WAIT_IF_LESS_THAN, 0, 0);
// Try to lock again
do
{ {
// Add ourselves to the list of threads blocked on this lock // Read the current lock state
if (__strex(lock, val-1)) val = __ldrex(lock);
goto _begin; // strex failed, try to lock again bAlreadyLocked = val < 0;
_wait: // Calculate the desired next state of the lock
// Wait for a thread to wake us up if (!bAlreadyLocked)
svcArbitrateAddress(arbiter, (u32)lock, ARBITRATION_WAIT_IF_LESS_THAN, 0, 0); val = -(val-1); // decrement the number of waiting threads *and* transition into locked state
else
// Try to lock again
do
{ {
val = __ldrex(lock); // Since the lock is still held, we need to cancel the atomic update and wait again
if (val < 0) __clrex();
{ break;
// Lock is still locked - keep waiting }
__clrex(); } while (__strex(lock, val));
goto _wait; }
}
} while (__strex(lock, -(val-1)));
return;
}
} while (__strex(lock, -val));
} }
int LightLock_TryLock(LightLock* lock) int LightLock_TryLock(LightLock* lock)