Cancel 例程简介
IRP 可以无限期保持挂起状态的任何驱动程序必须具有一个或多个 Cancel 例程。 例如,键盘驱动程序可能会无限期地等待用户按下某个键。 相反,如果驱动程序不会在五分钟内完成的 IRP 排入队列,则它可能不需要 Cancel 例程。
假设用户模式线程发出 I/O 请求,该请求由最高级别设备驱动程序的调度例程排队,请求线程在 IRP 排队时终止。 应取消代表已终止线程排队的 IRP。 因此,驱动程序必须在其排队的每个 IRP 中设置驱动程序提供的 Cancel 例程。
创建关联 IRP 的驱动程序必须在取消主 IRP 时取消它们。 由于关联的 IRP 不与请求线程关联,因此在取消主 IRP 时,主 IRP 的 Cancel 例程负责取消任何关联的 IRP。
任何驱动程序具有的 Cancel 例程数取决于驱动程序的设计。 一般情况下,驱动程序应该在其 I/O 处理中的每个阶段都有 一个 Cancel 例程,在该阶段,IRP 可能会无限期地处于挂起状态。 此类待定 IRP 据说 处于可取消状态。
请考虑以下设计准则:
分层驱动程序链中的最高级别驱动程序必须至少有一个 Cancel 例程,如果它将 IRP 排入队列或以其他方式使 IRP 处于可取消状态。 如有必要,它可以有多个 Cancel 例程。
较低级别的驱动程序,其中 IRP 可以保留相对较长的可取消状态,也应该有一个或多个 Cancel 例程。
如果驱动程序管理其自己的 IRP 内部队列,则其每个队列应具有单独的 Cancel 例程。
交互式设备的某些最高级别驱动程序(如键盘、鼠标、声音、并行类和串行驱动程序)必须具有 Cancel 例程。 某些较低级别的驱动程序(例如并行端口驱动程序,该驱动程序将 IRP 保留为相对较长的某个数量的较高级别的类驱动程序排队)也应该具有 Cancel 例程。
大容量存储设备驱动程序以及分层在它们的中间驱动程序不太可能具有 Cancel 例程。 文件系统驱动程序负责处理文件 I/O 请求的取消,而较低级别大容量存储驱动程序的 IRP 输入通常处理得太快,无法取消。