epoll vs select———— epoll内核源码理解

和上一篇select的比,这篇不敢叫赏析了,因为select有几篇优秀的文章并且代码复杂度简单一些,epoll也不是麻烦太多,但是可参考的文章没见到能讲清的。


一、感性认识
进一家餐馆,里面大厨众多,各个菜系的都有。你先点了一大批菜囊括了百大菜系,之后想的是哪个菜先上先吃。
select(无限时等版本):
1.先给每个厨师关照一下,“师傅,我是123号桌的,您有菜了麻烦叫一声”;(遍历fd相关file,调用每个file的poll函数,对每一个fd创建一个wait结构体,注册到该file的事件列表;同时自己维护一个entry集合保管这些wait)
2.如果恰好有一位厨师已经做好了,端走菜揣兜里,等所有厨师问完后跳到6;(第一次遍历成功返回)
3.如果第一次询问没有菜做好,那么旁边待着等待叫号;(否则挂起自己)
4.法餐大厨做好了烤蜗牛,按下铃铛叫了声“123号!”,听到“123号”的你很兴奋,但是你并不知道是谁叫的。甚至你不知道是不是外甥来北京找自己被叫的;(file发生事件后检查自己的相关事件列表,发现123号注册的wait事件符合条件,于是调用wait事件结构中的回调函数fun,fun把123置为可执行状态放入待执行队列。“外甥”模拟被信号中断这种不可预估的事件)
5.你排除了外甥事件之后,知道是某一道菜好了,就按照清单类似1再从头到尾问一遍,并且如愿以偿地得到了法国大厨有份做好的烤蜗牛的信息;(再次遍历,这次不注册事件只问菜好没)
6.有了当前的食物也就不管以后了,再访问每一个大厨,叫大厨们把自己销号,“师傅,菜好了别叫我了啊,啥时候我饿了自己会来再问你的”。(遍历entry集合,从文件事件列表中删除和自己相关地)


epoll:
1.你请了个服务员;(epoll_create)
2.服务员是餐馆的员工,有统一编码的工号;(epoll信息存储再内核空间中,返回文件描述符,对应struct file,epoll也像其他文件一样有自己的尽管支持很少操作的file_operations,也有自己的private_data struct eventpoll);
2.你向服务员点了德国大厨的猪肘子;(epoll_ctl,EPOLL_CTL_ADD,一次只能加一个)
3.因为你除了可以点菜,还能叫服务员帮你监控其它桌的上菜情况来看看别人的份量是不是比自己的大(epoll可以监控epoll描述符),当然对方也能监控其他桌...最后又反监控到自己头上(closed loops)。这样,理论上,1号桌有菜了,服务员应该通知关心1号桌有菜事件的2号桌,2号桌知道1号桌的消息应该传给三号桌...到头来n号桌又应该通知一号桌,所以对这种闭环死循环应该有监控和破解机制,服务员能做到;(epoll能够检查死循环和嵌套层次深的epoll监听,这儿其实没说明白,因为代码没追到底);
4.其实餐馆有项规定,同一个客人只能向一个大厨点一次菜就是只能发一次订单(对一个epoll一个fd只能add一次,可以改EPOLL_CTL_MOD,但是不能重复添加),服务员能够很快的查出客人123是否点过德国大厨的菜(epoll内部维护红黑树,key是fd的file指针和fd决定的,那么,同一个fd的fd+file组合肯定一致,但是dup之后只是file一致fd不一致,此时能够重复添加);
5.服务员开始执行业务了,像餐馆所有的反馈机制一样,每个大厨有一个自己的事件清单,清单有的写在背心上,有的记在脑子里(每个文件种类的事件链表位置都看实现),每个清单上写着对应的XXX(对于select就是当前进程current也就是食客,对于epoll就是服务员)该做什么事(回调函数)。服务员找到大厨,给了大厨点的菜(关心事件类型),大厨找到自己的小本本清单(执行文件的poll操作),把本子交给服务员(回调ep_ptable_queue_proc),服务员把自己的联系方式写上(ep_ptable_queue_proc函数内把新建entry加入file事件列表),还注明了有消息了联系自己的方法(ep_poll_callback函数)以及这次交易的订单号(epitem红黑树节点地址);
6.因为这次已经联系上厨师了,可以顺便看看大厨有没有做好的猪肘子(file的pool方法会返回自己的可读可写错误信息);
7.完事后服务员把订单号信息填入自己的清单(epitem插入红黑树);
8.如果已经有菜可以上了,并且之前有客人已经等上了(epoll_wait),那么就挨个唤醒(改状态,改队列,结果写回用户空间)。


9.上面是点餐已经结束了,对于select来说,用户回到餐位是知道了哪些菜已经做好了可以动手了;对于epoll来说,点和知道做好是两码事;这时客人可以干点别的,肚子饿了回来再专心等;
10.饿了回来,需要知道哪些菜好了,客户得自己按自己食量找纸给服务员,之后服务员会返回已经就绪菜的详情,一张纸只能写一道菜;(epoll_wait和maxevents,用户自行开辟空间)
11.在点餐到等菜这段时间,如果菜做好了,厨师会根据自己的清单把菜好的信息填到服务员的清单(回调ep_poll_callback函数把epitem插入epoll的就绪队列),这里有个细节,服务员有两个清单,当服务员在填写客户清单(处理epoll_wait)时清单一(rdllist)是不能交给厨师来填写的(锁链表),这时厨师会填入服务员清单二(ovflist);
12.饿了回来,问下服务员,服务员的两个清单都没有记录,客人就会知会服务员有菜了叫醒自己(init_waitqueue_entry(&wait, current);__add_wait_queue_exclusive(&ep->wq, &wait);),之后自己趴桌上睡会儿(schedule_hrtimeout_range);
13.和12不同,如果清单有记录,那么对每个记录,服务员会再次联系写该记录的厨师(file的poll操作,注意这里不是直接把事件类型存到epitem内,还是得实时重新查,只不过和select比起来只查有事件的那些),得到当时厨师做菜的状态,符合的话再通过填写用户给的纸把返回做菜信息给客户。
14.now everyone is happy.


二、代码分析
to do
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值