지연 프로시저 호출에 __sdv_save_request 및 __sdv_retrieve_request 사용

DPC(지연 프로시저 호출)는 프레임워크 요청 개체를 추적하기 어렵기 때문에 SDV(정적 드라이버 검증 도구)에 문제가 있습니다. 한 가지 어려움은 전역 포인터, 일반적으로 큐 컨텍스트 또는 작업 항목에서 요청을 검색해야 한다는 것입니다. 이러한 어려움을 극복하기 위해 정적 드라이버 검증 도구는 __sdv_save_request__sdv_retrieve_request 두 가지 함수를 제공합니다. 이러한 함수는 지연된 요청을 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 함수의 존재를 찾는 두 개의 드라이버 속성 규칙(AliasWithinDispatch, AliasWithinTimerDpc)이 있습니다.

다음 코드 예제에서 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;
}