应用程序调用的任何库函数,最终将会调被库函数封装的系统函数 ,此过程中发生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() 函数,把进程送入等待表中,不然某一事件(中断)使进程就绪后,找不到去哪唤醒,不能及时反应。可能使得响应动作延迟到休眠主动结束 才发生。