Revise algorithm used by LightLock_Lock/Unlock to fix potential issues

This commit is contained in:
fincs 2015-11-21 18:57:16 +01:00
parent 9b57720cee
commit 58b0b9db4d

View File

@ -32,9 +32,26 @@ _begin:
val = __ldrex(lock); val = __ldrex(lock);
if (val < 0) if (val < 0)
{ {
// Add ourselves to the list of threads blocked on this lock
if (__strex(lock, val-1))
goto _begin; // strex failed, try to lock again
_wait:
// Wait for a thread to wake us up
svcArbitrateAddress(arbiter, (u32)lock, ARBITRATION_WAIT_IF_LESS_THAN, 0, 0);
// Try to lock again
do
{
val = __ldrex(lock);
if (val < 0)
{
// Lock is still locked - keep waiting
__clrex(); __clrex();
svcArbitrateAddress(arbiter, (u32)lock, ARBITRATION_DECREMENT_AND_WAIT_IF_LESS_THAN, 0, 0); goto _wait;
goto _begin; // Try locking again }
} while (__strex(lock, -(val-1)));
return;
} }
} while (__strex(lock, -val)); } while (__strex(lock, -val));
} }
@ -60,14 +77,10 @@ void LightLock_Unlock(LightLock* lock)
do do
val = -__ldrex(lock); val = -__ldrex(lock);
while (__strex(lock, val)); while (__strex(lock, val));
if (val > 1) if (val > 1)
{
// Wake up exactly one thread // Wake up exactly one thread
do
val = __ldrex(lock);
while (__strex(lock, val >= 0 ? (val-1) : (val+1)));
svcArbitrateAddress(arbiter, (u32)lock, ARBITRATION_SIGNAL, 1, 0); svcArbitrateAddress(arbiter, (u32)lock, ARBITRATION_SIGNAL, 1, 0);
}
} }
void RecursiveLock_Init(RecursiveLock* lock) void RecursiveLock_Init(RecursiveLock* lock)