CustomTimerDpc 例程注册和排队

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

  1. KeInitializeDpc 注册其例程

  2. KeInitializeTimerKeInitializeTimerEx 以设置计时器对象

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

diagram illustrating using timer and dpc objects for a customtimerdpc routine.

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

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

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

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

如上图所示,对 KeSetTimer 或 KeSetTimerEx 的调用按指定间隔对计时器对象进行排队,如下所示:

  1. DueTime 过期时,计时器对象将取消排队并设置为 Signaled 状态。

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

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

    注意

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

可以指定到 KeSetTimer 和 KeSetTimerEx 的最小时间间隔约为 10 毫秒,因此当计时比每秒运行一次的 IoTimer 例程更小时,驱动程序可以使用 CustomTimerDpc 例程。

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

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