中断深入--> poll机制

在此之前

poll机制相当于让app 休眠一段时间,如果在这段时间里有数据 -----> app调用read读取数据
如果这段时间没有数据 ------> 不再等待,继续做app自己的事情

pool机制的流程

在这里插入图片描述
poll是在系统调用里面写好的,我们的驱动在 poll只做了两件事 把线程放入 waitqueue队列,但是不休眠 返回event 状态

有按键按下,不超时的情况

函数执行流程如上图①~⑧所示,重点从③开始看。假设一开始无按键数据:
③ APP 调用 poll 之后,进入内核态;
④ 导致驱动程序的 drv_poll 被调用:
注意 : drv_poll 要把自己这个线程挂入等待队列 wq 中;假设不放入队列里,那以后发生中断时,中断服务程序去哪里找到你嘛?
drv_poll 还会判断一下:有没有数据啊?返回这个状态。

⑤ 假设当前没有数据,则休眠一会;
⑥ 在休眠过程中,按下了按键,发生了中断:
在中断服务程序里记录了按键值,并且从 wq 中把线程唤醒了。
⑦ 线程从休眠中被唤醒,继续执行 for 循环,再次调用 drv_poll:
drv_poll 返回数据状态
⑧ 哦,你有数据,那从内核态返回到应用态吧
⑨ APP 调用 read 函数读数据

无数据,过了超时时间

如果一直没有数据,调用流程也是类似的,重点从③开始看,如下:
③ APP 调用 poll 之后,进入内核态;
④ 导致驱动程序的 drv_poll 被调用:
注意,drv_poll 要把自己这个线程挂入等待队列 wq 中;假设不放入队列里,那以后发生中断时,中断服务程序去哪里找到你嘛?
drv_poll 还会判断一下:有没有数据啊?返回这个状态。

⑤ 假设当前没有数据,则休眠一会;
⑥ 在休眠过程中,一直没有按下了按键,超时时间到:内核把这个线程唤醒;
⑦ 线程从休眠中被唤醒,继续执行 for 循环,再次调用 drv_poll:
drv_poll 返回数据状态
⑧ 哦,你还是没有数据,但是超时时间到了,那从内核态返回到应用态吧
⑨ APP 不能调用 read 函数读数据

注意几点:

① drv_poll 要把线程挂入队列 wq,但是并不是在 drv_poll 中进入休眠,而是在调用 drv_poll 之后休眠
② drv_poll 要返回数据状态
③ APP 调用一次 poll,有可能会导致 drv_poll 被调用 2 次
④ 线程被唤醒的原因有 2:中断发生了去队列 wq 中把它唤醒,超时时间到了内核把它唤醒
⑤ APP 要判断 poll 返回的原因:有数据,还是超时。有数据时再去调用 read 函数。

在驱动中如何写入poll机制

驱动程序的 pool 做了两件事

  1. 把线程放入 waitqueue队列,但是不休眠
  2. 返回event 状态
把线程放入 waitqueue队列

把当前线程挂入队列 wq:poll_wait
APP 调用一次 poll,可能导致 drv_poll 被调用 2 次,但是我们并不需要把当前线程挂入队列 2 次。
可以使用内核的函数 poll_wait 把线程挂入队列,如果线程已经在队列里了,它就不会再次挂入

返回event 状态

在这里插入图片描述
这些event也会传给 app ,具体含义在 linux 里面man一下
APP 调用 poll 函数时,有可能是查询“有没有数据可以读”:POLLIN,也有可能是查询“你有没有空间给我写数据”:POLLOUT。
所以 drv_poll 要返回自己的当前状态:(POLLIN | POLLRDNORM) 或 (POLLOUT | POLLWRNORM)。
POLLRDNORM 等同于 POLLIN,为了兼容某些 APP 把它们一起返回。
POLLWRNORM 等同于 POLLOUT ,为了兼容某些 APP 把它们一起返回。
APP 调用 poll 后,很有可能会休眠。对应的,在按键驱动的中断服务程序中,也要有唤醒操作。

在app中如何调用驱动里的poll

在linux 里面man 出 poll

在这里插入图片描述
构造出结构体,指定文件和想要监视的类型
在这里插入图片描述
在调用 poll 函数时,要指明:
① 你要监测哪一个文件:哪一个 fd
② 你想监测这个文件的哪种事件:是 POLLIN、还是 POLLOUT
最后,在 poll 函数返回时,要判断状态。

struct pollfd fds[1];
int timeout_ms = 5000;
int ret;
fds[0].fd = fd;
fds[0].events = POLLIN;
ret = poll(fds, 1, timeout_ms);
if ((ret == 1) && (fds[0].revents & POLLIN))
{
   
read(fd, &val, 4);
printf("get button : 0x%x\n", val);
}

代码编写

驱动编写
#include <linux/module.h>
#include <linux/poll.h>

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值