mirror of
https://github.com/reactos/reactos.git
synced 2025-02-23 08:55:19 +00:00
- Fix locking bugs in guarded mutex implementation. In race conditions some operations were not re-attempted.
- Fix some other logic bugs, including a serious bug in KeTrytoAcquireGuardedMutex which inversed the result. svn path=/trunk/; revision=25473
This commit is contained in:
parent
2e03cf0bb5
commit
4f9b8acb4d
3 changed files with 46 additions and 47 deletions
|
@ -745,7 +745,8 @@ ExReleasePushLockExclusive(PEX_PUSH_LOCK PushLock)
|
||||||
ASSERT(PushLock->Waiting || PushLock->Shared == 0);
|
ASSERT(PushLock->Waiting || PushLock->Shared == 0);
|
||||||
|
|
||||||
/* Unlock the pushlock */
|
/* Unlock the pushlock */
|
||||||
OldValue.Value = InterlockedExchangeAddSizeT((PLONG)PushLock, -1);
|
OldValue.Value = InterlockedExchangeAddSizeT((PLONG)PushLock,
|
||||||
|
-EX_PUSH_LOCK_LOCK);
|
||||||
|
|
||||||
/* Sanity checks */
|
/* Sanity checks */
|
||||||
ASSERT(OldValue.Locked);
|
ASSERT(OldValue.Locked);
|
||||||
|
|
|
@ -78,7 +78,7 @@ KeWaitForGate(IN PKGATE Gate,
|
||||||
|
|
||||||
/* Release the APC lock and return */
|
/* Release the APC lock and return */
|
||||||
KiReleaseApcLock(&ApcLock);
|
KiReleaseApcLock(&ApcLock);
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup a Wait Block */
|
/* Setup a Wait Block */
|
||||||
|
@ -122,8 +122,8 @@ KeWaitForGate(IN PKGATE Gate,
|
||||||
/* Find a new thread to run */
|
/* Find a new thread to run */
|
||||||
Status = KiSwapThread(Thread, KeGetCurrentPrcb());
|
Status = KiSwapThread(Thread, KeGetCurrentPrcb());
|
||||||
|
|
||||||
/* Check if we were executing an APC */
|
/* Make sure we weren't executing an APC */
|
||||||
if (Status != STATUS_KERNEL_APC) return;
|
if (Status == STATUS_SUCCESS) return;
|
||||||
}
|
}
|
||||||
} while (TRUE);
|
} while (TRUE);
|
||||||
}
|
}
|
||||||
|
@ -149,18 +149,14 @@ KeSignalGateBoostPriority(IN PKGATE Gate)
|
||||||
KiAcquireDispatcherObject(&Gate->Header);
|
KiAcquireDispatcherObject(&Gate->Header);
|
||||||
|
|
||||||
/* Make sure we're not already signaled or that the list is empty */
|
/* Make sure we're not already signaled or that the list is empty */
|
||||||
if (Gate->Header.SignalState)
|
if (Gate->Header.SignalState) break;
|
||||||
{
|
|
||||||
/* Lower IRQL and quit */
|
|
||||||
KeLowerIrql(OldIrql);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if our wait list is empty */
|
/* Check if our wait list is empty */
|
||||||
if (IsListEmpty(&Gate->Header.WaitListHead))
|
if (IsListEmpty(&Gate->Header.WaitListHead))
|
||||||
{
|
{
|
||||||
/* It is, so signal the event */
|
/* It is, so signal the event */
|
||||||
Gate->Header.SignalState = 1;
|
Gate->Header.SignalState = 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -187,7 +183,7 @@ KeSignalGateBoostPriority(IN PKGATE Gate)
|
||||||
RemoveEntryList(&WaitBlock->WaitListEntry);
|
RemoveEntryList(&WaitBlock->WaitListEntry);
|
||||||
|
|
||||||
/* Clear wait status */
|
/* Clear wait status */
|
||||||
WaitThread->WaitStatus = 0;
|
WaitThread->WaitStatus = STATUS_SUCCESS;
|
||||||
|
|
||||||
/* Set state and CPU */
|
/* Set state and CPU */
|
||||||
WaitThread->State = DeferredReady;
|
WaitThread->State = DeferredReady;
|
||||||
|
@ -223,6 +219,7 @@ KeSignalGateBoostPriority(IN PKGATE Gate)
|
||||||
|
|
||||||
/* Exit the dispatcher */
|
/* Exit the dispatcher */
|
||||||
KiExitDispatcher(OldIrql);
|
KiExitDispatcher(OldIrql);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,9 +30,6 @@ KiAcquireGuardedMutexContented(IN OUT PKGUARDED_MUTEX GuardedMutex)
|
||||||
BitsToRemove = GM_LOCK_BIT;
|
BitsToRemove = GM_LOCK_BIT;
|
||||||
BitsToAdd = GM_LOCK_WAITER_INC;
|
BitsToAdd = GM_LOCK_WAITER_INC;
|
||||||
|
|
||||||
/* Get the Count Bits */
|
|
||||||
OldValue = GuardedMutex->Count;
|
|
||||||
|
|
||||||
/* Start change loop */
|
/* Start change loop */
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
@ -42,6 +39,12 @@ KiAcquireGuardedMutexContented(IN OUT PKGUARDED_MUTEX GuardedMutex)
|
||||||
ASSERT((BitsToAdd == GM_LOCK_WAITER_INC) ||
|
ASSERT((BitsToAdd == GM_LOCK_WAITER_INC) ||
|
||||||
(BitsToAdd == GM_LOCK_WAITER_WOKEN));
|
(BitsToAdd == GM_LOCK_WAITER_WOKEN));
|
||||||
|
|
||||||
|
/* Get the Count Bits */
|
||||||
|
OldValue = GuardedMutex->Count;
|
||||||
|
|
||||||
|
/* Start internal bit change loop */
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
/* Check if the Guarded Mutex is locked */
|
/* Check if the Guarded Mutex is locked */
|
||||||
if (OldValue & GM_LOCK_BIT)
|
if (OldValue & GM_LOCK_BIT)
|
||||||
{
|
{
|
||||||
|
@ -50,25 +53,24 @@ KiAcquireGuardedMutexContented(IN OUT PKGUARDED_MUTEX GuardedMutex)
|
||||||
((OldValue & GM_LOCK_WAITER_WOKEN) != 0));
|
((OldValue & GM_LOCK_WAITER_WOKEN) != 0));
|
||||||
|
|
||||||
/* Unlock it by removing the Lock Bit */
|
/* Unlock it by removing the Lock Bit */
|
||||||
|
NewValue = OldValue ^ BitsToRemove;
|
||||||
NewValue = InterlockedCompareExchange(&GuardedMutex->Count,
|
NewValue = InterlockedCompareExchange(&GuardedMutex->Count,
|
||||||
OldValue ^ BitsToRemove,
|
NewValue,
|
||||||
OldValue);
|
OldValue);
|
||||||
if (NewValue == OldValue) break;
|
if (NewValue == OldValue) return;
|
||||||
|
|
||||||
/* Value got changed behind our backs, start over */
|
|
||||||
OldValue = NewValue;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* The Guarded Mutex isn't locked, so simply set the bits */
|
/* The Guarded Mutex isn't locked, so simply set the bits */
|
||||||
|
NewValue = OldValue + BitsToAdd;
|
||||||
NewValue = InterlockedCompareExchange(&GuardedMutex->Count,
|
NewValue = InterlockedCompareExchange(&GuardedMutex->Count,
|
||||||
OldValue + BitsToAdd,
|
NewValue,
|
||||||
OldValue);
|
OldValue);
|
||||||
if (NewValue != OldValue)
|
if (NewValue == OldValue) break;
|
||||||
{
|
}
|
||||||
/* Value got changed behind our backs, start over */
|
|
||||||
|
/* Old value changed, loop again */
|
||||||
OldValue = NewValue;
|
OldValue = NewValue;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now we have to wait for it */
|
/* Now we have to wait for it */
|
||||||
|
@ -79,7 +81,6 @@ KiAcquireGuardedMutexContented(IN OUT PKGUARDED_MUTEX GuardedMutex)
|
||||||
BitsToRemove = GM_LOCK_BIT | GM_LOCK_WAITER_WOKEN;
|
BitsToRemove = GM_LOCK_BIT | GM_LOCK_WAITER_WOKEN;
|
||||||
BitsToAdd = GM_LOCK_WAITER_WOKEN;
|
BitsToAdd = GM_LOCK_WAITER_WOKEN;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
|
@ -109,7 +110,7 @@ KiReleaseGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex)
|
||||||
GuardedMutex->Owner = NULL;
|
GuardedMutex->Owner = NULL;
|
||||||
|
|
||||||
/* Add the Lock Bit */
|
/* Add the Lock Bit */
|
||||||
OldValue = InterlockedExchangeAdd(&GuardedMutex->Count, 1);
|
OldValue = InterlockedExchangeAdd(&GuardedMutex->Count, GM_LOCK_BIT);
|
||||||
ASSERT((OldValue & GM_LOCK_BIT) == 0);
|
ASSERT((OldValue & GM_LOCK_BIT) == 0);
|
||||||
|
|
||||||
/* Check if it was already locked, but not woken */
|
/* Check if it was already locked, but not woken */
|
||||||
|
@ -247,7 +248,7 @@ KeTryToAcquireGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex)
|
||||||
|
|
||||||
/* Remove the lock */
|
/* Remove the lock */
|
||||||
OldBit = InterlockedBitTestAndReset(&GuardedMutex->Count, GM_LOCK_BIT_V);
|
OldBit = InterlockedBitTestAndReset(&GuardedMutex->Count, GM_LOCK_BIT_V);
|
||||||
if (OldBit)
|
if (!OldBit)
|
||||||
{
|
{
|
||||||
/* Re-enable APCs */
|
/* Re-enable APCs */
|
||||||
KeLeaveGuardedRegion();
|
KeLeaveGuardedRegion();
|
||||||
|
|
Loading…
Reference in a new issue