驱动层和应用层的通信问题,关于共享内存的改变,如何相互通知,分不够可以再加

lk_517 2006-05-31 05:18:42
驱动层和应用层的通信问题,关于共享内存的改变,如何相互通知,分不够可以再加

问题是这样的:我想在驱动和应用程序间共享一块内存,由驱动将数据写入共享内存中,然后由事件通知应用程序去读内存,对其数据作出判断,并将结果写入这块内存中的第2位,并将第1位置成0表示处理过了。但是驱动总是不能及时读到应用程序做出的改变。

目前我们可以判定应用程序的写入驱动是可以读到的,可是我希望通过应用程序的改变来决定驱动程序中下一步怎么走,这需要很快,最好是立刻读到有改变动作并读取改变值

我曾经试过在应用层中修改后通过deviceiocontrol传到驱动层,驱动层读出变化来,后来证实这条路走不通,具体原因就不说了,但是可以知道的是至少在0.00004秒之内就改变了值

可是如果我在驱动层直接用while来等待,就会造成死机,我不知道是因为应用程序改变太慢造成的还是因为应用层和驱动层同时操作了一块共享内存造成的

于是我改用for语句10000*10000次循环来看看应用程序什么时候改变的值,遗憾的是这么多次读取全部说明了应用程序还没有做出改变,我算了一下,这么多次循环,已经超过0.0004秒了,理论上改变已经进行了

我现在比较迷惑,到底有什么办法能让我在驱动中很快获得应用层改变的动作并马上读取改变后的值?

附上基本代码

驱动程序里:
// 分配与应用程序共享的内存
SystemVirtualAddress = ExAllocatePool(NonPagedPool, 1500);
Mdl = IoAllocateMdl(SystemVirtualAddress, 1500, FALSE, FALSE, NULL);
MmBuildMdlForNonPagedPool(Mdl);


// 将分配的内存映射到用户进程地址空间,并返回地址。
case IO_GET_SHAREMEMORY_ADDR:
try
{
UserVirtualAddress = MmMapLockedPages(Mdl, UserMode);
*((PVOID *)(Irp->AssociatedIrp.SystemBuffer)) = UserVirtualAddress;
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = sizeof(PVOID);
}
except(EXCEPTION_EXECUTE_HANDLER){}
//读取相关代码
if(!KeReadStateEvent(gpEventObject))
{
// 复制数据到共享内存
memset(ip_packet, 0, 100);
memcpy(ip_packet, (char *)ip, sizeof(IP_PACKET));
KeSetEvent(gpEventObject, 0, FALSE);//通知应用程序读内存

DbgPrint("现在的信号态是%ld\n", KeReadStateEvent(gpEventObject));
ip = (p_u_char)SystemVirtualAddress;
//for(i=0;i<1000;i++)
DbgPrint("当前的p_ip->doing为%d %d %d\n", ip[0],ip[1],ip[2]);
}
else{return 1;}
DbgPrint("当前的p_ip->doing为%d %d %d\n", ip[0],ip[1],ip[2]);
DbgPrint("gpEventObject被传进来了 当前的p_ip->doing为%d\n", p_ip->doing);
return 1;



应用程序的相关改变代码:

DeviceIoControl(m_hDevice,
IO_GET_SHAREMEMORY_ADDR,
NULL,
NULL,
szOutputBuffer,
sizeof(szOutputBuffer),
&dwReturn,
NULL
);
psharememory = *((PVOID *)szOutputBuffer);



WaitForSingleObject(pThis->m_hEvent, INFINITE);
p_u_char ip = (p_u_char)pThis->psharememory;
fout<<(int)ip[28]<<' '<<(int)ip[29]<<' '<<(int)ip[30]<<' '<<(int)ip[31]<<endl;
if(ip[28] == 202 && ip[29] == 205 && ip[30] == 3)
{
ip[1]=1;;
}
ip[0]=0;
...全文
1160 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
申宇田 2006-06-02
  • 打赏
  • 举报
回复
嗯,看来你的整体设计上有问题,你不应该在驱动里阻塞等待,这样很容易引起系统死记,这种设计不好,你应该想想有没有更好的架构。我的msn:phshentu at hotmail.com.
lk_517 2006-06-01
  • 打赏
  • 举报
回复


用的kesetevent和waitfoesingleobject
申宇田 2006-06-01
  • 打赏
  • 举报
回复
至于驱动通知应用程序,好像你已经解决了,是吗?
申宇田 2006-06-01
  • 打赏
  • 举报
回复
驱动里面开一个系统线程来专门处理这个变化,内核线程里面类似于这样:
while (1)
{
if ( KeWaitForSingleObject(...) )
{
...
}
else
{
}

if (bKillThread)
{
break;
}
}

具体做法参考Walter Oney的书。这样解决了应用程序通知驱动的问题。

lk_517 2006-06-01
  • 打赏
  • 举报
回复
我试验了一下

发现一个问题

即时你开辟了一个线程,在里面waitfor,但是我自己的处理函数也要用while等待阿,因为要等待新线程里面读取共享内存的值并根据这个值判断是否允许包通过

所以要用while(值)来判断是否继续执行下去,这不同样阻塞等待了么?
lk_517 2006-06-01
  • 打赏
  • 举报
回复
ok,我现在试验一下单独开一个线程wait

请等待

申宇田 2006-06-01
  • 打赏
  • 举报
回复
你这个子处理函数在什么时候调用啊?你不可能随便阻塞等待的,这样非常影响系统稳定性。
lk_517 2006-06-01
  • 打赏
  • 举报
回复
我就是在我自己的一个子处理函数中等待的

只是没有专门开辟一个新的线程

字处理函数流程是

修改共享内存-----kesetevent------kewait-----读取共享内存
申宇田 2006-06-01
  • 打赏
  • 举报
回复
只要理解大概的意思即可。如果event创建的流程没有问题,那么重启的原因就在于处理KeWaitForSingleObject()的地方不对。如果你不在内核线程里面等待事件置位,那你是在什么地方等待?
lk_517 2006-06-01
  • 打赏
  • 举报
回复
我们是应用层CreateFile,CreateEvent,然后通过DeviceIoControl把句柄传输进去
驱动接收句柄后用ObReferenceObjectByHandle绑定

这个流程应该是没有问题的,虽然没有用IoCreateSynchronizationEvent

注意点中,第三点不清楚什么意思,估计没有问题

第五点动对读请求应立即返回,立即返回是什么意思?

第六点主要是效率丢包的问题,现在暂时不考虑
申宇田 2006-06-01
  • 打赏
  • 举报
回复
你自己的处理子函数并不能保证时刻在排队等待调度,所以必须另外开一个内核线程才能时刻在排队等待,一旦在event被置位的时候,才能满足你的时间要求。

另外,转一下白云里的文章:
Q:
请问有什么方法实现驱动程序主动和应用程序进行实时通讯,而不用应用程序采用定时
查询的方法?
比如驱动有一事件发生需要立即通知应用程序,或驱动程序需要向应用程序读取一些内
容.

A:
有一个很容易的方式,在驱动程序和应用程序之间用一个事件。
在应用程序CreateFile的时候,驱动程序IoCreateSynchronizationEvent一个有名的事
件,然后应用程序CreateEvent/OpenEvent此有名事件即可。

注意点:
1,不要在驱动初始化的时候创建事件,此时大多不能成功创建;
2,让驱动先创建,那么此后应用程序打开时,只能读(Waitxxxx),不能写(SetEvent/
ResetEvent)。反之,如果应用程序先创建,则应用程序和驱动程序都有读写权限;
3,用名字比较理想,注意驱动中名字在\BaseNamedObjects\下,例如应用程序用“xxx
Event”,那么驱动中就是“\BaseNamedObjects\xxxEvent”;
4,用HANDLE的方式也可以,但是在WIN98下是否可行,未知。
5,此后,驱动对读请求应立即返回,否则就返回失败。不然将失去用事件通知的意义(
不再等待读完成,而是有需要(通知事件)时才会读);
6,应用程序发现有事件,应该在一个循环中读取,直到读取失败,表明没有数据可读;
否则会漏掉后续数据,而没有及时读取;
lk_517 2006-06-01
  • 打赏
  • 举报
回复
白云黄鹤bbs站里面的精华贴,你是说得胡老大的吧?

说实话,由于是赶鸭子上架,我无奈之下花两个通宵把驱动开发网以及白云相关的帖子全部看了一遍

所有的利用这种共享内存通信的方法,都是从驱动中传到应用程序中,都没有从应用程序修改之后再传回去的解释

我上面说了,头一步已经完成了,没有问题

KeWaitForSingleObject()是在我自己的一个处理子函数里面加的。你的意思是我可以专门开一个线程,在那里面等待?
lk_517 2006-06-01
  • 打赏
  • 举报
回复
补充一点,是打开应用程序就重新启动

不加kewaitforsingleobject就不会重新启动

所以我们估计是这里的问题
申宇田 2006-06-01
  • 打赏
  • 举报
回复
我想问题在于你定义的两个event,我记得在白云黄鹤bbs站里面的驱动编程板块的精华区有介绍应用程序和驱动通信的问题,你可以看看,会有启发的。
你说你在驱动里加了KeWaitForSingleObject()就重启,你是在驱动什么例程里面加的?我创建一个内核线程,然后这个内核线程专门用来处理这个event,应该不会有问题。
lk_517 2006-06-01
  • 打赏
  • 举报
回复
no,之前我们没有单独开任何内核线程

我们的整体设计是这样的

内核中定义两个事件event1和event2
应用层中创建两个事件对象

然后把这两个事件句柄和事件指针分别邦定

接下来

首先是应用层用waitforsingleobject(EVENT1)等待(这些符号表示含义,不是说就是这么用的,大家能看懂就行)

然后内核态接收到数据包,就kesetevent(event1)

然后应用层从waitforsingleobjec中跳出来,开始读取共享内存的数据,并判断,并根据判断往共享内存写入相应的东西

请注意,到这里都是正常的。

然后接下来,我们是在应用层setevent(event2)

此时驱动层正在执行kewaitforsingleobjec(EVENT2),按照我们的理解,一旦应用层set,驱动就能够从kewaitforsingleobjec中跳出来,然后读取相关共享内存地址,根据相应的内容进行下一步的动作

我认为理论上这样是可以的。可是我们一旦加入kewaitforsingleobjec,就会造成重新启动。

不知道我是否说明白了。共享内存是绝对没有问题的。

我刚接触驱动一个星期,现在在做ndis中间层的东西,很多纯属赶鸭子上架,说得白痴的地方还请海涵

希望上面这位朋友和其他朋友都能看看,只要解决,分绝对可以再加。
申宇田 2006-06-01
  • 打赏
  • 举报
回复
我觉得你有必要考虑你的整体设计,是否可以改进...
申宇田 2006-06-01
  • 打赏
  • 举报
回复
应该用Executive.
我不是很明白你的意思,你是说你们驱动里已经开了一个内核线程,如果是这样的话,再开一个线程就不太好了,复杂度大大增加。我一般不会在驱动里面开两个内核线程的。
lk_517 2006-06-01
  • 打赏
  • 举报
回复
KeWaitForSingleObject

我们之前也实验过,一加上就重新启动,实在头疼。不过我们没有加一个线程,而是在原来的线程中处理的

请问这位朋友, KeWaitForSingleObject的参数第二个,Executive还是UserRequest?根据msdn中所说,unless it is doing work on behalf of a user and is running in the context of a user thread, in which case it should set this value to UserRequest.

我感觉我们应该用UserReques

另外,是不是必须要重新开一个线程?

21,597

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 驱动开发/核心开发
社区管理员
  • 驱动开发/核心开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧