Linux驱动之POLL机制

yuanheci 2023年08月07日 626次浏览

  在学习POLL驱动的时候一开始云里雾里,看了网上好多博客,真的是良莠不齐,最后终于找到几篇好的,在这里总结一下。


1、总结

  • 应用程序中执行selectpoll时,会调用驱动的poll函数,但是不仅仅是这样,还会有其它系统调用~
  • 应用程序中执行一次select, 可能会调用驱动的poll两次。底层do_poll是核心,会将进程休眠(所以不用手动去schedule()切换)。唤醒方式为超时被内核唤醒或者一般在中断里面被唤醒。
  • 在驱动的poll函数里主要做两件事:
    • 调用poll_wait将当前等待队列头加入poll_table
    • 返回文件的事件状态(从而应用程序得知能否进行read等操作)。

2、POLL机制流程

image-1691401004492

函数执行流程如上图①~⑧所示,重点从③开始看。假设一开始无按键数据:
③ APP调用poll之后,进入内核态;
④ 导致驱动程序的drv_poll被调用:
注意,drv_poll要把自己这个线程挂入等待队列wq中;假设不放入队列里,那以后发生中断时,中断服务程序去哪里找到你嘛?
drv_poll还会判断一下:有没有数据啊?返回这个状态。
⑤ 假设当前没有数据,则休眠一会;
⑥ 在休眠过程中,按下了按键,发生了中断:
在中断服务程序里记录了按键值,并且从wq中把线程唤醒了。
⑦ 线程从休眠中被唤醒,继续执行for循环,再次调用drv_polldrv_poll返回数据状态。
⑧ 哦,你有数据,那从内核态返回到应用态吧
⑨ APP调用read函数读数据
如果一直没有数据,调用流程也是类似的,重点从③开始看,如下:
③ APP调用poll之后,进入内核态;
④ 导致驱动程序的drv_poll被调用:
注意,drv_poll要把自己这个线程挂入等待队列wq中;假设不放入队列里,那以后发生中断时,中断服务程序去哪里找到你嘛?
drv_poll还会判断一下:有没有数据啊?返回这个状态。
⑤ 假设当前没有数据,则休眠一会;
⑥ 在休眠过程中,一直没有按下了按键,超时时间到:内核把这个线程唤醒;
⑦ 线程从休眠中被唤醒,继续执行for循环,再次调用drv_polldrv_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机制中最核心的代码

image-1691401381257

① 从这里开始,将会导致驱动程序的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