CustomTimerDpc 例程注册和排队
驱动程序可以通过调用以下例程(通常从其 AddDevice 例程)来注册 CustomTimerDpc 例程:
KeInitializeDpc 注册其例程
KeInitializeTimer 或 KeInitializeTimerEx 以设置计时器对象
随后,驱动程序可以调用 KeSetTimer 或 KeSetTimerEx 来指定过期时间,并将计时器对象添加到系统的计时器队列。 达到过期时间后,系统会取消计时器对象的排队,并调用 CustomTimerDpc 例程。 下图演示了这些调用。
如上图所示,驱动程序必须为 DPC 对象和计时器对象提供存储。 大多数驱动程序在 设备扩展 或其他驱动程序分配的驻留内存中为这些对象提供存储。
在调用 KeSetTimer 时,驱动程序将指针传递到 Dpc 和 Timer 对象,以及以 100 纳秒为单位表示的 DueTime ,如上图所示。 DueTime 的正值指定自 1601 年 1 月 1 日 () 应调用 CustomTimerDpc 例程的绝对过期时间。 DueTime 的负值指定相对过期时间。
由于绝对计时器在特定系统时间过期,因此如果系统时间在计时器过期之前发生更改,则绝对计时器的等待持续时间不受影响。 另一方面,无论绝对系统时间发生更改,相对计时器始终在指定时间单位数过后过期。
若要重复调用 CustomTimerDpc 例程,请使用 KeSetTimerEx 设置计时器并在 Period 参数中指定定期间隔。 KeSetTimerEx 与 KeSetTimer 相同,但此附加参数除外。
如上图所示,调用 KeSetTimer 或 KeSetTimerEx 会将计时器对象排队指定间隔,如下所示:
当 DueTime 过期时,计时器对象将取消排队并设置为“已信号”状态。
如果计算机中的每个处理器当前都在大于或等于 DISPATCH_LEVEL 的 IRQL 上运行代码,则与计时器对象关联的 DPC 对象将放入 DPC 队列中。 否则,将调用 CustomTimerDpc 例程。
如果在 DueTime 间隔过期时 DPC 对象已在队列中,则当计算机中任何处理器上的 IRQL 低于 DISPATCH_LEVEL 时,将立即调用 CustomTimerDpc 例程。
注意
与所有 DPC 例程一样,在 IRQL = DISPATCH_LEVEL调用 CustomTimerDpc 例程。 当 DPC 例程运行时,会阻止所有线程在同一处理器上运行。 驱动程序开发人员应仔细设计其 CustomTimerDpc 例程,使其尽可能短地运行一段时间。
可指定给 KeSetTimer 和 KeSetTimerEx 的最小时间间隔约为 10 毫秒,因此驱动程序可以使用 CustomTimerDpc 例程,当计时间隔小于 IoTimer 例程(每秒运行一次)可以处理的时间。
在任何时候,只能对特定计时器对象的一次实例化排队。 使用相同的 Timer 对象指针再次调用 KeSetTimer 或 KeSetTimerEx 会取消排队的计时器对象并重置它。
设置 CustomTimerDpc 例程与设置 CustomDpc 例程完全相同,另外还有一个步骤来初始化计时器对象。 事实上,它们的原型是相同的,但 CustomTimerDpc 例程不能使用在其原型中声明的两 个 SystemArgument 指针。