fixed some bugs in ExWaitForRundownProtectionRelease() and
ExReleaseRundownProtectionEx()
Modified: trunk/reactos/ntoskrnl/ex/rundown.c
_____
Modified: trunk/reactos/ntoskrnl/ex/rundown.c
--- trunk/reactos/ntoskrnl/ex/rundown.c 2005-02-20 22:40:30 UTC (rev
13698)
+++ trunk/reactos/ntoskrnl/ex/rundown.c 2005-02-20 23:56:47 UTC (rev
13699)
@@ -1,4 +1,4 @@
-/* $Id:$
+/* $Id$
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
@@ -117,24 +117,28 @@
{
/* Get Pointer */
PRUNDOWN_DESCRIPTOR RundownDescriptor =
(PRUNDOWN_DESCRIPTOR)((ULONG_PTR)RunRef->Ptr & ~EX_RUNDOWN_ACTIVE);
+
+ ASSERT(RundownDescriptor != NULL);
+
+ Current = RundownDescriptor->References;
- /* Decrease Reference Count by
RundownDescriptor->References */
+ /* Decrease RundownDescriptor->References by Count
references */
for (;;)
{
ULONG_PTR PrevCount, NewCount;
- if ((Current >> EX_RUNDOWN_COUNT_SHIFT) ==
RundownDescriptor->References)
+ if ((Count >> EX_RUNDOWN_COUNT_SHIFT) == Current)
{
NewCount = 0;
}
else
{
- NewCount = (((Current >> EX_RUNDOWN_COUNT_SHIFT) -
RundownDescriptor->References) << EX_RUNDOWN_COUNT_SHIFT) |
EX_RUNDOWN_ACTIVE;
+ NewCount = ((RundownDescriptor->References - (Count
> EX_RUNDOWN_COUNT_SHIFT)) <<
EX_RUNDOWN_COUNT_SHIFT) |
EX_RUNDOWN_ACTIVE;
}
#ifdef _WIN64
- PrevCount =
(ULONG_PTR)InterlockedCompareExchange64((LONGLONG*)&RunRef->Count,
(LONGLONG)NewCount, (LONGLONG)Current);
+ PrevCount =
(ULONG_PTR)InterlockedCompareExchange64((LONGLONG*)&RundownDescriptor->R
eferences, (LONGLONG)NewCount, (LONGLONG)Current);
#else
- PrevCount =
(ULONG_PTR)InterlockedCompareExchange((LONG*)&RunRef->Count,
(LONG)NewCount, (LONG)Current);
+ PrevCount =
(ULONG_PTR)InterlockedCompareExchange((LONG*)&RundownDescriptor->Referen
ces, (LONG)NewCount, (LONG)Current);
#endif
if (PrevCount == Current)
{
@@ -212,40 +216,45 @@
ULONG_PTR PrevCount, NewPtr, PrevPtr;
RUNDOWN_DESCRIPTOR RundownDescriptor;
-#ifdef _WIN64
- PrevCount =
(ULONG_PTR)InterlockedCompareExchange64((LONGLONG*)&RunRef->Ptr,
(LONGLONG)EX_RUNDOWN_ACTIVE, 0LL);
-#else
- PrevCount =
(ULONG_PTR)InterlockedCompareExchange((LONG*)&RunRef->Ptr,
EX_RUNDOWN_ACTIVE, 0);
-#endif
-
- if (PrevCount == 0 ||
- PrevCount & EX_RUNDOWN_ACTIVE)
- {
- return;
- }
+ PrevCount = RunRef->Count;
- /* save the reference counter */
- RundownDescriptor.References = PrevCount >> EX_RUNDOWN_COUNT_SHIFT;
-
- /* Pending references... wait on them to be closed with an event */
- KeInitializeEvent(&RundownDescriptor.RundownEvent,
NotificationEvent, FALSE);
-
- NewPtr = (ULONG_PTR)&RundownDescriptor | EX_RUNDOWN_ACTIVE;
- PrevCount = EX_RUNDOWN_ACTIVE;
-
- do
+ if (PrevCount != 0 && !(PrevCount & EX_RUNDOWN_ACTIVE))
{
+ /* save the reference counter */
+ RundownDescriptor.References = PrevCount >>
EX_RUNDOWN_COUNT_SHIFT;
+
+ /* Pending references... wait on them to be closed with an
event */
+ KeInitializeEvent(&RundownDescriptor.RundownEvent,
NotificationEvent, FALSE);
+
+ ASSERT(!((ULONG_PTR)&RundownDescriptor & EX_RUNDOWN_ACTIVE));
+
+ NewPtr = (ULONG_PTR)&RundownDescriptor | EX_RUNDOWN_ACTIVE;
+
+ for (;;)
+ {
#ifdef _WIN64
- PrevPtr =
(ULONG_PTR)InterlockedCompareExchange64((LONGLONG*)&RunRef->Ptr,
(LONGLONG)NewPtr, (LONGLONG)PrevCount);
+ PrevPtr =
(ULONG_PTR)InterlockedCompareExchange64((LONGLONG*)&RunRef->Ptr,
(LONGLONG)NewPtr, (LONGLONG)PrevCount);
#else
- PrevPtr =
(ULONG_PTR)InterlockedCompareExchange((LONG*)&RunRef->Ptr, (LONG)NewPtr,
(LONG)PrevCount);
+ PrevPtr =
(ULONG_PTR)InterlockedCompareExchange((LONG*)&RunRef->Ptr, (LONG)NewPtr,
(LONG)PrevCount);
#endif
-
- PrevCount = PrevPtr;
- } while (PrevPtr != PrevCount);
-
- /* Wait for whoever needs to release to notify us */
- KeWaitForSingleObject(&RundownDescriptor.RundownEvent, Executive,
KernelMode, FALSE, NULL);
+ if (PrevPtr == PrevCount)
+ {
+ /* Wait for whoever needs to release to notify us */
+ KeWaitForSingleObject(&RundownDescriptor.RundownEvent,
Executive, KernelMode, FALSE, NULL);
+ break;
+ }
+ else if (PrevPtr == 0 || (PrevPtr & EX_RUNDOWN_ACTIVE))
+ {
+ /* some one else was faster, let's just bail */
+ break;
+ }
+
+ PrevCount = PrevPtr;
+
+ /* save the changed reference counter and try again */
+ RundownDescriptor.References = PrevCount >>
EX_RUNDOWN_COUNT_SHIFT;
+ }
+ }
}
/* EOF */