排队和取消排队 IRP

由于 I/O 管理器支持多任务和多线程系统中的异步 I/O,因此对设备的 I/O 请求的传入速度可能快于其驱动程序处理到完成的速度,尤其是在多处理器计算机中。 因此,绑定到任何特定设备的 IRP 必须在驱动程序中排队,当其设备已忙于处理另一个 IRP 时。

因此,最低级别的驱动程序需要以下项之一:

  • StartIo 例程,I/O 管理器调用该例程来启动驱动程序已排队到系统提供的 IRP 队列的 IRP 的 I/O 操作, (请参阅 IoStartPacket) 。

  • 一种内部 IRP 排队和取消排队机制,驱动程序使用该机制来管理传入速度超过其满足速度的 IRP。 驱动程序可以使用设备队列、互锁队列或取消安全队列。 有关详细信息,请参阅 驱动程序托管的 IRP 队列

只有满足并完成调度例程中每个可能的 IRP 的最低级别设备驱动程序不需要 StartIo 例程,也不需要 IRP 的驱动程序托管队列。

更高级别的驱动程序几乎从不具有 StartIo 例程。 大多数中间驱动程序既没有 StartIo 例程,也没有内部队列;中间驱动程序通常可以从其调度例程传递具有有效参数的 IRP,并对其 IoCompletion 例程中的任何 IRP 执行所需的任何后处理。

下面通常介绍一些设计注意事项,这些注意事项用于确定是否使用内部驱动程序管理的 IRP 队列来实现 StartIo 例程。

驱动程序中的 StartIo 例程

对于一次只能处理一个设备 I/O 操作的计算机外围设备,设备驱动程序可以实现 StartIo 例程。 对于这些驱动程序,I/O 管理器提供 IoStartPacketIoStartNextPacket 例程,以便与系统提供的 IRP 队列进行排队和取消排队。

有关 StartIo 例程的详细信息,请参阅 编写 StartIo 例程

驱动程序中 IRP 的内部队列

如果设备可以支持多个并发 I/O 操作,则其最低级别的设备驱动程序必须设置内部请求队列并管理其自己的 IRP 队列。 例如,系统串行驱动程序在其设备上维护单独的读取、写入、清除和等待操作队列,因为它支持全双工串行设备。

向一些基础设备驱动程序发送请求的更高级别的驱动程序也可能维护 IRP 的内部队列。 例如,文件系统驱动程序几乎始终具有 IRP 的内部队列。

有关详细信息,请参阅 驱动程序托管的 IRP 队列

内部队列同步

具有设备专用线程的驱动程序和使用执行工作线程的最高级别驱动程序 (包括大多数文件系统驱动程序) 通常会为 IRP 设置自己的队列。 队列由驱动程序线程或驱动程序提供的工作线程回调以及处理 IRP 的其他驱动程序例程共享。

实现自己的队列结构的驱动程序必须确保同步对队列的访问,并且已取消的 IRP 将从队列中删除。 为了简化驱动程序编写器的此任务,取消安全的 IRP 队列提供了一个标准框架,你可以在实现 IRP 队列时使用。 有关详细信息 ,请参阅取消安全 IRP 队列 。 这是实现 IRP 队列的首选方法。

驱动程序还可以显式实现所有 IRP 队列同步和取消逻辑。 例如,驱动程序可以使用互锁队列。 驱动程序的调度例程将 IRP 插入互锁队列,驱动程序创建的线程或驱动程序的工作线程回调通过调用 ExInterlockedXxxList 支持例程将其删除。

例如,系统软盘控制器驱动程序使用互锁队列。 其设备专用线程处理由其他设备驱动程序的 StartIo 例程完成的相同 IRP 处理,以及由其他设备驱动程序的 DpcForIsr 例程完成的 IRP 的某些相同处理。

驱动程序中具有 StartIo 例程的内部队列

管理其内部队列的驱动程序也可以具有 StartIo 例程,但不需要。 大多数最低级别的设备驱动程序要么有 StartIo 例程,要么管理自己的 IRP 队列,但不能同时管理两者。

SCSI 端口驱动程序例外,该驱动程序具有 StartIo 例程并管理 IRP 的内部队列。 I/O 管理器将 IRP 排队到与驱动程序创建的表示 SCSI HBA 的设备对象关联的设备队列中的端口驱动程序 的 StartIo 例程。 SCSI 端口驱动程序还会设置和管理每个目标设备的 IRP 的设备队列, (对应于计算机中任何 HBA 驱动的 SCSI 总线上的 SCSI 逻辑单元) 。

每当 SCSI 总线上的任何设备特别繁忙时,SCSI 端口驱动程序使用其补充设备队列将 SCSI 类驱动程序发送的 IRP 保存在特定于 LU 的队列中。 实际上,此驱动程序的特定于 LU 的补充设备队列允许 SCSI 端口驱动程序通过 HBA 序列化异类 SCSI 设备的操作,同时使 HBA 的 SCSI 总线上的每台设备尽可能繁忙。