天天看点

DPC计时器

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;
}
           
DPC计时器

KeInitializeTimer函数分析

DPC计时器

KeInitializeTimerEx函数分析

如下图,箭头所指,仅仅是填写传入KTIMER对象的字段

DPC计时器

KeInitializeDpc函数分析

DPC计时器

KeInitializeTimer函数分析

DPC计时器

KeSetTimerEx函数分析

DPC计时器
DPC计时器
DPC计时器

32BIT-XP下实验

继续阅读