讨论的内核版本为2.6.38
引言
在开始对源码的学习之前我们先来回顾下epoll对于程序员来说涉及到的主要接口和结构.
int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
struct epoll_event {
__uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
//以下解释来源于百度,文末附上链接
EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭);
EPOLLOUT:表示对应的文件描述符可以写;
EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);
EPOLLERR:表示对应的文件描述符发生错误;
EPOLLHUP:表示对应的文件描述符被挂断;
EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。
EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里。
值得一提的是对于epoll_ctl时的event来说,其实默认内核会注册EPOLLHUP,EPOLLHUP与LT.
有了这些函数,对我们来说使用epoll当然也不是什么难事啦,我们需要在使用前使用epoll_create创建一个epfd,然后使用epoll_ctl向epoll结构中添加fd,这一步我们会设置我们需要的事件,如果事件到了,但我们没有注册的话poll触发回调时不会把事件加入到rdllist中,也不会拷贝向用户空间,我们也就自然看不到了.在加入了一些fd以后,我们只需要执行epoll_wait即可,这里有一个小小的问题,就是如果事件在epoll_ctl(ADD)以后,epoll_wait之前来会如何,这时意味着事件已经加入到了rdllist中,我们不必担心,在epoll_wait之前内核会进行检测,如果rdllist不为空,不会进入睡眠,会直接执行,即遍历rdllist,把数据拷贝向用户空间.至于rdllist是什么,后面几篇文章会解释.
我们有必要说说epoll为何如此高效:
- 使用内核中的slab机制分配epoll_entry和epitem这些会经常操作的数据结构,slab机制可以把经常使用的对象利用缓存存起来,避免多次初始化,且可以更好的利用硬件的高速缓存.
- 在我看的这个版本的内核代码实现中(2.6.38),所有在一个文件系统内创建的epoll共享一个inode,而使用不同的fd,这样更好的节省了内存.
- 一个巧妙的回调的使用是epoll如此高效的最主要的原因,相比与select和poll,epoll在注册的fd中注册一个回调,fd会在poll的时候触发回调,把fd相对应的epitem结构加入rdllist中,这样每次epoll_wait被触发后发送往用户态的fd就都是我们注册的event发生的fd了,避免了用户态的遍历,这样可以在有大量不活跃fd时有可观的效率提升.会在epoll_ctl篇中提及.
- 因为我们是注册了一个回调,所以我们也不必在每次epoll_wait后重新注册事件,这也是一个重要的点.
- 利用红黑树存储epitem,使得增删查的效率有了显著的提升.
我建议的学习路线是先看简单的浏览一遍基本数据结构,即epitem和eventpoll,而不必深究其作用,作用等到看代码时再理解,这样可以有一个更深的印象,也不会在开始时一脸懵.
下面是文章的正文部分:
epoll源码解析(1) epoll_create
epoll源码解析(2) epoll_ctl
epoll源码解析(3) epoll_wait
参考:
http://edsionte.com/techblog/archives/4019 slab
poll机制
SYSCALL_DEFINEx
https://blog.csdn.net/pmt123456/article/details/77814936?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
https://blog.csdn.net/Function_Dou/article/details/80404239?ops_request_misc=%7B%22request_id%22%3A%22158260901119725256754418%22%2C%22scm%22%3A%2220140713.130056874…%22%7D&request_id=158260901119725256754418&biz_id=0&utm_source=distribute.pc_search_result.none-task