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));