Menggunakan __sdv_save_request dan __sdv_retrieve_request untuk Panggilan Prosedur Yang Ditangguhkan

Panggilan prosedur yang ditangguhkan (DPC) menghadirkan tantangan bagi Pemverifikasi Driver Statis (SDV) karena sulit untuk melacak objek permintaan kerangka kerja. Salah satu kesulitannya adalah bahwa permintaan harus diambil dari pointer global, biasanya dari konteks antrean, atau dari item kerja. Untuk mengatasi kesulitan ini, Verifier Driver Statis menyediakan dua fungsi: __sdv_save_request, dan __sdv_retrieve_request. Fungsi-fungsi ini memetakan permintaan yang ditangguhkan ke permintaan yang dapat dilacak SDV.

Fungsi __sdv_save_request, dan __sdv_retrieve_request memiliki sintaks berikut:

__sdv_save_request( request ) 
__sdv_retrieve_request( request ) 

Di mana permintaan dapat menjadi handel ke objek permintaan kerangka kerja apa pun.

Fungsi-fungsi ini hanya digunakan oleh alat analisis statis. Fungsi diabaikan oleh pengkompilasi.

Contoh kode berikut menunjukkan bagaimana fungsi __sdv_save_request dan __sdv_retrieve_request digunakan untuk memandu SDV, sehingga SDV dapat memetakan permintaan yang ditangguhkan. SDV dapat menggunakan pemetaan ini untuk memverifikasi aturan DeferredRequestCompleted . Aturan DeferredRequestCompleted mengharuskan __sdv_save_request dan __sdv_retrieve_request muncul dalam kode Anda. Ada dua aturan properti driver (AliasWithinDispatch, AliasWithinTimerDpc) yang mencari keberadaan fungsi __sdv_save_request dan __sdv_retrieve_request .

Dalam contoh kode berikut, fungsi EchoEvtIoRead adalah fungsi panggilan balik peristiwa EvtIoRead yang menyimpan handel ke objek permintaan kerangka kerja di area konteks antrean. Fungsi EchoEvtTimerFunc adalah fungsi panggilan balik peristiwa EvtTimerFunc yang mengambilnya.

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

Contoh kode berikut menunjukkan bagaimana fungsi __sdv_retrieve_request memetakan permintaan yang ada sehingga SDV dapat melacaknya untuk penyelesaian.

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