[DRWTSN32] Print some extra exception info
[reactos.git] / ntoskrnl / ex / rundown.c
index da96b08..be9e6fc 100644 (file)
@@ -376,8 +376,6 @@ ExfWaitForRundownProtectionRelease(IN PEX_RUNDOWN_REF RunRef)
     ASSERT(WaitBlock.Count == 0);
 }
 
-/* FIXME: STUBS **************************************************************/
-
 /*
  * @implemented NT5.2
  */
@@ -387,7 +385,7 @@ ExfAcquireRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCache
 {
     PEX_RUNDOWN_REF RunRef;
 
-    RunRef = ExGetRunRefForCurrentProcessor(RunRefCacheAware);
+    RunRef = ExGetRunRefForGivenProcessor(RunRefCacheAware, KeGetCurrentProcessorNumber());
     return _ExAcquireRundownProtection(RunRef);
 }
 
@@ -401,7 +399,7 @@ ExfAcquireRundownProtectionCacheAwareEx(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCac
 {
     PEX_RUNDOWN_REF RunRef;
 
-    RunRef = ExGetRunRefForCurrentProcessor(RunRefCacheAware);
+    RunRef = ExGetRunRefForGivenProcessor(RunRefCacheAware, KeGetCurrentProcessorNumber());
     return ExfAcquireRundownProtectionEx(RunRef, Count);
 }
 
@@ -414,8 +412,8 @@ ExfReleaseRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCache
 {
     PEX_RUNDOWN_REF RunRef;
 
-    RunRef = ExGetRunRefForCurrentProcessor(RunRefCacheAware);
-    return _ExReleaseRundownProtection(RunRef);
+    RunRef = ExGetRunRefForGivenProcessor(RunRefCacheAware, KeGetCurrentProcessorNumber());
+    _ExReleaseRundownProtection(RunRef);
 }
 
 /*
@@ -428,41 +426,132 @@ ExfReleaseRundownProtectionCacheAwareEx(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCac
 {
     PEX_RUNDOWN_REF RunRef;
 
-    RunRef = ExGetRunRefForCurrentProcessor(RunRefCacheAware);
-    return ExfReleaseRundownProtectionEx(RunRef, Count);
+    RunRef = ExGetRunRefForGivenProcessor(RunRefCacheAware, KeGetCurrentProcessorNumber());
+    ExfReleaseRundownProtectionEx(RunRef, Count);
 }
 
 /*
- * @unimplemented NT5.2
+ * @implemented NT5.2
  */
 VOID
 FASTCALL
 ExfWaitForRundownProtectionReleaseCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware)
 {
-    DBG_UNREFERENCED_PARAMETER(RunRefCacheAware);
-    UNIMPLEMENTED;
+    PEX_RUNDOWN_REF RunRef;
+    EX_RUNDOWN_WAIT_BLOCK WaitBlock;
+    PEX_RUNDOWN_WAIT_BLOCK WaitBlockPointer;
+    ULONG_PTR ProcCount, Current, Value, OldValue, TotalCount;
+
+    ProcCount = RunRefCacheAware->Number;
+    /* No proc, nothing to do */
+    if (ProcCount == 0)
+    {
+        return;
+    }
+
+    TotalCount = 0;
+    WaitBlock.Count = 0;
+    WaitBlockPointer = (PEX_RUNDOWN_WAIT_BLOCK)((ULONG_PTR)&WaitBlock |
+                                                EX_RUNDOWN_ACTIVE);
+    /* We will check all our runrefs */
+    for (Current = 0; Current < ProcCount; ++Current)
+    {
+        /* Get the runref for the proc */
+        RunRef = ExGetRunRefForGivenProcessor(RunRefCacheAware, Current);
+        /* Loop for setting the wait block */
+        do
+        {
+            Value = RunRef->Count;
+            ASSERT((Value & EX_RUNDOWN_ACTIVE) == 0);
+
+            /* Remove old value and set our waitblock instead */
+            OldValue = ExpChangeRundown(RunRef, WaitBlockPointer, Value);
+            if (OldValue == Value)
+            {
+                break;
+            }
+
+            Value = OldValue;
+        }
+        while (TRUE);
+
+        /* Count the deleted values */
+        TotalCount += Value;
+    }
+
+    /* Sanity check: we didn't overflow */
+    ASSERT((LONG_PTR)TotalCount >= 0);
+    if (TotalCount != 0)
+    {
+        /* Init the waitblock event */
+        KeInitializeEvent(&WaitBlock.WakeEvent,
+                          SynchronizationEvent,
+                          FALSE);
+
+        /* Do we have to wait? If so, go ahead! */
+        if (InterlockedExchangeAddSizeT(&WaitBlock.Count,
+                                        (LONG_PTR)TotalCount >> EX_RUNDOWN_COUNT_SHIFT) ==
+                                       -(LONG_PTR)(TotalCount >> EX_RUNDOWN_COUNT_SHIFT))
+        {
+            KeWaitForSingleObject(&WaitBlock.WakeEvent, Executive, KernelMode, FALSE, NULL);
+        }
+    }
 }
 
 /*
- * @unimplemented NT5.2
+ * @implemented NT5.2
  */
 VOID
 FASTCALL
 ExfRundownCompletedCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware)
 {
-    DBG_UNREFERENCED_PARAMETER(RunRefCacheAware);
-    UNIMPLEMENTED;
+    PEX_RUNDOWN_REF RunRef;
+    ULONG ProcCount, Current;
+
+    ProcCount = RunRefCacheAware->Number;
+    /* No proc, nothing to do */
+    if (ProcCount == 0)
+    {
+        return;
+    }
+
+    /* We will mark all our runrefs active */
+    for (Current = 0; Current < ProcCount; ++Current)
+    {
+        /* Get the runref for the proc */
+        RunRef = ExGetRunRefForGivenProcessor(RunRefCacheAware, Current);
+        ASSERT((RunRef->Count & EX_RUNDOWN_ACTIVE) != 0);
+
+        ExpSetRundown(RunRef, EX_RUNDOWN_ACTIVE);
+    }
 }
 
 /*
- * @unimplemented NT5.2
+ * @implemented NT5.2
  */
 VOID
 FASTCALL
 ExfReInitializeRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware)
 {
-    DBG_UNREFERENCED_PARAMETER(RunRefCacheAware);
-    UNIMPLEMENTED;
+    PEX_RUNDOWN_REF RunRef;
+    ULONG ProcCount, Current;
+
+    ProcCount = RunRefCacheAware->Number;
+    /* No proc, nothing to do */
+    if (ProcCount == 0)
+    {
+        return;
+    }
+
+    /* We will mark all our runrefs inactive */
+    for (Current = 0; Current < ProcCount; ++Current)
+    {
+        /* Get the runref for the proc */
+        RunRef = ExGetRunRefForGivenProcessor(RunRefCacheAware, Current);
+        ASSERT((RunRef->Count & EX_RUNDOWN_ACTIVE) != 0);
+
+        ExpSetRundown(RunRef, 0);
+    }
 }
 
 /*
@@ -473,9 +562,9 @@ NTAPI
 ExAllocateCacheAwareRundownProtection(IN POOL_TYPE PoolType,
                                       IN ULONG Tag)
 {
-    PVOID PoolToFree;
     PEX_RUNDOWN_REF RunRef;
-    ULONG RunRefSize, Count, Offset;
+    PVOID PoolToFree, RunRefs;
+    ULONG RunRefSize, Count, Align;
     PEX_RUNDOWN_REF_CACHE_AWARE RunRefCacheAware;
 
     PAGED_CODE();
@@ -495,7 +584,8 @@ ExAllocateCacheAwareRundownProtection(IN POOL_TYPE PoolType,
     }
     else
     {
-        RunRefSize = KeGetRecommendedSharedDataAlignment();
+        Align = KeGetRecommendedSharedDataAlignment();
+        RunRefSize = Align;
         ASSERT((RunRefSize & (RunRefSize - 1)) == 0);
     }
 
@@ -512,13 +602,27 @@ ExAllocateCacheAwareRundownProtection(IN POOL_TYPE PoolType,
     }
 
     /* On SMP, check for alignment */
-    if (RunRefCacheAware->Number > 1)
+    if (RunRefCacheAware->Number > 1 && (ULONG_PTR)PoolToFree & (Align - 1))
+    {
+        /* Not properly aligned, do it again! */
+        ExFreePoolWithTag(PoolToFree, Tag);
+
+        /* Allocate a bigger buffer to be able to align properly */
+        PoolToFree = ExAllocatePoolWithTag(PoolType, RunRefSize * (RunRefCacheAware->Number + 1), Tag);
+        if (PoolToFree == NULL)
+        {
+            ExFreePoolWithTag(RunRefCacheAware, Tag);
+            return NULL;
+        }
+
+        RunRefs = (PVOID)ALIGN_UP_BY(PoolToFree, Align);
+    }
+    else
     {
-        /* FIXME: properly align run refs */
-        UNIMPLEMENTED;
+        RunRefs = PoolToFree;
     }
 
-    RunRefCacheAware->RunRefs = PoolToFree;
+    RunRefCacheAware->RunRefs = RunRefs;
     RunRefCacheAware->PoolToFree = PoolToFree;
 
     /* And initialize runref */
@@ -526,9 +630,8 @@ ExAllocateCacheAwareRundownProtection(IN POOL_TYPE PoolType,
     {
         for (Count = 0; Count < RunRefCacheAware->Number; ++Count)
         {
-            Offset = RunRefCacheAware->RunRefSize * Count;
-            RunRef = (PEX_RUNDOWN_REF)((ULONG_PTR)RunRefCacheAware->RunRefs + Offset);
-            RunRef->Count = 0;
+            RunRef = ExGetRunRefForGivenProcessor(RunRefCacheAware, Count);
+            _ExInitializeRundownProtection(RunRef);
         }
     }
 
@@ -566,7 +669,7 @@ ExInitializeRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCac
 {
     PVOID Pool;
     PEX_RUNDOWN_REF RunRef;
-    ULONG Count, RunRefSize, Offset;
+    ULONG Count, RunRefSize, Align;
 
     PAGED_CODE();
 
@@ -586,8 +689,13 @@ ExInitializeRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCac
     }
     else
     {
-        /* FIXME: Properly align on SMP */
-        UNIMPLEMENTED;
+        /* Get alignment constraint */
+        Align = KeGetRecommendedSharedDataAlignment();
+
+        /* How many runrefs given the alignment? */
+        RunRefSize = Align;
+        Count = ((Size - sizeof(EX_RUNDOWN_REF_CACHE_AWARE)) / Align) - 1;
+        Pool = (PVOID)ALIGN_UP_BY(Pool, Align);
     }
 
     /* Initialize the structure */
@@ -603,9 +711,8 @@ ExInitializeRundownProtectionCacheAware(IN PEX_RUNDOWN_REF_CACHE_AWARE RunRefCac
     {
         for (Count = 0; Count < RunRefCacheAware->Number; ++Count)
         {
-            Offset = RunRefCacheAware->RunRefSize * Count;
-            RunRef = (PEX_RUNDOWN_REF)((ULONG_PTR)RunRefCacheAware->RunRefs + Offset);
-            RunRef->Count = 0;
+            RunRef = ExGetRunRefForGivenProcessor(RunRefCacheAware, Count);
+            _ExInitializeRundownProtection(RunRef);
         }
     }
 }