DPC计时器,是除了IO计时器的另一种内核方式的计时器技术,它能实现比IO计时器(秒级别)更加细微级别的时间间隔,
实现DPC 计时器所需要的函数 KeInitializeTimer,KeInitializeDpc,KeSetTimer
#include <ntddk.h>
KTIMER kTimer = { 0 };
KDPC dpc1 = { 0 };
KDPC dpc2 = { 0 };
VOID DriverUnload(PDRIVER_OBJECT pDriverObj){
return;
}
VOID SetDueTime(ULONG seconds, PLARGE_INTEGER pAccordingLi){
LONG dueTime = -1 * seconds * 1000 * 1000 * 10;
*pAccordingLi = RtlConvertLongToLargeInteger(dueTime);
}
VOID
MyDeferredRoutine(
_In_ struct _KDPC *Dpc,
_In_opt_ PVOID DeferredContext,
_In_opt_ PVOID SystemArgument1,
_In_opt_ PVOID SystemArgument2
){
LARGE_INTEGER li = { 0 };
KdPrint(("this text is from my DeferedRoutine \n"));
SetDueTime(10, &li);
KeSetTimer(&kTimer, li, &dpc2);
return;
}
VOID DPCTimer(){
KeInitializeTimer(&kTimer);
KeInitializeDpc(&dpc1, MyDeferredRoutine, NULL);
KeInitializeDpc(&dpc2, MyDeferredRoutine, NULL);
LARGE_INTEGER li = { 0 };
SetDueTime(3, &li);
KeSetTimer(&kTimer,li, &dpc1);
SetDueTime(10, &li);
KeSetTimer(&kTimer, li, &dpc2);
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegPath){
pDriverObj->DriverUnload = DriverUnload;
DPCTimer();
KdPrint(("Enter DPCTimer ...\n"));
return STATUS_SUCCESS;
}
需要注意的是
1. KTIMER 对象,KDPC对象的生命周期要长,不能是局部变量的生存周期,因为你创建了这些对象时,不光只有你在使用它,系统也需要在未来操作它,故而,若是在函数中 定义 这些对象,存在于未出函数时的栈中,故而,出函数后其位置的数据会变得不可预料,可认为无效,这时候很有可能造成系统崩溃。
2.它是一次性的,故而你需要在DPC回调函数中再一次调用KeSetTimer并设置相应的时间间隔
3.如我在实例中所写,我 原本的意思是初始化2个DPC,然后绑定到同一个KTIMER,在不同的时间间隔触发,一个3秒后,
一个10秒后,可结果只触发了10秒的,可见前面设定的被后面设定的给摸掉了
4.你卸载驱动时,如我的例子这般,系统会崩溃的,为什么,因为你的DPC 被插入到CPU 的DPC队列时,与其绑定的DPC
回调函数是在你的模块中的,而且,KDPC,KTIMER对象也是在这模块中定义的,卸载后果,可想而知
【解决之道:在DriverUnload中加上KeCancelTimer 调用】
之前:
VOID DPCTimer(){
KeInitializeTimer(&kTimer);
KeInitializeDpc(&dpc1, MyDeferredRoutine, NULL);
KeInitializeDpc(&dpc2, MyDeferredRoutine, NULL);
LARGE_INTEGER li = { 0 };
SetDueTime(3, &li);
KeSetTimer(&kTimer,li, &dpc1);
SetDueTime(10, &li);
KeSetTimer(&kTimer, li, &dpc2);
}
之后:
VOID DriverUnload(PDRIVER_OBJECT pDriverObj){
KeCancelTimer(&kTimer);//取消定时器
KeStallExecutionProcessor(5 * 1000 * 1000);//过5秒再退出,留有缓冲余地
return;
}
KeInitializeTimer函数分析
KeInitializeTimerEx函数分析
如下图,箭头所指,仅仅是填写传入KTIMER对象的字段
KeInitializeDpc函数分析
KeInitializeTimer函数分析
KeSetTimerEx函数分析
32BIT-XP下实验