次の方法で共有


遅延プロシージャ呼び出しのための __sdv_save_request と __sdv_retrieve_request の使用

遅延プロシージャ呼び出し (DPC) は、フレームワーク要求オブジェクトを追跡することが困難であるため、静的ドライバー検証ツール (SDV) に課題を提示します。 1 つの難しさに、要求をグローバル ポインター (通常はキュー コンテキストから)、または作業項目から取得する必要があるということが上げられます。 この難しさを克服するために、静的ドライバー検証ツールには、__sdv_save_request __sdv_retrieve_request の 2 つの機能が用意されています。 これらの関数は、遅延要求を SDV が追跡できる要求にマップします。

__sdv_save_request 関数と __sdv_retrieve_request 関数には、次の構文があります。

__sdv_save_request( request ) 
__sdv_retrieve_request( request ) 

要求は、任意のフレームワーク要求オブジェクトへのハンドルにすることができます。

これらの関数は、静的分析ツールでのみ使用されます。 関数はコンパイラによって無視されます。

次のコード例は、SDV が遅延要求を マップできるように、__sdv_save_request 関数と __sdv_retrieve_request 関数を使用して SDV をガイドする方法を示しています。 SDV では、このマッピングを使用して DeferredRequestCompleted ルールを確認できます。 DeferredRequestCompleted ルールでは、コードに __sdv_save_request__sdv_retrieve_request が表示されている必要があります。 __sdv_save_request 関数と __sdv_retrieve_request 関数の存在を検索する 2 つのドライバー プロパティ ルール (AliasWithinDispatchAliasWithinTimerDpc) があります。

次のコード例では、EchoEvtIoRead 関数は、キュー コンテキスト領域のフレームワーク要求オブジェクトにハンドルを保存する EvtIoRead イベント コールバック関数です。 関数 EchoEvtTimerFunc は、それを取得する EvtTimerFunc イベント コールバック関数です。

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

次のコード例は、__sdv_retrieve_request 関数が既存の要求をマップして、SDV が完了を追跡できるようにする方法を示しています。

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