Share via


Uso de __sdv_save_request y __sdv_retrieve_request para llamadas a procedimiento diferido

Las llamadas a procedimientos diferidos (DPC) presentan desafíos al Comprobador de controladores estáticos (SDV) porque es difícil realizar un seguimiento del objeto de solicitud del marco. Una dificultad es que la solicitud se debe recuperar desde un puntero global, normalmente desde el contexto de la cola o desde un elemento de trabajo. Para superar esta dificultad, static Driver Verifier proporciona dos funciones: __sdv_save_request y __sdv_retrieve_request. Estas funciones asignan la solicitud diferida a una solicitud que SDV puede realizar un seguimiento.

Las funciones __sdv_save_request y __sdv_retrieve_request tienen la sintaxis siguiente:

__sdv_save_request( request ) 
__sdv_retrieve_request( request ) 

Donde la solicitud puede ser un identificador para cualquier objeto de solicitud de marco.

Estas funciones solo las usan las herramientas de análisis estático. El compilador omite las funciones.

En el ejemplo de código siguiente se muestra cómo se usan las funciones __sdv_save_request y __sdv_retrieve_request para guiar sdV, de modo que SDV pueda asignar la solicitud diferida. SDV puede usar esta asignación para comprobar la regla DeferredRequestCompleted . La regla DeferredRequestCompleted requiere que __sdv_save_request y __sdv_retrieve_request aparezcan en el código. Hay dos reglas de propiedad de controlador (AliasWithinDispatch, AliasWithinTimerDpc) que buscan la existencia de las funciones __sdv_save_request y __sdv_retrieve_request .

En el ejemplo de código siguiente, la función EchoEvtIoRead es una función de devolución de llamada de eventos EvtIoRead que guarda el identificador en el objeto de solicitud de marco en el área de contexto de cola. La función EchoEvtTimerFunc es una función de devolución de llamada de evento EvtTimerFunc que la recupera.

VOID
EchoEvtIoRead(
 )in WDFQUEUE   Queue,
 __in WDFREQUEST Request,
 __in size_t      Length
    )
{
/* ..................... */
    // Mark the request as cancelable
    WdfRequestMarkCancelable(Request, EchoEvtRequestCancel);
 
 
    // Defer the completion to another thread from the timer DPC and save the handle to the framework request object by using the __sdv_save_request function. 
    queueContext->CurrentRequest = Request;    
 __sdv_save_request(Request);

    queueContext->CurrentStatus  = Status;

    return;
}

En el ejemplo de código siguiente se muestra cómo la función __sdv_retrieve_request asigna una solicitud existente para que SDV pueda realizar el seguimiento de la finalización.

VOID
EchoEvtTimerFunc(
    IN WDFTIMER     Timer
    )
{...................................................
    queue = WdfTimerGetParentObject(Timer);
    queueContext = QueueGetContext(queue);

    //
    // The DPC is automatically synchronized to the queue lock,
    // so this prevents race conditions from occurring without explicit driver-managed locking. The __sdv_retrieve_request function is used so that SDV can restore the deferred request in the timer DPC. Because we know that this deferred request is valid (because it has been previously saved), the __analysis_assume function is used to suppress false defects that might otherwise result in this code path.

    //
 __sdv_retrieve_request(queueContext->CurrentRequest);
    Request = queueContext->CurrentRequest;
 __analysis_assume(Request != NULL);
    if( Request != NULL ) {

        //
        // Try to remove cancel status from the request.
        //
        // The request is not completed if it is already canceled
        // because the EchoEvtIoCancel function has run, or is about to run,
        // and we are racing with it. 

        Status = WdfRequestUnmarkCancelable(Request);
// Because we know that the request is not NULL in this code path and that the request is no longer marked cancelable, we can use the __analysis_assume function to suppress the reporting of a false defect. 

 __analysis_assume(Status != STATUS_CANCELLED);
        if( Status != STATUS_CANCELLED ) {

            queueContext->CurrentRequest = NULL;
            Status = queueContext->CurrentStatus;

            KdPrint(("CustomTimerDPC Completing request 0x%p, Status 0x%x \n", Request,Status));

            WdfRequestComplete(Request, Status);
        }
        else {
            KdPrint(("CustomTimerDPC Request 0x%p is STATUS_CANCELLED, not completing\n",
                                Request));
        }
    }

    return;
}