应用层 和 内核通讯
2013-04-08 16:41
197 查看
fd=open(DEVICE,O_RDWR|O_NONBLOCK|O_SYNC|O_EXCL);
for(;;){
FD_ZERO(&set);
FD_SET(fd,&set);
n=select(wd_fd+1,&set,NULL,NULL,NULL);
if(FD_ISSET(wd_fd,&set)){
dosomething
}
}
=========================================================================
staticDECLARE_WAIT_QUEUE_HEAD(read_wq);
---------------
staticconststructfile_operationsfops={
.poll=what_poll,
};
/*Poll*/
unsignedintwhat_poll(structfile*file,poll_table*wait)
{
unsignedintmask=0;
poll_wait(file,&read_wq,wait);(1)阻塞在此
if(warning_flag==1)
mask|=POLLIN|POLLRDNORM;
returnmask;
}
---------------
tasklet_init(interrupt_tasklet,interrupt_tasklet_body,(unsignedlong)0);
staticirqreturn_tinterrupt()
{
tasklet_schedule(&interrupt_tasklet);
}
voidinterrupt_tasklet_body(unsignedlongdata)
{
wake_up_interruptible(&read_wq);
}
==========================================================================
/article/5205727.html
“小王,来聊聊,今天面试的情况怎么样,应该挺顺利的吧..”看着小王平淡的眉头,我问道。
“唉,别提了,你说,我的运气咋这差呢,面试前你不是给我讲了有关阻塞的问题吗,我见了面试官是吧,还跟他好好的用今天排队的例子说了有关阻塞的问题,但是..”小王哀声叹气地说到。
“别但是了,怎么啦..”
“可问题是面试官压根就没打算问我有关阻塞的问题及解决方案,但是问我说:这样吧,你给我说说在Linux设备驱动中有关非阻塞的方法,我这一听,傻眼了不是,你刚好给我讲的是阻塞的东西,可人家偏要问我有关非阻塞的问题,我..”小王欲哭无泪啊..
“怎么这样呢,算了,机会多的是,亡羊补牢,我现在就给你说说有关非阻塞的问题----Linux设备驱动程序之阻塞非阻塞IO----轮询操作”。
通过上一节,我们都明白了,有关阻塞的相关知识(不知道,那我没辙了,饭送到嘴,你还挑食,难不成我拿把起子把嘴撬开不成,自己看上一篇吧),现在就来聊聊对
立面非阻塞。
使用非阻塞I/O的应用程序通常会使用select()和poll()系统调用查询是否可对设备进行无阻塞的访问,这两个系统调用最终又会引发设备驱动中的poll()函数被执行
,所以我们的问题就集中到了如何编写设备驱动中的poll()函数就可以了。二话不说,先来看看设备驱动中的poll()函数原型:
unsignedint(*poll)(structfile*filp,structpoll_table*wait);
这个函数要进行下面两项工作。首先,对可能引起设备文件状态变化的等待队列调用poll_wait(),将对应的等待队列头添加到poll_table.然后,返回表示是否能对设备进行无阻塞读写访问的掩码。在上面提到了一个poll_wait()函数,它的原型:
voidpoll_wait(structfile*filp,wait_queue_head_t*queue,poll_table*wait);
它的作用就是把当前进程添加到wait参数指定的等待列表(poll_table)中。需要注意的是这个函数是不会引起阻塞的,呵呵,谁给它取得个名字带wait的,给咱们添这么多麻烦。
“等等,你先停停,你是高手,我可是菜鸟呢,你先给我说说poll_table结构吧,心里总是想它是什么..”小王打断我道。
行行,说起这个结构,我也是费了一番周折,它定义在“include/linux/poll.h,line38“,具体如下:
看看,其实没什么吧,不要想的太复杂了
经过以上驱动程序的poll()函数应该返回设备资源的可获取状态,即POLLIN,POLLOUT,POLLPRI,POLLERR,POLLNVAL等宏的位"或"结果.每个宏的含义都表示设备的一种状态,如:
"小王,你明白了没.."看着小王眨巴眨巴的小眼睛,我说。
"呵呵,你干脆给我来个典型模板,行不?"小王苛求道。
行,没问题,你现在特殊时期,我是有求必应。请看下
"小王,这次看明白了吧,要是还看不明白,我就再给你讲讲用户空间的轮询编程,两个结合起来也许好懂点,行不"。我补充道。
在用户程序中,select()和poll()本质上是一样的,不同只是引入的方式不同,前者是在BSDUNIX中引入的,后者是在SystemV中引入的。用的比较广泛的是select
系统调用。原型如下:
intselect(intnumfds,fd_set*readfds,fd_set*writefds,fd_set*exceptionfds,structtimeval*timeout);
其中readfs,writefds,exceptfds分别是select()监视的读,写和异常处理的文件描述符集合,numfds的值是需要检查的号码最高的文件描述符加1,timeout则是一个时间上限值,超过该值后,即使仍没有描述符准备好也会返回。
最后我们利用上面的文件描述符集的相关来写个验证添加了设备轮询的驱动,把上边两块联系起来:
for(;;){
FD_ZERO(&set);
FD_SET(fd,&set);
n=select(wd_fd+1,&set,NULL,NULL,NULL);
if(FD_ISSET(wd_fd,&set)){
dosomething
}
}
=========================================================================
staticDECLARE_WAIT_QUEUE_HEAD(read_wq);
---------------
staticconststructfile_operationsfops={
.poll=what_poll,
};
/*Poll*/
unsignedintwhat_poll(structfile*file,poll_table*wait)
{
unsignedintmask=0;
poll_wait(file,&read_wq,wait);(1)阻塞在此
if(warning_flag==1)
mask|=POLLIN|POLLRDNORM;
returnmask;
}
---------------
tasklet_init(interrupt_tasklet,interrupt_tasklet_body,(unsignedlong)0);
staticirqreturn_tinterrupt()
{
tasklet_schedule(&interrupt_tasklet);
}
voidinterrupt_tasklet_body(unsignedlongdata)
{
wake_up_interruptible(&read_wq);
}
==========================================================================
“小王,来聊聊,今天面试的情况怎么样,应该挺顺利的吧..”看着小王平淡的眉头,我问道。
“唉,别提了,你说,我的运气咋这差呢,面试前你不是给我讲了有关阻塞的问题吗,我见了面试官是吧,还跟他好好的用今天排队的例子说了有关阻塞的问题,但是..”小王哀声叹气地说到。
“别但是了,怎么啦..”
“可问题是面试官压根就没打算问我有关阻塞的问题及解决方案,但是问我说:这样吧,你给我说说在Linux设备驱动中有关非阻塞的方法,我这一听,傻眼了不是,你刚好给我讲的是阻塞的东西,可人家偏要问我有关非阻塞的问题,我..”小王欲哭无泪啊..
“怎么这样呢,算了,机会多的是,亡羊补牢,我现在就给你说说有关非阻塞的问题----Linux设备驱动程序之阻塞非阻塞IO----轮询操作”。
通过上一节,我们都明白了,有关阻塞的相关知识(不知道,那我没辙了,饭送到嘴,你还挑食,难不成我拿把起子把嘴撬开不成,自己看上一篇吧),现在就来聊聊对
立面非阻塞。
使用非阻塞I/O的应用程序通常会使用select()和poll()系统调用查询是否可对设备进行无阻塞的访问,这两个系统调用最终又会引发设备驱动中的poll()函数被执行
,所以我们的问题就集中到了如何编写设备驱动中的poll()函数就可以了。二话不说,先来看看设备驱动中的poll()函数原型:
unsignedint(*poll)(structfile*filp,structpoll_table*wait);
这个函数要进行下面两项工作。首先,对可能引起设备文件状态变化的等待队列调用poll_wait(),将对应的等待队列头添加到poll_table.然后,返回表示是否能对设备进行无阻塞读写访问的掩码。在上面提到了一个poll_wait()函数,它的原型:
voidpoll_wait(structfile*filp,wait_queue_head_t*queue,poll_table*wait);
它的作用就是把当前进程添加到wait参数指定的等待列表(poll_table)中。需要注意的是这个函数是不会引起阻塞的,呵呵,谁给它取得个名字带wait的,给咱们添这么多麻烦。
“等等,你先停停,你是高手,我可是菜鸟呢,你先给我说说poll_table结构吧,心里总是想它是什么..”小王打断我道。
行行,说起这个结构,我也是费了一番周折,它定义在“
typedefstructpoll_table_struct{ poll_queue_procqproc; unsignedlongkey; }poll_table;
看看,其实没什么吧,不要想的太复杂了
经过以上驱动程序的poll()函数应该返回设备资源的可获取状态,即POLLIN,POLLOUT,POLLPRI,POLLERR,POLLNVAL等宏的位"或"结果.每个宏的含义都表示设备的一种状态,如:
常量 | 说明 |
POLLIN | 普通或优先级带数据可读 |
POLLRDNORM | 普通数据可读 |
POLLRDBAND | 优先级带数据可读 |
POLLPRI | 高优先级数据可读 |
POLLOUT | 普通数据可写 |
POLLWRNORM | 普通数据可写 |
POLLWRBAND | 优先级带数据可写 |
POLLERR | 发生错误 |
POLLHUP | 发生挂起 |
POLLNVAL | 描述字不是一个打开的文件 |
"呵呵,你干脆给我来个典型模板,行不?"小王苛求道。
行,没问题,你现在特殊时期,我是有求必应。请看下
staticunsignedintXXX_poll(structfile*filp,poll_table*wait) { unsignedintmask=0; structXXX_dev*dev=filp->private_data;//获得设备结构指针 ... poll_wait(filp,&dev->r_wait,wait);//加读等待对列头 poll_wait(filp,&dev->w_wait,wait);//加写等待队列头 if(...)//可读 { mask|=POLLIN|POLLRDNORM;//标识数据可获得 } if(...)//可写 { mask|=POLLOUT|POLLRDNORM;//标识数据可写入 } .. returnmask; }
"小王,这次看明白了吧,要是还看不明白,我就再给你讲讲用户空间的轮询编程,两个结合起来也许好懂点,行不"。我补充道。
在用户程序中,select()和poll()本质上是一样的,不同只是引入的方式不同,前者是在BSDUNIX中引入的,后者是在SystemV中引入的。用的比较广泛的是select
系统调用。原型如下:
intselect(intnumfds,fd_set*readfds,fd_set*writefds,fd_set*exceptionfds,structtimeval*timeout);
其中readfs,writefds,exceptfds分别是select()监视的读,写和异常处理的文件描述符集合,numfds的值是需要检查的号码最高的文件描述符加1,timeout则是一个时间上限值,超过该值后,即使仍没有描述符准备好也会返回。
structtimeval { inttv_sec;//秒 inttv_usec;//微秒 }
涉及到文件描述符集合的操作主要有以下几种:
1)清除一个文件描述符集FD_ZERO(fd_set*set);
2)将一个文件描述符加入文件描述符集中FD_SET(intfd,fd_set*set);
3)将一个文件描述符从文件描述符集中清除FD_CLR(intfd,fd_set*set);
4)判断文件描述符是否被置位FD_ISSET(intfd,fd_set*set);
最后我们利用上面的文件描述符集的相关来写个验证添加了设备轮询的驱动,把上边两块联系起来:
必要的头文件
#defineFIFO_CLEAR0x1
#defineBUFFER_LEN20
main()
{
intfd,num;
charrd_ch[BUFFER_LEN];
fd_setrfds,wfds;
/*以非阻塞方式打开/dev/polltest设备文件*/
fd=open("/dev/polltest",O_RDONLY|O_NONBLOCK);
if(fd!=-1)
{/*FIFO清0*/
if(ioctl(fd,FIFO_CLEAR,0)<0)
{
printf("ioctlcommandfailed\n");
}
while(1)
{
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_SET(fd,&rfds);
FD_SET(fd,&wfds);
select(fd+1,&rfds,&wfds,NULL,NULL);
/*数据可获得*/
if(FD_ISSET(fd,&rfds))
{
printf("Devicecanbereadnow\n");
}
/*数据可写入*/
if(FD_ISSET(fd,&wfds))
{
printf("Devicecanbewrittennow\n");
}
}
}
else
{
printf("Deviceopenfailurenow\n");
}
}
相关文章推荐
- Visual Studio 2013开发 mini-filter driver step by step 应用层与内核通讯(8)
- 视酷即时通讯系统应用源码 V1.0
- php扩展开发与内核应用
- 解决应用的反调试方案解析(修改IDA调试端口修改内核信息)
- 2.6内核Makefile简单语法与应用
- 2011--通讯应用新趋势
- 创建安全的ASP.NET应用:认证,授权和安全通讯
- 网络多媒体通讯应用解决方案
- 转:应用服务器底层通讯框架学习笔记(stub和skeleton)
- Android应用中通过AIDL机制实现进程间的通讯实例
- 音视频即时通讯的应用趋势
- 多媒体音视频通讯应用解决方案
- 2.6内核Makefile简单语法与应用
- 在网络通讯中应用Protobuf
- linux内核层与应用层通讯方法
- C#使用Xamarin开发可移植移动应用(5.进阶篇显示弹出窗口与通讯中心)附源码
- android内核字符驱动设备实战之----------应用框架层aidl服务编程篇
- linux应用编程--信号通讯(上)
- 总结应用和驱动之间用事件通讯的办法
- 再读内核存储管理(6):高速缓存的应用