WdfRequestMarkCancelableEx function (wdfrequest.h)
[Applies to KMDF and UMDF]
The WdfRequestMarkCancelableEx method enables cancellation of a specified I/O request.
Syntax
NTSTATUS WdfRequestMarkCancelableEx(
[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
WdfRequestMarkCancelableEx returns STATUS_SUCCESS if it successfully enables cancellation of the specified I/O request. Otherwise, this method might return one of the following values:
Return code | Description |
---|---|
|
The I/O request has been canceled. See Remarks for more info. |
|
|
This method might also return other NTSTATUS values.
A bug check occurs if the driver supplies an invalid object handle.
Remarks
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. For info on choosing between the two methods, see WdfRequestMarkCancelable.
When calling WdfRequestMarkCancelableEx, 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.
If WdfRequestMarkCancelableEx returns failure, the driver must perform the same cancellation activities that the EvtRequestCancel callback function performs. For example:
- Finish or stop processing the request, along with subrequests that it might have created.
- Call WdfRequestComplete, specifying a status value of STATUS_CANCELLED.
Because WdfRequestMarkCancelableEx never calls EvtRequestCancel, this method is safe from the deadlock risk described in the Remarks of WdfRequestMarkCancelable.
Processing a request after enabling cancellation
After a driver calls WdfRequestMarkCancelableEx to enable canceling, the request remains cancelable while the driver owns the request object, unless the driver calls WdfRequestUnmarkCancelable.If a driver has called WdfRequestMarkCancelableEx, 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 WdfRequestMarkCancelableEx 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 WdfRequestMarkCancelableEx to enable canceling.
Examples
The following code examples show 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.
Example 1: A driver that uses automatic synchronization.
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
);
}
Example 2: A driver that uses its own synchronization.
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);
}
Requirements
Requirement | Value |
---|---|
Target Platform | Universal |
Minimum KMDF version | 1.9 |
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) |