同步示例

以下示例说明了微型驱动程序在同步方面需要执行的操作,并包括不应使用同步时的示例:

  • 示例一:具有正常运行的 ISR 的微型驱动程序

    如果启用了流类同步,则会使用 KeSynchronizeExecution 在引发 IRQL 时调用所有微型驱动程序入口点,这意味着在微型驱动程序执行其代码时会屏蔽适配器的 IRQ 级别和所有较低的 IRQ 级别。 因此,微型驱动程序必须在此模式下仅执行少量工作。

    微型驱动程序不应在引发 IRQL 时运行通常超过 10 到 20 微秒的代码。 如果使用 stream.sys调试版本,流类会记录在引发 IRQL 时花费的时间量,并在驱动程序花费太多时间时断言。 如果微型驱动程序只需为请求编程硬件 DMA 寄存器,或者只需读取 ISR 中的端口,则通常可以接受在引发 IRQL 时执行其所有处理。

    如果微型驱动程序需要执行多个微秒的处理,例如通过 PIO 传输数据的微型驱动程序,微型驱动程序应使用 StreamClassCallAtNewPriority 来计划DISPATCH_LEVEL回调。 在回调中,微型驱动程序最多可能需要 1/2 到 1 毫秒才能执行其处理。 在此模式下需要记住的一点是,DISPATCH_LEVEL回调 与 ISR 同步。

    如果微型驱动程序在回调期间以及 ISR 中访问资源(例如端口或队列)时硬件保持稳定,则这种缺乏同步并不是问题。 但是,如果不稳定可能是个问题,微型驱动程序必须使用 StreamClassCallAtNewPriority 来计划 HIGH 优先级回调,其中DISPATCH_LEVEL回调涉及与 ISR 使用的资源共享的资源。

    请注意,HIGH 优先级回调等效于调用 KeSynchronizeExecutionKeSynchronizeExecution 要求微型驱动程序引用 StreamClassCallAtNewPriority 不具有的多个参数,但通常这两个参数会导致相同的行为。

    如果微型驱动程序偶尔需要运行超过 1/2 到 1 毫秒的代码,或者偶尔需要在PASSIVE_LEVEL(如初始化时)调用服务,则可以 使用 StreamClassCallAtNewPriority 设置为 LOW 优先级来获取PASSIVE_LEVEL工作线程。 请注意,低优先级回调未与任何内容同步,微型驱动程序可以在运行低优先级回调时接收新请求(假设 ReadyForNextRequest NotificationType 参数挂起)或 ISR 调用。

  • 示例二:没有 ISR 的微型驱动程序

    如果启用了流类同步,则微型驱动程序的入口点均在DISPATCH_LEVEL调用。 微型驱动程序最多可以处理大约 1/2 到 1 毫秒的持续时间,而无需调整优先级。 如果微型驱动程序偶尔需要运行超过 1/2 毫秒的代码,或者偶尔需要在PASSIVE_LEVEL(如初始化时)调用服务, 则可以使用具有 LOW 优先级的 StreamClassCallAtNewPriority 来获取PASSIVE_LEVEL工作线程。 请注意,低优先级回调未与任何内容同步,微型驱动程序可能会在运行低优先级回调时接收新请求(假设 ReadyForNextRequest NotificationType 参数挂起)。

  • 不应使用流类同步时

    下面是不应使用流类同步的情况的示例。 这些设置包括:

    • 当驱动程序频繁(超过 20% 的请求时,微型驱动程序接收的请求)需要执行超过 1 毫秒的处理,或者需要频繁调用PASSIVE_LEVEL服务(如 Microsoft DirectDraw 服务)。 使用 stream.sys调试版本时,流类将断言这两种情况,并在启用同步时停止。

    • 当微型驱动程序是没有关联硬件的筛选器时。 此类微型驱动程序应在PASSIVE_LEVEL运行,因为没有要与之同步的基础硬件,微型驱动程序通常执行大量处理。 在这种情况下,执行自己的同步比使用流类同步浪费开销更容易。 如有必要,请使用互斥体来保护队列。

      同步代码中的 Bug 通常很难找到,在某些环境中(例如在多处理器系统上运行的基于 NT 的操作系统)bug 可能仅在压力数小时后出现。 根据供应商的经验,这些不是大多数供应商具有调试能力或愿望的东西。 只有熟悉编写完全异步 WDM 设备驱动程序的驱动程序编写器才应尝试执行自己的同步。

    • 当微型驱动程序是总线上的总线类型驱动程序(例如 USB 或 1394 外围驱动程序)时,它并不真正担心实际硬件的同步,但只需在PASSIVE_LEVEL调用下一层请求,并在DISPATCH_LEVEL接收回调。