向Windows内核驱动传递用户层定义的事件Event,并响应内核层的通知

完整的程序在下载:http://download.csdn.net/detail/dijkstar/7913249

用户层创建的事件Event是一个Handle句柄,和内核中的创建的内核模式下的KEVENT是一个东西。因此,在应用层创建的事件,可以在内核层获得并使用。这一部分的原理,见张帆编著的《Windows驱动技术详解》章节8.5.4,P237页;

程序是来自于《Windows驱动技术详解》章节8.5.4(驱动程序和应用程序交互事件对象)和章节10.2.1(DPC定时器)。

首先,在应用层创建一个等待事件Event,创建监控这个等待事件的线程,并把等待事件Event传递给内核:

  1. //

  2.  

    // 1. 创建用户层的等待事件,传入内核

  3.  

    // 2. 创建线程,用于监测内核事件的到来

  4.  

    //

  5.  

    HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

  6.  

    HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, Thread1, &hEvent, 0, NULL);

  7.  

  8.  

    //先将用户层的等待Event传入内核

  9.  

    DeviceIoControl(hDevice, IOCTL_SET_EVENT, &hEvent, sizeof(hEvent), NULL, 0, &dwOutput, NULL);

监控线程的内容:(里面用了查询指令周期数,可以测试每次等待WaitFor××的时间)

  1. UINT WINAPI Thread1(LPVOID para)

  2.  

    {

  3.  

    HANDLE *phEvent = (HANDLE *)para;

  4.  

    while(1)

  5.  

    {

  6.  

    //获得初始值

  7.  

    QueryPerformanceCounter(&litmp);

  8.  

    qt1=litmp.QuadPart;

  9.  

  10.  

    //等待

  11.  

    WaitForSingleObject(*phEvent, INFINITE);

  12.  

  13.  

  14.  

    //获得终止值

  15.  

    QueryPerformanceCounter(&litmp);

  16.  

    qt2=litmp.QuadPart;

  17.  

    //获得对应的时间值,转到毫秒单位上

  18.  

    dfm=(double)(qt2-qt1);

  19.  

    dft=dfm/dff;

  20.  

  21.  

  22.  

    printf("本次等待用时: %.3f 毫秒\n", dft*1000.0);

  23.  

    }

  24.  

    }

用户层还通知驱动内核启动一个DPC定时器,用于每次来触发应用层的等待事件Event:

  1. DWORD dwMircoSeconds = 1000 * 50; //单位微秒

  2.  

    DeviceIoControl(hDevice, IOCTL_START_TIMER, &dwMircoSeconds, sizeof(DWORD), NULL, 0, &dwOutput, NULL);

在驱动程序中,首先取出来应用层传递进来的事件,并把它转化为内核对象:

  1. case IOCTL_SET_EVENT:

  2.  

    {

  3.  

    //把传递进来的用户层等待事件取出来

  4.  

    HANDLE hUserEvent = *(HANDLE *)pIrp->AssociatedIrp.SystemBuffer;

  5.  

  6.  

    //将用户层事件转化为内核等待对象

  7.  

    status = ObReferenceObjectByHandle(hUserEvent, EVENT_MODIFY_STATE,

  8.  

    *ExEventObjectType, KernelMode, (PVOID*)&pDevExt->pEvent, NULL);

  9.  

  10.  

    KdPrint(("status = %d\n", status));//status应该为0才对

  11.  

  12.  

    ObDereferenceObject(pDevExt->pEvent);

  13.  

    break;

  14.  

    }

在内核的每次定时器到来时,激活等待事件,等于触发激活应用层的WaitFor××函数向下继续执行:

  1. #pragma LOCKEDCODE

  2.  

    VOID PollingTimerDpc( IN PKDPC pDpc,

  3.  

    IN PVOID pContext,

  4.  

    IN PVOID SysArg1,

  5.  

    IN PVOID SysArg2 )

  6.  

    {

  7.  

    PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pContext;

  8.  

    PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;

  9.  

    KeSetTimer(

  10.  

    &pdx->pollingTimer,

  11.  

    pdx->pollingInterval,

  12.  

    &pdx->pollingDPC );

  13.  

    KdPrint(("PollingTimerDpc\n"));

  14.  

  15.  

    //定时器到来,通知用户层

  16.  

    if(pdx->pEvent)

  17.  

    KeSetEvent(pdx->pEvent, IO_NO_INCREMENT, FALSE);

  18.  

  19.  

  20.  

    /*

  21.  

    //检验是运行在任意线程上下文

  22.  

    PEPROCESS pEProcess = IoGetCurrentProcess();

  23.  

    PTSTR ProcessName = (PTSTR)((ULONG)pEProcess + 0x174);

  24.  

    KdPrint(("%s\n",ProcessName));

  25.  

    */

  26.  

    }

程序中其他部分见源码解释,这个程序还有两个问题,一是应用层必须正常退出,否则驱动内核层因不能正常关闭DPC定时器,而继续执行已经找不到的等待事件,引起蓝屏崩溃;二是虽然在内核里,DPC定时器的触发精度为1个100ns级别,但当触发周期设置为20ms以下时,在应用层监控WaitFor,都是十几个毫秒的分辨精度,再向下设置已经没有意义。

jpg 改 rar 

原文地址:https://www.cnblogs.com/kuangke/p/9397830.html

时间: 2024-10-03 20:45:56

向Windows内核驱动传递用户层定义的事件Event,并响应内核层的通知的相关文章

Linux内核工程导论——用户空间设备管理

用户空间设备管理 用户空间所能见到的所有设备都放在/dev目录下(当然,只是一个目录,是可以变化的),文件系统所在的分区被当成一个单独的设备也放在该目录下.以前的2.4版本的曾经出现过devfs,这个思路非常好,在内核态实现对磁盘设备的动态管理.可以做到当用户访问一个设备的设备的时候,devfs驱动才会去加载该设备的驱动.甚至每个节点的设备号都是动态获得的.但是该机制的作者不再维护他的代码,linux成员经过讨论,使用用户态的udev代替内核态的devfs,所以现在的devfs已经废弃了.用户态

理解Windows内核模式与用户模式

 1.基础 运行 Windows 的计算机中的处理器有两个不同模式:"用户模式"和"内核模式".根据处理器上运行的代码的类型,处理器在两个模式之间切换.应用程序在用户模式下运行,核心操作系统组件在内核模式下运行.多个驱动程序在内核模式下运行,但某些驱动程序在用户模式下运行. 当启动用户模式的应用程序时,Windows 会为该应用程序创建"进程".进程为应用程序提供专用的"虚拟地址空间"和专用的"句柄表格"

windows内核驱动中的链表结构

windows内核驱动中的链表结构与数据结构中的链表结构在构造上有很大不同,以循环双链表为例 数据结构中的链表结构: 数据就像集装箱,可以直接放置在火车上,而节点就像每节之间的挂接装置. 内核驱动中的链表结构: 数据就像车厢,自带挂接装置(节点) 1.链表结构体不同 数据结构中的链表结构,包含有节点和数据, struct DataList{ DataType data; struct DataList* next; struct DataList* prev; }; 驱动中的链表结构,仅包含有节

内核空间与用户空间的通信方式

内核空间与用户空间的通信方式 下面总结了7种方式,主要对以前不是很熟悉的方式做了编程实现,以便加深印象. 1.使用API:这是最常使用的一种方式了 A.get_user(x,ptr):在内核中被调用,获取用户空间指定地址的数值并保存到内核变量x中. B.put_user(x,ptr):在内核中被调用,将内核空间的变量x的数值保存到到用户空间指定地址处. C.Copy_from_user()/copy_to_user():主要应用于设备驱动读写函数中,通过系统调用触发. 2.使用proc文件系统:

linux内核空间与用户空间信息交互方法

linux内核空间与用户空间信息交互方法 本文作者: 康华:计算机硕士,主要从事Linux操作系统内核.Linux技术标准.计算机安全.软件测试等领域的研究与开发工作,现就职于信息产业部软件与集成电路促进中心所属的MII-HP Linux软件实验室.如果需要可以联系通过[email protected]联系他. 摘要:在进行设备驱动程序,内核功能模块等系统级开发时,通常需要在内核和用户程序之间交换信息.Linux提供了多种方法可以用来完成这些任务.本文总结了各种常用的信息交换方法,并用简单的例子

linux内核驱动学习(八)----驱动分类 | 学习方法 | 硬件访问

驱动分类: 对于驱动,我们一般按两种方法进行分类:常规分类法和总线分类法. 按照常规分类法,可以分为以下三类: 1.字符设备: 以字节为最小访问单位的设备.一般通过字符设备文件来访问字符设备驱动程序.字符驱动程序则负责驱动字符设备, ,这样的驱动通常支持open.close.read.write系统调用,应用程序可以通过设备文件(比如/dev/ttySAC0等)来访问字符设备(串口).例如:串口\led\按键 2.块设备: 以块(一般512字节)为最 小传输单位的设备.大多数UNIX系统中,块设

AndroidM 内核空间到用户空间接口类型

Android系统中, 驱动程序因商业需求分为运行在用户空间的hardware层以及运行在内核空间的驱动程序, 大多情况下内核驱动都需要提供用户空间访问的接口. Linux内核空间到用户空间的接口有主要有以下几种类型1.系统调用    系统调用是指系统实现的所有系统调用所构成的集合,即程序接口.    linux系统调用分为:进程控制,文件系统控制,系统控制,内存管理,网络管理,用户管理,进程管理等类型    linux操作系统中,系统调用的ID通常在arch/{体系结构}/include/as

tiny4412 串口驱动分析七 --- log打印的几个阶段之内核启动阶段(earlyprintk)

作者:彭东林 邮箱:[email protected] 开发板:tiny4412ADK+S700 4GB Flash 主机:Wind7 64位 虚拟机:Vmware+Ubuntu12_04 u-boot:U-Boot 2010.12 Linux内核版本:linux-3.0.31 Android版本:android-4.1.2 下面要分析的是内核Log打印的几个阶段 自解压阶段 内核启动阶段 内核启动完全以后 shell终端下 在这个阶段内核log打印可以调用printk和printascii,同

Linux内核中断引入用户空间(异步通知机制)【转】

转自:http://blog.csdn.net/kingdragonfly120/article/details/10858647 版权声明:本文为博主原创文章,未经博主允许不得转载. 当Linux内核空间发生中断后怎么使用户空间的应用程序运行相应的函数呢,当芯片有数据到来时内核会产生一个中断,但是怎样通知应用程序来取数据,以前这个问题一直困扰我很长时间,后来发现linux中有异步通知机制,在用户程序中用signal注册一个响应SIGIO信号的回调函数,然后在驱动程序中向该进程发出SIGIO信号