/*++ * @name ExNotifyCallback * @implemented * * Calls a function pointer (a registered callback) * See: http://www.osronline.com/ddkx/kmarch/k102_2f5e.htm * http://vmsone.com/~decuslib/vmssig/vmslt99b/nt/wdm-callback.txt * * @param CallbackObject * Which callback to call * * @param Argument1 * Pointer/data to send to callback function * * @param Argument2 * Pointer/data to send to callback function * * @return None * * @remarks None * *--*/ VOID NTAPI ExNotifyCallback(IN PCALLBACK_OBJECT CallbackObject, IN PVOID Argument1, IN PVOID Argument2) { PLIST_ENTRY RegisteredCallbacks; PCALLBACK_REGISTRATION CallbackRegistration; KIRQL OldIrql; /* Check if we don't have an object or registrations */ if (!(CallbackObject) || (IsListEmpty(&CallbackObject->RegisteredCallbacks))) { /* Don't notify */ return; } /* Acquire the Lock */ KeAcquireSpinLock(&CallbackObject->Lock, &OldIrql); /* Enumerate through all the registered functions */ for (RegisteredCallbacks = CallbackObject->RegisteredCallbacks.Flink; RegisteredCallbacks != &CallbackObject->RegisteredCallbacks; RegisteredCallbacks = RegisteredCallbacks->Flink) { /* Get a pointer to a Callback Registration from the List Entries */ CallbackRegistration = CONTAINING_RECORD(RegisteredCallbacks, CALLBACK_REGISTRATION, Link); /* Don't bother doing notification if it's pending to be deleted */ if (!CallbackRegistration->UnregisterWaiting) { /* Mark the Callback in use, so it won't get deleted */ CallbackRegistration->Busy += 1; /* Release the Spinlock before making the call */ KeReleaseSpinLock(&CallbackObject->Lock, OldIrql); /* Call the Registered Function */ CallbackRegistration->CallbackFunction(CallbackRegistration-> CallbackContext, Argument1, Argument2); /* Get SpinLock back */ KeAcquireSpinLock(&CallbackObject->Lock, &OldIrql); /* We are not in use anymore */ CallbackRegistration->Busy -= 1; /* Check if removal is pending and we're not active */ if ((CallbackRegistration->UnregisterWaiting) && !(CallbackRegistration->Busy)) { /* Signal the callback event */ KeSetEvent(&ExpCallbackEvent, 0, FALSE); } } } /* Release the Callback Object */ KeReleaseSpinLock(&CallbackObject->Lock, OldIrql); }
VOID ExNotifyCallback ( __in PCALLBACK_OBJECT CallbackObject, __in_opt PVOID Argument1, __in_opt PVOID Argument2 ) /*++ Routine Description: This function notifies all registered callbacks . Arguments: CallbackObject - supplies a pointer to the callback object should be notified. SystemArgument1 - supplies a pointer will be passed to callback function. SystemArgument2 - supplies a pointer will be passed to callback function. Return Value: None. --*/ { PLIST_ENTRY Link; PCALLBACK_REGISTRATION CallbackRegistration; KIRQL OldIrql; if (CallbackObject == NULL || IsListEmpty (&CallbackObject->RegisteredCallbacks)) { return ; } // // Synchronize with callback object // KeAcquireSpinLock (&CallbackObject->Lock, &OldIrql); // // call registered callbacks at callers IRQL level // ( done if FIFO order of registration ) // if (OldIrql == DISPATCH_LEVEL) { // // OldIrql is DISPATCH_LEVEL, just invoke all callbacks without // releasing the lock // for (Link = CallbackObject->RegisteredCallbacks.Flink; Link != &CallbackObject->RegisteredCallbacks; Link = Link->Flink) { // // Get current registration to notify // CallbackRegistration = CONTAINING_RECORD (Link, CALLBACK_REGISTRATION, Link); // // Notify registration // CallbackRegistration->CallbackFunction( CallbackRegistration->CallbackContext, Argument1, Argument2 ); } // next registration } else { // // OldIrql is < DISPATCH_LEVEL, the code being called may be pageable // and the callback object spinlock needs to be released around // each registration callback. // for (Link = CallbackObject->RegisteredCallbacks.Flink; Link != &CallbackObject->RegisteredCallbacks; Link = Link->Flink ) { // // Get current registration to notify // CallbackRegistration = CONTAINING_RECORD (Link, CALLBACK_REGISTRATION, Link); // // If registration is being removed, don't bother calling it // if (!CallbackRegistration->UnregisterWaiting) { // // Set registration busy // CallbackRegistration->Busy += 1; // // Release SpinLock and notify this callback // KeReleaseSpinLock (&CallbackObject->Lock, OldIrql); CallbackRegistration->CallbackFunction( CallbackRegistration->CallbackContext, Argument1, Argument2 ); // // Synchronize with CallbackObject // KeAcquireSpinLock (&CallbackObject->Lock, &OldIrql); // // Remove our busy count // CallbackRegistration->Busy -= 1; // // If the registration removal is pending, kick global // event let unregister continue // if (CallbackRegistration->UnregisterWaiting && CallbackRegistration->Busy == 0) { KeSetEvent (&ExpCallbackEvent, 0, FALSE); } } } } // // Release callback // KeReleaseSpinLock (&CallbackObject->Lock, OldIrql); }