Sdílet prostřednictvím


Použití __sdv_save_request a __sdv_retrieve_request pro volání odložených procedur

Odložená volání procedur (DPCS) představují problémy se statickým ověřením ovladače (SDV), protože je obtížné sledovat objekt požadavku architektury. Jednou z potíží je, že požadavek musí být načten z globálního ukazatele, obvykle z kontextu fronty nebo z pracovní položky. Chcete-li tuto potíže překonat, Static Driver Verifier poskytuje dvě funkce: __sdv_save_requesta __sdv_retrieve_request. Tyto funkce mapují odloženou žádost na žádost, kterou může SDV sledovat.

Funkce __sdv_save_requesta __sdv_retrieve_request mají následující syntaxi:

__sdv_save_request( request ) 
__sdv_retrieve_request( request ) 

Kde požadavek může být popisovač libovolného objektu požadavku architektury.

Tyto funkce používají jenom nástroje pro statickou analýzu. Funkce jsou kompilátorem ignorovány.

Následující příklad kódu ukazuje, jak se k vodítku SDV používají funkce __sdv_save_request a __sdv_retrieve_request, aby SDV mohl mapovat odložený požadavek. SDV může toto mapování použít k ověření pravidla DeferredRequestCompleted. Pravidlo DeferredRequestCompleted vyžaduje, aby se v kódu zobrazily __sdv_save_request a __sdv_retrieve_request. Existují dvě pravidla vlastností ovladače (AliasWithinDispatch, AliasWithinTimerDpc), která hledají existenci __sdv_save_request a __sdv_retrieve_request funkcí.

V následujícím příkladu kódu je funkce EchoEvtIoRead je EvtIoRead funkci zpětného volání událostí, která ukládá popisovač do objektu požadavku rozhraní v kontextové oblasti fronty. Funkce EchoEvtTimerFunc je EvtTimerFunc funkci zpětného volání události, která ji načte.

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

Následující příklad kódu ukazuje, jak __sdv_retrieve_request funkce mapuje existující požadavek, aby SDV mohl sledovat jeho dokončení.

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