poll 机制
- 一、poll机制概述
- 二、使用流程
- 三、编程
- 3.1 驱动编程
- 3.1 应用编程
- 四、POLL 机制的内核代码详解
- 五、编译后上机实验
poll 机制与休眠唤醒机制的区别:
休眠唤醒方式时,进程如果没有得到唤醒信号,需要一直休眠,进程就干不了其他事情了,但是使用poll机制时,可以设置一个超时时间,在超时时间内休眠,超时后可以去干别的。简单说:
应用程序必须要等待某个时间发生:用休眠唤醒机制。
应用程序可以在设定的时间内等待某时间发生,超时后还得去干别的。
一、poll机制概述
① APP不知道是否有事件发生,调用poll函数并传入超时时间。此时线程先放入队列。
② APP进入内核态,如果有事件发生,则poll立即返回。线程也出队列,APP被唤醒。
③ 如果没数据,就休眠一段时间。
④ 如果在休眠期间,有中断被调用,唤醒了队列中的线程,APP被唤醒。
⑤ 当超时时间到了之后,内核也会唤醒 APP。
⑥ APP根据函数的返回值就知道是否有数据,如果有数据就调用read读数据。
二、使用流程
主要的流程在图中展示的很清楚,注意几点:
① 驱动中的drv_poll把线程挂入队列,但并不在drv_poll中休眠,休眠的过程是在内核文件系统中完成的。
② drv_poll要返回数据状态,因为驱动工程师给我们简化了好多事儿,所以我们写这个函数要遵守一定规则,返回的状态必须是指定好的几个,其中常用的有:
POLLIN :有数据可读
POLLOUT:可以写数据了
③ APP 调用一次 poll,有可能会导致 drv_poll 被调用 2 次
④ 线程被唤醒的原因有 2:中断发生了去队列 wq 中把它唤醒,超时时间到了内核把它唤醒
⑤ APP要判断poll返回的原因,有数据还是超时,并分别处理。
三、编程
3.1 驱动编程
驱动程序中实现file_operation结构体中的poll接口函数实现例子如下:
其中poll要做两件事:
① 把当前线程挂入队列 wq,用内核的函数poll_wait
② APP 调用 poll 函数时,有可能是查询“有没有数据可以读” :POLLIN,也有可能是查询“你有没有空间给我写数据” :POLLOUT。
POLLRDNORM 等同于 POLLIN,为了兼容某些 APP 把它们一起返回。
POLLWRNORM 等同于 POLLIN,为了兼容某些 APP 把它们一起返回。
3.1 应用编程
注意:APP 可以调用 poll 或 select 函数,这 2 个函数的作用是一样的。
可以监测多个文件,监测多种事件,常用的就POLLIN,POLLIN。
poll函数简要说明:
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
参数fds 要传入一个结构体数组,数组用于存储要监测的文件句柄(可多个)、指定的捕获类型,返回的捕获类型。
参数nfds指明fds 中有多少个文件句柄啊。
参数timeout为超时时间,单位为ms。
应用程序部分代码如下:
fds[0].fd = fd;fds[0].events = POLLIN; //看有没有数据可读nfds = 1; //fds.fd 这个文件存放文件句柄的数组中有几个要监控timeout = 5000; //单位为mswhile (1){ret = poll(fds, nfds, timeout);if (1 == ret && (fds[0].revents & POLLIN)) //poll返回了 且 得是有数据可读{read(fd, &val, 4); /* 3. 读文件 */printf("get button : 0x%x\n", val);} else if (0 == ret){printf("time out !!! \n");}}
四、POLL 机制的内核代码详解
待补充,,,
五、编译后上机实验
注:提前修改设备树,支持pinctrl子系统,gpio子系统,在设备树中添加节点并指定中断信息。
**下图为在超时时间内按下按键:**按下一次按键后,驱动中dev_poll被调用了两次。
**下图为等待poll超时:**可见ev_poll被调用了两次。