NTKERNELAPI PVOID FASTCALL ObFastReferenceObjectLocked ( IN PEX_FAST_REF FastRef ) /*++ Routine Description: This routine does a slow object reference. This must be called while holding a lock. Arguments: FastRef - Rundown block to be used to reference the object Return Value: PVOID - Object that was referenced or NULL if there was no object. --*/ { PVOID Object; EX_FAST_REF OldRef; OldRef = *FastRef; Object = ExFastRefGetObject (OldRef); if (Object != NULL) { ObReferenceObject (Object); } return Object; }
NTKERNELAPI PVOID FASTCALL ObFastReferenceObject ( IN PEX_FAST_REF FastRef ) /*++ Routine Description: This routine attempts a fast reference of an object in a fast ref structure. Arguments: FastRef - Rundown block to be used for the reference Return Value: PVOID - Object that was referenced or NULL if we failed --*/ { EX_FAST_REF OldRef; PVOID Object; ULONG RefsToAdd, Unused; // // Attempt the fast reference // OldRef = ExFastReference (FastRef); Object = ExFastRefGetObject (OldRef); // // We fail if there wasn't an object or if it has no cached references // left. Both of these cases had the cached reference count zero. // Unused = ExFastRefGetUnusedReferences (OldRef); if (Unused <= 1) { if (Unused == 0) { return NULL; } // // If we took the counter to zero then attempt to make life easier for // the next referencer by resetting the counter to its max. Since we now // have a reference to the object we can do this. // RefsToAdd = ExFastRefGetAdditionalReferenceCount (); ObReferenceObjectEx (Object, RefsToAdd); // // Try to add the added references to the cache. If we fail then just // release them. // if (!ExFastRefAddAdditionalReferenceCounts (FastRef, Object, RefsToAdd)) { ObDereferenceObjectEx (Object, RefsToAdd); } } return Object; }
NTKERNELAPI PVOID FASTCALL ObFastReplaceObject ( IN PEX_FAST_REF FastRef, IN PVOID Object ) /*++ Routine Description: This routine does a swap of the object. This must be called while holding a lock. Arguments: FastRef - Rundown block to be used to do the swap. Return Value: PVOID - Object that was in the block before the swap.. --*/ { EX_FAST_REF OldRef; PVOID OldObject; ULONG RefsToReturn; // // If we have been given an object then bias it by the correct amount. // if (Object != NULL) { ObReferenceObjectEx (Object, ExFastRefGetAdditionalReferenceCount ()); } // // Do the swap // OldRef = ExFastRefSwapObject (FastRef, Object); OldObject = ExFastRefGetObject (OldRef); // // If there was an original object then we need to work out how many // cached references there were (if any) and return them. // if (OldObject != NULL) { RefsToReturn = ExFastRefGetUnusedReferences (OldRef); if (RefsToReturn > 0) { ObDereferenceObjectEx (OldObject, RefsToReturn); } } return OldObject; }
PEX_CALLBACK_ROUTINE_BLOCK ExReferenceCallBackBlock ( IN OUT PEX_CALLBACK CallBack ) /*++ Routine Description: This function takes a reference on the call back block inside the callback structure. Arguments: CallBack - Call back to obtain the call back block from Return Value: PEX_CALLBACK_ROUTINE_BLOCK - Referenced structure or NULL if these wasn't one --*/ { EX_FAST_REF OldRef; PEX_CALLBACK_ROUTINE_BLOCK CallBackBlock; // // Get a reference to the callback block if we can. // OldRef = ExFastReference (&CallBack->RoutineBlock); // // If there is no callback then return // if (ExFastRefObjectNull (OldRef)) { return NULL; } // // If we didn't get a reference then use a lock to get one. // if (!ExFastRefCanBeReferenced (OldRef)) { PKTHREAD CurrentThread; CurrentThread = KeGetCurrentThread (); KeEnterCriticalRegionThread (CurrentThread); ExAcquirePushLockExclusive (&ExpCallBackFlush); CallBackBlock = ExFastRefGetObject (CallBack->RoutineBlock); if (CallBackBlock && !ExAcquireRundownProtection (&CallBackBlock->RundownProtect)) { CallBackBlock = NULL; } ExReleasePushLockExclusive (&ExpCallBackFlush); KeLeaveCriticalRegionThread (CurrentThread); if (CallBackBlock == NULL) { return NULL; } } else { CallBackBlock = ExFastRefGetObject (OldRef); // // If we just removed the last reference then attempt fix it up. // if (ExFastRefIsLastReference (OldRef) && !ExpCallBackReturnRefs) { ULONG RefsToAdd; RefsToAdd = ExFastRefGetAdditionalReferenceCount (); // // If we can't add the references then just give up // if (ExAcquireRundownProtectionEx (&CallBackBlock->RundownProtect, RefsToAdd)) { // // Repopulate the cached refs. If this fails we just give them back. // if (!ExFastRefAddAdditionalReferenceCounts (&CallBack->RoutineBlock, CallBackBlock, RefsToAdd)) { ExReleaseRundownProtectionEx (&CallBackBlock->RundownProtect, RefsToAdd); } } } } return CallBackBlock; }
BOOLEAN ExCompareExchangeCallBack ( IN OUT PEX_CALLBACK CallBack, IN PEX_CALLBACK_ROUTINE_BLOCK NewBlock, IN PEX_CALLBACK_ROUTINE_BLOCK OldBlock ) /*++ Routine Description: This function assigns, removes or swaps a low overhead callback function. Arguments: CallBack - Callback structure to be modified NewBlock - New block to be installed in the callback OldBlock - The old block that must be there now to be replaced Return Value: BOOLEAN - TRUE: The swap occured, FALSE: The swap failed --*/ { EX_FAST_REF OldRef; PEX_CALLBACK_ROUTINE_BLOCK ReplacedBlock; if (NewBlock != NULL) { // // Add the additional references to the routine block // if (!ExAcquireRundownProtectionEx (&NewBlock->RundownProtect, ExFastRefGetAdditionalReferenceCount () + 1)) { ASSERTMSG ("Callback block is already undergoing rundown", FALSE); return FALSE; } } // // Attempt to replace the existing object and balance all the reference counts // OldRef = ExFastRefCompareSwapObject (&CallBack->RoutineBlock, NewBlock, OldBlock); ReplacedBlock = ExFastRefGetObject (OldRef); // // See if the swap occured. If it didn't undo the original references we added. // If it did then release remaining references on the original // if (ReplacedBlock == OldBlock) { PKTHREAD CurrentThread; // // We need to flush out any slow referencers at this point. We do this by // acquiring and releasing a lock. // if (ReplacedBlock != NULL) { CurrentThread = KeGetCurrentThread (); KeEnterCriticalRegionThread (CurrentThread); ExAcquireReleasePushLockExclusive (&ExpCallBackFlush); KeLeaveCriticalRegionThread (CurrentThread); ExReleaseRundownProtectionEx (&ReplacedBlock->RundownProtect, ExFastRefGetUnusedReferences (OldRef) + 1); } return TRUE; } else { // // The swap failed. Remove the addition references if we had added any. // if (NewBlock != NULL) { ExReleaseRundownProtectionEx (&NewBlock->RundownProtect, ExFastRefGetAdditionalReferenceCount () + 1); } return FALSE; } }