自己动手实现Epoll

Epoll是Linux 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. Epoll的LT(水平触发)与ET(边沿触发)

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

一、Epoll数据结构

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

Epitem的定义

Eventpoll的定义

数据结构如下图所示。

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

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

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

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

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

二、Epoll锁机制

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

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

List添加

346行:获取spinlock。

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

348行:添加到list中。

349行:将eventpoll的rdnum域 加1。

350行:释放spinlock

List删除

301行:获取spinlock

304行:判读rdnum与maxevents的大小,避免event溢出。

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

309行:获取list首个结点

310行:移除list首个结点。

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

313行:copy epitem的event到用户空间的events。

316行:copy数量加1

317行:eventpoll中rdnum减一。

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

Rbtree的添加

149行:获取互斥锁。

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

160行:分配epitem。

167行:sockid赋值

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

170行:将epitem添加到rbrtree中。

173行:释放互斥锁。

Rbtree删除:

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状态。需要将监听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事件。

四、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回调函数。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,692评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,482评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,995评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,223评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,245评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,208评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,091评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,929评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,346评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,570评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,739评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,437评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,037评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,677评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,833评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,760评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,647评论 2 354

推荐阅读更多精彩内容