Linux设备驱动之poll机制

       应用程序调用的任何库函数,最终将会调被库函数封装的系统函数 ,此过程中发生swi中断,用户进程从用户状态变成了核心态,当我们的应用程序调用pool() 函数时,最终调用的是 sys_poll() 函数。

       sys_poll()的函数原型如下:

       asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds,long timeout_msecs)。

       解读:函数定义前加宏asmlinkage ,表示这些函数通过堆栈而不是通过寄存器传递参数。 gcc编译器在汇编过程中调用c语言函数时传递参数有两种方法:一种是通过堆栈,另一种是通过寄存器。缺省时采用寄存器,假如你要在你的汇编过程中调用c语言函数,并且想通过堆栈传递参数,你定义的c函数时要在函数前加上宏asmlinkage。对于函数的相关参数类型,可以在主机系统中通过 man poll 命令,查看相关参数的介绍,这里就不列举出来。

       Pool机制相关函数的调用流程:

(1)pool()函数调用sys_poll()函数。sys_poll()函数首先处理传入的超时时间的值,接着调用do_sys_poll(ufds, nfds, &timeout_jiffies) 函数。

(2)do_sys_poll()函数调用poll_initwait(&table) 来初始化进程等待表,接着调用do_poll(nfds, head, &table, timeout)函数。

(3)do_poll(nfds, head, &table, timeout)函数调用do_pollfd()函数,do_pollfd()函数调用设备驱动程序中自己写的 XXX_poll() 函数,如果XXX_poll()函数返回1,则count加1。

    Select.c文件中do_poll() 函数的部分关键代码:

    for (walk = list; walk != NULL; walk = walk->next) {

                     struct pollfd * pfd, * pfd_end;

                     pfd = walk->entries;

                     pfd_end = pfd + walk->len;

                     for (; pfd != pfd_end; pfd++) {

                            if (do_pollfd(pfd, pt)) {

                                   count++;

                                   pt = NULL;

                            }

                       }

               }

      双层for循环,可以检查多个设备,

     接下来,do_poll()  函数会判断函数到底是直接返回 还是先使进程进入休眠,等待你传入的timeout_msecs 时间后再恢复运行

      if (count || !*timeout || signal_pending(current))

              break;

     从上面可以看到,直接返回的条件:有设备(count不等于0),超时,等待信号。同时poll() 函数返回值为设备数的值。

     否则的话,程序继续执行。

     最终执行到:

              __timeout = schedule_timeout(__timeout),进程进入休眠。

      休眠指定的时间之后:

              __set_current_state(TASK_RUNNING),进程又恢复运行,poll() 函数返回值为0

       在驱动程序中,自己的xxx_poll() 函数一定要调用poll_wait() 函数,把进程送入等待表中,不然某一事件(中断)使进程就绪后,找不到去哪唤醒,不能及时反应。可能使得响应动作延迟到休眠主动结束 才发生。

你可能感兴趣的:(嵌入式Linux)