本文出自悠然品鉴转载请注明出处:http://www.youranshare.com/codeorg/sid/130.html
在驱动程序编程中会经常使用到定时器这个东东,定时器可以应用到很多地方,比如你要进行一个轮查询,那就需要每隔一段时间向设备发送一次请求;这里小悠简单的介绍一下最基本的I/O定时器的使用方法以及注意事项。
I/O定时器是DDK提供的一种定时器,这种定时器的间隔只能是1S,开启后会每隔1S执行一次对应的例程,我们可以在定时器例程中做下处理,让他成为每隔nS执行一次我们想要的操作,比如我们需要2S执行一次,我们就是用一个变量记录定时器执行的次数,没执行一次,我们就将计数器减少1S,当结果为0的时候就执行我们的事件处理就好了。
在使用I/O定时器的时候需要初始化,要不会无情的蓝屏的…,初始化使用函数:
NTSTATUS IoInitializeTimer( __in PDEVICE_OBJECT DeviceObject, __in PIO_TIMER_ROUTINE TimerRoutine, __in_opt __drv_aliasesMem PVOID Context );
参数一:这个是与定时器相关的设备对象指针
参数二:定时器执行需要的例程
参数三:向定时器传递的参数指针
返回值:返回初始化的状态,成功或者失败
定时器执行的例程的形式如下:
void OnTimer(IN PDEVICE_OBJECT pDev,IN PVOID Context) { ... }
另外还需要值得说的是,I/O定时器运行在IRQL(中断请求级)的DISPATCH_LEVEL层的,也就是说如果发生了缺页中断,是无法打断打断定时器,然后去做缺页处理的,这样如果产生了缺页中断就会被直接忽略掉,会照成严重的错误。所以你的定时器不能使用分页的机制,应当使用#pragma LOCKEDCODE非分页内存。
同时I/O定时器这货是运行在任意线程的,并不一定是IRP发起的线程中,因此不能使用应用程序的内存地址哦,下面是调试的结果:
先说一下基本的流程,后面我将附加上示例代码下载:
① 在DriverEntry入口中初始化定时器
② 在IRP_MJ_DEVICE_CONTROL 控制例程中开启你的定时器
③ 执行定时器,通过判断当前过了多少个1S来判断是否需要执行你的事件处理。
④ 在IRP_MJ_DEVICE_CONTROL 控制例程关闭你的定时器
另外在定时器中需要用互斥锁,要防止在操作的时候别的线程修改我们的计数器
LONG InterlockedDecrement( LPLONG lpAddend // variable address );
属于互锁函数,用在同一进程内,需要对共享的一个变量,做减法的时候,防止其他线程访问这个变量,是实现线程同步的一种办法(互锁函数)
LONG __cdecl _InterlockedCompareExchange ( __inout __drv_interlocked LONG volatile *Destination, __in LONG ExChange, __in LONG Comperand );
是把目标操作数(第1参数所指向的内存中的数)与一个值(第3参数)比较,如果相等,则用另一个值(第2参数)与目标操作数(第1参数所指向的内存中的数)交换;InterlockedExchange是不比较直接交换。整个操作过程是锁定内存的,其它处理器不会同时访问内存,从而实现多处理器环境下的线程互斥。
附上定时器处理例程的函数:
#pragma LOCKEDCODE void OnTimer(IN PDEVICE_OBJECT pDev,IN PVOID Context) { KdPrint(("进入定时器...n")); //1S会执行一次,要判断 PDEVICE_EXT pExt = (PDEVICE_EXT)pDev->DeviceExtension; //使用同步,保证 元 同步 InterlockedDecrement(&pExt->nTimer); LONG result = InterlockedCompareExchange(&pExt->nTimer,2,0); if (result==0) { KIRQL lev = KeGetCurrentIrql(); KdPrint(("定时器执行一次...%dn",(ULONG)lev)); } //显示一下当前的线程 信息 PEPROCESS pEprocess = IoGetCurrentProcess(); PTSTR szName = (PTSTR)pEprocess->ImageFileName; KdPrint(("当前的线程所属进程:%s n",szName)); }
小悠的示例工程中忘记说明#pragma LOCKEDCODE的定义了,请自行添加上#define定义
#define PAGEDCODE code_seg("PAGE") #define LOCKEDCODE code_seg() #define INITCODE code_seg("INIT") #define PAGEDDATA data_seg("PAGE") #define LOCKEDDATA data_seg() #define INITDATA data_seg("INIT")
示例工程下载地址:
解压密码 yscode
百度网盘下载地址:http://pan.baidu.com/s/1sjBEsf7