WdfRequestMarkCancelable function (wdfrequest.h)
[Applies to KMDF and UMDF]
The WdfRequestMarkCancelable method enables cancellation of a specified I/O request.
Syntax
void WdfRequestMarkCancelable(
[in] WDFREQUEST Request,
[in] PFN_WDF_REQUEST_CANCEL EvtRequestCancel
);
Parameters
[in] Request
A handle to a framework request object.
[in] EvtRequestCancel
A pointer to a driver-defined EvtRequestCancel callback function, which the framework calls if it cancels the I/O request.
Return value
None
Remarks
A bug check occurs if the driver supplies an invalid object handle.
After your driver has received an I/O request from the framework, the driver can call WdfRequestMarkCancelable or, starting with KMDF version 1.9, WdfRequestMarkCancelableEx to make the request cancelable.
When calling WdfRequestMarkCancelable, your driver must specify an EvtRequestCancel callback function. The framework calls the callback function if the I/O manager or another driver is attempting to cancel the I/O request.
Choosing between WdfRequestMarkCancelable and WdfRequestMarkCancelableEx
If your driver uses the framework's automatic synchronization, the driver can call either WdfRequestMarkCancelable or WdfRequestMarkCancelableEx.If the driver does not use automatic synchronization, it must call WdfRequestMarkCancelableEx instead of WdfRequestMarkCancelable for the following reasons:
- If the specified request has already been canceled, WdfRequestMarkCancelable calls the driver's EvtRequestCancel callback function before returning. If the driver acquires a spinlock before calling WdfRequestMarkCancelable and attempts to acquire the same spinlock inside EvtRequestCancel, the same thread attempts to acquire the same spinlock twice, causing a deadlock.
- However, because WdfRequestMarkCancelableEx never calls EvtRequestCancel, this scenario does not occur. If the request has already been canceled, WdfRequestMarkCancelableEx returns STATUS_CANCELLED. If your driver acquires a spinlock (which sets the IRQL to DISPATCH_LEVEL) before calling WdfRequestMarkCancelableEx and releases the spinlock (which sets the IRQL to PASSIVE_LEVEL) after WdfRequestMarkCancelableEx returns, the EvtRequestCancel callback function will not be called before the spinlock is released. Therefore, a deadlock does not occur even if the EvtRequestCancel callback function uses the same spinlock.
Processing a request after enabling cancellation
After a driver calls WdfRequestMarkCancelable to enable canceling, the request remains cancelable while the driver owns the request object, unless the driver calls WdfRequestUnmarkCancelable.If a driver has called WdfRequestMarkCancelable, and if the driver's EvtRequestCancel callback function has not executed and called WdfRequestComplete, the driver must call WdfRequestUnmarkCancelable before it calls WdfRequestComplete outside of the EvtRequestCancel callback function.
If the driver calls WdfRequestForwardToIoQueue to forward the request to a different queue, the following rules apply:
-
I/O requests cannot be cancelable when your driver forwards them to a different queue.
Generally, your driver should not call WdfRequestMarkCancelable to enable canceling the request before calling WdfRequestForwardToIoQueue. If the driver does make the request cancelable, it must call WdfRequestUnmarkCancelable to disable cancellation before calling WdfRequestForwardToIoQueue.
-
While the request is in the second queue, the framework owns it and can cancel it without notifying the driver.
If the driver requires cancellation notification (so that it can deallocate any resources that it might have allocated before calling WdfRequestForwardToIoQueue), the driver should register an EvtIoCanceledOnQueue callback function, and it should use request-specific context memory to store information about the request's resources.
- After the framework has dequeued the request from the second queue and delivered it to the driver, the driver can call WdfRequestMarkCancelable to enable canceling.
Examples
The following code example shows parts of two callback functions:
- An EvtIoRead callback function that performs request-specific work (such as creating subrequests to send to an I/O target), then enables cancellation of the received I/O request.
- An EvtRequestCancel callback function that cancels an I/O request.
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
);
}
Requirements
Requirement | Value |
---|---|
Target Platform | Universal |
Minimum KMDF version | 1.0 |
Minimum UMDF version | 2.0 |
Header | wdfrequest.h (include Wdf.h) |
Library | Wdf01000.sys (KMDF); WUDFx02000.dll (UMDF) |
IRQL | <=DISPATCH_LEVEL |
DDI compliance rules | 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) |