阅读:712回复:0
取消IRP--3
Because of the singular list entry, device objects must serialize their attempts to queue themselves on controller (or DMA adapter) objects. Thus, it is important in any attempt to cancel an IRP that is pending on an outstanding queued request, to try and remove the request from the controller\'s queue. This must be done atomically with respect to the system, which will also try to remove the request from the queue for processing on the device. This can be done using the function KeRemoveEntryDeviceQueue, which has the prototype:
BOOLEAN KeRemoveEntryDeviceQueue( IN PKDEVICE_QUEUE DeviceQueue, IN PKDEVICE_QUEUE_ENTRY DeviceQueueEntry ); For the parameter DeviceQueue, one would use &(pController->DeviceWaitQueue) and for DeviceQueueEntry, one would use &(pDeviceObject->Queue.Wcb.WaitQueueEntry) If the device object cannot be successfully removed from the controller\'s device queue, the IRP cannot be safely canceled in the cancel routine, since starting the next IRP on the device may try to queue the device again on the controller object, thus corrupting the list. Actually, most sane design methodologies would indicate that an outstanding request on a device must be fully resolved, and the device state known, before the IRP can be completed or canceled. This ensures that there will be no problems in either starting the next IRP, or with extraneous processing occurring after the cancelled IRP has been completed, which can be undesirable. The following is pseudo-code for the steps that must be taken in the various routines to make an IRP that is pending on a controller object cancelable. The main details are presented, but there are several \"routine\" details that are omitted for clarity sake. The DriverWorks?controller example CONTROLR has been updated using the same logic presented here. These fragments assume that the IRP has simply been serialized prior to attempting to gain control of the resources managed by the controller, and that the device state has not been altered by the IRP in any other way that needs to be corrected in the cancel routine. In StartIo routine: Remove the IRP from the cancelable state it was in while queued, testing to see if the IRP was canceled, and dealing with it appropriately if it was. Enter QueueSync spinlock, a private spinlock created for the sole purpose of allowing the cancel routine to be set and the request queued to the controller atomically, with no chance that the cancel routine will proceed before the request is queued. Place the IRP into a cancelable state, using the CancelInProgress routine as its cancel routine, while testing to see if the IRP was canceled, and dealing with it appropriately if it was. Queue our request on the controller object. Leave the QueueSync spinlock. In CancelInProgress routine: Release global cancel spinlock. Enter QueueSync spinlock. Leave QueueSync spinlock. Now it is assured that the request has been queued. Try to remove the device\'s KDEVICE_QUEUE_ENTRY from the controller\'s KDEVICE_QUEUE. If successful, complete the IRP in the canceled state, and start the next IRP on the device. If not successful, signal an event, CancelComplete. This will indicate to the callback routine that the cancel routine has finished executing. Note in this case, the IRP is not completed, nor the next IRP started from the cancel routine. |
|
最新喜欢:![]() |