Epoll的实现原理

简介: Epoll的实现原理

Epoll是Linux IO多路复用的一种IO管理机制。内核的实现代码在Linux内核源码的fs/eventpoll.c中。是比select和poll更高性能的一种IO管理机制。

前期准备

在实现epoll之前,要先了解内核epoll的运行原理。内核的epoll可以从四方面来理解。

  1. Epoll 的数据结构,rbtree 对<fd, event>的存储,ready 队列存储就绪 io。
  2. Epoll的线程安全,SMP的运行,以及防止死锁。
  3. Epoll内核回调
  4. Epoll的LT和ET

具体实现

Epoll数据结构

Epoll 主要由两个结构体:eventpoll 与 epitem。Epitem 是每一个 IO 所对应的的事件。比如

epoll_ctl EPOLL_CTL_ADD 操作的时候,就需要创建一个 epitem。Eventpoll 是每一个 epoll 所

对应的的。比如 epoll_create 就是创建一个 eventpoll。

  • Epitem定义

  • Eventpoll定义

数据结构示意图

List用来存储就绪的IO。当内核IO准备就绪的时候就会执行epoll_event_callback的回调函数,将epitem添加到List中。当epoll_wait激活重新运行的时候,将list的epitem逐一copy到events参数中。

RBtree用来存储所有io数据,方便快速通过io_fd查找。也从insert与remove来讨论。

当 App 执行 epoll_ctl EPOLL_CTL_ADD 操作,将 epitem 添加到 rbtree

中。当 App 执行 epoll_ctl EPOLL_CTL_ADD 操作,将 epitem 从rbtree中删除。

Epoll锁机制

// 获取自旋锁  
pthread_spin_lock(&ep->lock);
// epitem的rdy置1,代表epitem在就绪队列重,后续触发相同事件只需要修改event
epi->rdy = 1;
// 添加到list中
LIST_INSERT_HEAD(&ep->rdlist, epi, rdlink);
// 将eventpoll的rdnum加1
ep->rdnum ++;
// 释放spinlock
pthread_spin_unlock(&ep->lock);

Epoll回调

Epoll 的回调函数何时执行,此部分需要与 Tcp 的协议栈一起来阐述。Tcp 协议栈的时序图如

下图所示,epoll 从协议栈回调的部分从下图的编号 1,2,3,4。具体 Tcp 协议栈的实现,后续

从另外的文章中表述出来。下面分别对四个步骤详细描述

编号 1:是 tcp 三次握手,对端反馈 ack 后,socket 进入 rcvd 状态。需要将监听 socket 的

event 置为 EPOLLIN,此时标识可以进入到 accept 读取 socket 数据。

编号 2:在 established 状态,收到数据以后,需要将 socket 的 event 置为 EPOLLIN 状态。

编号 3:在 established 状态,收到 fin 时,此时 socket 进入到 close_wait。需要 socket 的 event

置为 EPOLLIN。读取断开信息。

编号 4:检测 socket 的 send 状态,如果对端 cwnd>0 是可以,发送的数据。故需要将 socket

置为 EPOLLOUT。

所以在此四处添加 EPOLL 的回调函数,即可使得 epoll 正常接收到 io 事件。

有点尴尬,这个图等我有空了再重新画一遍,我不知道他要vip才能无水印。

LT和ET

LT(水平触发)与 ET(边沿触发)是电子信号里面的概念。不清楚可以 man epoll 查看的。

如下图所示:

比如:event = EPOLLIN | EPOLLLT,将 event 设置为 EPOLLIN 与水平触发。只要 event 为 EPOLLIN

时就能不断调用 epoll 回调函数。

比如: event = EPOLLIN | EPOLLET,event 如果从 EPOLLOUT 变化为 EPOLLIN 的时候,就会触

发。在此情形下,变化只发生一次,故只调用一次 epoll 回调函数。关于水平触发与边沿触

发放在 epoll 回调函数执行的时候,如果为 EPOLLET(边沿触发),与之前的 event 对比,如

果发生改变则调用 epoll 回调函数,如果为 EPOLLLT(水平触发),则查看 event 是否为 EPOLLIN,

即可调用 epoll 回调函数。

相关文章
|
5月前
|
应用服务中间件 Go nginx
Swoole 源码分析之 epoll 多路复用模块
IO多路复用技术通过使用少量的线程或进程同时监视多个IO事件,能够更高效地处理大量的IO操作,从而提高系统的性能和资源利用率。
56 0
Swoole 源码分析之 epoll 多路复用模块
|
5月前
|
存储 安全 网络协议
epoll的底层实现原理
epoll的底层实现原理
51 0
|
5月前
epoll(2) 使用及源码分析的引子
epoll(2) 使用及源码分析的引子
|
6月前
|
监控 Linux
epoll 的用法
【4月更文挑战第16天】epoll 通过改进的接口设计,避免了用户态 - 内核态频繁的数据拷贝,大大提高了系统性能。在使用 epoll 的时候,我们一定要理解条件触发和边缘触发两种模式。
|
6月前
|
存储 安全 网络协议
epoll的实现原理
epoll的实现原理
77 0
|
6月前
|
Linux API C++
epoll封装reactor原理剖析与代码实现(1)
epoll封装reactor原理剖析与代码实现(1)
205 0
|
6月前
|
监控 Java 应用服务中间件
epoll封装reactor原理剖析与代码实现(2)
epoll封装reactor原理剖析与代码实现(2)
91 0
|
6月前
|
监控 Linux API
epoll-reactor模型原理及代码解析
epoll-reactor模型原理及代码解析
145 0
|
存储 监控 安全
2.9 epoll的实现原理
2.9 epoll的实现原理
99 0
|
存储 监控 NoSQL
epoll底层原理
epoll是Linux内核为处理大批量文件描述符而作了改进的poll,是Linux下多路复用IO接口select/poll的增强版本。
431 0
epoll底层原理