Condividi tramite


Uso di __sdv_save_request e __sdv_retrieve_request per chiamate di procedure posticipate

Le chiamate di routine posticipate (DPC) presentano problemi al verifica driver statico (SDV) perché è difficile tenere traccia dell'oggetto richiesta del framework. Una difficoltà è che la richiesta deve essere recuperata da un puntatore globale, in genere dal contesto della coda o da un elemento di lavoro. Per superare questa difficoltà, il verifica driver statico offre due funzioni: __sdv_save_request e __sdv_retrieve_request. Queste funzioni mappano la richiesta posticipata a una richiesta che SDV può tenere traccia.

Le funzioni __sdv_save_request e __sdv_retrieve_request hanno la sintassi seguente:

__sdv_save_request( request ) 
__sdv_retrieve_request( request ) 

Dove la richiesta può essere un handle per qualsiasi oggetto richiesta framework.

Queste funzioni vengono usate solo dagli strumenti di analisi statici. Le funzioni vengono ignorate dal compilatore.

Nell'esempio di codice seguente viene illustrato come vengono usate le funzioni __sdv_save_request e __sdv_retrieve_request per guidare SDV, in modo che SDV possa eseguire il mapping della richiesta posticipata. SDV può usare questo mapping per verificare la regola DeferredRequestCompleted . La regola DeferredRequestCompleted richiede che __sdv_save_request e __sdv_retrieve_request vengano visualizzati nel codice. Esistono due regole di proprietà driver (AliasWithinDispatch, AliasWithinTimerDpc) che cercano l'esistenza delle funzioni di __sdv_save_request e __sdv_retrieve_request .

Nell'esempio di codice seguente la funzione EchoEvtIoRead è una funzione di callback degli eventi EvtIoRead che salva l'handle nell'oggetto richiesta framework nell'area del contesto della coda. La funzione EchoEvtTimerFunc è una funzione di callback dell'evento EvtTimerFunc che lo 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;
}

Nell'esempio di codice seguente viene illustrato come la funzione di __sdv_retrieve_request esegue il mapping di una richiesta esistente in modo che SDV possa tenere traccia per il completamento.

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;
}