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实现原理 的相关文章

  • 如何从程序内部获取指向程序的特定可执行文件部分的指针? (也许是诽谤)

    我在 Linux 环境中 需要编写一个程序来检索放置在其可执行文件的某个部分中的一些数据 那么 如何从程序内部获取指向程序某个部分 通过其名称 的指针呢 我知道可以使用elf getdata 将节的索引作为参数传递给 get 和Elf Da
  • 如果输入被重定向则执行操作

    我想知道如果我的输入被重定向 我应该如何在 C 程序中执行操作 例如 假设我有已编译的程序 prog 并且我将输入 input txt 重定向到它 我这样做 prog lt input txt 我如何在代码中检测到这一点 一般来说 您无法判
  • Java时区混乱

    我正在运行 Tomcat 应用程序 并且需要显示一些时间值 不幸的是 时间快到了 还有一个小时的休息时间 我调查了一下 发现我的默认时区被设置为 sun util calendar ZoneInfo id GMT 08 00 offset
  • Linux下单个目录下文件过多会怎样?

    如果一个目录中有大约 1 000 000 个单独的文件 大部分大小为 100k 其中没有其他目录和文件 是否会以任何其他可能的方式降低效率或产生缺点 ARG MAX 会对此提出异议 例如 rm rf 在目录中时 会说 参数太多 想要执行某种
  • 有没有办法提高linux管道的性能?

    我正在尝试使用 64 位将超高速数据从一个应用程序传输到另一个应用程序CentOS http en wikipedia org wiki CentOS6 我使用以下方法进行了基准测试dd发现阻碍我的是管道而不是程序中的算法 我的目标是达到
  • BeagleBone Black 如何用作大容量存储设备?

    是否可以使用 BB 作为大容量存储设备 我希望将其连接到可以从 USB 连接 例如 USB 闪存驱动器 读取文件的音频播放器并充当包含一个特定文件夹的数据存储设备 及其子文件夹 从文件系统 如果可能 在连接到开发板的闪存驱动器上 正如设备规
  • 在 MacOS 上构建需要 net461 的 dotnet SDK 项目的最简单方法

    我有一个 dotnet SDK sln and a build proj with
  • 每个虚拟主机的错误日志?

    在一台运行 Apache 和 PHP 5 的 Linux 服务器上 我们有多个带有单独日志文件的虚拟主机 我们似乎无法分离 phperror log虚拟主机之间 覆盖此设置
  • Linux 上的“软/硬 nofile”是什么意思

    当我尝试在RedHat EL5上安装软件时 我得到了错误 软 硬nofile的期望值是4096 而默认值是1024 我设法增加了这个数字 但我不知道参数是什么 他们指的是软链接和硬链接吗 我改变的方法是 a 修改 etc security
  • 使用 .htaccess 启用 PHP 短标签

    我在自己的 Centos 服务器上设置了 Apache 并具有多个虚拟 Web 服务器 并且我希望仅为位于以下位置的其中一个 Web 服务器启用 PHP 短标记 var www ostickets html 我可以通过添加成功启用短标签sh
  • 进程如何知道它已收到信号

    如果我错了 请纠正我 以下是我对信号的理解 据我所知 信号生成 和信号传递有2个不同 事物 为了产生信号 操作系统只是在位数组中设置一个位 在过程控制中维护 工艺块 PCB 每一位 对应于特定信号 当设置一个位时 这意味着 该位对应的信号为
  • 删除 Python 中某些操作的 root 权限

    在我的 Python 脚本中 我执行了一些需要 root 权限的操作 我还创建并写入文件 我不想由 root 独占所有 而是由运行我的脚本的用户独占所有 通常 我使用以下命令运行脚本sudo 有办法做到上述吗 您可以使用以下方式在 uid
  • 设置 Vim 背景颜色

    当我尝试更改背景颜色时 vimrc或者直接在 Vim 中使用以下命令 set background dark 这根本不影响我的背景 也没有light选项 不过 当我运行 gvim 时 看起来还不错 有没有办法在不更改 Konsole 设置的
  • “./somescript.sh”和“. ./somescript.sh”有什么区别

    今天我按照一些说明在 Linux 中安装软件 有一个需要首先运行的脚本 它设置一些环境变量 指令告诉我执行 setup sh 但是我执行时犯了一个错误 setup sh 所以环境没有设置 最后我注意到了这一点并继续进行 我想知道这两种调用脚
  • 使用 hcitool 扫描低功耗蓝牙?

    当我运行此命令时 BLE 设备扫描仅持续 5 秒 sudo timeout 5s hcitool i hci0 lescan 输出显示在终端屏幕中 但是 当我将输出重定向到文件以保存广告设备的地址时 每次运行该命令时 我都会发现该文件是空的
  • 在Linux中创建可执行文件

    我计划做的一件事是编写 非常简单的 Perl 脚本 并且我希望能够在不从终端显式调用 Perl 的情况下运行它们 我明白 要做到这一点 我需要授予他们执行权限 使用 chmod 执行此操作非常简单 但它似乎也是一个稍微费力的额外步骤 我想要
  • 如何从 Linux 命令行确定 LCD 显示器是否打开

    如何通过 Linux 命令行判断计算机的显示器是否打开 关闭 我传统上认为显示器是仅输出的设备 但我注意到 Gnome 显示器首选项对话框具有 检测显示器 功能 这可以推广到确定显示器是否物理关闭吗 VESA DDC 连接是I2C http
  • Linux 阻塞与非阻塞串行读取

    I have 这段代码 https stackoverflow com questions 6947413 how to open read and write from serial port in c用于在Linux中从串行读取 但我不
  • python 可以检测它运行在哪个操作系统下吗?

    python 可以检测操作系统 然后为文件系统构建 if else 语句吗 我需要将 Fn 字符串中的 C CobaltRCX 替换为 FileSys 字符串 import os path csv from time import strf
  • 在Linux中将日期附加到文件名

    我想在文件名旁边添加日期 somefile txt 例如 somefile 25 11 2009 txt 或 somefile 25Nov2009 txt 或任何类似的内容 也许脚本或终端窗口中的某些命令可以执行 我正在使用Linux Ub

随机推荐

  • 配置静态路由小实验

    实验拓扑 实验要求 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中的就绪队