在学习POLL
驱动的时候一开始云里雾里,看了网上好多博客,真的是良莠不齐,最后终于找到几篇好的,在这里总结一下。
1、总结
- 应用程序中执行
select
、poll
时,会调用驱动的poll
函数,但是不仅仅是这样,还会有其它系统调用~ - 应用程序中执行一次select, 可能会调用驱动的poll两次。底层
do_poll
是核心,会将进程休眠(所以不用手动去schedule()
切换)。唤醒方式为超时被内核唤醒或者一般在中断里面被唤醒。 - 在驱动的
poll
函数里主要做两件事:- 调用
poll_wait
将当前等待队列头加入poll_table
。 - 返回文件的事件状态(从而应用程序得知能否进行
read
等操作)。
- 调用
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
函数读数据
注意几点:
① drv_poll
要把线程挂入队列wq
,但是并不是在drv_poll
中进入休眠,而是在调用drv_poll
之后休眠
② drv_poll
要返回数据状态
③ APP调用一次poll
,有可能会导致drv_poll
被调用2次
④ 线程被唤醒的原因有2:中断发生了去队列wq
中把它唤醒,超时时间到了内核把它唤醒
⑤ APP要判断poll
返回的原因:有数据,还是超时。有数据时再去调用read
函数。
3、do_poll函数
do_poll
函数位于s/select.c
文件中,这是POLL
机制中最核心的代码
① 从这里开始,将会导致驱动程序的poll
函数被第一次调用。
沿着②③④⑤,你可以看到:驱动程序里的poll_wait
会调用__pollwait
函数把线程放入某个队列。
当执行完①之后,在⑥或⑦处,pt->_qproc
被设置为NULL
,所以第二次调用驱动程序的poll
时,不会再次把线程放入某个队列里。
⑧ 如果驱动程序的poll
返回有效值,则count
非0,跳出循环;
⑨ 否则休眠一段时间;当休眠时间到,或是被中断唤醒时,会再次循环、再次调用驱动程序的poll
。
引用链接
https://cloud.tencent.com/developer/article/1708996
https://www.cnblogs.com/hanyan225/archive/2010/10/13/1850497.html
https://blog.csdn.net/hanchaoman/article/details/7446882