epoll实现原理

2023-11-09

用户态协议栈,为什么要实现epoll?

epoll并不是协议栈里面的,为什么要实现用户态协议栈?

因为内核的epoll是对内核文件系统vfs fd进行的管理,是跟内核协议栈一起使用的,内核协议栈处理io后通过回调的方式来操作epoll中的就绪队列;而用户态协议栈,fd是用户空间的,内核的epoll没办法对用户空间fd进行管理,所以用户态协议栈必须要有用户态的epoll。

用户态epoll是参考内核的epoll,在用户空间实现了epoll的功能。

内核epoll代码:fs/eventpoll.c

epoll设计需要考虑以下4个方面:

  1. 数据结构选择;
  2. 协议栈如何与epoll模块通信;
  3. epoll如果加锁;
  4. ET与LT如何实现?

epoll数据结构

epoll至少有两个集合

  1. 所有交由epoll管理的fd的总集;
  2. 就绪fd,可读可写的集合。

总集用什么数据结构去存储?

是key-value的格式,通过fd要能够找到value。

  1. hash
  2. 数组
  3. 红黑树
  4. b树/b+树
  5. avl树

数组大小受限,不容易扩展;查找效率低。

hash,存储空间浪费;对于数量足够大的时候,查找效率高。

avl,对于查找、删除、性能,红黑树由于avl树。

btree/b+tree,多叉树,叶子节点都在同一层,降低层高,主要用于磁盘存储。

rbtree,对于查找效率和空间利用率综合考虑,是最优的。

总集选择用红黑树。

就绪集合选择什么数据结构去存储?

就绪集合不是以查找为主,所有的就绪fd都需要被拿出去处理。

可以选择线性数据结构:

  1. 队列

就绪集合选择队列,先进先出。

epoll使用红黑树和队列,红黑树存放需要检测的节点,队列存放就绪的节点。

img

epoll工作环境

img

epoll与select/poll的区别

  1. 使用:每次调用poll,都需要把fd的总集传进去,从用户空间copy到内核空间;epoll不需要。poll返回后,应用程序需要遍历fd集合,看哪些fd可读可写了;而epoll返回的直接是就绪队列,其中所有fd都是可读可写的。
  2. 实现原理:poll在实现的时候,内核采用循环遍历总集的方式去查看每一个fd是否就绪;epoll是在协议栈中通过callback将就绪的节点加入到就绪队列。

epoll三个函数

int epoll_create(int size);

  1. 分配一个eventpoll;
  2. 初始化红黑树的根节点epfd。
    eventpoll与epfd一一对应。

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
操作红黑树,根据op对红黑树进行增删改

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
把就绪队列的数据从内核copy到用户空间。

如果maxevents小于就绪队列大小,比如就绪队列大小为100,maxevents传入50,怎么办呢?

先将就绪队列里面的50个节点copy到用户空间,之后下次epoll_wait再copy 50个节点。

协议栈通知epoll的时机

epoll怎么知道哪个io就绪了,需要将节点加入到就绪队列?

img

recv的情况,是在回复了ack后,协议栈才通知epoll。

send的情况,如果之前sendbuff是满的,需要等发送了一次数据,收到对端回复的ack,清空一部分sendbuff数据,再通知epoll。

收到网络包后,能够解析出五元组,根据五元组能够查找到对应的fd,在到红黑树去查找到对应的节点。

红黑树和就绪队列是个什么关系?红黑树的节点和就绪队列的节点是一个节点。每次将红黑树的节点加入到就绪队列,并不是将节点从红黑树中delete掉,

img

协议栈回调到epoll,都需要做什么?

回调函数都需要做哪些事情?

需要传哪些参数?

fd,EPOLLIN、EPOLLOUT事件

需要做的事情:

  1. 通过fd查找对应的节点;
  2. 把节点加入到就绪队列里面。

epoll是线程安全的吗

epoll是否线程安全,就需要考虑epoll三个接口是否线程安全?

epoll_create,对epoll进行初始化,是线程安全的。

epoll_ctl, 是操作红黑树;epoll_wait, 是操作就绪队列。

需要考虑epoll工作环境,epoll是工作在应用程序和协议栈之间。应用程序调用epoll_ctl的时候,协议栈是否会有回调操作红黑树?调用epoll_wait从就绪队列里面copy出来的时候,协议栈是否会操作就绪队列?要保证线程安全,需要对红黑树和就绪队列加锁。

红黑树加锁,有两种加锁方法:

  1. 对整棵树加锁;
  2. 对子树加锁。

对子树加锁是一件很麻烦的事情。所以实现的是对整棵树加锁,使用mutex。

就绪队列,使用spinlock。

epoll_wait,使用条件等待,cond + cdmtx

img

ET、LT如何实现?

ET和LT是如何实现的?会不会回调?
LT : 水平触发,如果没有读完,会一直触发
ET:不管有没有读完,只触发一次

ET、LT本质区别就是回调次数。

ET 接收到数据,调用一次回调

LT recvbuffer里面有数据,就调用回调。

协议栈里面有一个while(1)循环检测。

while (1) {
	// 协议栈处理网卡数据
    // 这里就会判断调用回调的次数
}

一直回调怎么实现?就是上面提到的,有一个while(1),不断去检测。

ET适合小块

LT适合大块

epoll代码

数据结构

struct epitem {
	RB_ENTRY(epitem) rbn;
	LIST_ENTRY(epitem) rdlink;
	int rdy; //exist in list 
	
	int sockfd;
	struct epoll_event event; 
};

struct eventpoll {
	ep_rb_tree rbr;
	int rbcnt;
	
	LIST_HEAD( ,epitem) rdlist;
	int rdnum;

	int waiting;

	pthread_mutex_t mtx; //rbtree update
	pthread_spinlock_t lock; //rdlist update
	
	pthread_cond_t cond; //block for event
	pthread_mutex_t cdmtx; //mutex for cond
	
};

epoll api实现

  1. int epoll_create(int size);
    创建eventpoll,初始化rbtree,rdlist,以及epoll中使用的锁和条件变量
  2. int epoll_ctl(int epid, int op, int sockid, struct epoll_event *event)
    根据op,EPOLL_CTL_ADD/EPOLL_CTL_DEL/EPOLL_CTL_MOD,操作红黑树。
  3. int epoll_wait(int epid, struct epoll_event *events, int maxevents, int timeout)
    将就绪队列中的数据(fd, events)从内核空间copy到用户空间, 并将数据从就绪队列中移除。
    timeout > 0, 使用 pthread_cond_timedwait()
    timeout < 0, 一直阻塞,使用pthread_cond_wait(), 阻塞到就绪队列里面有数据。协议栈调用callback通知epoll,发送signal,epoll_wait解除阻塞。
  4. int epoll_event_callback(struct eventpoll *ep, int sockid, uint32_t event)
    移除。
    timeout > 0, 使用 pthread_cond_timedwait()
    timeout < 0, 一直阻塞,使用pthread_cond_wait(), 阻塞到就绪队列里面有数据。协议栈调用callback通知epoll,发送signal,epoll_wait解除阻塞。
  5. int epoll_event_callback(struct eventpoll *ep, int sockid, uint32_t event)
    根据fd,从rbtree中找到节点,并加入到就绪队列中。协议栈通过callback来通知epoll模块fd就绪。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

epoll实现原理 的相关文章

  • 正则表达式删除块注释也删除 * 选择器

    我正在尝试使用 bash 从 css 文件中删除所有块注释 我有以下 sed 命令的正则表达式 sed r s w s w d 这可以很好地去除块注释 例如 This is a comment this is another comment
  • Linux无法删除文件

    当我找到文件时 我在删除它们时遇到问题 任务 必须找到带有空格的文件并将其删除 我的尝试 rm find L root grep i 但我有错误 rm cannot remove root test No such file or dire
  • Ubuntu Python shebang 线不工作

    无法让 shebang 线在 Ubuntu 中为 python 脚本工作 我每次只收到命令未找到错误 test py usr bin env python print Ran which python usr bin python 在 sh
  • 如何在线程创建和退出时调用函数?

    include
  • 如何在不使用 IDE 的情况下在 Linux 上运行 Java 项目

    我是 Java 新手 基本上 我开发了一个java项目 其中包含Eclipse中的多个Java包 该项目在我安装了 redhat Linux 的桌面上运行正常 然而 我需要在一个更强大的没有安装X11的Linux服务器 redhat ent
  • 在 docker 中重定向命令输出

    我想为我的服务器做一些简单的日志记录 它是一个在 Docker 容器中运行的小型 Flask 应用程序 这是 Dockerfile Dockerfile FROM dreen flask MAINTAINER dreen WORKDIR s
  • 批量删除文件名中包含 BASH 中特殊字符的子字符串

    我的目录中有一个文件列表 opencv calib3d so2410 so opencv contrib so2410 so opencv core so2410 so opencv features2d so2410 so opencv
  • 在 .gitconfig 中隐藏 GitHub 令牌

    我想将所有点文件存储在 GitHub 上 包括 gitconfig 这需要我将 GitHub 令牌隐藏在 gitconfig 中 为此 我有一个 gitconfig hidden token 文件 这是我打算编辑并放在隐藏令牌的 git 下
  • python获取上传/下载速度

    我想在我的计算机上监控上传和下载速度 一个名为 conky 的程序已经在 conky conf 中执行了以下操作 Connection quality alignr wireless link qual perc wlan0 downspe
  • Linux 上的静态 Qt5 构建:部署时如何处理字体?

    我使用这些配置选项创建了 Qt 5 2 0 库的静态版本 Ubuntu 12 04 开源 确认许可 force pkg config 发布 静止的 前缀 home juzzlin qt5 无icu opengl桌面 无油嘴滑舌 辅助功能 n
  • linux-x64 二进制文件无法在 linuxmusl-x64 平台上使用错误

    我正在安装Sharp用于使用 package json 的 Nodejs 项目的 docker 映像上的映像压缩包 当我创建容器时 我收到有关 Sharp 包的以下错误 app node modules sharp lib libvips
  • 如何在 Ubuntu 中创建公共 HTML 文件夹?

    简单的问题 但由于某种原因我无法在谷歌上找到确切的答案 我在 Slicehost 上安装了全新的 Ubuntu 并且想在我的主目录中为包含一堆静态 HTML 文件的简单网站创建一个公共目录 我该怎么做呢 只是打字的问题吗mkdir publ
  • 尽管 if 语句,Visual Studio 仍尝试包含 Linux 标头

    我正在尝试创建一个强大的头文件 无需更改即可在 Windows 和 Linux 上进行编译 为此 我的包含内容中有一个 if 语句 如下所示 if defined WINDOWS include
  • 如何根据标签将单个 XML 文件拆分为多个

    我有一个带有标签的 XML 文件 我想像这样分割文件
  • 添加文件时运行 shell 命令

    我的 Linux 机器上有一个名为 images 的文件夹 该文件夹连接到一个网站 该网站的管理员可以向该网站添加图片 但是 当添加图片时 我想要一个命令来运行调整目录中所有图片的大小 简而言之 我想知道当新文件添加到特定位置时如何使服务器
  • CMake 链接 glfw3 lib 错误

    我正在使用 CLion 并且正在使用 glfw3 库编写一个程序 http www glfw org docs latest http www glfw org docs latest 我安装并正确执行了库中的所有操作 我有 a 和 h 文
  • 使用包管理器时如何管理 Perl 模块?

    A 最近的问题 https stackoverflow com questions 397817 unable to find perl modules in intrepid ibex ubuntu这让我开始思考 在我尝试过的大多数 Li
  • 配置tomat的server.xml文件并自动生成mod_jk.conf

    我在用apache 2 2 15 and tomcat6 6 0 24 on CentOS 6 4并希望使用 tomcat 服务器的功能 通过添加以下内容自动生成 mod jk conf 文件
  • C修改printf()输出到文件

    有没有办法修改printf为了将字符串输出到文件而不是控制台 我尝试在互联网上查找一些内容 发现了类似的电话dup dup2 and fflush这可能与此有关 EDIT 也许我不清楚 问题是这是C考试问题 问题如下 解释一个通常将字符串输
  • 使用 python 脚本更改 shell 中的工作目录

    我想实现一个用户态命令 它将采用其参数之一 路径 并将目录更改为该目录 程序完成后 我希望 shell 位于该目录中 所以我想实施cd命令 但需要外部程序 可以在 python 脚本中完成还是我必须编写 bash 包装器 Example t

随机推荐

  • 配置静态路由小实验

    实验拓扑 实验要求 1 使用 eNSP 搭建如下拓扑图 2 基本配置 接口 IP 地址 设备主机名等 3 配置静态路由 使 PC1 PC2 和 PC3 可以互通 4 配置浮动静态路由 使 PC3 通过 AR3 的 G0 0 1 接口访问其他
  • surfaceDestroyed什么时候被调用

    今天看别人的代码 突然有个疑问 surfaceDestroyed这个函数什么时候被调用呢 上网搜了一番 基本都说是surface被销毁的时候 才会调用surfaceDestroyed 问题又来了surface什么时候被销毁呢 大家都知道su
  • python基础案例练习一

    员工管理系统练习 1 显示系统菜单 2 获得用户输入的菜单 3 根据用户的输入判断执行操作 存储员工信息 employee def show menu print 20 员工管理系统菜单 20 print 1 添加员工信息 print 2
  • 考试座位号 C语言

    每个 PAT 考生在参加考试时都会被分配两个座位号 一个是试机座位 一个是考试座位 正常情况下 考生在入场时先得到试机座位号码 入座进入试机状态后 系统会显示该考生的考试座位号码 考试时考生需要换到考试座位就座 但有些考生迟到了 试机已经结
  • 恶意数据包(pcap)下载网站合集

    收集一些恶意数据包下载网站 方便研究学习 https wiki wireshark org SampleCaptures https www netresec com page PcapFiles https www malware tra
  • xml中使用include引入布局

    为了复用布局 使用include方式引用 activity top bar xml 代码如下 需要注意的是 父容器LinearLayout中layout height为wrap content 而不是match parent 以免引入到其他
  • 如何动态创建二维数组[cpp]

    我们常见的用new来 动态创建一维数组 int m std cin gt gt m int 数组名 new int m 动态创建二维数组 方法一 int n 地图的长宽 cin gt gt n int map new int n 创建一个指
  • js 实现颜色值格式转换 rgb和十六进制的转换

    本文章是以prototype原型的方式 给string字符串类型添加方法 用于实现颜色值格式的转换 如果你不用原型方法 那么你只要借鉴实现方法就好了 RGB转换为16进制 String prototype colorHex function
  • Lightgbm多余信息显示

    LightGBM Warning No further splits with positive gain best gain inf 设置参数 verbosity 1 或 verbose 1
  • Python安装教程(2023年,3月)

    一 Python下载 1 进入Python官网 官网地址 https www python org 2 点击 Downloads 展开后点击 Windows 跳转到下载python版本页面 选择 Stable Releases 稳定版本 我
  • [gfirefly深入解析]--总体架构及demo讲解

    gfirefly是开源的分布式游戏服务器端框架 是firefly的gevent版本 想了解更多关于firefly可参考http www oschina net question 947559 147468 这是firefly的官网http
  • 【读书笔记】《Web全栈工程师的自我修养》

    读书笔记 Web全栈工程师的自我修养 推荐书单 1 什么是全栈工程师 黑客与画家 专业主义 2 如何成为全栈工程师 重来 更为简单有效的商业思维 精益创业 3 从学生到工程师 编程之美 微软技术面试心得 4 野生程序员的故事 打造Faceb
  • TOP命令及参数解析

    Top命令是linux 下常用的系统性能分析工具 能够实时显示系统中各个进程的资源占用状况 类似于windows的任务管理器 下面详细介绍它的使用方法 top 可以显示当前系统正在执行的进程的相关信息 包括进程ID 内存占用率 CPU占用率
  • 机器学习-分类-线性分类器

    在一个机器学习任务中 如果每一条数据的目标值是离散的 则该任务是一个分类任务 解决分类问题基本的方法有 线性分类器 决策树 朴素贝叶斯 人工神经网络 K近邻 KNN 支持向量机 SVM 组合基本分类器的集成学习算法 随机森林 Adaboos
  • java中float和double型数据在赋值时有哪些注意事项?,java语言中float和double类型的数据在编程时的注意事项...

    float和double类型的数据在编程时的需要注意的地方 package execisetest public class AccuranceTest public static void main String args float a
  • Rsync命令使用

    Rsync优点 持增量备份 第 次全量备份 第 次增量备份 边复制 边 较 边统计 传输效率很 数据集中备份 客户端可以推送数据 服务端 也可以从服务端获取数据 以客户端为参照物 保持 件属性 符号链接 硬链接 权限 时间等 安全 式传输
  • 微信企业号回调模式配置详细讲解

    对于微信企业号 我相信很多人都不陌生了 今天跟大家一起来探讨一下用java怎么去实现微信企业号回调模式配置 为什么需要开启回调模式 对于这点 我相信官方文档中说得比我更清楚 但是我还是想大家熟悉一下什么是回调模式 说白了就是当你有一个属于自
  • mysql in 查询时 入参为逗号隔开的字符如何查询,使用 find_in_set 代替 in

    SELECT FROM lao car model where find in set id 101 102 41840930066432 find in set 函数中 id 查询的字段名
  • 传统支付方式不能满足线下支付的需求

    刷脸支付趋势现在可以在便利店 餐饮店看见这样的场合 收银台不见了 换成了一块类似平板大小的显示屏 上边标注了刷脸支付 消费者在屏幕上点击开启刷脸支付 将脸部对准摄像头 摄像头采集到消费者面部信息后即可完成支付 消费金额就直接从消费者账户中扣
  • epoll实现原理

    用户态协议栈 为什么要实现epoll epoll并不是协议栈里面的 为什么要实现用户态协议栈 因为内核的epoll是对内核文件系统vfs fd进行的管理 是跟内核协议栈一起使用的 内核协议栈处理io后通过回调的方式来操作epoll中的就绪队