- Implemented InterlockedBitTestAndReset, InterlockedBitTestAndSet, InterlockedExchangeAddSizeT. - Rundown re-implementation:
* Added inlined functions for internal system use for quickest path. * Correctly named all functions Exf instead of Ex. * Removed PAGED_CODE(); macro where it shouldn't be used. * Addded multiple ASSERTS for sanity checks. * Used macros for win64/32 portability. * Fixed the following bugs/features: * ExfAcquireRundownProtection: ** Added specific code instead of calling the generic function. Rundown locks are performance critical and a dedicated path is prefered. * ExfAcquireRundownProtectionEx: ** Added a quick immediate check to see if the rundown is active. * ExfReleaseRundownProtection: ** Added specific code instead of calling the generic function. Rundown locks are performance critical and a dedicated path is prefered. * ExfReleaseRundownProtectionEx: ** Simplified the loop code. ** Fixed a bug in signaling of the event during waitblock count removal * ExfWaitForRundownProtectionRelease: ** Add quick case when we don't actually need a full wait. ** Simplified loop code. * Added stubs for cache-aware implementation. * Documented the functions. Modified: trunk/reactos/include/ndk/exfuncs.h Modified: trunk/reactos/ntoskrnl/cm/ntfunc.c Modified: trunk/reactos/ntoskrnl/ex/rundown.c Modified: trunk/reactos/ntoskrnl/include/internal/ex.h Modified: trunk/reactos/ntoskrnl/ntoskrnl.def Modified: trunk/reactos/ntoskrnl/ntoskrnl.xml Modified: trunk/reactos/w32api/include/winnt.h _____
Modified: trunk/reactos/include/ndk/exfuncs.h --- trunk/reactos/include/ndk/exfuncs.h 2005-12-29 19:02:06 UTC (rev 20434) +++ trunk/reactos/include/ndk/exfuncs.h 2005-12-29 19:12:09 UTC (rev 20435) @@ -37,11 +37,62 @@
// VOID FASTCALL -ExEnterCriticalRegionAndAcquireFastMutexUnsafe(PFAST_MUTEX FastMutex); +ExEnterCriticalRegionAndAcquireFastMutexUnsafe( + PFAST_MUTEX FastMutex +);
VOID FASTCALL -ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(PFAST_MUTEX FastMutex); +ExReleaseFastMutexUnsafeAndLeaveCriticalRegion( + PFAST_MUTEX FastMutex +); + +// +// Pushlock functions +// +VOID +FASTCALL +ExfAcquirePushLockExclusive( + PEX_PUSH_LOCK PushLock +); + +VOID +FASTCALL +ExfAcquirePushLockShared( + PEX_PUSH_LOCK PushLock +); + +VOID +FASTCALL +ExfReleasePushLock( + PEX_PUSH_LOCK PushLock +); + +VOID +FASTCALL +ExfReleasePushLockExclusive( + PEX_PUSH_LOCK PushLock +); + +VOID +FASTCALL +ExfReleasePushLockShared( + PEX_PUSH_LOCK PushLock +); + +VOID +FASTCALL +ExfTryToWakePushLock( + PEX_PUSH_LOCK PushLock +); + +VOID +FASTCALL +ExfUnblockPushLock( + PEX_PUSH_LOCK PushLock, + PVOID CurrentWaitBlock +); + #endif
// _____
Modified: trunk/reactos/ntoskrnl/cm/ntfunc.c --- trunk/reactos/ntoskrnl/cm/ntfunc.c 2005-12-29 19:02:06 UTC (rev 20434) +++ trunk/reactos/ntoskrnl/cm/ntfunc.c 2005-12-29 19:12:09 UTC (rev 20435) @@ -147,7 +147,7 @@
CurrentCallback = CONTAINING_RECORD(CurrentEntry, REGISTRY_CALLBACK, ListEntry); if(!CurrentCallback->PendingDelete && - ExAcquireRundownProtectionEx(&CurrentCallback->RundownRef, 1)) + ExAcquireRundownProtection(&CurrentCallback->RundownRef)) { /* don't hold locks during the callbacks! */ ExReleaseFastMutex(&CmiCallbackLock); @@ -160,7 +160,7 @@ /* don't release the rundown protection before holding the callback lock so the pointer to the next callback isn't cleared in case this callback get's deleted */ - ExReleaseRundownProtectionEx(&CurrentCallback->RundownRef, 1); + ExReleaseRundownProtection(&CurrentCallback->RundownRef); if(!NT_SUCCESS(Status)) { /* one callback returned failure, don't call any more callbacks */ _____
Modified: trunk/reactos/ntoskrnl/ex/rundown.c --- trunk/reactos/ntoskrnl/ex/rundown.c 2005-12-29 19:02:06 UTC (rev 20434) +++ trunk/reactos/ntoskrnl/ex/rundown.c 2005-12-29 19:12:09 UTC (rev 20435) @@ -1,10 +1,10 @@
/* * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel + * PROJECT: ReactOS Kernel * FILE: ntoskrnl/ex/rundown.c - * PURPOSE: Rundown Protection Functions - * - * PROGRAMMERS: Alex Ionescu & Thomas Weidenmueller - Implementation + * PURPOSE: Rundown and Cache-Aware Rundown Protection + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) + * Thomas Weidenmueller */
/* INCLUDES *****************************************************************/ @@ -15,261 +15,489 @@
/* FUNCTIONS *****************************************************************/
-/* - * @implemented - */ +/*++ + * @name ExfAcquireRundownProtection + * @implemented NT5.1 + * + * The ExfAcquireRundownProtection routine acquires rundown protection for + * the specified descriptor. + * + * @param RunRef + * Pointer to a rundown reference descriptor. + * + * @return TRUE if access to the protected structure was granted, FALSE otherwise. + * + * @remarks Callers of ExfAcquireRundownProtection can be running at any IRQL. + * + *--*/ BOOLEAN FASTCALL -ExAcquireRundownProtection ( - IN PEX_RUNDOWN_REF RunRef - ) +ExfAcquireRundownProtection(IN PEX_RUNDOWN_REF RunRef) { - /* Call the general function with only one Reference add */ - return ExAcquireRundownProtectionEx(RunRef, 1); + ULONG_PTR Value = RunRef->Count, NewValue; + + /* Make sure a rundown is not active */ + if (Value & EX_RUNDOWN_ACTIVE) return FALSE; + + /* Loop until successfully incremented the counter */ + for (;;) + { + /* Add a reference */ + NewValue = Value + EX_RUNDOWN_COUNT_INC; + + /* Change the value */ + Value = ExpChangeRundown(RunRef, NewValue, Value); + if (Value == NewValue) return TRUE; + + /* Make sure a rundown is not active */ + if (Value & EX_RUNDOWN_ACTIVE) return FALSE; + } }
-/* - * @implemented - */ +/*++ + * @name ExfAcquireRundownProtectionEx + * @implemented NT5.2 + * + * The ExfAcquireRundownProtectionEx routine acquires multiple rundown + * protection references for the specified descriptor. + * + * @param RunRef + * Pointer to a rundown reference descriptor. + * + * @param Count + * Number of times to reference the descriptor. + * + * @return TRUE if access to the protected structure was granted, FALSE otherwise. + * + * @remarks Callers of ExfAcquireRundownProtectionEx can be running at any IRQL. + * + *--*/ BOOLEAN FASTCALL -ExAcquireRundownProtectionEx ( - IN PEX_RUNDOWN_REF RunRef, - IN ULONG Count - ) +ExfAcquireRundownProtectionEx(IN PEX_RUNDOWN_REF RunRef, + IN ULONG Count) { - ULONG_PTR PrevCount, Current; + ULONG_PTR Value = RunRef->Count, NewValue;
- PAGED_CODE(); + /* Make sure a rundown is not active */ + if (Value & EX_RUNDOWN_ACTIVE) return FALSE;
+ /* Convert the count to our internal representation */ Count <<= EX_RUNDOWN_COUNT_SHIFT;
/* Loop until successfully incremented the counter */ - do + for (;;) { - Current = RunRef->Count; + /* Add references */ + NewValue = Value + Count;
+ /* Change the value */ + Value = ExpChangeRundown(RunRef, NewValue, Value); + if (Value == NewValue) return TRUE; + /* Make sure a rundown is not active */ - if (Current & EX_RUNDOWN_ACTIVE) - { - return FALSE; - } - -#ifdef _WIN64 - PrevCount = (ULONG_PTR)InterlockedExchangeAdd64((LONGLONG*)&RunRef->Count, (LONGLONG)Count); -#else - PrevCount = (ULONG_PTR)InterlockedExchangeAdd((LONG*)&RunRef->Count, (LONG)Count); -#endif - } while (PrevCount != Current); - - /* Return Success */ - return TRUE; + if (Value & EX_RUNDOWN_ACTIVE) return FALSE; + } }
-/* - * @implemented - */ +/*++ + * @name ExfInitializeRundownProtection + * @implemented NT5.1 + * + * The ExfInitializeRundownProtection routine initializes a rundown + * protection descriptor. + * + * @param RunRef + * Pointer to a rundown reference descriptor. + * + * @return None. + * + * @remarks Callers of ExfInitializeRundownProtection can be running at any IRQL. + * + *--*/ VOID FASTCALL -ExInitializeRundownProtection ( - IN PEX_RUNDOWN_REF RunRef - ) +ExfInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef) { - PAGED_CODE(); - /* Set the count to zero */ RunRef->Count = 0; }
-/* - * @implemented - */ +/*++ + * @name ExfReInitializeRundownProtection + * @implemented NT5.1 + * + * The ExfReInitializeRundownProtection routine re-initializes a rundown + * protection descriptor. + * + * @param RunRef + * Pointer to a rundown reference descriptor. + * + * @return None. + * + * @remarks Callers of ExfReInitializeRundownProtection can be running at any IRQL. + * + *--*/ VOID FASTCALL -ExReInitializeRundownProtection ( - IN PEX_RUNDOWN_REF RunRef - ) +ExfReInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef) { PAGED_CODE();
+ /* Sanity check */ + ASSERT((RunRef->Count & EX_RUNDOWN_ACTIVE) != 0); + /* Reset the count */ -#ifdef _WIN64 - InterlockedExchange64((LONGLONG*)&RunRef->Count, 0LL); -#else - InterlockedExchange((LONG*)&RunRef->Count, 0); -#endif + InterlockedExchange((PLONG)&RunRef->Count, 0); }
- -/* - * @implemented - */ +/*++ + * @name ExfRundownCompleted + * @implemented NT5.1 + * + * The ExfRundownCompleted routine completes the rundown of the specified + * descriptor by setting the active bit. + * + * @param RunRef + * Pointer to a rundown reference descriptor. + * + * @return None. + * + * @remarks Callers of ExfRundownCompleted must be running at IRQL <= APC_LEVEL. + * + *--*/ VOID FASTCALL -ExReleaseRundownProtectionEx ( - IN PEX_RUNDOWN_REF RunRef, - IN ULONG Count - ) +ExfRundownCompleted(IN PEX_RUNDOWN_REF RunRef) { PAGED_CODE();
- Count <<= EX_RUNDOWN_COUNT_SHIFT; + /* Sanity check */ + ASSERT((RunRef->Count & EX_RUNDOWN_ACTIVE) != 0);
- for (;;) + /* Mark the counter as active */ + InterlockedExchange((PLONG)&RunRef->Count, EX_RUNDOWN_ACTIVE); +} + +/*++ + * @name ExfReleaseRundownProtection + * @implemented NT5.1 + * + * The ExfReleaseRundownProtection routine releases the rundown protection + * reference for the specified descriptor. + * + * @param RunRef + * Pointer to a rundown reference descriptor. + * + * @return None. + * + * @remarks Callers of ExfReleaseRundownProtection can be running at any IRQL. + * + *--*/ +VOID +FASTCALL +ExfReleaseRundownProtection(IN PEX_RUNDOWN_REF RunRef) +{ + ULONG_PTR Value = RunRef->Count, NewValue; + PEX_RUNDOWN_WAIT_BLOCK WaitBlock; + + /* Check if rundown is not active */ + if (!(Value & EX_RUNDOWN_ACTIVE)) { - ULONG_PTR Current = RunRef->Count; + /* Loop until successfully incremented the counter */ + for (;;) + { + /* Sanity check */ + ASSERT((Value >= EX_RUNDOWN_COUNT_INC) || (KeNumberProcessors > 1));
- /* Check if Rundown is active */ - if (Current & EX_RUNDOWN_ACTIVE) + /* Get the new value */ + NewValue = Value - EX_RUNDOWN_COUNT_INC; + + /* Change the value */ + Value = ExpChangeRundown(RunRef, NewValue, Value); + if (Value == NewValue) return; + + /* Loop again if we're still not active */ + if (Value & EX_RUNDOWN_ACTIVE) break; + } + } + + /* Get the wait block */ + WaitBlock = (PEX_RUNDOWN_WAIT_BLOCK)(Value & ~EX_RUNDOWN_ACTIVE); + ASSERT((WaitBlock->Count > 0) || (KeNumberProcessors > 1)); + + /* Remove the one count */ + if (InterlockedExchangeAddSizeT(&WaitBlock->Count, -1)) + { + /* We're down to 0 now, so signal the event */ + KeSetEvent(&WaitBlock->RundownEvent, IO_NO_INCREMENT, FALSE); + } +} + +/*++ + * @name ExfReleaseRundownProtectionEx + * @implemented NT5.2 + * + * The ExfReleaseRundownProtectionEx routine releases multiple rundown + * protection references for the specified descriptor. + * + * @param RunRef + * Pointer to a rundown reference descriptor. + * + * @param Count + * Number of times to dereference the descriptor. + * + * @return None. + * + * @remarks Callers of ExfAcquireRundownProtectionEx can be running at any IRQL. + * + *--*/ +VOID +FASTCALL +ExfReleaseRundownProtectionEx(IN PEX_RUNDOWN_REF RunRef, + IN ULONG Count) +{ + ULONG_PTR Value = RunRef->Count, NewValue; + PEX_RUNDOWN_WAIT_BLOCK WaitBlock; + + /* Check if rundown is not active */ + if (!(Value & EX_RUNDOWN_ACTIVE)) + { + /* Loop until successfully incremented the counter */ + for (;;) { - /* Get Pointer */ - PEX_RUNDOWN_WAIT_BLOCK RundownDescriptor = (PEX_RUNDOWN_WAIT_BLOCK)(Current & ~EX_RUNDOWN_ACTIVE); + /* Sanity check */ + ASSERT((Value >= EX_RUNDOWN_COUNT_INC * Count) || (KeNumberProcessors > 1));
- if (RundownDescriptor == NULL) - { - /* the rundown was completed and there's no one to notify */ - break; - } + /* Get the new value */ + NewValue = Value - (Count * EX_RUNDOWN_COUNT_INC);
- Current = RundownDescriptor->Count; + /* Change the value */ + Value = ExpChangeRundown(RunRef, NewValue, Value); + if (Value == NewValue) return;
- /* Decrease RundownDescriptor->Count by Count Count */ - for (;;) - { - ULONG_PTR PrevCount, NewCount; + /* Loop again if we're still not active */ + if (Value & EX_RUNDOWN_ACTIVE) break; + } + }
- if ((Count >> EX_RUNDOWN_COUNT_SHIFT) == Current) - { - NewCount = 0; - } - else - { - NewCount = ((RundownDescriptor->Count - (Count >> EX_RUNDOWN_COUNT_SHIFT)) << EX_RUNDOWN_COUNT_SHIFT) | EX_RUNDOWN_ACTIVE; - } -#ifdef _WIN64 - PrevCount = (ULONG_PTR)InterlockedCompareExchange64((LONGLONG*)&RundownDescriptor->C ount, (LONGLONG)NewCount, (LONGLONG)Current); -#else - PrevCount = (ULONG_PTR)InterlockedCompareExchange((LONG*)&RundownDescriptor->Count, (LONG)NewCount, (LONG)Current); -#endif - if (PrevCount == Current) - { - if (NewCount == 0) - { - /* Signal the event so anyone waiting on it can now kill it */ - KeSetEvent(&RundownDescriptor->RundownEvent, 0, FALSE); - } + /* Get the wait block */ + WaitBlock = (PEX_RUNDOWN_WAIT_BLOCK)(Value & ~EX_RUNDOWN_ACTIVE); + ASSERT((WaitBlock->Count >= Count) || (KeNumberProcessors > 1));
- /* Successfully decremented the counter, so bail! */ - break; - } + /* Remove the count */ + if (InterlockedExchangeAddSizeT(WaitBlock->Count, -(LONG)Count) == + (LONG)Count) + { + /* We're down to 0 now, so signal the event */ + KeSetEvent(&WaitBlock->RundownEvent, IO_NO_INCREMENT, FALSE); + } +}
- Current = PrevCount; - } +/*++ + * @name ExfWaitForRundownProtectionRelease + * @implemented NT5.1 + * + * The ExfWaitForRundownProtectionRelease routine waits until the specified + * rundown descriptor has been released. + * + * @param RunRef + * Pointer to a rundown reference descriptor. + * + * @return None. + * + * @remarks Callers of ExfWaitForRundownProtectionRelease must be running + * at IRQL <= APC_LEVEL. + * + *--*/ +VOID +FASTCALL +ExfWaitForRundownProtectionRelease(IN PEX_RUNDOWN_REF RunRef) +{ + ULONG_PTR Value, Count, NewValue; + EX_RUNDOWN_WAIT_BLOCK WaitBlock; + PEX_RUNDOWN_WAIT_BLOCK WaitBlockPointer; + PKEVENT Event; + PAGED_CODE();
- break; - } - else + /* Set the active bit */ + Value = ExpChangeRundown(RunRef, EX_RUNDOWN_ACTIVE, 0); + if ((Value == 0) || (Value == EX_RUNDOWN_ACTIVE)) return; + + /* No event for now */ + Event = NULL; + WaitBlockPointer = (PEX_RUNDOWN_WAIT_BLOCK)((ULONG_PTR)&WaitBlock | + EX_RUNDOWN_ACTIVE); + + /* Start waitblock set loop */ + for(;;) + { + /* Save the count */ + Count = Value >> EX_RUNDOWN_COUNT_SHIFT; + + /* If the count is over one or we don't have en event yet, create it */ + if (Count || !Event) { - ULONG_PTR PrevCount, NewCount = Current - (ULONG_PTR)Count; -#ifdef _WIN64 - PrevCount = (ULONG_PTR)InterlockedCompareExchange64((LONGLONG*)&RunRef->Count, (LONGLONG)NewCount, (LONGLONG)Current); -#else - PrevCount = (ULONG_PTR)InterlockedCompareExchange((LONG*)&RunRef->Count, (LONG)NewCount, (LONG)Current); -#endif - if (PrevCount == Current) - { - /* Successfully decremented the counter, so bail! */ - break; - } + /* Initialize the event */ + KeInitializeEvent(&WaitBlock.RundownEvent, + NotificationEvent, + FALSE); + + /* Set the pointer */ + Event = &WaitBlock.RundownEvent; } + + /* Set the count */ + WaitBlock.Count = Count; + + /* Now set the pointer */ + NewValue = ExpChangeRundown(RunRef, PtrToUlong(WaitBlockPointer), Value); + if (NewValue == Value) break; + + /* Loop again */ + Value = NewValue; + ASSERT((Value & EX_RUNDOWN_ACTIVE) == 0); } + + /* If the count was 0, we're done */ + if (!Count) return; + + /* Wait for whoever needs to release to notify us */ + KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL); + ASSERT(WaitBlock.Count == 0); }
+/* FIXME: STUBS **************************************************************/ + /* -* @implemented -*/ + * @unimplemented NT5.2 + */ +BOOLEAN +FASTCALL +ExfAcquireRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware) +{ + DBG_UNREFERENCED_PARAMETER(RunRefCacheAware); + UNIMPLEMENTED; + return FALSE; +} + +/* + * @unimplemented NT5.2 + */ +BOOLEAN +FASTCALL +ExfAcquireRundownProtectionCacheAwareEx(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware, + IN ULONG Count) +{ + DBG_UNREFERENCED_PARAMETER(RunRefCacheAware); + DBG_UNREFERENCED_PARAMETER(Count); + UNIMPLEMENTED; + return FALSE; +} + +/* + * @unimplemented NT5.2 + */ VOID FASTCALL -ExReleaseRundownProtection ( - IN PEX_RUNDOWN_REF RunRef - ) +ExfReleaseRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware) { - /* Call the general function with only 1 reference removal */ - ExReleaseRundownProtectionEx(RunRef, 1); + DBG_UNREFERENCED_PARAMETER(RunRefCacheAware); + UNIMPLEMENTED; }
/* - * @implemented + * @unimplemented NT5.2 */ VOID FASTCALL -ExRundownCompleted ( - IN PEX_RUNDOWN_REF RunRef - ) +ExfReleaseRundownProtectionCacheAwareEx(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware, + IN ULONG Count) { - PAGED_CODE(); + DBG_UNREFERENCED_PARAMETER(RunRefCacheAware); + DBG_UNREFERENCED_PARAMETER(Count); + UNIMPLEMENTED; +}
- /* mark the counter as active */ -#ifdef _WIN64 - InterlockedExchange64((LONGLONG*)&RunRef->Count, (LONGLONG)EX_RUNDOWN_ACTIVE); -#else - InterlockedExchange((LONG*)&RunRef->Count, EX_RUNDOWN_ACTIVE); -#endif +/* + * @unimplemented NT5.2 + */ +VOID +FASTCALL +ExfWaitForRundownProtectionReleaseCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware) +{ + DBG_UNREFERENCED_PARAMETER(RunRefCacheAware); + UNIMPLEMENTED; }
/* - * @implemented + * @unimplemented NT5.2 */ VOID FASTCALL -ExWaitForRundownProtectionRelease ( - IN PEX_RUNDOWN_REF RunRef - ) +ExfRundownCompletedCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware) { - ULONG_PTR PrevCount, NewPtr, PrevPtr; - EX_RUNDOWN_WAIT_BLOCK RundownDescriptor; + DBG_UNREFERENCED_PARAMETER(RunRefCacheAware); + UNIMPLEMENTED; +}
- PAGED_CODE(); +/* + * @unimplemented NT5.2 + */ +VOID +FASTCALL +ExfReInitializeRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware) +{ + DBG_UNREFERENCED_PARAMETER(RunRefCacheAware); + UNIMPLEMENTED; +}
- PrevCount = RunRef->Count; +/* + * @unimplemented NT5.2 + */ +PEX_RUNDOWN_REF_CACHE_AWARE +NTAPI +ExAllocateCacheAwareRundownProtection(IN POOL_TYPE PoolType, + IN ULONG Tag) +{ + DBG_UNREFERENCED_PARAMETER(PoolType); + DBG_UNREFERENCED_PARAMETER(Tag); + UNIMPLEMENTED; + return NULL; +}
- if (PrevCount != 0 && !(PrevCount & EX_RUNDOWN_ACTIVE)) - { - /* save the reference counter */ - RundownDescriptor.Count = PrevCount >> EX_RUNDOWN_COUNT_SHIFT; +/* + * @unimplemented NT5.2 + */ +VOID +NTAPI +ExFreeCacheAwareRundownProtection(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware) +{ + DBG_UNREFERENCED_PARAMETER(RunRefCacheAware); + UNIMPLEMENTED; +}
- /* Pending Count... wait on them to be closed with an event */ - KeInitializeEvent(&RundownDescriptor.RundownEvent, NotificationEvent, FALSE); +/* + * @unimplemented NT5.2 + */ +VOID +NTAPI +ExInitializeRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware, + IN ULONG Count) +{ + DBG_UNREFERENCED_PARAMETER(RunRefCacheAware); + DBG_UNREFERENCED_PARAMETER(Count); + UNIMPLEMENTED; +}
- 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); -#else - PrevPtr = (ULONG_PTR)InterlockedCompareExchange((LONG*)&RunRef->Ptr, (LONG)NewPtr, (LONG)PrevCount); -#endif - 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.Count = PrevCount >> EX_RUNDOWN_COUNT_SHIFT; - } - } +/* + * @unimplemented NT5.2 + */ +SIZE_T +NTAPI +ExSizeOfRundownProtectionCacheAware(VOID) +{ + UNIMPLEMENTED; + return 0; }
-/* EOF */ _____
Modified: trunk/reactos/ntoskrnl/include/internal/ex.h --- trunk/reactos/ntoskrnl/include/internal/ex.h 2005-12-29 19:02:06 UTC (rev 20434) +++ trunk/reactos/ntoskrnl/include/internal/ex.h 2005-12-29 19:12:09 UTC (rev 20435) @@ -77,6 +77,58 @@
STDCALL ExpInitializeProfileImplementation(VOID);
+/* Rundown Functions ********************************************************/ + +VOID +FASTCALL +ExfInitializeRundownProtection( + OUT PEX_RUNDOWN_REF RunRef +); + +VOID +FASTCALL +ExfReInitializeRundownProtection( + OUT PEX_RUNDOWN_REF RunRef +); + +BOOLEAN +FASTCALL +ExfAcquireRundownProtection( + IN OUT PEX_RUNDOWN_REF RunRef +); + +BOOLEAN +FASTCALL +ExfAcquireRundownProtectionEx( + IN OUT PEX_RUNDOWN_REF RunRef, + IN ULONG Count +); + +VOID +FASTCALL +ExfReleaseRundownProtection( + IN OUT PEX_RUNDOWN_REF RunRef +); + +VOID +FASTCALL +ExfReleaseRundownProtectionEx( + IN OUT PEX_RUNDOWN_REF RunRef, + IN ULONG Count +); + +VOID +FASTCALL +ExfRundownCompleted( + OUT PEX_RUNDOWN_REF RunRef +); + +VOID +FASTCALL +ExfWaitForRundownProtectionRelease( + IN OUT PEX_RUNDOWN_REF RunRef +); + /* HANDLE TABLE FUNCTIONS ***************************************************/
#define EX_HANDLE_ENTRY_LOCKED (1 << ((sizeof(PVOID) * 8) - 1)) @@ -192,6 +244,184 @@ return ExSystemExceptionFilter(); }
+/* RUNDOWN *******************************************************************/ + +#ifdef _WIN64 +#define ExpChangeRundown(x, y, z) InterlockedCompareExchange64((PLONGLONG)x, y, z) +#define ExpSetRundown(x, y) InterlockedExchange64((PLONGLONG)x, y) +#else +#define ExpChangeRundown(x, y, z) InterlockedCompareExchange((PLONG)x, y, z) +#define ExpSetRundown(x, y) InterlockedExchange((PLONG)x, y) +#endif + +/*++ + * @name ExfAcquireRundownProtection + * INTERNAL MACRO + * + * The ExfAcquireRundownProtection routine acquires rundown protection for + * the specified descriptor. + * + * @param RunRef + * Pointer to a rundown reference descriptor. + * + * @return TRUE if access to the protected structure was granted, FALSE otherwise. + * + * @remarks This is the internal macro for system use only.In case the rundown + * was active, then the slow-path will be called through the exported + * function. + * + *--*/ +BOOLEAN +FORCEINLINE +ExAcquireRundownProtection(IN PEX_RUNDOWN_REF RunRef) +{ + ULONG_PTR Value, NewValue, OldValue; + + /* Get the current value and mask the active bit */ + Value = RunRef->Count &~ EX_RUNDOWN_ACTIVE; + + /* Add a reference */ + NewValue = Value + EX_RUNDOWN_COUNT_INC; + + /* Change the value */ + OldValue = ExpChangeRundown(RunRef, NewValue, Value); + if (OldValue != Value) + { + /* Rundown was active, use long path */ + return ExfAcquireRundownProtection(RunRef); + } + + /* Success */ + return TRUE; +} + +/*++ + * @name ExReleaseRundownProtection + * INTERNAL MACRO + * + * The ExReleaseRundownProtection routine releases rundown protection for + * the specified descriptor. + * + * @param RunRef + * Pointer to a rundown reference descriptor. + * + * @return TRUE if access to the protected structure was granted, FALSE otherwise. + * + * @remarks This is the internal macro for system use only.In case the rundown + * was active, then the slow-path will be called through the exported + * function. + * + *--*/ +VOID +FORCEINLINE +ExReleaseRundownProtection(IN PEX_RUNDOWN_REF RunRef) +{ + ULONG_PTR Value, NewValue, OldValue; + + /* Get the current value and mask the active bit */ + Value = RunRef->Count &~ EX_RUNDOWN_ACTIVE; + + /* Remove a reference */ + NewValue = Value - EX_RUNDOWN_COUNT_INC; + + /* Change the value */ + OldValue = ExpChangeRundown(RunRef, NewValue, Value); + + /* Check if the rundown was active */ + if (OldValue != Value) + { + /* Rundown was active, use long path */ + ExfReleaseRundownProtection(RunRef); + } + else + { + /* Sanity check */ + ASSERT((Value >= EX_RUNDOWN_COUNT_INC) || (KeNumberProcessors > 1)); + } +} + +/*++ + * @name ExInitializeRundownProtection + * INTERNAL MACRO + * + * The ExInitializeRundownProtection routine initializes a rundown + * protection descriptor. + * + * @param RunRef + * Pointer to a rundown reference descriptor. + * + * @return None. + * + * @remarks This is the internal macro for system use only. + * + *--*/ +VOID +FORCEINLINE +ExInitializeRundownProtection(IN PEX_RUNDOWN_REF RunRef) +{ + /* Set the count to zero */ + RunRef->Count = 0; +} + +/*++ + * @name ExWaitForRundownProtectionRelease + * INTERNAL MACRO + * + * The ExWaitForRundownProtectionRelease routine waits until the specified + * rundown descriptor has been released. + * + * @param RunRef + * Pointer to a rundown reference descriptor. + * + * @return None. + * + * @remarks This is the internal macro for system use only. If a wait is actually + * necessary, then the slow path is taken through the exported function. + * + *--*/ +VOID +FORCEINLINE +ExWaitForRundownProtectionRelease(IN PEX_RUNDOWN_REF RunRef) +{ + ULONG_PTR Value; + + /* Set the active bit */ + Value = ExpChangeRundown(RunRef, EX_RUNDOWN_ACTIVE, 0); + if ((Value) || (Value != EX_RUNDOWN_ACTIVE)) + { + /* If the the rundown wasn't already active, then take the long path */ + ExfWaitForRundownProtectionRelease(RunRef); + } +} + +/*++ + * @name ExRundownCompleted + * INTERNAL MACRO + * + * The ExRundownCompleted routine completes the rundown of the specified [truncated at 1000 lines; 168 more skipped]