Author: ion
Date: Tue Jan 16 17:20:19 2007
New Revision: 25485
URL: 
http://svn.reactos.org/svn/reactos?rev=25485&view=rev
Log:
- Implement ExCompareExchangeCallBack. The CallBack implementation is now ready for
testing.
Modified:
    trunk/reactos/ntoskrnl/ex/callback.c
Modified: trunk/reactos/ntoskrnl/ex/callback.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ex/callback.c?rev…
==============================================================================
--- trunk/reactos/ntoskrnl/ex/callback.c (original)
+++ trunk/reactos/ntoskrnl/ex/callback.c Tue Jan 16 17:20:19 2007
@@ -37,6 +37,7 @@
 POBJECT_TYPE ExCallbackObjectType;
 KEVENT ExpCallbackEvent;
+EX_PUSH_LOCK ExpCallBackFlush;
 /* PRIVATE FUNCTIONS *********************************************************/
@@ -254,6 +255,98 @@
     }
 }
+BOOLEAN
+NTAPI
+ExCompareExchangeCallBack(IN OUT PEX_CALLBACK CallBack,
+                          IN PEX_CALLBACK_ROUTINE_BLOCK NewBlock,
+                          IN PEX_CALLBACK_ROUTINE_BLOCK OldBlock)
+{
+    EX_FAST_REF Value, NewValue;
+    PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock;
+    PEX_FAST_REF FastRef = &CallBack->RoutineBlock;
+
+    /* Check that we have a new block */
+    if (NewBlock)
+    {
+        /* Acquire rundown */
+        if (!ExfAcquireRundownProtectionEx(&NewBlock->RundownProtect,
+                                           MAX_FAST_REFS + 1))
+        {
+            /* This should never happen */
+            ASSERTMSG("Callback block is already undergoing rundown", FALSE);
+            return FALSE;
+        }
+    }
+
+    /* Sanity check and start swap loop */
+    ASSERT(!(((ULONG_PTR)NewBlock) & MAX_FAST_REFS));
+    for (;;)
+    {
+        /* Get the current value */
+        Value = *FastRef;
+
+        /* Make sure there's enough references to swap */
+        if (!((Value.Value ^ (ULONG_PTR)OldBlock) <= MAX_FAST_REFS)) break;
+
+        /* Check if we have an object to swap */
+        if (NewBlock)
+        {
+            /* Set up the value with maximum fast references */
+            NewValue.Value = (ULONG_PTR)NewBlock | MAX_FAST_REFS;
+        }
+        else
+        {
+            /* Write the object address itself (which is empty) */
+            NewValue.Value = (ULONG_PTR)NewBlock;
+        }
+
+        /* Do the actual compare exchange */
+        NewValue.Object = InterlockedCompareExchangePointer(&FastRef->Object,
+                                                            NewValue.Object,
+                                                            Value.Object);
+        if (NewValue.Object != Value.Object) continue;
+
+        /* All done */
+        break;
+    }
+
+    /* Get the routine block */
+    CallbackRoutineBlock = (PVOID)(Value.Value & ~MAX_FAST_REFS);
+
+    /* Make sure the swap worked */
+    if (CallbackRoutineBlock == OldBlock)
+    {
+        /* Make sure we replaced a valid pointer */
+        if (CallbackRoutineBlock)
+        {
+            /* Acquire the flush lock and immediately release it */
+            KeEnterCriticalRegion();
+            ExWaitOnPushLock(&ExpCallBackFlush);
+
+            /* Release rundown protection */
+            KeLeaveCriticalRegion();
+            ExfReleaseRundownProtectionEx(&CallbackRoutineBlock->RundownProtect,
+                                          Value.RefCnt + 1);
+        }
+
+        /* Compare worked */
+        return TRUE;
+    }
+    else
+    {
+        /* It failed, check if we had a block */
+        if (NewBlock)
+        {
+            /* We did, remove the refernces that we had added */
+            ExfReleaseRundownProtectionEx(&NewBlock->RundownProtect,
+                                          MAX_FAST_REFS + 1);
+        }
+
+        /* Return failure */
+        return FALSE;
+    }
+}
+
 VOID
 NTAPI
 ExpDeleteCallback(IN PVOID Object)
@@ -286,6 +379,9 @@
     OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
     HANDLE DirectoryHandle;
     ULONG i;
+
+    /* Setup lightweight callback lock */
+    ExpCallBackFlush.Value = 0;
     /* Initialize the Callback Object type  */
     RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));