linux下poll和epoll内核源代码剖析
最近做项目用了epoll,于是打算深究一下,看了看linux内核的代码,凑成浅文一篇,欢迎指正。
《poll和epoll内核源码剖析》(一)
《poll和epoll内核源码剖析》(二)
《poll和epoll内核源码剖析》(三)
《poll和epoll内核源码剖析》(一)
《poll和epoll内核源码剖析》(二)
《poll和epoll内核源码剖析》(三)
====== 2010.5.14 ======
基于qixinkui同学的疑问,我修改了“poll是轮询”这一错误提法(在第二篇里),然后增加了对EPOLLET的代码分析(第三篇)。poll和epoll的区别在于fd数量很大时,两者的事件模型效率不同,而NAPI,它是驱动程序的功能,只会影响某个fd的通知速度,所以这里就不补充讨论了。有了NAPI,对poll和epoll都一样有利。
====== 2010.6.8 ======
问:当你讲sys_epoll_wait()->ep_poll()这个函数时,里面有个for循环 。你说它除了睡觉和判断ep->rdllist是否为空外什么也没干。我的疑问是既然它 睡觉了,也就是阻塞了,它还怎么进行判断?这两者的关系是怎样的?
答:下面的代码是ep_poll里的那个“循环”,1531行的代码是判断rdllist是否为空的,1539行是睡觉用的。
你所说,睡觉了,也就阻塞了,也就是1539行的schedule_timeout,当前进程自动放弃CPU,但是,是用的schedule_timeout而不是schedule。用了schedule,当前进程放弃CPU,直到内核在以后的某次进程调度中重新选择该进程;而schedule_timeout,那就是经过一个时间后(这里是jtimeout),进程会重新被唤醒获得CPU,然后从schedule_timeout函数返回。返回后继续循环,继续判断rdllist是否为空,为空就接着 schedule_timeout......
说白了,这个“睡觉”,不是永远睡下去,是一定会醒来的,醒来了再接着判断。不是说他边睡觉边判断。
1524 for (;;) {
1525 /*
1526 * We don't want to sleep if the ep_poll_callback() sends us
1527 * a wakeup in between. That's why we set the task state
1528 * to TASK_INTERRUPTIBLE before doing the checks.
1529 */
1530 set_current_state(TASK_INTERRUPTIBLE);
1531 if (!list_empty(&ep->rdllist) || !jtimeout)
1532 break;
1533 if (signal_pending(current)) {
1534 res = -EINTR;
1535 break;
1536 }
1537
1538 write_unlock_irqrestore(&ep->lock, flags);
1539 jtimeout = schedule_timeout(jtimeout);
1540 write_lock_irqsave(&ep->lock, flags);
1541 }
1542 __remove_wait_queue(&ep->wq, &wait);
1543
1544 set_current_state(TASK_RUNNING);
1545 }
1524 for (;;) {
1525 /*
1526 * We don't want to sleep if the ep_poll_callback() sends us
1527 * a wakeup in between. That's why we set the task state
1528 * to TASK_INTERRUPTIBLE before doing the checks.
1529 */
1530 set_current_state(TASK_
1531 if (!list_empty(&ep->rdllist) || !jtimeout)
1532 break;
1533 if (signal_pending(current)) {
1534 res = -EINTR;
1535 break;
1536 }
1537
1538 write_unlock_irqrestore(&ep->
1539 jtimeout = schedule_timeout(jtimeout);
1540 write_lock_irqsave(&ep->lock, flags);
1541 }
1542 __remove_wait_queue(&ep->wq, &wait);
1543
1544 set_current_state(TASK_
1545 }
相关文章
- [kernel] linux在多核处理器上的负载均衡原理 - 07 20, 2010
- [kernel] 在release方法里,而不是flush方法里释放 - 06 01, 2010
- [linux] tail和poll无关 - 06 01, 2010
写的真好,看了很多遍了~~
过奖了,流水账而已
poll 是自己挨个去问每个fd“好没有?”、“好没有?“(poll),而epoll是给了每个fd一个命令“好了就调我的函数!”,然后就去睡了,等着设备驱动通知它....epoll的方法显然更英明、更高效。
请问,怎么我看过文章之后,感觉 poll 和 epoll 都是使用了回调函数的方式,poll并不是轮询的方式(“好没有?”“好没有?”)?
另外,对于epoll 支持的 edge trigger 方式的高效原因所在也没有讲出来。是否有新的研究可以解释一下这部分的内容?
另,对于kernel 驱动程序的 NAPI架构(结合使用了中断和轮询),对于这里的性能有没有什么影响?
谢谢,麻烦楼主作答。
写得不错,楼主对代码研究很深入,讲解要点准确到位。顶!!
epoll ET 那里解释说,把没有标上EPOLLET”(标红代码)且“事件被关注”的fd被重新放回了rdllist。,假如复制回的fd上次关注的事件为EPOLLIN,如果read把该fd的缓冲区内容读完,该fd会自动从就绪rdllist删除,重新把该进程挂入相关的fd事件等待队列?
- &(pwq->pt)->qproc = __pollwait; /*此行已经被我“翻译”了,方便观看*/
+(&(pwq->pt))->qproc = __pollwait; /*此行已经被我“翻译”了,方便观看*/
写的很不错哦