分类: WINDOWS
2012-03-16 22:19:21
IRP请求的最终结局无非有两个:要么被完成了,要么被取消了。完成IRP请求的过程已经在前面讲过了,这里仔细讲一个IRP请求的取消。 为什么要取消IRP请求呢?一般来讲,原因不外乎是本请求操作超时或设备故障导致的。具体理解,可以考虑如下两种情形: 情形1:驱动发送一个请求到下级驱动,下级驱动由于忙,将它放到自己的请求队中去,下级驱动一直忙,请求一直没有得到处理,而这个请求又比较重要,如果一直得不到处理就会造成系统处于死锁。于是,驱动就会给这个请求加上超时机制,若超过一定的时间还没有得到处理结果,就通知下级驱动直接取消该请求。 情形2:驱动发送很多请求到下级驱动去处理,下级驱动返回了一个请求的结果。可是,这个结果是个错误,而且是个很严重的错误,比如设备出故障了。这时,就要将设备进行错误恢复,如重启设备,同时,其它送下去的请求都要同时取消掉。 驱动如何被取消? 一般来讲,取消的发起者一定是上层的驱动,而取消的实际执行者,则是下层的驱动。 1. 上层的驱动通过调用 IoCancelIrp( Irp ) 来取消某个请求。这个请求应该是被某个下层驱动放在缓冲队列中等待处理或正在处理。 2. 下层驱动为了能支持驱动取消机制,一般都在收到IRP请求时就马上注册一个取消回调例程 CancelRoutine,注册的函数是 IoSetCancelRoutine( Irp, CancelRoutine ); 3. IoCancelIrp 调用中就会去先调用 IoAcquireCancelSpinLock,再调用这个设置好的CancelRoutine,注意,CancelRoutine是 Irp中的一个数据成员,也就是说设备堆栈中的所有驱动都共用这个成员函数。 4. CancelRoutine中,驱动一般会根据当前Irp的状态来做相应的操作。如果Irp是在请求队列中,就会先将它移出队列,设置好返回状态STATUS_CANCELLED,然后再调用IoCompleteRequest来直接完成这个请求,最后千万不要忘记调用 IoReleaseCancelSpinLock( Irp的CancelIrql ) 来释放回旋锁。 |