徒手造了个轮子 — 实现epoll
Epoll是Linux IO多路复用的管理机制。作为现在Linux平台高性能网络IO必要的组件。内核的实现可以参照:fs/eventpoll.c .
为什么需要自己实现epoll呢?现在自己打算做一个用户态的协议栈。采用单线程的模式。github.com/wangbojing/…,至于为什么要实现用户态协议栈?可以自行百度C10M的问题。
由于协议栈做到了用户态故需要自己实现高性能网络IO的管理。所以epoll就自己实现一下。代码:github.com/wangbojing/…
在实现epoll之前,先得好好理解内核epoll的运行原理。内核的epoll可以从四方面来理解。
1. Epoll的数据结构,rbtree对<fd, event>的存储,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,具体实现可以参照。
github.com/wangbojing/…
三、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回调函数。
徒手造了个轮子 — 实现epoll相关推荐
- 一些造好的轮子-视频下载工具
一些造好的轮子 视频下载工具 -- 科技改变生活 几个很好用的工具推荐及一些基本的使用方法: YOU-GET You-Get是一个基于Python3的下载工具.使用You-Get可以很轻松的下载网上的 ...
- 使用vue造个小轮子vue-asign,canvas生成电子签名,满足需求
优化需求,内容是生成电子签名,发现好多个项目都重复写,于是打算自己造个小轮子,名字就叫vue-asign,说明文档如下: vue-asign Canvas 生成电子签名 支持vue2.vue3 演示d ...
- 该不该造自己的轮子?
你在学习和写代码的过程中一定听过这个说法:不要重复造轮子,使用现成的类库就好. 一般知名的类库都是大公司开发并维护的,正确性与性能都有保证.自己再重新开发一个相同功能的类库,消耗时间.消耗精力.大概率 ...
- swift开源项目精选(已经造好的轮子)
Swift 开源项目精选 站在个人的角度,并基于<Swift 语言指南>,针对开源项目做了一个甄别.筛选.当然,由于个人能力及涉足范围所限,还远远不够,其中肯定有偏颇及不足,还望同学们多多 ...
- tkinter 利器--------pmw模块,里面有很多造好的轮子,有详细的demo
2019独角兽企业重金招聘Python工程师标准>>> tkinter 利器--------pmw模块,用pip就能下载最新版本 转载于:https://my.oschina.net ...
- 经常造轮子的 AI 工程师水平通常不会太差
题图 | 邵姺画 引子 | 造轮子还是不造轮子,这是一个问题 理查德·费曼教授去世后,人们在他的黑板上发现了 What I cannot create, I do not understand 这句话 ...
- 你们应该听说过”w8ay“这个ID吧!一个喜欢造轮子的小子
他是w8scan.w9scan.w11scan.airbug的作者.他也是hack-requests的开发者.他在2018 Kcon以学生的身份展示了"自动化扫描工具".他也在Fr ...
- 造轮子是什么意思_程序员为什么热衷于造轮子,升职加薪吗?
作者:小傅哥 博客: https://bugstack.cn- 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 哪个架构师没造过轮子? 你想过这样一件事吗? 是先具备能力在安排职位,还是先安排 ...
- 因为造轮子,我一个月就转正了 | 原力计划
作者 | Baldwin_KeepMind 责编 | 伍杏玲 出品 | CSDN博客 2019年6月,我通过社招入职现在所工作的公司,理论上应该有三个月时间的试用期,只有试用期表现良好我才有机会转正, ...
最新文章
- nodejs入门教程之http的get和request简介及应用
- MySQL第9天:MySQL索引优化分析之join查询
- QSS之图形渐变填充
- python字符串类型_Python3的字符串类型(疯狂Python)
- Eclipse 插件之间互相依赖, 导出Jar包安装, 报错“java.lang.NoClassDefFoundError”
- Android Studio GPU/CPU/Network/Memory monitor使用
- Hibernate配置文件
- 驱动调试助手V2.9
- cocos 发布android 返回值2,用cocos creator打包发布的时候,编译失败是怎么回事?执行命令出错,返回值:1。...
- 初识THINKPHP--关于路径的问题(xampp下的htdocs为根目录)
- 云小课|3种常用Git工作流推荐
- 谷歌服务框架_谷歌服务框架下载_谷歌服务框架全版本整理
- 2022年信息安全工程师考试知识点:Web安全
- 拥抱云原生,聊聊高度解耦的密码管理解法
- 如何用网站统计工具追踪访客来路
- Kaggle下载数据集时,手机收不到短信验证码解决方法--亲测有效
- 【javascript】纯原生js的轻便组织结构图,树状图,支持自定义样式
- vue项目某个APP页面实现手机物理按键返回、路由拦截、localStorage存取参数
- 《从0到1》读书摘要
- 【C++】基于OpenGL的音乐可视化(一):PCM音频数据的解析
热门文章
- 单链表的整表创建以及整表删除
- zend studio安装xdebug调试工具
- 在MFC框架下使用osg报内存泄露的解决办法
- 微信跳一跳高分系列二:adb shell 中的常用命令
- 查看、修改linux系统的最大链接数限制、文件描述符限制、端口范围限制、虚拟内存等...
- 转:WEB前端性能优化规则
- 第五十四天 how can I 坚持
- 每次ubuntu12.04重启后,/etc/resolv.conf被重写为空或127.0.0.1
- String 类详解
- CVE-2015-1635(MS15-034)-HTTP.sys远程代码执行复现