Author: ion
Date: Tue Jan 16 10:20:16 2007
New Revision: 25484
URL:
http://svn.reactos.org/svn/reactos?rev=25484&view=rev
Log:
- Implement ExReferenceCallBackBlock and ExDereferenceCallBackBlock.
- Code is very similar to Ob* Fast Referencing, and the use of macros to encapsulate
generic referencing should be done later. Essentially, Ob sticks ObRefs around FastRefs,
while ExCallbacks sticks ExRundown around FastRefs.
Modified:
trunk/reactos/include/ddk/winddk.h
trunk/reactos/ntoskrnl/ex/callback.c
Modified: trunk/reactos/include/ddk/winddk.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/include/ddk/winddk.h?rev=2…
==============================================================================
--- trunk/reactos/include/ddk/winddk.h (original)
+++ trunk/reactos/include/ddk/winddk.h Tue Jan 16 10:20:16 2007
@@ -6519,6 +6519,22 @@
IN OUT PKGUARDED_MUTEX GuardedMutex
);
+NTKERNELAPI
+BOOLEAN
+FASTCALL
+ExAcquireRundownProtectionEx(
+ IN OUT PEX_RUNDOWN_REF RunRef,
+ IN ULONG Count
+);
+
+NTKERNELAPI
+VOID
+FASTCALL
+ExReleaseRundownProtectionEx(
+ IN OUT PEX_RUNDOWN_REF RunRef,
+ IN ULONG Count
+);
+
/* Fast Mutex */
#define ExInitializeFastMutex(_FastMutex) \
{ \
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 10:20:16 2007
@@ -42,7 +42,7 @@
VOID
NTAPI
-ExInitializeCallback(IN OUT PEX_CALLBACK Callback)
+ExInitializeCallBack(IN OUT PEX_CALLBACK Callback)
{
/* Initialize the fast references */
Callback->RoutineBlock.Object = NULL;
@@ -73,7 +73,7 @@
VOID
NTAPI
-ExFreeCallback(IN PEX_CALLBACK_ROUTINE_BLOCK Callback)
+ExFreeCallBack(IN PEX_CALLBACK_ROUTINE_BLOCK Callback)
{
/* Just free it from memory */
ExFreePool(Callback);
@@ -108,15 +108,125 @@
ExDereferenceCallBackBlock(IN OUT PEX_CALLBACK CallBack,
IN PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock)
{
- /* FIXME: TODO */
+ PEX_FAST_REF FastRef = &CallBack->RoutineBlock;
+ EX_FAST_REF Value, NewValue;
+
+ /* Sanity checks */
+ ASSERT(CallbackRoutineBlock);
+ ASSERT(!(((ULONG_PTR)CallbackRoutineBlock) & MAX_FAST_REFS));
+
+ /* Start dereference loop */
+ for (;;)
+ {
+ /* Get the current count */
+ Value = *FastRef;
+ if ((Value.Value ^ (ULONG_PTR)CallbackRoutineBlock) < MAX_FAST_REFS)
+ {
+ /* Decrease the reference count */
+ NewValue.Value = Value.Value + 1;
+ NewValue.Object = InterlockedCompareExchangePointer(&FastRef->Object,
+ NewValue.Object,
+ Value.Object);
+ if (NewValue.Object != Value.Object) continue;
+
+ /* We're all done */
+ break;
+ }
+ else
+ {
+ /* Release rundown protection */
+ ExReleaseRundownProtection(&CallbackRoutineBlock->RundownProtect);
+ }
+ }
}
PEX_CALLBACK_ROUTINE_BLOCK
NTAPI
ExReferenceCallBackBlock(IN OUT PEX_CALLBACK CallBack)
{
- /* FIXME: TODO */
- return NULL;
+ PEX_FAST_REF FastRef = &CallBack->RoutineBlock;
+ EX_FAST_REF Value, NewValue;
+ PEX_CALLBACK_ROUTINE_BLOCK CallbackRoutineBlock;
+
+ /* Start reference loop */
+ for (;;)
+ {
+ /* Get the current count */
+ Value = *FastRef;
+ if (Value.RefCnt != 0)
+ {
+ /* Increase the reference count */
+ NewValue.Value = Value.Value - 1;
+ NewValue.Object = InterlockedCompareExchangePointer(&FastRef->Object,
+ NewValue.Object,
+ Value.Object);
+ if (NewValue.Object != Value.Object) continue;
+ }
+
+ /* All done */
+ break;
+ }
+
+ /* Fail if there isn't any object */
+ if (!Value.Value) return NULL;
+
+ /* Check if we don't have a reference */
+ if (!Value.RefCnt)
+ {
+ /* FIXME: Race */
+ CallbackRoutineBlock = NULL;
+ DPRINT1("Unhandled callback race condition\n");
+ KEBUGCHECK(0);
+ }
+ else
+ {
+ /* Get the callback block */
+ CallbackRoutineBlock = (PVOID)(Value.Value &~ MAX_FAST_REFS);
+
+ /* Check if this is the last reference */
+ if (Value.RefCnt == 1)
+ {
+ /* Acquire rundown protection */
+ if (ExfAcquireRundownProtectionEx(&CallbackRoutineBlock->
+ RundownProtect,
+ MAX_FAST_REFS))
+ {
+ /* Sanity check */
+ ASSERT(!(((ULONG_PTR)CallbackRoutineBlock) & MAX_FAST_REFS));
+
+ /* Start reference loop */
+ for (;;)
+ {
+ /* Check if the current count is too high */
+ Value = *FastRef;
+ if (((Value.RefCnt + MAX_FAST_REFS) > MAX_FAST_REFS) ||
+ ((Value.Value &~ MAX_FAST_REFS) !=
+ (ULONG_PTR)CallbackRoutineBlock))
+ {
+ /* Backdown the rundown acquire */
+ ExfReleaseRundownProtectionEx(&CallbackRoutineBlock->
+ RundownProtect,
+ MAX_FAST_REFS);
+ break;
+ }
+
+ /* Increase the reference count */
+ NewValue.Value = Value.Value + MAX_FAST_REFS;
+ NewValue.Object =
+ InterlockedCompareExchangePointer(&FastRef->Object,
+ NewValue.Object,
+ Value.Object);
+ if (NewValue.Object != Value.Object) continue;
+
+ /* Break out if the change was OK */
+ break;
+ }
+ }
+ }
+ }
+
+ /* Return the callback block */
+ return CallbackRoutineBlock;
}
VOID