Author: ion
Date: Thu Apr 12 00:00:53 2007
New Revision: 26322
URL:
http://svn.reactos.org/svn/reactos?rev=26322&view=rev
Log:
- Fix several pushlock bugs (thanks in part to hto). Should fix bug 2063.
Modified:
trunk/reactos/ntoskrnl/ex/pushlock.c
Modified: trunk/reactos/ntoskrnl/ex/pushlock.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ex/pushlock.c?rev…
==============================================================================
--- trunk/reactos/ntoskrnl/ex/pushlock.c (original)
+++ trunk/reactos/ntoskrnl/ex/pushlock.c Thu Apr 12 00:00:53 2007
@@ -76,31 +76,24 @@
ASSERT(!OldValue.MultipleShared);
/* Check if it's locked */
- if (OldValue.Locked)
- {
- /* If it's locked we must simply un-wake it*/
- for (;;)
- {
- /* It's not waking anymore */
- NewValue.Value = OldValue.Value &~ EX_PUSH_LOCK_WAKING;
-
- /* Sanity checks */
- ASSERT(!NewValue.Waking);
- ASSERT(NewValue.Locked);
- ASSERT(NewValue.Waiting);
-
- /* Write the New Value */
- NewValue.Ptr = InterlockedCompareExchangePointer(PushLock,
- NewValue.Ptr,
- OldValue.Ptr);
- if (NewValue.Value == OldValue.Value) return;
-
- /* Someone changed the value behind our back, update it*/
- OldValue = NewValue;
-
- /* Check if it's still locked */
- if (!OldValue.Locked) break;
- }
+ while (OldValue.Locked)
+ {
+ /* It's not waking anymore */
+ NewValue.Value = OldValue.Value &~ EX_PUSH_LOCK_WAKING;
+
+ /* Sanity checks */
+ ASSERT(!NewValue.Waking);
+ ASSERT(NewValue.Locked);
+ ASSERT(NewValue.Waiting);
+
+ /* Write the New Value */
+ NewValue.Ptr = InterlockedCompareExchangePointer(PushLock,
+ NewValue.Ptr,
+ OldValue.Ptr);
+ if (NewValue.Value == OldValue.Value) return;
+
+ /* Someone changed the value behind our back, update it*/
+ OldValue = NewValue;
}
/* Save the First Block */
@@ -131,8 +124,17 @@
!(PreviousWaitBlock))
{
/* Destroy the pushlock */
- if (InterlockedCompareExchangePointer(PushLock, 0, OldValue.Ptr) ==
- OldValue.Ptr) break;
+ NewValue.Value = 0;
+ ASSERT(!NewValue.Waking);
+
+ /* Write the New Value */
+ NewValue.Ptr = InterlockedCompareExchangePointer(PushLock,
+ NewValue.Ptr,
+ OldValue.Ptr);
+ if (NewValue.Value == OldValue.Value) break;
+
+ /* Someone changed the value behind our back, update it*/
+ OldValue = NewValue;
}
else
{
@@ -224,7 +226,7 @@
/* Loop the blocks */
LastWaitBlock = WaitBlock->Last;
- while (LastWaitBlock)
+ while (!LastWaitBlock)
{
/* Save the block */
PreviousWaitBlock = WaitBlock;
@@ -393,13 +395,13 @@
{
PEX_PUSH_LOCK_WAIT_BLOCK WaitBlock = pWaitBlock;
EX_PUSH_LOCK NewValue, OldValue;
-
+
/* Detect invalid wait block alignment */
- ASSERT((ULONG_PTR)pWaitBlock & 0x10);
+ ASSERT(((ULONG_PTR)pWaitBlock & 0xF) == 0);
/* Set the waiting bit */
WaitBlock->Flags = EX_PUSH_LOCK_FLAGS_WAIT;
-
+
/* Get the old value */
OldValue = *PushLock;
@@ -414,7 +416,7 @@
WaitBlock,
OldValue.Ptr);
if (OldValue.Ptr == NewValue.Ptr) break;
-
+
/* Try again with the new value */
NewValue = OldValue;
}
@@ -492,10 +494,10 @@
/* Point to ours */
NewValue.Value = (OldValue.Value & EX_PUSH_LOCK_MULTIPLE_SHARED) |
- EX_PUSH_LOCK_LOCK |
- EX_PUSH_LOCK_WAKING |
- EX_PUSH_LOCK_WAITING |
- PtrToUlong(&WaitBlock);
+ EX_PUSH_LOCK_LOCK |
+ EX_PUSH_LOCK_WAKING |
+ EX_PUSH_LOCK_WAITING |
+ PtrToUlong(WaitBlock);
/* Check if the pushlock was already waking */
if (OldValue.Waking) NeedWake = TRUE;
@@ -515,7 +517,7 @@
NewValue.Value = EX_PUSH_LOCK_MULTIPLE_SHARED |
EX_PUSH_LOCK_LOCK |
EX_PUSH_LOCK_WAITING |
- PtrToUlong(&WaitBlock);
+ PtrToUlong(WaitBlock);
}
else
{
@@ -525,7 +527,7 @@
/* Point to our wait block */
NewValue.Value = EX_PUSH_LOCK_LOCK |
EX_PUSH_LOCK_WAITING |
- PtrToUlong(&WaitBlock);
+ PtrToUlong(WaitBlock);
}
}
@@ -589,10 +591,10 @@
}
/*++
- * @name ExAcquirePushLockExclusive
+ * @name ExAcquirePushLockShared
* @implemented NT5.1
*
- * The ExAcquirePushLockShared macro acquires a shared PushLock.
+ * The ExAcquirePushLockShared routine acquires a shared PushLock.
*
* @params PushLock
* Pointer to the pushlock which is to be acquired.
@@ -616,7 +618,7 @@
for (;;)
{
/* Check if it's unlocked or if it's waiting without any sharers */
- if (!(OldValue.Locked) || (OldValue.Waiting && OldValue.Shared == 0))
+ if (!(OldValue.Locked) || (!(OldValue.Waiting) && (OldValue.Shared >
0)))
{
/* Check if anyone is waiting on it */
if (!OldValue.Waiting)
@@ -671,10 +673,10 @@
EX_PUSH_LOCK_LOCK)) |
EX_PUSH_LOCK_WAKING |
EX_PUSH_LOCK_WAITING |
- PtrToUlong(&WaitBlock);
+ PtrToUlong(WaitBlock);
/* Check if the pushlock was already waking */
- if (OldValue.Waking) NeedWake = TRUE;
+ if (!OldValue.Waking) NeedWake = TRUE;
}
else
{
@@ -682,10 +684,9 @@
WaitBlock->Last = WaitBlock;
/* Point to our wait block */
- NewValue.Value = (OldValue.Value & (EX_PUSH_LOCK_MULTIPLE_SHARED |
- EX_PUSH_LOCK_WAKING)) |
+ NewValue.Value = (OldValue.Value & EX_PUSH_LOCK_PTR_BITS) |
EX_PUSH_LOCK_WAITING |
- PtrToUlong(&WaitBlock);
+ PtrToUlong(WaitBlock);
}
/* Sanity check */
@@ -700,9 +701,10 @@
#endif
/* Write the new value */
- if (InterlockedCompareExchangePointer(PushLock,
- NewValue.Ptr,
- OldValue.Ptr) != OldValue.Ptr)
+ NewValue.Ptr = InterlockedCompareExchangePointer(PushLock,
+ NewValue.Ptr,
+ OldValue.Ptr);
+ if (NewValue.Ptr != OldValue.Ptr)
{
/* Retry */
OldValue = NewValue;
@@ -748,15 +750,15 @@
* @name ExfReleasePushLock
* @implemented NT5.1
*
- * The ExReleasePushLockExclusive routine releases a previously
- * exclusively acquired PushLock.
+ * The ExReleasePushLock routine releases a previously acquired PushLock.
+ *
*
* @params PushLock
* Pointer to a previously acquired pushlock.
*
* @return None.
*
- * @remarks Callers of ExReleasePushLockExclusive must be running at IRQL <=
APC_LEVEL.
+ * @remarks Callers of ExfReleasePushLock must be running at IRQL <= APC_LEVEL.
* This macro should usually be paired up with KeLeaveCriticalRegion.
*
*--*/
@@ -794,11 +796,7 @@
NewValue.Ptr = InterlockedCompareExchangePointer(PushLock,
NewValue.Ptr,
OldValue.Ptr);
- if (NewValue.Value == OldValue.Value)
- {
- /* No waiters left, we're done */
- goto quit;
- }
+ if (NewValue.Value == OldValue.Value) return;
/* Did it enter a wait state? */
OldValue = NewValue;
@@ -812,21 +810,17 @@
/* Find the last Wait Block */
for (WaitBlock = (PEX_PUSH_LOCK_WAIT_BLOCK)((ULONG_PTR)OldValue.Ptr &
~EX_PUSH_LOCK_PTR_BITS);
- WaitBlock->Last;
+ !WaitBlock->Last;
WaitBlock = WaitBlock->Next);
/* Make sure the Share Count is above 0 */
- if (WaitBlock->ShareCount)
+ if (WaitBlock->ShareCount > 0)
{
/* This shouldn't be an exclusive wait block */
- ASSERT(WaitBlock->Flags&EX_PUSH_LOCK_FLAGS_EXCLUSIVE);
+ ASSERT(WaitBlock->Flags & EX_PUSH_LOCK_FLAGS_EXCLUSIVE);
/* Do the decrease and check if the lock isn't shared anymore */
- if (InterlockedExchangeAdd(&WaitBlock->ShareCount, -1))
- {
- /* Someone is still holding the lock */
- goto quit;
- }
+ if (InterlockedDecrement(&WaitBlock->ShareCount) > 0) return;
}
}
@@ -854,10 +848,7 @@
NewValue.Ptr = InterlockedCompareExchangePointer(PushLock,
NewValue.Ptr,
OldValue.Ptr);
- if (NewValue.Value == OldValue.Value) break;
-
- /* The value changed, try the unlock again */
- continue;
+ if (NewValue.Value == OldValue.Value) return;
}
else
{
@@ -880,12 +871,9 @@
/* The write was successful. The pushlock is Unlocked and Waking */
ExfWakePushLock(PushLock, NewValue);
- break;
- }
- }
-quit:
- /* Done! */
- return;
+ return;
+ }
+ }
}
/*++
@@ -912,38 +900,29 @@
PEX_PUSH_LOCK_WAIT_BLOCK WaitBlock;
/* Check if someone is waiting on the lock */
- if (!OldValue.Waiting)
- {
- /* Nobody is waiting on it, so we'll try a quick release */
- for (;;)
- {
- /* Check if it's shared */
- if (OldValue.Shared > 1)
- {
- /* Write the Old Value but decrease share count */
- NewValue = OldValue;
- NewValue.Shared--;
- }
- else
- {
- /* Simply clear the lock */
- NewValue.Value = 0;
- }
-
- /* Write the New Value */
- NewValue.Ptr = InterlockedCompareExchangePointer(PushLock,
- NewValue.Ptr,
- OldValue.Ptr);
- if (NewValue.Value == OldValue.Value)
- {
- /* No waiters left, we're done */
- goto quit;
- }
-
- /* Did it enter a wait state? */
- OldValue = NewValue;
- if (NewValue.Waiting) break;
- }
+ while (!OldValue.Waiting)
+ {
+ /* Check if it's shared */
+ if (OldValue.Shared > 1)
+ {
+ /* Write the Old Value but decrease share count */
+ NewValue = OldValue;
+ NewValue.Shared--;
+ }
+ else
+ {
+ /* Simply clear the lock */
+ NewValue.Value = 0;
+ }
+
+ /* Write the New Value */
+ NewValue.Ptr = InterlockedCompareExchangePointer(PushLock,
+ NewValue.Ptr,
+ OldValue.Ptr);
+ if (NewValue.Value == OldValue.Value) return;
+
+ /* Did it enter a wait state? */
+ OldValue = NewValue;
}
/* Ok, we do know someone is waiting on it. Are there more then one? */
@@ -952,15 +931,15 @@
/* Find the last Wait Block */
for (WaitBlock = (PEX_PUSH_LOCK_WAIT_BLOCK)((ULONG_PTR)OldValue.Ptr &
~EX_PUSH_LOCK_PTR_BITS);
- WaitBlock->Last;
+ !WaitBlock->Last;
WaitBlock = WaitBlock->Next);
/* Sanity checks */
ASSERT(WaitBlock->ShareCount > 0);
- ASSERT(WaitBlock->Flags&EX_PUSH_LOCK_FLAGS_EXCLUSIVE);
+ ASSERT(WaitBlock->Flags & EX_PUSH_LOCK_FLAGS_EXCLUSIVE);
/* Do the decrease and check if the lock isn't shared anymore */
- if (InterlockedExchangeAdd(&WaitBlock->ShareCount, -1)) goto quit;
+ if (InterlockedDecrement(&WaitBlock->ShareCount) > 0) return;
}
/*
@@ -987,10 +966,7 @@
NewValue.Ptr = InterlockedCompareExchangePointer(PushLock,
NewValue.Ptr,
OldValue.Ptr);
- if (NewValue.Value == OldValue.Value) break;
-
- /* The value changed, try the unlock again */
- continue;
+ if (NewValue.Value == OldValue.Value) return;
}
else
{
@@ -1013,12 +989,9 @@
/* The write was successful. The pushlock is Unlocked and Waking */
ExfWakePushLock(PushLock, NewValue);
- break;
- }
- }
-quit:
- /* Done! */
- return;
+ return;
+ }
+ }
}
/*++