来源:百问网
作者:韦东山
本文字数:2344,阅读时长:4分钟
在前面引入中断时,我们曾经举过一个例子:
妈妈怎么知道卧室里小孩醒了?
使用休眠-唤醒的方式等待某个事件发生时,有一个缺点:等待的时间可能很久。我们可以加上一个超时时间,这时就可以使用poll机制。
妈妈进入房间时,会先看小孩醒没醒,闹钟响之后走出房间之前又会再看小孩醒没醒。
注意:看了2次小孩!
POLL机制也是类似的,流程如下:
函数执行流程如上图①~⑧所示,重点从③开始看。假设一开始无按键数据:
③ 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函数读数据
注意几点:
使用poll机制时,驱动程序的核心就是提供对应的drv_poll函数。
在drv_poll函数中要做2件事:
APP调用poll后,很有可能会休眠。对应的,在按键驱动的中断服务程序中,也要有唤醒操作。
驱动程序中poll的代码如下:
static unsigned int gpio_key_drv_poll(struct file *fp, poll_table * wait)
{ printk("%s %s line %dn", __FILE__, __FUNCTION__, __LINE__);
poll_wait(fp, &gpio_key_wait, wait);
return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM;
}
注意:APP可以调用poll或select函数,这2个函数的作用是一样的。
poll/select函数可以监测多个文件,可以监测多种事件:
事件类型 说明
POLLIN 有数据可读
POLLRDNORM 等同于POLLIN
POLLRDBAND Priority band data can be read,有优先级较较高的“band data”可读
linux系统中很少使用这个事件
POLLPRI 高优先级数据可读
POLLOUT 可以写数据
POLLWRNORM 等同于POLLOUT
POLLWRBAND Priority data may be written
POLLERR 发生了错误
POLLHUP 挂起
POLLNVAL 无效的请求,一般是fd未open