管理 I/O 队列
启动 I/O 队列
当驱动程序调用 WdfIoQueueCreate 来创建 I/O 队列时,框架会自动使队列能够接收 I/O 请求并将其传递给驱动程序。
驱动程序通常从 EvtDriverDeviceAdd 回调函数中调用 WdfIoQueueCreate。 在驱动程序的 EvtDriverDeviceAdd 回调函数返回后,框架可以开始向驱动程序传递 I/O 请求。
如果驱动程序使用 电源管理的 I/O 队列,则框架无法开始向驱动程序传递请求,直到设备进入其工作状态,并且框架已调用驱动程序的 EvtDeviceD0Entry 回调函数。
停止和重启 I/O 队列
驱动程序可以调用 WdfIoQueueStop 或 WdfIoQueueStopSynchronously ,以暂时阻止框架从 I/O 队列传递 I/O 请求。 若要恢复 I/O 请求的传递,驱动程序会调用 WdfIoQueueStart。
如果驱动程序使用电源管理的 I/O 队列,则当设备离开其工作 (D0) 状态时,框架会自动停止设备的队列,并在设备状态返回到 D0 时重启队列。
将请求添加到 I/O 队列
当系统向驱动程序发送读取、写入或设备 I/O 控制请求时,框架会将该请求置于 I/O 队列中。 驱动程序可以通过调用 WdfDeviceConfigureRequestDispatching 来控制框架存储在每个队列中的请求类型。
驱动程序还可以通过调用 WdfRequestForwardToIoQueue 来重新排队从框架收到的请求。
从 I/O 队列获取请求
如果驱动程序为 I/O 队列指定顺序或并行 调度方法 ,它将在 请求处理程序中接收请求。
如果驱动程序指定手动或顺序调度方法,它可以通过调用 WdfIoQueueRetrieveNextRequest 或 WdfIoQueueRetrieveRequestByFileObject 来获取请求。
搜索 I/O 请求
如果驱动程序为 I/O 队列指定手动 调度方法 ,则可以使用以下步骤搜索队列中的特定请求:
调用 WdfIoQueueFindRequest 以查找与驱动程序指定的条件匹配的请求。
调用 WdfIoQueueRetrieveFoundRequest 以检索 WdfIoQueueFindRequest 所在的请求。
清除或清空 I/O 队列
清除 I/O 队列意味着停止将 I/O 请求插入队列,并取消队列中已有的任何请求。
清空 I/O 队列意味着停止将 I/O 请求插入队列,同时允许将队列中已有的任何请求传递到驱动程序。
驱动程序通常仅在队列不受电源管理的情况下清除或清空其队列。 对于电源管理的 I/O 队列,驱动程序可以提供 EvtIoStop 和 EvtIoResume 回调函数。
如果某些驱动程序的队列不受电源管理,则当队列的关联设备或 I/O 通道不可用时,可能需要清除或清空队列。 通常,除非每个请求很有可能包含非常重要的信息,否则将清除队列,而不是清空队列。 例如,网络设备的驱动程序可能会清除其队列,而存储设备的驱动程序可能会清空其队列。
如果希望驱动程序清除或清空 I/O 队列,驱动程序可以调用以下队列对象方法之一:
WdfIoQueuePurge 或 WdfIoQueuePurgeSynchronously,用于停止将 I/O 请求排队到 I/O 队列并取消未处理的请求。
WdfIoQueueDrain 或 WdfIoQueueDrainSynchronously,用于停止将 I/O 请求排队到 I/O 队列,同时允许传递和处理已排队的请求。
调用 WdfIoQueueDrain 和 WdfIoQueueDrainSynchronously 时要小心。 由于清空操作会等待请求完成,因此,如果确定队列的挂起请求将及时完成,则只应清空队列。 如果不知道 I/O 请求需要多长时间才能完成,并且取消未完成的请求是可以接受的,请考虑清除队列。
将请求从一个 I/O 队列移动到另一个 I/O 队列
在驱动程序收到 I/O 请求后,你可能希望驱动程序将请求重新排队到不同的 I/O 队列中。 为此,驱动程序调用 WdfRequestForwardToIoQueue 或 WdfRequestForwardToParentDeviceIoQueue,这将请求添加到指定队列的尾部。 最终,框架将使用指定队列的调度方法再次将请求传送到驱动程序。 有关将 I/O 请求从一个 I/O 队列移动到另一个队列的详细信息,请参阅 重新排队 I/O 请求。
在 I/O 请求排队之前截获该请求
驱动程序可以在框架将请求放入 I/O 队列之前截获 I/O 请求。 若要截获 I/O 请求,驱动程序必须调用 WdfDeviceInitSetIoInCallerContextCallback 来注册 EvtIoInCallerContext 回调函数。
框架将 EvtIoInCallerContext 回调函数与设备相关联。 因此,框架每次收到系统要发送到设备的请求时,都会调用 EvtIoInCallerContext 回调函数。
通常,当 EvtIoInCallerContext 回调函数收到请求时,它会对该请求执行一些初步处理。 接下来,回调函数调用 WdfDeviceEnqueueRequest,这将请求返回给框架。 然后,框架可以将请求置于适当的 I/O 队列中,就像未调用 EvtIoInCallerContext 回调函数时一样。
驱动程序可能提供 EvtIoInCallerContext 回调函数的主要原因是驱动程序必须处理支持 I/O 方法的 I/O 操作,该方法既 不调用缓冲,也不直接 I/O。 对于此 I/O 方法,驱动程序必须访问 I/O 请求发起者的进程上下文中收到的缓冲区。 有关详细信息,请参阅 访问 Framework-Based 驱动程序中的数据缓冲区。
获取 I/O 队列属性
若要获取框架队列对象的属性,驱动程序可以调用以下方法:
WdfIoQueueGetDevice,用于获取队列对象所属的设备对象的句柄。
WdfIoQueueGetState,用于获取有关队列 的状态信息 。