Synchronizing IRP Cancellation
From a driver's perspective, an IRP can be canceled at any time. IRP cancellation occurs asynchronously; therefore, drivers must be able to handle a number of potential race conditions, created if the IRP is canceled at any of the following points:
After a driver routine is called, but before it queues an IRP.
After a driver routine is called, but before it tries to process an IRP. For example, an IRP might be canceled after a driver's StartIo routine is called, but before the StartIo routine removes the IRP from the device queue.
After the driver routine dequeues the IRP, but before it starts the requested I/O.
Note that after a driver queues an IRP and releases any spin locks that protect the queue, another thread can access and change the IRP. When the original thread resumes—even as soon as the next line of code—the IRP might have already been canceled or otherwise changed.
Driver can use the cancel-safe IRP queue framework to implement IRP queuing. The system then registers a Cancel routine for the driver that automatically handles synchronization to safely cancel IRPs. See Cancel-Safe IRP Queues for more information. Otherwise, drivers must implement their own synchronization.
The following members of an IRP contain information about cancellation:
Irp->Cancel indicates whether an IRP is being canceled or should be canceled.
Irp->CancelRoutine indicates whether an IRP is cancelable. If this member contains a pointer to a cancel routine, then the IRP is cancelable. If this member is NULL, then the IRP is not cancelable. If this member is NULL, but Irp->Cancel is set, that indicates that the cancel routine is running and the IRP is in the process of being canceled.
If a driver handles cancelable IRPs, it is responsible for setting the appropriate Cancel routine in each IRP that it holds in a cancelable state.
This section includes the following topics on synchronizing IRP cancellation.