Synchronizing Cancellation of Sent Requests

When a driver attempts to cancel an I/O request that it has forwarded to an I/O target, the driver must ensure that it passes a valid request handle to the WdfRequestCancelSentRequest method. The request handle becomes invalid if the I/O target completes the request, because the driver's CompletionRoutine callback function will call WdfRequestComplete (which attempts to delete the request object).

To avoid this problem, the driver can keep track of the requests that it has sent to the I/O target by, for example, creating a collection of request objects. The driver can call WdfSpinLockAcquire to synchronize access to the collection.

When the driver's CompletionRoutine callback function is called, it acquires the lock, removes the completed request's handle from the collection, and calls WdfSpinLockRelease to release the lock.

Before attempting to cancel a request that the driver has forwarded to an I/O target, the driver can:

  1. Call WdfSpinLockAcquire to acquire a spin lock.

  2. Find the request object's handle in the collection, to ensure that driver's completion routine hasn't completed the request and removed the handle from the collection.

  3. Call WdfObjectReference to increment the request object's reference count so that the object cannot be deleted.

  4. Call WdfSpinLockRelease to release the spin lock.

  5. Call WdfRequestCancelSentRequest.

  6. Call WdfObjectDereference to decrement the object's reference count.

This sequence ensures that if the I/O target completes the request before the driver calls WdfRequestCancelSentRequest, the request's handle is still valid (because of the incremented reference count) even if the driver's CompletionRoutine callback function calls WdfRequestComplete.