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 */