- 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:
Alex Ionescu 2007-01-15 21:34:36 +00:00
parent 2e03cf0bb5
commit 4f9b8acb4d
3 changed files with 46 additions and 47 deletions

View file

@ -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);

View file

@ -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;
} }
} }

View file

@ -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();