阅读:1154回复:1
DPC 延迟过程调用
作者: JIURL
邮箱: thejiurl@gmail.com 主页: http://jiurl.blogsome.com/ http://jiurl.yeah.net/ $ 前言 这篇文章应该写于 2005年4月13日,是写给自己备忘的研究文档,本来是根本没有打算放出来的。 $ DPC deferred procedure call (DPC) 延迟过程调用 dpc 主要是为了减少处于高 IRQL 的硬件中断处理的时间。 由于低 IRQL 的硬件中断不能中断 高 IRQL 的硬件中断处理。 而可能有些硬件的中断处理代码量比较大,花的时间比较多,会造成其他硬件中断的响应会等的时间比较长。 很有可能就是因为 时钟中断处理,非常非常频繁,代码量也比较多,可能会比较大的影响到其他硬件中断的响应,至于硬件中断响应比较慢可能会对不同的硬件造成什么结果,有待研究。 $ DPC 队列 整个系统只有一个 DPC 队列,至少对单cpu的系统是如此,对于多cpu系统有可能是一个cpu一个,有待验证。 这个队列是个 LIST_ENTRY 链表。 链表头在 pcr 的 +800 struct _LIST_ENTRY DpcListHead。 链的深度在 pcr 的 +808 uint32 DpcQueueDepth。 所有的 dpc 都链在这个链上。 链上的每项是个 KDPC 结构。 struct _KDPC (sizeof=32) +00 int16 Type +02 byte Number +03 byte Importance +04 struct _LIST_ENTRY DpcListEntry +04 struct _LIST_ENTRY *Flink +08 struct _LIST_ENTRY *Blink +0c function *DeferredRoutine +10 void *DeferredContext +14 void *SystemArgument1 +18 void *SystemArgument2 +1c uint32 *Lock $ DPC 的源头 所有的 DPC 都是在 IRQL >= DISPATCH_LEVEL 的代码中产生的。 也就是只有 IRQL 大于等于 DISPATCH_LEVEL 的代码使用 DPC。 DPC 都是在硬件中断服务例程(ISR)中,由硬件中断服务例程根据自己的需要,链入到 DPC 队列中的。 中断服务例程中调用 KeInsertQueueDpc 将 dpc 链入 dpc 队列,或者,中断服务例程直接操作 dpc 链表,将 dpc 链入。 KeInsertQueueDpc 除了将 dpc 链入链之外,还会调用 KiRequestSoftwareInterrupt(DISPATCH_LEVEL),如果调用是的 IRQL 高于 DISPATCH_LEVEL,会使得 dpc pending,等到 irql 降下来的时候得到执行。 如果是自己直接操作链来将dpc链入的话,也需要自己调用类似 KiRequestSoftwareInterrupt(DISPATCH_LEVEL) 的函数。 $ DPC 的执行 在硬件中断处理的最后,会调用 HalEndSystemInterrupt。 HalEndSystemInterrupt 中,会将 IRQL 降低,然后检查是否有 DPC pending,有的话,会调用 KiDispatchInterrupt 处理 dpc。 KiDispatchInterrupt 中调用 KiRetireDpcList 处理 dpc。 也就是说,当在硬件中断处理中加入一个 dpc,那么当这个硬件中断处理结束的时候,就会调用这个被加入的 DPC。 a:所有处理都放在isr中 b:处理分两部分,必须要做的放在isr中,剩下的放在dpc中,isr中使用dpc a的处理代码一直执行下来,只可能被irql比它高的硬件中断中断。 b的isr一直执行下来,紧接着执行dpc。isr部分只能被irql比它高的硬件中断中断。dpc部分可被任何硬件中断中断。 $ DPC 不可能受到线程切换的影响 会不会 DPC 中的代码执行到一半,发生线程切换,或者线程抢占,CPU 转去执行什么线程? 答案是绝对不会。 这是由于负责线程切换,抢占的代码就是运行在 IRQL DISPATCH_LEVEL,而 IRQL 小于等于当前 IRQL 的中断不能发生。 所以运行 dpc 时,irql 为 DISPATCH_LEVEL,根本就不会发生线程切换,线程抢占之类的事情。 当然中断中,就更不会了。 $ KiDispatchInterrupt DISPATCH_LEVEL 上执行的代码有两大种, 一种是各种 isr 加的 dpc,处理一个 dpc,也就是调用这个 dpc 中的 DeferredRoutine。 一种是关于线程调度的。 KiDispatchInterrupt 是和 dpc 相关的重要函数。 KiDispatchInterrupt 主要做以下工作: { 从 pcr 中得到 dpc 链表头。 如果链表不空的话,调用 KiRetireDpcList 处理 dpc。也就是一个一个的调用dpc里的 DeferredRoutine。 检查 pcr 中的 QuantumEnd,看是否为0。不为0进行 QuantumEnd 的处理。 检查 pcr 中的 NextThread,看是否为0。不为0进行 更换新的线程的 处理。 } 由于 KiDispatchInterrupt 会在各种硬件中断处理的结束有可能得到调用,当硬件中断处理过程中使用dpc的情况下就会在中断处理结束的时候被调用。 如果有任何代码使用 DISPATCH_LEVEL RequestSoftwareInterrupt 的话,KiDispatchInterrupt 也可能被立即执行。 QuantumEnd 不为0的情况,目前只有一种情况引起,就是时钟中断处理中,将当前线程的 Quantum 减少后,发现当前线程 Quantum 用完,就会设置 QuantumEnd,并在 时钟中断 处理结束的时候,引起 KiDispatchInterrupt 执行。 NextThread 不为0的情况,是哪些情况下引起的,还待研究。 |
|
|
沙发#
发布于:2007-01-10 09:57
乱转酒爷的东西,当心他劈了你
![]() |
|
|