Ejemplo n.º 1
0
/*++
 * @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);
}
Ejemplo n.º 2
0
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);
}