阅读:610回复:0
取消IRP--4
In ControllerCallback routine:
Remove IRP from the cancelable state it was in while queued on the controller object, testing to see if the IRP has been canceled. If the IRP has been canceled, queue a work item WaitForCancel and deallocate the controller object. If the IRP has not been canceled, proceed with the work that the device must do to satisfy the IRP, keeping the controller object until that work is done and then releasing it. In WaitForCancel routine: Wait on the CancelComplete event. Complete the IRP in the canceled state, and start the next IRP on the device. There are several interesting points to discuss concerning the above logic. Most of these points involve tricky timing issues that come to light when analyzing the task of synchronizing two asynchronous threads of execution, namely the cancel thread and the controller callback thread. This endeavor leads to most of the complexity shown in the pseudocode. First, consider the spinlock QueueSync, which is used in the StartIo and CancelInProgress routines. This spinlock is necessary, since without it the cancel routine could try to dequeue the device object from the controller\'s queue before it has been queued, in which case it will not find the request. This would result in queuing a canceled request to the controller. Ultimately, this situation would be resolved when the request is dequeued by the system, but it will not happen in a timely manner, which is the intent in the first place. One very important point to note, with regards to this spinlock, is that the ControllerCallback routine may be called with the spinlock held if the system finds the controller is not busy and calls the routine inline to the queuing request on the controller. This is not a problem so long as the callback routine does not try to reacquire the spinlock, which would result in a deadlock. Next, consider an IRP that is canceled and the possible ordering of events. The IRP may be canceled while the request is still queued on the controller object. In this case the cancel routine will be able to successfully remove it from the queue, complete it as canceled, and start the next IRP on the device. Another possibility is that the system dequeues the request and calls the ControllerCallback routine before the IRP is canceled. If the IRP is canceled after the callback routine succeeds in making the IRP not cancelable, the system will not call the cancel routine, and the IRP will complete normally when processing is completed on the device. Note that it is not compulsory to complete an IRP that has been canceled with a canceled status. Instead, that IRP should simply be completed soon. A final possibility is that the system dequeues the request just as the cancel routine is being run. In this case, both the cancel routine and the callback routine will execute. When the cancel routine runs, it will not find the request queued on the controller object. Instead of completing the IRP and starting the next IRP, the cancel routine will signal the CancelComplete event indicating it has run. When the callback routine runs, it will detect that the IRP has been canceled, and it will queue a work item to wait for the CancelComplete event. The reason a work item must be used is that the callback routine may be running at DEVICE IRQL, precluding the ability to wait. The reason to wait on the event in the WaitForCancel routine is to ensure that both the cancel and callback processing have been completed, before completing this IRP or starting the next IRP on the device. This ensures that our device state is fully resolved before the next IRP is started. The ability to cancel pending requests on controller objects may not be required for most driver designs. Certainly, any design in which requests will not remain pending for very long before being serviced will not benefit greatly from the added complexity. In a small subset of designs, however, this ability might be critical. It is somewhat unfortunate, therefore, that the underlying mechanics are somewhat hidden in the call to the IoAllocateController routine, since it forces our solution to rely on that mechanism remaining constant. While it is unlikely that this mechanism will change, the fact remains that its design makes use of the driver\'s device object in a semi-opaque manner, instead of opening up the interface by exposing the underlying device queue mechanism. Indeed, the design could have been made much more generalized by the inclusion of a parameter allowing the KDEVICE_QUEUE_ENTRY to be specified in the call to IoAllocateController, eliminating the dependence on the singular instance enmeshed in the driver\'s device object |
|
最新喜欢:![]() |