自己动手实现Epoll
admin
2023-03-13 01:01:11
0


自己动手实现Epoll


EpollLinux IO多路复用的管理机制。作为现在Linux平台高性能网络IO必要的组件。内核的实现可以参照:fs/eventpoll.c .

为什么需要自己实现epoll呢?现在自己打算做一个用户态的协议栈。采用单线程的模式。https://github.com/wangbojing/NtyTcp,至于为什么要实现用户态协议栈?可以自行百度C10M的问题。

由于协议栈做到了用户态故需要自己实现高性能网络IO的管理。所以epoll就自己实现一下。代码:https://github.com/wangbojing/NtyTcp/blob/master/src/nty_epoll_rb.c

 

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

1.      Epoll的数据结构,rbtree的存储,ready队列存储就绪io

2.      Epoll的线程安全,SMP的运行,以及防止死锁。

3.      Epoll内核回调。

4.      EpollLT(水平触发)与ET(边沿触发)

下面从这四个方面来实现epoll

一、Epoll数据结构

Epoll主要由两个结构体:eventpollepitemEpitem是每一个IO所对应的的事件。比如 epoll_ctl EPOLL_CTL_ADD操作的时候,就需要创建一个epitemEventpoll是每一个epoll所对应的的。比如epoll_create 就是创建一个eventpoll

Epitem的定义

自己动手实现Epoll

Eventpoll的定义

自己动手实现Epoll

数据结构如下图所示。

自己动手实现Epoll

List 用来存储准备就绪的IO。对于数据结构主要讨论两方面:insertremove。同样如此,对于list我们也讨论insertremove。何时将数据插入到list中呢?当内核IO准备就绪的时候,则会执行epoll_event_callback的回调函数,将epitem添加到list中。

那何时删除list中的数据呢?当epoll_wait激活重新运行的时候,将listepitem逐一copyevents参数中。

Rbtree用来存储所有io的数据,方便快速通io_fd查找。也从insertremove来讨论。

对于rbtree何时添加:当App执行epoll_ctl EPOLL_CTL_ADD操作,将epitem添加到rbtree中。何时删除呢?当App执行epoll_ctl EPOLL_CTL_DEL操作,将epitem添加到rbtree中。

Listrbtree的操作又如何做到线程安全,SMP,防止死锁呢?

 

 

二、Epoll锁机制

Epoll 从以下几个方面是需要加锁保护的。List的操作,rbtree的操作,epoll_wait的等待。

List使用最小粒度的锁spinlock,便于在SMP下添加操作的时候,能够快速操作list

List添加

自己动手实现Epoll

346行:获取spinlock

347行:epitem rdy置为1,代表epitem已经在就绪队列中,后续再触发相同事件就只需更改event

348行:添加到list中。

349行:将eventpollrdnum 1

350行:释放spinlock

 

List删除

自己动手实现Epoll

301行:获取spinlock

304行:判读rdnummaxevents的大小,避免event溢出。

307行:循环遍历list,判断添加list不能为空

309行:获取list首个结点

310行:移除list首个结点。

311行:将epitemrdy域置为0,标识epitem不再就绪队列中。

313行:copy epitemevent到用户空间的events

316行:copy数量加1

317行:eventpollrdnum减一。

避免SMP体系下,多核竞争。此处采用自旋锁,不适合采用睡眠锁。

 

Rbtree的添加

自己动手实现Epoll

149行:获取互斥锁。

153行:查找sockidepitem是否存在。存在则不能添加,不存在则可以添加。

160行:分配epitem

167行:sockid赋值

168行:将设置的event添加到epitemevent域。

170行:将epitem添加到rbrtree中。

173行:释放互斥锁。

 

Rbtree删除:

自己动手实现Epoll

177行:获取互斥锁。

181行:删除sockid的结点,如果不存在,则rbtree返回-1

188行:释放epitem

190行:释放互斥锁。

 

Epoll_wait的挂起。

采用pthread_cond_wait,具体实现可以参照。

https://github.com/wangbojing/NtyTcp/blob/master/src/nty_epoll_rb.c

 

 

三、Epoll回调

Epoll 的回调函数何时执行,此部分需要与Tcp的协议栈一起来阐述。Tcp协议栈的时序图如下图所示,epoll从协议栈回调的部分从下图的编号1,2,3,4。具体Tcp协议栈的实现,后续从另外的文章中表述出来。下面分别对四个步骤详细描述

编号1:是tcp三次握手,对端反馈ack后,socket进入rcvd状态。需要将监听socketevent置为EPOLLIN,此时标识可以进入到accept读取socket数据。

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

编号3:在established状态,收到fin时,此时socket进入到close_wait。需要socketevent置为EPOLLIN。读取断开信息。

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

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

自己动手实现Epoll

自己动手实现Epoll自己动手实现Epoll自己动手实现Epoll


四、LTET

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

自己动手实现Epoll

比如:event = EPOLLIN | EPOLLLT,将event设置为EPOLLIN与水平触发。只要eventEPOLLIN时就能不断调用epoll回调函数。

比如: event = EPOLLIN | EPOLLETevent如果从EPOLLOUT变化为EPOLLIN的时候,就会触发。在此情形下,变化只发生一次,故只调用一次epoll回调函数。关于水平触发与边沿触发放在epoll回调函数执行的时候,如果为EPOLLET(边沿触发),与之前的event对比,如果发生改变则调用epoll回调函数,如果为EPOLLLT(水平触发),则查看event是否为EPOLLIN,即可调用epoll回调函数。



BAT, 滴滴,今日头条,美图,美团等一线内推 技术岗位内推 

QQ群935760465


相关内容

热门资讯

AI开源公开信签署企业增至50... IT之家 7 月 26 日消息,英伟达、微软、IBM、Meta 等 25 家美国科技企业本周(7 月...
南阳快手短视频代运营企业的服务... 在短视频平台快速发展的背景下,企业通过快手等渠道进行内容运营已成为常见的市场动作。对于希望借助短视频...
普通人该如何跟上科技发展的步伐 这个被称作科技的词汇, 听起来既有宏大之感, 又颇为遥远, 好似仅仅归属于在实验室里专心致志钻研的科...
原创 王... 菲尔兹奖名单一出,邓煜和王虹两位华人数学家共同获奖,本应是一件令人振奋的喜讯。然而,王虹那段仅3分1...
《万物》杂志首个阅读空间亮相正... 26日,由国内知名的青少年家庭科普期刊《万物》杂志与广州正佳自然科学探索中心联合打造的阅读互动空间—...
从康复机器人到脑机接口 智能康... 天津北方网讯:对脑卒中患者来说,重新抬起手臂、迈出一步,往往需要持续的康复训练,逐步恢复运动功能;对...
原创 苹... 当苹果、谷歌、斯坦福、麻省理工都无法留住一位年轻的中国AI天才时,究竟是什么力量吸引他毅然回国?为何...
为什么新能源车供应链要本地化? 当前汽车产业变革加速,电动化成为核心发展方向。车企为了在激烈市场中站稳脚跟,必须优化生产结构。其中,...
携程罚单的真正影响,不是酒店变... 文 | 听风译码 7月25日,市场监管总局对携程开出51.79亿元天价罚单。 全网叫好。 但如果你...
自己管理自己,我国成功发射两颗... 7月24日消息,力箭一号遥十五运载火箭今日在东风商业航天创新试验区成功发射,以“一箭5星”方式将5颗...