Windows内核源码详尽分析-DPC篇

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

DPC

DPC不同APC,DPC的全名是‘延迟过程调用’。

DPC最初作用是设计为中断服务程序的一部分。因为每次触发中断,都会关中断,然后执行中断服务例程。由于关中断了,所以中断服务例程必须短小精悍,不能消耗过多时间,否则会导致系统丢失大量其他中断。但是有的中断,其中断服务例程要做的事情本来就很多,那怎么办?于是,可以在中断服务例程中先执行最紧迫的那部分工作,然后把剩余的相对来说不那么重要的工作移入到DPC函数中去执行。因此,DPC又叫ISR的后半部。(比如每次时钟中断后,其isr会扫描系统中的所有定时器是否到点,若到点就调用各定时器的函数。但是这个扫描过程比较耗时,因此,时钟中断的isr会将扫描工作纳入dpc中进行)

每当触发一个中断时,中断服务例程可以在当前cpu中插入一个DPC,当执行完isr,退出isr后, cpu 就会扫描它的dpc队列,依次执行里面的每个dpc,当执行完dpc后,才又回到当前线程的中断处继续执行。

typedef struct _KDPC {

UCHAR Type; //DPC类型(分为普通DPC和线程化DPC)

UCHAR Importance;//该DPC的重要性,将决定挂在队列头还是尾

volatile USHORT Number;//第5位为0就表示当前cpu,否则,最低4位表示目标cpu号

LIST_ENTRY DpcListEntry;//用来挂入dpc链表

PKDEFERRED_ROUTINE DeferredRoutine;//dpc函数

PVOID DeferredContext;//dpc函数的参数

PVOID SystemArgument1;//挂入时的系统附加参数1

PVOID SystemArgument2;//挂入时的系统附加参数2

volatile PVOID DpcData;//所在的dpc队列

} KDPC, *PKDPC, *RESTRICTED_POINTER PRKDPC;

VOID

KeInitializeDpc(IN PKDPC Dpc,//DPC对象(DPC也是一种内核对象)

IN PKDEFERRED_ROUTINE DeferredRoutine, //DPC函数

IN PVOID DeferredContext)//DPC函数的参数

{

KiInitializeDpc(Dpc, DeferredRoutine, DeferredContext, DpcObject);

}

VOID

KiInitializeDpc(IN PKDPC Dpc,

IN PKDEFERRED_ROUTINE DeferredRoutine,

IN PVOID DeferredContext,

IN KOBJECTS Type)

{

Dpc->Type = Type;

Dpc->Number = 0;//初始的目标cpu为当前cpu

Dpc->Importance= MediumImportance;

Dpc->DeferredRoutine = DeferredRoutine;

Dpc->DeferredContext = DeferredContext;

Dpc->DpcData = NULL;//表示该DPC尚未挂入任何DPC队列

}

DPC初始化构造时的目标cpu默认都是当前cpu。

BOOLEAN KeInsertQueueDpc(IN PKDPC Dpc,IN PVOID SystemArgument1,IN PVOID SystemArgument2) {

KIRQL OldIrql;

PKPRCB Prcb, CurrentPrcb;

ULONG Cpu;

PKDPC_DATA DpcData;

BOOLEAN DpcConfigured = FALSE, DpcInserted = FALSE;

KeRaiseIrql(HIGH_LEVEL, &OldIrql);//插入过程的中断级是最高的,这个过程不会被打断。

CurrentPrcb = KeGetCurrentPrcb();

//检查目标cpu号的第5位为1(32 = 00100000),就表示其它cpu,低4位表示cpu号

if (Dpc->Number >= 32)

{

Cpu = Dpc->Number - 32;

Prcb = KiProcessorBlock[Cpu];

}

Else //否则,表示当前cpu

{

Cpu = Prcb->Number;

Prcb = CurrentPrcb;//目标cpu就是当前cpu

}

//if 要插入的是一个线程化dpc并且那个cpu启用了线程化dpc机制

if ((Dpc->Type == ThreadedDpcObject) && (Prcb->ThreadDpcEnable))

DpcData = &Prcb->DpcData[DPC_THREADED]; //目标cpu的线程化dpc队列else

DpcData = &Prcb->DpcData[DPC_NORMAL];//目标cpu的普通dpc队列

KiAcquireSpinLock(&DpcData->DpcLock);

//if 尚未挂入任何dpc队列

if (!InterlockedCompareExchangePointer(&Dpc->DpcData, DpcData, NULL))

{

Dpc->SystemArgument1 = SystemArgument1;

Dpc->SystemArgument2 = SystemArgument2;

DpcData->DpcQueueDepth++;

DpcData->DpcCount++;

DpcConfigured = TRUE;

//不管如何,先把dpc挂到目标cpu的dpc队列中

if (Dpc->Importance == HighImportance)

InsertHeadList(&DpcData->DpcListHead, &Dpc->DpcListEntry);

else

InsertTailList(&DpcData->DpcListHead, &Dpc->DpcListEntry);

if (&Prcb->DpcData[DPC_THREADED] == DpcData)

{

相关文档
最新文档