内核poll和select系统调用的图解(1)-poll系统调用的整体结构图

970阅读 0评论2013-12-02 embeddedlwp
分类:LINUX

       虽然五年前就学了驱动中poll方法的实现,LDD3的描诉也是比较详细的,但当时我是初学者,理解的不够深入,就算学了也很快就还给了LDD3。这次复习驱动的poll方法,顺便认真跟踪了内核poll系统调用的源码,从整体的poll实现结构上理解了从用户层传递下来的poll系统调用在内核中是的实现。这一下就豁然开朗了,彻底明白了驱动中的poll方法为什么如此简单,也明白了驱动中poll的实现在整个poll系统调用中处的位置。 

      poll(轮询)操作在应用程序中用于同时阻塞在多个文件上,当其中任何一个文件有应用程序所等待的事件(可读、可写、出错等)时,poll返回相应的掩码通知应用程序,使得应用程序知道应该对哪个文件做何种操作。按照我的理解,poll的本质可以这样解释:休眠等待多个指定文件中的任何一个发生特定的事件,并将被该文件唤醒;醒来后轮询所有相关文件(通过再次调用所有文件对应驱动的poll方法),获取所有被监控文件的事件信息返回给应用程序。

     从这里就可以看出:

1)其中等待队列的使用是必不可少的。实际上调用poll的进程将会休眠在多个等待队列(一般所有被监控文件的都有至少一个的等待队列)上,从其中任何一个队列上唤醒该进程,都可能使poll函数返回。

2)驱动中的poll方法实现休眠,而是:


  1. i、把当前进程添加到相应的等待队列中(仅在休眠时执行,唤醒时不会执行此功能)。
  2. ii、返回文件当前的状态掩码(告知是否有事件发生,休眠和唤醒都会执行)。

      通过对内核源码、《深入Linux设备驱动程序内核机制》的学习,我对Poll系统调用和内核驱动的poll方法的关系和结构有了整体且深入的了解,基本搞清了poll系统调用的执行脉络。对于poll系统调用的内核原理,请大家先看《深入Linux设备驱动程序内核机制》那本书写的比较详细了,我不废话了。以后我会把我自己觉得需要注意的地方写出来。这里我把这个关系和数据结构图绘制了出来,请大家指正:


对于等待队列的情况,我用下面一个例子和图来示意一下:

例如有3个进程:

task-1:使用poll检测文件1~3

task-2:使用poll检测文件2~3

task-3:使用poll检测文件3

则等待队列的情况如下:

之后,假设task-2由于文件2或3被唤醒,且task-1/3对此不感兴趣(未设置该掩码),那么等待队列的情况如下:


    等待队列入口项的添加和删除主要是由poll_initwait(&table);和poll_freewait(&table);完成。
    poll_initwait(&table);完成初始化struct poll_wqueues table的工作,而poll_freewait(&table);负责清理这个结构体。这里需要注意的是等待队列中的wait_queue_t并不是在唤醒函数pollwake从队列中删除的,而是最后由poll_freewait(&table);集中处理的。而唤醒函数和普通的wait_event的唤醒函数有很大不同,请大家对比上面的图和之前我写的《对Linux系统休眠的理解》中的图。

上一篇:Linux系统下的单调时间函数
下一篇:linux kernel 中的 CPU指令cmpxchg函数=分析