天天看点

DPC

DeferredProcecure Call,延迟过程调用。是一种执行在任意线程上下文的DISPATCH_LEVEL层的可执行例程。硬件中断使用他们处理来自设备的中断。硬件驱动这样做是因为ISR通常运行在更高IRQLs(高于DISPATCH_LEVEL),如果他们花费太长时间,可能会降低系统的整体性能。因此,ISR典型的队列一个DPC并且马上返回,所以系统可以处理其它的中断请求。软驱动能使用DPCs快速的执行短任务。

DPC的用法很简单:用KeInitializeDpc来初始化一个KDPC对象,然后用KeInsertQueueDpc来队列他们。当处理器的IRQL从高优先级降到DISPATCH_LEVEL时,内核处理所有在队列中的DPCs。

每一个CPU保持着他们自己拥有的DPC队列。这个队列存放在CPU相关的KPRCB结构体中。一个是普通的DPC队列,另外一个是线程DPC队列。

Windows有一些机制来处理DPC。如KiIdleLoop、CPU处于DISPATCH_LEVEL或者在系统初始化的一个线程里(KiStartDpcThread)。

运行在DISPATCH_LEVEL这个IRQL上的线程不能被其它软中断(低于DISPATCH_LEVEL)打断。换句话说,如果在DPC例程里有一个死循环,和它相关的CPU便会一直自旋,使得系统看起来好像被冻结了。在多处理器上,或许不会被冻结但是执行这个DPC的处理器将不能被线程调度器使用。另外,DPC例程中不能等待任何的可分发对象,因为这些分发对象他们自己就运行在DISPATCH_LEVEL,这就是为什么相KeWaitForSingleObject和KeDelayExecuteThread不能在DPC例程中被调用的原因。

Windows有运行在特定时间周期的DPC看门狗例程用来检测DPC,bugchecks是DPC_WATCHDOG_VIOLATION(0x133)。可以用KeQueryDpcWatchdogInformation来查询这个看门狗的周期。

一些RootKits用DPC来同步访问全局链表。例如,可以从ActiveProcessLinks中移除一个实体来隐藏进程。因为这个链表能被任意处理器在任何时候修改,一些RootKits作者使用DPC连同其它同步机制来安全的处理这个问题。

继续阅读