WdfRequestMarkCancelable 函数 (wdfrequest.h)

[适用于 KMDF 和 UMDF]

WdfRequestMarkCancelable 方法允许取消指定的 I/O 请求。

语法

void WdfRequestMarkCancelable(
  [in] WDFREQUEST             Request,
  [in] PFN_WDF_REQUEST_CANCEL EvtRequestCancel
);

参数

[in] Request

框架请求对象的句柄。

[in] EvtRequestCancel

指向驱动程序定义的 EvtRequestCancel 回调函数的指针,框架在取消 I/O 请求时调用该回调函数。

返回值

备注

如果驱动程序提供无效的对象句柄,则会发生 bug 检查。

驱动程序收到来自框架 的 I/O 请求 后,驱动程序可以调用 WdfRequestMarkCancelable ,或者从 KMDF 版本 1.9 开始调用 WdfRequestMarkCancelableEx ,使请求可取消。

调用 WdfRequestMarkCancelable 时,驱动程序必须指定 EvtRequestCancel 回调函数。 如果 I/O 管理器或其他驱动程序尝试取消 I/O 请求,框架将调用回调函数。

在 WdfRequestMarkCancelable 和 WdfRequestMarkCancelableEx 之间进行选择

如果驱动程序使用框架的 自动同步,则驱动程序可以调用 WdfRequestMarkCancelableWdfRequestMarkCancelableEx

如果驱动程序不使用自动同步,则必须调用 WdfRequestMarkCancelableEx 而不是 WdfRequestMarkCancelable ,原因如下:

  • 如果指定的请求已被取消, WdfRequestMarkCancelable 在返回之前调用驱动程序的 EvtRequestCancel 回调函数。 如果驱动程序在调用 WdfRequestMarkCancelable 之前获取了一个旋转锁,并尝试在 EvtRequestCancel 中获取同一个旋转锁,则同一线程会尝试获取同一个旋转锁两次,从而导致死锁。
  • 但是,由于 WdfRequestMarkCancelableEx 从不调用 EvtRequestCancel,因此不会发生这种情况。 如果请求已取消, WdfRequestMarkCancelableEx 将返回 STATUS_CANCELLED。 如果驱动程序获取旋转锁 (在调用 WdfRequestMarkCancelableEx 之前将 IRQL 设置为 DISPATCH_LEVEL) ,并在 WdfRequestMarkCancelableEx 返回后释放将 IRQL 设置为PASSIVE_LEVEL) 的旋转锁 (,则不会在释放旋转锁之前调用 EvtRequestCancel 回调函数。 因此,即使 EvtRequestCancel 回调函数使用相同的旋转锁,也不会发生死锁。

启用取消后处理请求

驱动程序调用 WdfRequestMarkCancelable 以启用取消后,该请求在驱动程序 拥有 请求对象时仍可取消,除非驱动程序调用 WdfRequestUnmarkCancelable

如果驱动程序已调用 WdfRequestMarkCancelable,并且驱动程序的 EvtRequestCancel 回调函数尚未执行并调用 WdfRequestComplete,则驱动程序必须先调用 WdfRequestUnmarkCancelable,然后才能在 EvtRequestCancel 回调函数外部调用 WdfRequestComplete

如果驱动程序调用 WdfRequestForwardToIoQueue 将请求转发到其他队列,则以下规则适用:

  • 当驱动程序将 I/O 请求转发到其他队列时,无法取消它们。

    通常,驱动程序不应调用 WdfRequestMarkCancelable 来启用在调用 WdfRequestForwardToIoQueue 之前取消请求。 如果驱动程序使请求可取消,则必须在调用 WdfRequestForwardToIoQueue 之前调用 WdfRequestUnmarkCancelable 来禁用取消。

  • 当请求位于第二个队列中时,框架拥有它,并且可以取消它,而无需通知驱动程序。

    如果驱动程序需要取消通知 (以便它可以在调用 WdfRequestForwardToIoQueue) 之前解除分配的任何资源,则驱动程序应注册 EvtIoCanceledOnQueue 回调函数,并且它应使用特定于请求的上下文内存来存储有关请求资源的信息。

  • 框架从第二个队列取消请求排队并将其传递到驱动程序后,驱动程序可以调用 WdfRequestMarkCancelable 来启用取消。
有关 WdfRequestMarkCancelable 的详细信息,请参阅 取消 I/O 请求

示例

下面的代码示例演示两个回调函数的一部分:

  • 一个 EvtIoRead 回调函数,它执行特定于请求的工作 (,例如创建要发送到 I/O 目标) 的子请求,然后允许取消收到的 I/O 请求。
  • 取消 I/O 请求的 EvtRequestCancel 回调函数。
驱动程序必须使用框架的 自动同步
VOID
MyEvtIoRead(
    IN WDFQUEUE  Queue,
    IN WDFREQUEST  Request,
    IN size_t  Length
    )
{
...
    // Perform request-specific work here
    // (such as creating subrequests 
    // to send to an I/O target). 
...
    WdfRequestMarkCancelable(
                             Request,
                             MyEvtRequestCancel
                             );
    }
...
}
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
                       );
}

要求

要求
目标平台 通用
最低 KMDF 版本 1.0
最低 UMDF 版本 2.0
标头 wdfrequest.h (包括 Wdf.h)
Library 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) , MarkCancOnReqLocal (kmdf) ReqIsCancOnCancReq (kmdf) ReqMarkCancelableSend (kmdf) ReqNotCanceledLocal (kmdf) RequestCompleted (kmdf) RequestCompletedLocal (kmdf)

另请参阅

EvtRequestCancel

WdfRequestComplete

WdfRequestForwardToIoQueue

WdfRequestMarkCancelableEx

WdfRequestUnmarkCancelable