Linux I/O复用 --- epoll部分源码剖析

epoll_creat( )

  1. 在内核注册文件系统eventpollfs,挂载此文件系统
    /*
    linux一切皆文件,便于处理
    若返回指针,指针如果出错则无法判断,而fd可以通过current -> files -> fd_array[ ]找到其真伪
    epoll_creat为什么返回一个fd?因为它对应的就是这个文件系统中创建的新文件
    */

  2. 创建两个内核cache(频繁分配小块内存,应该创建kmem_cahe来做内存池),分别存放struct epitem(事件信息) 和eppoll_entry(用于挂在设备等待队列下)
    创建struct eventpoll(红黑树根/就绪链表)结构,放入file -> private data
    /*
    一个新创建的epoll文件带有一个struct eventpoll结构,这个结构上再挂一个红黑树,而这个红黑树就是每次epoll_ctl 时 fd 存放的地方
    */
    epoll_ctl( )

  3. 检测红黑树中有没有当前fd 有则返回,没有则插入树中:
    ep_insert( )
    创建struct eppoll_entry(为了放入设备等待队列)
    设置其唤醒回调函数为ep_poll_callback
    加入设备等待队列 (设备驱动)
    (当设备就绪,唤醒等待队列上的等待者时,ep_poll_callback就会被调用,将epitem放入rdlist,每次调用epoll_wait就只收集rdlist里的fd就可以了)
    在这里插入图片描述

ET/LT 模式
把rdlist里的fd挪到txlist(挪完后rdlist就空了)
epoll_wait( )
| 睡眠 & 检查rdlist是否为空
– ep_poll( )
| 接着把txlist里的fd拷给用户空间,然后ep_reinject_items把一部分fd从txlist里返还给rdlist以便下次还能从rdlist中发现它
– ep_reinject_items( )
将txlist中 没有标注EPOLLET且事件被关注的fd重新放回rdlist,下一次epoll_wait( )会再次响应

Q:Epoll的ET/LT模式在实现上有什么区别?内核上两种模式是如何实现的?
LT模式:当socket缓冲区可读 / 可写时,提醒应用程序处理,若数据未一次处理完成,则会反复提醒。
ET模式:当socket缓冲区可读 / 可写时,只提醒应用程序一次,应用程序必须一次处理完所有数据,直到返回 EAGAIN,否则就会丢失数据。

内核实现:
调用epoll_wait( )后,循环检测rdlist是否为空,当rdlist中有就绪的fd时,将fd复制到txlist(清空rdlist),然后再从txlist复制到用户空间,应用程序得到epoll_wait( )返回后处理数据;若应用程序一次未处理完所有的就绪的fd,在LT模式下,未处理的fd将会被放回rdlist( )调用时返回;而ET模式下,这些未处理的fd将被忽略;

发布了1 篇原创文章 · 获赞 6 · 访问量 2770

猜你喜欢

转载自blog.csdn.net/weixin_38054045/article/details/103448139