网站已经改版为Wordpress版本,这里是旧版本的快照,请不要在页面中留言.

Windows 内核驱动I/O定时器


本文出自悠然品鉴转载请注明出处: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


  • 标签:
  • I/O定时器
  • 内核定时器
网站已经改版为Wordpress版本,这里是旧版本的快照,请不要在页面中留言.