다음을 통해 공유


WdfRequestMarkCancelableEx 함수(wdfrequest.h)

[KMDF 및 UMDF에 적용]

WdfRequestMarkCancelableEx 메서드를 사용하면 지정된 I/O 요청을 취소할 수 있습니다.

구문

NTSTATUS WdfRequestMarkCancelableEx(
  [in] WDFREQUEST             Request,
  [in] PFN_WDF_REQUEST_CANCEL EvtRequestCancel
);

매개 변수

[in] Request

프레임워크 요청 개체에 대한 핸들입니다.

[in] EvtRequestCancel

I/O 요청을 취소하는 경우 프레임워크가 호출하는 드라이버 정의 EvtRequestCancel 콜백 함수에 대한 포인터입니다.

반환 값

WdfRequestMarkCancelableEx 는 지정된 I/O 요청을 성공적으로 취소할 수 있으면 STATUS_SUCCESS 반환합니다. 그렇지 않으면 이 메서드는 다음 값 중 하나를 반환할 수 있습니다.

반환 코드 설명
STATUS_CANCELLED
I/O 요청이 취소되었습니다. 자세한 내용은 비고를 참조하세요.
STATUS_INVALID_DEVICE_REQUEST
  • 드라이버는 I/O 요청을 소유하지 않습니다.
  • I/O 요청은 이미 취소할 수 있습니다.
 

이 메서드는 다른 NTSTATUS 값을 반환할 수도 있습니다.

드라이버가 잘못된 개체 핸들을 제공하는 경우 버그 검사 발생합니다.

설명

드라이버가 프레임워크에서 I/O 요청을 받은 후 드라이버는 WdfRequestMarkCancelable 을 호출하거나 KMDF 버전 1.9부터 WdfRequestMarkCancelableEx 를 호출하여 요청을 취소할 수 있도록 할 수 있습니다. 두 메서드 중에서 선택하는 방법에 대한 자세한 내용은 WdfRequestMarkCancelable을 참조하세요.

WdfRequestMarkCancelableEx를 호출할 때 드라이버는 EvtRequestCancel 콜백 함수를 지정해야 합니다. I/O 관리자 또는 다른 드라이버가 I/O 요청을 취소하려고 하는 경우 프레임워크는 콜백 함수를 호출합니다.

WdfRequestMarkCancelableEx가 실패를 반환하는 경우 드라이버는 EvtRequestCancel 콜백 함수가 수행하는 것과 동일한 취소 작업을 수행해야 합니다. 예를 들면 다음과 같습니다.

  1. 생성되었을 수 있는 하위 쿼리와 함께 요청 처리를 완료하거나 중지합니다.
  2. WdfRequestComplete를 호출하여 STATUS_CANCELLED 상태 값을 지정합니다.
구현은 아래 코드 예제를 참조하세요.

WdfRequestMarkCancelableExEvtRequestCancel을 호출하지 않으므로 이 메서드는 WdfRequestMarkCancelable의 설명에 설명된 교착 상태 위험으로부터 안전합니다.

취소를 사용하도록 설정한 후 요청 처리

드라이버가 WdfRequestMarkCancelableEx를 호출하여 취소를 사용하도록 설정한 후에는 드라이버가 WdfRequestUnmarkCancelable을 호출하지 않는 한 드라이버가 요청 개체를 소유하는 동안 요청을 취소할 수 있습니다.

드라이버가 WdfRequestMarkCancelableEx를 호출하고 드라이버의 EvtRequestCancel 콜백 함수가 실행되지 않고 WdfRequestComplete를 호출한 경우 드라이버는 EvtRequestCancel 콜백 함수 외부에서 WdfRequestComplete를 호출하기 전에 WdfRequestUnmarkCancelable 호출해야 합니다.

드라이버가 WdfRequestForwardToIoQueue 를 호출하여 요청을 다른 큐로 전달하는 경우 다음 규칙이 적용됩니다.

  • 드라이버가 다른 큐로 전달할 때 I/O 요청을 취소할 수 없습니다.

    일반적으로 드라이버는 WdfRequestForwardToIoQueue 를 호출하기 전에 요청을 취소할 수 있도록 WdfRequestMarkCancelableEx를 호출해서는 안 됩니다. 드라이버가 요청을 취소할 수 있도록 하는 경우 WdfRequestForwardToIoQueue를 호출하기 전에 취소를 사용하지 않도록 설정하려면 WdfRequestUnmarkCancelable을 호출해야 합니다.

  • 요청이 두 번째 큐에 있는 동안 프레임워크는 요청을 소유하고 드라이버에 알리지 않고 취소할 수 있습니다.

    드라이버에 취소 알림이 필요한 경우( WdfRequestForwardToIoQueue를 호출하기 전에 할당되었을 수 있는 리소스의 할당을 취소할 수 있도록) 드라이버는 EvtIoCanceledOnQueue 콜백 함수를 등록해야 하며 요청 관련 컨텍스트 메모리를 사용하여 요청의 리소스에 대한 정보를 저장해야 합니다.

  • 프레임워크가 두 번째 큐에서 요청을 큐에서 제거하고 드라이버에 전달한 후 드라이버는 WdfRequestMarkCancelableEx 를 호출하여 취소를 사용하도록 설정할 수 있습니다.
WdfRequestMarkCancelableEx에 대한 자세한 내용은 I/O 요청 취소를 참조하세요.

예제

다음 코드 예제에서는 두 콜백 함수의 일부를 보여 줍니다.

  • 요청별 작업(예: I/O 대상에 보낼 하위 쿼리 만들기)을 수행한 다음 수신된 I/O 요청을 취소하는 EvtIoRead 콜백 함수입니다.
  • I/O 요청을 취소하는 EvtRequestCancel 콜백 함수입니다.
첫 번째 예제에서 드라이버는 프레임워크의 자동 동기화를 사용합니다. 두 번째 예제에서 드라이버는 스핀 잠금을 사용하여 자체 동기화를 제공합니다.

예제 1: 자동 동기화를 사용하는 드라이버입니다.

VOID
MyEvtIoRead(
    IN WDFQUEUE  Queue,
    IN WDFREQUEST  Request,
    IN size_t  Length
    )
{
...
    NTSTATUS status;
...
    // Perform request-specific work here
    // (such as creating subrequests 
    // to send to an I/O target). 
...
    status = WdfRequestMarkCancelableEx(
                                        Request,
                                        MyEvtRequestCancel
                                        );

    if (!NT_SUCCESS(status)) {
       // Remove request-specific work here, because
       // we don't want the work to be done if the
       // request was canceled or an error occurred.

        WdfRequestComplete (Request, status);
    }
...
}

VOID
MyEvtRequestCancel(
    IN WDFREQUEST  Request
 )
{
    // Remove request-specific work here, because
    // we don't want the work to be done if the
    // request was canceled.

    WdfRequestComplete(
                       Request,
                       STATUS_CANCELLED
                       );
}

예제 2: 자체 동기화를 사용하는 드라이버입니다.

VOID
MyEvtIoRead(
    IN WDFQUEUE  Queue,
    IN WDFREQUEST  Request,
    IN size_t  Length
    )
{
...
    NTSTATUS status;
...
    WdfSpinlockAcquire(MyCancelSpinLock);
    // Perform request-specific work here
    // (such as creating subrequests 
    // to send to an I/O target). 
...
    status = WdfRequestMarkCancelableEx(
                                        Request,
                                        MyEvtRequestCancel
                                        );

    if (!NT_SUCCESS(status)) {
        // Remove request-specific work here, because
        // we don't want the work to be done if the
        // request was canceled or an error occurred.
     }
    WdfSpinlockRelease(MyCancelSpinLock);
    if (!NT_SUCCESS(status)) {
        WdfRequestComplete (
                            Request,
                            Status
                            );
    }
...
}
VOID
MyEvtRequestCancel(
    IN WDFREQUEST  Request
 )
{
    WdfSpinlockAcquire(MyCancelSpinLock);
    // Remove request-specific work here, because
    // we don't want the work to be done if the
    // request was canceled.
    WdfSpinlockRelease(MyCancelSpinLock);
    WdfRequestComplete (Request, STATUS_CANCELLED);
}

요구 사항

요구 사항
대상 플랫폼 유니버설
최소 KMDF 버전 1.9
최소 UMDF 버전 2.0
머리글 wdfrequest.h(Wdf.h 포함)
라이브러리 Wdf01000.sys(KMDF); WUDFx02000.dll(UMDF)
IRQL <=DISPATCH_LEVEL
DDI 규정 준수 규칙 DeferredRequestCompleted(kmdf), DriverCreate(kmdf), EvtIoStopCancel(kmdf), InvalidReqAccess(kmdf), InvalidReqAccessLocal(kmdf), KmdfIrql(kmdf), KmdfIrql2(kmdf), KmdfIrqlExplicit(kmdf), MarkCancOnCancReqLocal(kmdf), ReqIsCancOnCancReq(kmdf), ReqMarkCancelableSend(kmdf), ReqNotCanceledLocal(kmdf), RequestCompleted(kmdf), RequestCompletedLocal( kmdf)

추가 정보

EvtRequestCancel

WdfRequestComplete

WdfRequestForwardToIoQueue

WdfRequestMarkCancelable

WdfRequestUnmarkCancelable