Synchronizing Cancel and Completion Code

If your driver calls WdfRequestMarkCancelable or WdfRequestMarkCancelableEx to make an I/O request cancelable, there is potential for a synchronization problem. For example, your driver and device might perform device I/O operations asynchronously by means of EvtInterruptIsr and EvtInterruptDpc callback functions, and both the EvtInterruptDpc and EvtRequestCancel callback functions might contain calls to WdfRequestComplete.

The driver must call WdfRequestComplete only once, to either complete or cancel the request. But if the EvtInterruptDpc and EvtRequestCancel callback functions are not synchronized with each other, the framework can call one while the other is executing.

Avoiding this problem is easy if your driver uses the framework's automatic synchronization, because automatic synchronization ensures that the callback functions will be called one at a time.

If your driver does not use the framework's automatic synchronization, it can use framework locks to synchronize cancel and completion code.

Whether the driver uses framework's automatic synchronization or provides its own synchronization, the driver's EvtRequestCancel callback function must call WdfRequestComplete to cancel a request. The driver's EvtInterruptDpc callback function should call WdfRequestUnmarkCancelable as follows:

Status = WdfRequestUnmarkCancelable(Request);
if( Status != STATUS_CANCELLED ) {
    WdfRequestComplete(Request, RequestStatus);
    }

This code ensures that the driver does not call WdfRequestComplete to complete the request if the driver has already called it to cancel the request.

For more information about the rules that your driver must follow when it calls WdfRequestUnmarkCancelable, see WdfRequestUnmarkCancelable.