对于dpc的初步理解

       DPC的有效定义:它们是驱动程序可以通过该方法再IRQL DISPATCH_LEVEL上请求回调到任意线程上下文的方法。DPC对象本身仅是具有LIST_ENTRY,回调指针,回调的某些上下问以及一些控制数据。
       DPC实际上要排队到特定的处理器,这是通过将DPC对象链接到位于目标处理器控制块(PRCB)中的DPC列表来完成的。对于O/S而言,确定DPC对象排队的处理器。
       默认情况下,DPC排队到调用KeInsertQueueDpc的处理器(当前处理器)。
       驱动程序可以使用功能KeSetTargetProcessorDpc指示给定处理器用于特定DPC对象。

       一旦DPC对象已排队到处理器,则随后将同一DPC对象排队的尝试将被忽略,直到DPC对象被出队(windows执行其回调)。这就是KeInsertQueueDpc的BOOLEAN返回值所指示的:
TRUE表示Windows将DPC排队到目标处理器,而FALSE表示DPC对象已经排队到某个处理器。

       因为DPC数据结构仅具有单个LIST_ENTRY字段,因此一次只能出现在单个队列中。

将DPC对象插入到目标处理器的DOC列表的开头还是结尾是DPC优先级功能的一方面。
可以使用功能KeSetImportanceDpc设置给定DPC对象的重要性。通过此DDI,可以指示DPC对象的重要性为低,中或高。
在高版本中,可以将重要性设置为"中高"。低,中和中高重要性DPC放置在DPC队列的末端,而高重要性DPC放置在队列的前面。

DISPATCH_LEVEL软件中断

       将DPC排队到目标处理器后,通常会在处理器上生成DISPATCH_LEVEL软件中断。在DPC对象排队时是否请求DISPATCH_LEVEL软件中断的选择主要基于:
       DPC的重要性,DPC的目标处理器,DPC列表在目标处理器上的深度以及 目标处理器上DPC列表的"排水率"。

       如果DPC对象的目标处理器是当前处理器,并且DPC对象除了低优先级以外还具有其他重要性,则请求DISPATCH_LEVEL软件中断。
       对于低重要性DPC,仅当操作系统认为处理器没有足够快地服务DPC时才请求软件中断,这是因为DPC队列变大或没有以足够快的速率耗尽。
       如果其中任何一个为真,则即使DPC的重要性不高,也会请求中断。

       如果DPC对象的目标处理器不是当前处理器,则决策过程将有所不同。因为在另一个处理器上请求中断将设计昂贵的处理器间中断(IPI),所以请求该中断的情况收到限制。
       在vista之前,仅当DPC的重要性很高或目标处理器上的DPC队列太深时才发出IPI请求。
       Vista将中等重要性的DPC添加到检查中,并通过要求目标处理器处于空闲状态以请求DISPATCH_LEVEL软件中断,进一步减少了IPI的数量。

       在调用KeInsertQueueDpc时,系统可能处于两种情况:第一种情况将以IRQL<DISPATCH_LEVEL运行,在这种情况下,将立即发送DISPATCH_LEVEL中断。
       第二种情况是当前处理器的IRQL>=DISPATCH_LEVEL,在这种情况下,中断将一直待处理,直到IRQL即将返回到IRQL<DISPATCH_LEVEL。

       在耗尽DPC列表之前,windows希望确保它具有一个新的执行堆栈,以便DPC例程可以运行。
       在当前堆栈没有太多剩余空间的情况下,这可能会减少堆栈溢出的事件。
       每个PRCB还包含一个指向先前分配的DPC堆栈的指针,windows会在调用任何DPC之前切换到该堆栈。

       从空闲线程发送,要么将出现另一个DPC,该请求将请求DISPATCH_LEVEL中断,并且DPC将被随后的流水队列拾起或者将出现空闲循环,并注意到DPC队列不为空。

       空闲循环的一部分工作是检查DPC队列并确定其是否为空。
       如果发现队列不为空,它将开始通过使条目出队并调用回调来耗尽队列。

       在这种情况下,堆栈不会切换,因此DPC实际上在空闲线程的堆栈上执行。
       因为空闲循环本身使用的线程栈很少,所以在这种情况下,进行交换栈的工作没有太多用处。

扫描二维码关注公众号,回复: 12901443 查看本文章

猜你喜欢

转载自blog.csdn.net/qq_31932681/article/details/107500725
今日推荐