- 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(a)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]