mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 16:36:33 +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);
|
||||
|
||||
/* Unlock the pushlock */
|
||||
OldValue.Value = InterlockedExchangeAddSizeT((PLONG)PushLock, -1);
|
||||
OldValue.Value = InterlockedExchangeAddSizeT((PLONG)PushLock,
|
||||
-EX_PUSH_LOCK_LOCK);
|
||||
|
||||
/* Sanity checks */
|
||||
ASSERT(OldValue.Locked);
|
||||
|
|
|
@ -78,7 +78,7 @@ KeWaitForGate(IN PKGATE Gate,
|
|||
|
||||
/* Release the APC lock and return */
|
||||
KiReleaseApcLock(&ApcLock);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Setup a Wait Block */
|
||||
|
@ -122,8 +122,8 @@ KeWaitForGate(IN PKGATE Gate,
|
|||
/* Find a new thread to run */
|
||||
Status = KiSwapThread(Thread, KeGetCurrentPrcb());
|
||||
|
||||
/* Check if we were executing an APC */
|
||||
if (Status != STATUS_KERNEL_APC) return;
|
||||
/* Make sure we weren't executing an APC */
|
||||
if (Status == STATUS_SUCCESS) return;
|
||||
}
|
||||
} while (TRUE);
|
||||
}
|
||||
|
@ -149,18 +149,14 @@ KeSignalGateBoostPriority(IN PKGATE Gate)
|
|||
KiAcquireDispatcherObject(&Gate->Header);
|
||||
|
||||
/* Make sure we're not already signaled or that the list is empty */
|
||||
if (Gate->Header.SignalState)
|
||||
{
|
||||
/* Lower IRQL and quit */
|
||||
KeLowerIrql(OldIrql);
|
||||
return;
|
||||
}
|
||||
if (Gate->Header.SignalState) break;
|
||||
|
||||
/* Check if our wait list is empty */
|
||||
if (IsListEmpty(&Gate->Header.WaitListHead))
|
||||
{
|
||||
/* It is, so signal the event */
|
||||
Gate->Header.SignalState = 1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -187,7 +183,7 @@ KeSignalGateBoostPriority(IN PKGATE Gate)
|
|||
RemoveEntryList(&WaitBlock->WaitListEntry);
|
||||
|
||||
/* Clear wait status */
|
||||
WaitThread->WaitStatus = 0;
|
||||
WaitThread->WaitStatus = STATUS_SUCCESS;
|
||||
|
||||
/* Set state and CPU */
|
||||
WaitThread->State = DeferredReady;
|
||||
|
@ -223,6 +219,7 @@ KeSignalGateBoostPriority(IN PKGATE Gate)
|
|||
|
||||
/* Exit the dispatcher */
|
||||
KiExitDispatcher(OldIrql);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,9 +30,6 @@ KiAcquireGuardedMutexContented(IN OUT PKGUARDED_MUTEX GuardedMutex)
|
|||
BitsToRemove = GM_LOCK_BIT;
|
||||
BitsToAdd = GM_LOCK_WAITER_INC;
|
||||
|
||||
/* Get the Count Bits */
|
||||
OldValue = GuardedMutex->Count;
|
||||
|
||||
/* Start change loop */
|
||||
for (;;)
|
||||
{
|
||||
|
@ -42,43 +39,47 @@ KiAcquireGuardedMutexContented(IN OUT PKGUARDED_MUTEX GuardedMutex)
|
|||
ASSERT((BitsToAdd == GM_LOCK_WAITER_INC) ||
|
||||
(BitsToAdd == GM_LOCK_WAITER_WOKEN));
|
||||
|
||||
/* Check if the Guarded Mutex is locked */
|
||||
if (OldValue & GM_LOCK_BIT)
|
||||
{
|
||||
/* Sanity check */
|
||||
ASSERT((BitsToRemove == GM_LOCK_BIT) ||
|
||||
((OldValue & GM_LOCK_WAITER_WOKEN) != 0));
|
||||
/* Get the Count Bits */
|
||||
OldValue = GuardedMutex->Count;
|
||||
|
||||
/* Unlock it by removing the Lock Bit */
|
||||
NewValue = InterlockedCompareExchange(&GuardedMutex->Count,
|
||||
OldValue ^ BitsToRemove,
|
||||
OldValue);
|
||||
if (NewValue == OldValue) break;
|
||||
|
||||
/* Value got changed behind our backs, start over */
|
||||
OldValue = NewValue;
|
||||
}
|
||||
else
|
||||
/* Start internal bit change loop */
|
||||
for (;;)
|
||||
{
|
||||
/* The Guarded Mutex isn't locked, so simply set the bits */
|
||||
NewValue = InterlockedCompareExchange(&GuardedMutex->Count,
|
||||
OldValue + BitsToAdd,
|
||||
OldValue);
|
||||
if (NewValue != OldValue)
|
||||
/* Check if the Guarded Mutex is locked */
|
||||
if (OldValue & GM_LOCK_BIT)
|
||||
{
|
||||
/* Value got changed behind our backs, start over */
|
||||
OldValue = NewValue;
|
||||
continue;
|
||||
/* Sanity check */
|
||||
ASSERT((BitsToRemove == GM_LOCK_BIT) ||
|
||||
((OldValue & GM_LOCK_WAITER_WOKEN) != 0));
|
||||
|
||||
/* Unlock it by removing the Lock Bit */
|
||||
NewValue = OldValue ^ BitsToRemove;
|
||||
NewValue = InterlockedCompareExchange(&GuardedMutex->Count,
|
||||
NewValue,
|
||||
OldValue);
|
||||
if (NewValue == OldValue) return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The Guarded Mutex isn't locked, so simply set the bits */
|
||||
NewValue = OldValue + BitsToAdd;
|
||||
NewValue = InterlockedCompareExchange(&GuardedMutex->Count,
|
||||
NewValue,
|
||||
OldValue);
|
||||
if (NewValue == OldValue) break;
|
||||
}
|
||||
|
||||
/* Now we have to wait for it */
|
||||
KeWaitForGate(&GuardedMutex->Gate, WrGuardedMutex, KernelMode);
|
||||
ASSERT((GuardedMutex->Count & GM_LOCK_WAITER_WOKEN) != 0);
|
||||
/* Old value changed, loop again */
|
||||
OldValue = NewValue;
|
||||
}
|
||||
|
||||
/* Ok, the wait is done, so set the new bits */
|
||||
BitsToRemove = GM_LOCK_BIT | GM_LOCK_WAITER_WOKEN;
|
||||
BitsToAdd = GM_LOCK_WAITER_WOKEN;
|
||||
}
|
||||
/* Now we have to wait for it */
|
||||
KeWaitForGate(&GuardedMutex->Gate, WrGuardedMutex, KernelMode);
|
||||
ASSERT((GuardedMutex->Count & GM_LOCK_WAITER_WOKEN) != 0);
|
||||
|
||||
/* Ok, the wait is done, so set the new bits */
|
||||
BitsToRemove = GM_LOCK_BIT | GM_LOCK_WAITER_WOKEN;
|
||||
BitsToAdd = GM_LOCK_WAITER_WOKEN;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,7 +110,7 @@ KiReleaseGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex)
|
|||
GuardedMutex->Owner = NULL;
|
||||
|
||||
/* Add the Lock Bit */
|
||||
OldValue = InterlockedExchangeAdd(&GuardedMutex->Count, 1);
|
||||
OldValue = InterlockedExchangeAdd(&GuardedMutex->Count, GM_LOCK_BIT);
|
||||
ASSERT((OldValue & GM_LOCK_BIT) == 0);
|
||||
|
||||
/* Check if it was already locked, but not woken */
|
||||
|
@ -247,7 +248,7 @@ KeTryToAcquireGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex)
|
|||
|
||||
/* Remove the lock */
|
||||
OldBit = InterlockedBitTestAndReset(&GuardedMutex->Count, GM_LOCK_BIT_V);
|
||||
if (OldBit)
|
||||
if (!OldBit)
|
||||
{
|
||||
/* Re-enable APCs */
|
||||
KeLeaveGuardedRegion();
|
||||
|
|
Loading…
Reference in a new issue