访问共享状态信息

使用以下一般准则来设计和编写用于维护状态的 SynchCritSection 例程:

  • 若要访问 ISR 也访问的数据,驱动程序例程必须调用 SynchCritSection 例程。 非关键节代码可能会中断。 请记住,仅仅获取旋转锁来保护 ISR 也访问的数据是不够的,因为 ISR 在 DIRQL 中执行并获取 (KeAcquireSpinLock 的自旋锁) 只会引发 IRQL DISPATCH_LEVEL,从而允许中断在当前处理器上调用 ISR。

  • 为维护一组离散状态变量的状态信息的每个 SynchCritSection 例程指定责任。 也就是说,避免编写保持重叠状态信息的 SynchCritSection 例程。

    这可以防止 SynchCritSection 例程 (和 ISR) 尝试同时访问同一状态之间的争用和可能的争用条件。

    这还可确保每个 SynchCritSection 例程尽快返回控制权,因为一个 SynchCritSection 例程永远不必等待另一个更新某些相同状态信息来返回控制权的例程。

  • 避免编写单个大型常规用途 SynchCritSection 例程,该例程对条件执行更多测试,以确定要执行的操作,而不是实际执行有用的工作。 另一方面,请避免使用许多从不执行条件语句 的 SynchCritSection 例程,因为每个例程仅更新状态信息的单个字节。

  • 每个 SynchCritSection 例程必须尽快返回控制权,因为运行任何 SynchCritSection 例程都会阻止驱动程序的 ISR 执行。

下面是在设备扩展中维护计时器计数器的技术。 假设驱动程序使用计数器来确定 I/O 操作是否已超时。此外,假设驱动程序不与 I/O 操作重叠。

  • 驱动程序的 StartIo 例程将计时器计数器初始化为每个 I/O 请求的某个初始值。 然后,驱动程序在其设备超时值中添加一秒,以防其 IoTimer 例程刚刚返回控制权。

  • 驱动程序的 ISR 必须将此计时器计数器设置为减 1。

  • 每秒调用驱动程序的 IoTimer 例程一次,以读取时间计数器并确定 ISR 是否已将其设置为减 1。 否则, IoTimer 例程通过使用 KeSynchronizeExecution 调用SynchCritSection_1例程来递减计数器。

    如果计数器为零,指示请求超时,则SynchCritSection_1例程调用SynchCritSection_2例程来对设备重置操作进行编程。 如果计数器为减 1,则 IoTimer 例程仅返回 。

  • 如果驱动程序的 DpcForIsr 例程必须重新编程设备以开始部分传输操作,则必须像 StartIo 例程一样重新初始化计时器计数器。

    DpcForIsr 例程还必须使用 KeSynchronizeExecution 调用SynchCritSection_2例程,或者调用SynchCritSection_3例程,以便对设备进行另一个传输操作编程。

在此方案中,驱动程序有多个 SynchCritSection 例程,每个例程都有离散的特定职责;一个用于维护其计时器计数器,另一个或多个用于对设备进行编程。 每个 SynchCritSection 例程都可以快速返回控制,因为它执行单个离散任务。

请注意,驱动程序有一个SynchCritSection_1例程,该例程与驱动程序的 ISR 一起维护计时器计数器的状态。 因此,在多个 SynchCritSection 例程和 ISR 之间,访问计时器计数器时不存在争用。