CustomTimerDpc 例程注册和排队

驱动程序可以通过调用以下例程(通常从其 AddDevice 例程)来注册 CustomTimerDpc 例程:

  1. KeInitializeDpc 注册其例程

  2. KeInitializeTimerKeInitializeTimerEx 以设置计时器对象

随后,驱动程序可以调用 KeSetTimerKeSetTimerEx 来指定过期时间,并将计时器对象添加到系统的计时器队列。 达到过期时间后,系统会取消计时器对象的排队,并调用 CustomTimerDpc 例程。 下图演示了这些调用。

说明将计时器和 dpc 对象用于 customtimerdpc 例程的示意图。

如上图所示,驱动程序必须为 DPC 对象和计时器对象提供存储。 大多数驱动程序在 设备扩展 或其他驱动程序分配的驻留内存中为这些对象提供存储。

在调用 KeSetTimer 时,驱动程序将指针传递到 DpcTimer 对象,以及以 100 纳秒为单位表示的 DueTime ,如上图所示。 DueTime 的正值指定自 1601 年 1 月 1 日 () 应调用 CustomTimerDpc 例程的绝对过期时间DueTime 的负值指定相对过期时间

由于绝对计时器在特定系统时间过期,因此如果系统时间在计时器过期之前发生更改,则绝对计时器的等待持续时间不受影响。 另一方面,无论绝对系统时间发生更改,相对计时器始终在指定时间单位数过后过期。

若要重复调用 CustomTimerDpc 例程,请使用 KeSetTimerEx 设置计时器并在 Period 参数中指定定期间隔。 KeSetTimerExKeSetTimer 相同,但此附加参数除外。

如上图所示,调用 KeSetTimerKeSetTimerEx 会将计时器对象排队指定间隔,如下所示:

  1. 当 DueTime 过期时,计时器对象将取消排队并设置为“已信号”状态。

  2. 如果计算机中的每个处理器当前都在大于或等于 DISPATCH_LEVEL 的 IRQL 上运行代码,则与计时器对象关联的 DPC 对象将放入 DPC 队列中。 否则,将调用 CustomTimerDpc 例程。

  3. 如果在 DueTime 间隔过期时 DPC 对象已在队列中,则当计算机中任何处理器上的 IRQL 低于 DISPATCH_LEVEL 时,将立即调用 CustomTimerDpc 例程。

    注意

    与所有 DPC 例程一样,在 IRQL = DISPATCH_LEVEL调用 CustomTimerDpc 例程。 当 DPC 例程运行时,会阻止所有线程在同一处理器上运行。 驱动程序开发人员应仔细设计其 CustomTimerDpc 例程,使其尽可能短地运行一段时间。

可指定给 KeSetTimerKeSetTimerEx 的最小时间间隔约为 10 毫秒,因此驱动程序可以使用 CustomTimerDpc 例程,当计时间隔小于 IoTimer 例程(每秒运行一次)可以处理的时间。

在任何时候,只能对特定计时器对象的一次实例化排队。 使用相同的 Timer 对象指针再次调用 KeSetTimerKeSetTimerEx 会取消排队的计时器对象并重置它。

设置 CustomTimerDpc 例程与设置 CustomDpc 例程完全相同,另外还有一个步骤来初始化计时器对象。 事实上,它们的原型是相同的,但 CustomTimerDpc 例程不能使用在其原型中声明的两 个 SystemArgument 指针。