- 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->Count, (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]