12.2 Handling Cancelable IRPs

If an NT driver handles cancelable IRPs, it is responsible for setting the appropriate Cancel routine in each IRP that will be put into a cancelable state as it is processed in stages by the driver's routines.

The following summarizes guidelines for driver routines that handle cancelable IRPs.

Handling Cancelable IRPs in Driver Routines That Pass IRPs On

If a device driver has a StartIo routine, its Dispatch routines must specify a driver-supplied Cancel routine's entry point when they call IoStartPacket.

Otherwise, any driver's Dispatch routine(s) must do the following before queueing an IRP for further processing by other driver routines:

1.Call IoAcquireCancelSpinLock.

2.Call IoSetCancelRoutine with the input IRP and the entry point for a driver-supplied Cancel routine.

3.Call IoReleaseCancelSpinLock.

In a similar manner, any routine in such a driver that passes an IRP on for further processing by other routines in the same driver should set up a Cancel routine if that request could be held in a cancelable state before another driver routine begins processing it.

Drivers that manage their own queue(s) of IRPs, rather than using the I/O-manager-supplied device queue, do not need to acquire the cancel spin lock when calling IoSetCancelRoutine.

Handling Cancelable IRPs In Driver Routines That Process Requests

A driver's StartIo routine, if any, and/or any other routine that dequeues or is called with an IRP that was held in a cancelable state must do the following:

1.Call IoAcquireCancelSpinLock.

2.Check the Irp->Cancel field to determine whether to cancel the IRP or to begin processing for the request.

·If Irp->Cancel is set to TRUE, call IoReleaseCancelSpinLock and return control.

·Otherwise, do the following:

1.Call IoSetCancelRoutine with a NULL CancelRoutine pointer to remove the IRP from the cancelable state.

2.Call IoReleaseCancelSpinLock.

3.Start the requested device I/O operation for the target device object or, from a higher-level driver, pass the request on to lower drivers.

Any other driver routine that dequeues an IRP or is called with an IRP that might have been held pending for an indefinite interval should do likewise. That is, such a routine must test whether the IRP should be cancelled or remove the IRP from the cancelable state before it begins I/O processing for that IRP.

Drivers that manage their own queue(s) of IRPs, rather than using the I/O-manager-supplied device queue, do not need to acquire the cancel spin lock when calling IoSetCancelRoutine.

In any driver that handles cancelable IRPs, every driver routine that processes an IRP before the underlying device has been programmed for the requested I/O operation should check the cancelable state of all incoming IRPs. That is, a highest-level NT device driver with both StartIo and ControllerControl routines should process incoming IRPs in both these driver routines as already described.

Using the System Cancel Spin Lock

Consider the following implementation guidelines for driver routines that change the state of cancelable IRPs, including all routines that might complete an IRP with STATUS_CANCELLED:

·In drivers that use the I/O-manager-supplied device queue, any driver routine besides the Cancel routine that changes the cancelable state of an IRP must first call IoAcquireCancelSpinLock to acquire the system cancel spin lock.

This ensures that only the caller can change the cancelable state of that IRP for the following reasons:

·It prevents the I/O Manager from calling the driver's Cancel routine with that IRP.

·It prevents any other driver routine, such as its DispatchCleanup routine, from simultaneously attempting to change the cancelable state of that IRP.

·In drivers that manage their own queue(s) of IRPs and synchronize queue access using driver-supplied spin locks, the driver routines do not need to acquire the cancel spin lock when calling IoSetCancelRoutine.

·Any driver routine that calls IoAcquireCancelSpinLock must call IoReleaseCancelSpinLock as quickly as possible.

·Never call IoCompleteRequest with an IRP while holding a spin lock.

Attempting to complete an IRP while holding a spin lock can cause deadlocks.