2、应用程序及驱动-poll和select使用说明
1、poll机制(如果中断机制出问题了,poll机制是对中断机制的补充,比如等一个小孩,如果小孩生病了,因此隔一段时间应该去找他)
poll机制就是给定一段时间,在这一段时间内程序处于睡眠状态一直等待某一个资源,它会在两种情况下返回①时间到了②等到了资源。
驱动程序的实现并不复杂,但原理有待分析。
首先要在file_operation里添加.poll
= forth_drv_poll,然后
unsigned int forth_drv_poll(structfile *file,poll_table *wait)
{
unsigned int mask = 0;
poll_wait(file,&button_waitq,wait);//不会立刻休眠,在调用forth_drv_poll的函数中有休眠函数,调用__pollwait将当前进程current加入到等待队列,在中断函数中唤醒该等待队列
if(ev_press)
mask |= POLLIN | POLLRDNORN;
return mask;
}
当应用程序调用poll()时,对应系统调用sys_poll(),然后执行do_sys_poll ()再之后是poll_initwait();在poll_initwait()中注册一下回调函数__pollwait,它就是我们的驱动程序执行poll_wait()时,真正被调用的函。再执行do_poll(),在这个函数里有一个死循环
(sys_poll,通过宏定义SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds,int, timeout_msecs)在select.c中被设置)
do_poll(nfds,head, &table, end_time);
for(;;)
{
for(; pfd != pfd_end; pfd++) //查询多个驱动程序
{
if(do_pollfd(pfd, pt)) -> mask = file->f_op->poll(file, pwait); return mask;//在poll中调用poll_wait,这里就是在调用do_poll之前通过poll_initwait设置为__pollwait
{
//do_pollfd函数相当于调用驱动里面的forth_drv_poll函数,下面另外再进行分析,返回值mask非零,count++,记录等待事件发生的进程数
count++;
pt = NULL;
}
}
if(count || timed_out) //若count不为0(有等待的事件发生了)或者timed_out不为0(有信号发生或超时),则推出休眠
break;
//上述条件不满足下面开始进入休眠,若有等待的事件发生了,超时或收到信号则唤醒
poll_schedule_timeout(wait,TASK_INTERRUPTIBLE, to, slack)
//在hrtimer_init_sleeper函数里面设置了回调函数,会wake_up当前进程
}
然后总结一下整个驱动程序的流程:
先把部分测试程序贴出来:
while(1){
ret = poll(fds,1,5000);
if(ret == 0)
{
printf("time out \n");
}
else
{
read(fd,&key_values,1);
printf("key_value = 0x%x\n",key_values);
}
}
当程序执行poll()的时候,会发生如上所示的过程,当执行到驱动程序的forth_drv_poll()时,会把进程放到button_waitq队列里,但不会立刻休眠,同时mask的值仍然是0.所以count不能执行加1,所以就不满足break的条件,然后执行休眠_timeout的命令。
①如果在time_out的时间结束了还没有发生中断,此时仍处于死循环for中,但时间已经用完,所以当在执行到break的条件是会得到满足,那么就会跳出for死循环,同时poll()函数返回0,再打印出“time
out”;
②如果在在time_out的时间内发生了中断,在中断处理函数中,就会把中断事件标志置1,然后把进程唤醒,同时得到按键的值,中断处理完成后又会回到for死循环中,再次执行驱动程序的forth_drv_poll()函数,此时由于中断事件标志为1,所以会返回一个非零的mask,进而count++,打破break跳出死循环,然后poll()返回一个非零的ret同时在接下来执行read函数,获得键值之后,将键值打印出来。
这就是poll机制的一个例子。
2、select机制
在用户程序中,select()和poll()本质上是一样的, 不同只是引入的方式不同,前者是在BSD UNIX中引入的,后者是在System V中引入的。用的比较广泛的是select
系统调用。原型如下:
int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptionfds, struct timeval *timeout);
其中readfs,writefds,exceptfds分别是select()监视的读,写和异常处理的文件描述符集合,numfds的值是需要检查的号码最高的文件描述符加1,timeout则是一个时间上限值,超过该值后,即使仍没有描述符准备好也会返回。
struct timeval
{
int tv_sec; //秒
int tv_usec; //微秒
}
涉及到文件描述符集合的操作主要有以下几种:
1)清除一个文件描述符集 FD_ZERO(fd_set *set);
2)将一个文件描述符加入文件描述符集中 FD_SET(int fd,fd_set *set);
3)将一个文件描述符从文件描述符集中清除 FD_CLR(int fd,fd_set *set);
4)判断文件描述符是否被置位 FD_ISSET(int fd,fd_set *set);
最后我们利用上面的文件描述符集的相关来写个验证添加了设备轮询的驱动,把上边两块联系起来:
poll_wait必要的头文件
#define FIFO_CLEAR 0x1
#define BUFFER_LEN 20
main()
{
int fd, num;
char rd_ch[BUFFER_LEN];
fd_set rfds,wfds;
fd = open("/dev/polltest", O_RDONLY | O_NONBLOCK);
if (fd != - 1)
{
if (ioctl(fd, FIFO_CLEAR, 0) < 0)
{
printf("ioctl command failed\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("Device can be read now\n");
}
if (FD_ISSET(fd, &wfds))
{
printf("Device can be written now\n");
}
}
}
else
{
printf("Device open failure now\n");
}
}
2、应用程序及驱动-poll和select使用说明的更多相关文章
- Linux 设备驱动--- Poll 方法 --- Select【转】
转自:http://blog.csdn.net/yikai2009/article/details/8653842 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] Sele ...
- (十二)Linux内核驱动之poll和select
使用非阻塞 I/O 的应用程序常常使用 poll, select, 每个允许一个进程来决定它是否可读或者写一个或多个文件而不阻塞. 这些调用也可阻塞进程直到任何一个给定集合的文件描述符可用来读或写. ...
- 3.字符设备驱动------Poll机制
1.poll情景描述 以之前的按键驱动为例进行说明,用阻塞的方式打开按键驱动文件/dev/buttons,应用程序使用read()函数来读取按键的键值. ) { read(fd, &key_v ...
- 四、poll()、select()和epoll()
在用户程序中,poll()和select()系统调用用于对设备进行无阻塞访问.poll()和select()最终会调用设备驱动中的poll()函数,在我所使用的Linux内核中,还有扩展的poll() ...
- poll 和 select 底层的数据结构
poll 和 select 系统调用的真正实现是相当地简单, 对那些感兴趣于它如何工作的人; epoll 更加复杂一点但是建立在同样的机制上. 无论何时用户应用程序调用 poll, select, 或 ...
- linux poll 和 select
使用非阻塞 I/O 的应用程序常常使用 poll, select, 和 epoll 系统调用. poll, select 和 epoll 本质上有相同的功能: 每个允许一个进程来决定它是否可读或者写一 ...
- 【Pyhton Network】使用poll()或select()实现非阻塞传输
通常情况下,socket上的I/O会阻塞.即除非操作结束,否则程序不会照常进行.而以下集中情况需要在非阻塞模式下进行:1. 网络接口在等待数据时是活动的,可以做出相应:2. 在不使用线程或进程的情况下 ...
- poll和select
都允许进程决定是否可以对一个或者多个打开的文件做非阻塞的读取或写入.这些调用也会阻塞进程,直到给定的文件描述符集合中的任何一个可读取或写入.常常用于那些要使用多个输入或输出流而又不会阻塞与其中任意一个 ...
- poll() 与 select()比较
比较poll() 与select() 尽管poll()和select()所做的是相同的工作,不过poll()优于select(),原因: 1.poll()不需要用户计算并传递作为参数的最高编号的 ...
随机推荐
- 关于node的fs路径问题
我在写一个静态网页的服务器中遇到的一个问题,当时没理解就去查了 因为要访问最外部的json文件,就定义了一个模块读取文件,然后在外边的server.js中调用 但是一直路径错误. 我相信很多人和我一样 ...
- 认知 Git 和 GitHub
今天被一个大牛的大哥问了个问题,问住了.原问题是“你是到github吗?git呢?” 我堂而皇之的说,“他们不是同一个吗?” 结果大牛大哥狠狠地回了我一句“百度去”..好吧我乖乖去百度了. 这是我百度 ...
- 码农Coding Peasant(s):一般指从事没有发展前景的软件开发职位
码农Coding Peasant(s):一般指从事没有发展前景的软件开发职位,这种职位只能强化职业者在单方面的技术领域技能,学不到新技术,同时也是部分从事软件开发工作人员的一个自嘲的称号.一个依靠写代 ...
- 分享一个表格插入和删除编辑功能用jQuery实现
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- ES6--基础语法(一)
一.支持环境:node.js完全支持,标准浏览器完全支持.二.测试环境: chrome下需要在script标签的最先开始的地方需要添加"use strict". firefox下需 ...
- Mybatis 一对多 多对1
http://blog.csdn.net/z69183787/article/details/46833565 http://blog.csdn.net/rain097790/article/deta ...
- 洛谷 P1256 显示图像
P1256 显示图像 题目描述 古老的显示屏是由N×M个像素(Pixel)点组成的.一个像素点的位置是根据所在行数和列数决定的.例如P(2,1)表示第2行第1列的像素点.那时候,屏幕只能显示黑与白两种 ...
- 公告:本博客搬迁到:http://www.courtier.cc
公告: 您好,本人意见本博客搬迁到:http://www.courtier.cc
- Windows简单入门-送给第一次使用电脑的朋友
序言 写本篇文章前.不得不说我已经好久没有写博客了,快接近3个月了 吧,本来去年说參加今年的博客之星的,结果这都立即结束了:不得不说对自己有些嘲讽. 本篇文章是纯小白文章.之所以写这个是由于前段时间妹 ...
- 1.3 Quick Start中 Step 4: Send some messages官网剖析(博主推荐)
不多说,直接上干货! 一切来源于官网 http://kafka.apache.org/documentation/ Step 4: Send some messages Step : 发送消息 Kaf ...