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=25... ============================================================================== --- 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