本文从WordPress迁移而来, 查看全部WordPress迁移文章

epoll原理简述:epoll = 一颗红黑树 + 一张准备就绪句柄链表 + 少量的内核cacheselect/poll 每次调用时都要传递你所要监控的所有socket给select/poll系统调用,这意味着需要将用户态的socket列表copy到内核态,如果以万计的句柄会导致每次都要copy几十几百KB的内存到内核态,非常低效。

调用epoll_create后,内核就已经在内核态开始准备帮你存储要监控的句柄了,每次调用epoll_ctl只是在往内核的数据结构里塞入新的socket句柄。

epoll向内核注册了一个文件系统,用于存储上述的被监控socket。当调用epoll_create时,就会在这个虚拟的epoll文件系统里创建一个file结点。当然这个file不是普通文件,它只服务于epoll。

epoll在被内核初始化时(操作系统启动),同时会开辟出epoll自己的内核高速cache区,用于安置每一个我们想监控的socket,这些socket会以红黑树的形式保存在内核cache里,以支持快速的查找、插入、删除。

这个内核高速cache区,就是建立连续的物理内存页,然后在之上建立slab层,简单的说,就是物理上分配好你想要的size的内存对象,每次使用时都是使用空闲的已分配好的对象。

调用epoll_create时,内核除了帮我们在epoll文件系统里建了个file结点,在内核cache里建了个红黑树用于存储以后epoll_ctl传来的socket外,还会再建立一个list链表,用于存储准备就绪的事件,当epoll_wait调用时,仅仅观察这个list链表里有没有数据即可。有数据就返回,没有数据就sleep,等到timeout时间到后即使链表没数据也返回。

通常情况下即使我们要监控百万计的句柄,大多一次也只返回很少量的准备就绪句柄而已,所以,epoll_wait仅需要从内核态copy少量的句柄到用户态而已

这个准备就绪list链表是怎么维护的呢?当我们执行epoll_ctl时,除了把socket放到epoll文件系统里file对象对应的红黑树上之外,还会给内核中断处理程序注册一个回调函数,告诉内核,如果这个句柄的中断到了,就把它放到准备就绪list链表里。

所以,当一个socket上有数据到了,内核在把网卡上的数据copy到内核中后就来把socket插入到准备就绪链表里了。

【转】epoll的两种工作模式:

Epoll的2种工作方式-水平触发(LT)和边缘触发(ET)

假如有这样一个例子:

我们已经把一个用来从管道中读取数据的文件句柄(RFD)添加到epoll描述符

这个时候从管道的另一端被写入了2KB的数据

调用epoll_wait(2),并且它会返回RFD,说明它已经准备好读取操作

然后我们读取了1KB的数据

调用epoll_wait(2)……

Edge Triggered 工作模式:

如果我们在第1步将RFD添加到epoll描述符的时候使用了EPOLLET标志,那么在第5步调用epoll_wait(2)之后将有可能会挂起,因为剩余的数据还存在于文件的输入缓冲区内,而且数据发出端还在等待一个针对已经发出数据的反馈信息。只有在监视的文件句柄上发生了某个事件的时候 ET 工作模式才会汇报事件。因此在第5步的时候,调用者可能会放弃等待仍在存在于文件输入缓冲区内的剩余数据。在上面的例子中,会有一个事件产生在RFD句柄上,因为在第2步执行了一个写操作,然后,事件将会在第3步被销毁。因为第4步的读取操作没有读空文件输入缓冲区内的数据,因此我们在第5步调用 epoll_wait(2)完成后,是否挂起是不确定的。epoll工作在ET模式的时候,必须使用非阻塞套接口,以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死。最好以下面的方式调用ET模式的epoll接口,在后面会介绍避免可能的缺陷。

基于非阻塞文件句柄

只有当read(2)或者write(2)返回EAGAIN时才需要挂起,等待。但这并不是说每次read()时都需要循环读,直到读到产生一个EAGAIN才认为此次事件处理完成,当read()返回的读到的数据长度小于请求的数据长度时,就可以确定此时缓冲中已没有数据了,也就可以认为此事读事件已处理完成。

Level Triggered 工作模式:

相反的,以LT方式调用epoll接口的时候,它就相当于一个速度比较快的poll(2),并且无论后面的数据是否被使用,因此他们具有同样的职能。因为即使使用ET模式的epoll,在收到多个chunk的数据的时候仍然会产生多个事件。调用者可以设定EPOLLONESHOT标志,在 epoll_wait(2)收到事件后epoll会与事件关联的文件句柄从epoll描述符中禁止掉。因此当EPOLLONESHOT设定后,使用带有

EPOLL_CTL_MOD标志的epoll_ctl(2)处理文件句柄就成为调用者必须作的事情。

struct epoll_event1

2

3

4

5

6

7

8

9

10

11typedef union epoll_data {

void *ptr;

int fd;

__uint32_t u32;

__uint64_t u64;

} epoll_data_t;

//感兴趣的事件和被触发的事件

struct epoll_event {

__uint32_t events; /* Epoll events */

epoll_data_t data; /* User data variable */

};

所以当我们在epoll中为一个文件注册一个事件时,如果不需要什么额外的信息,只需要简单在epoll_data.fd = 当前文件的fd

(尽管这并不是必须的,在网上找到的几乎所有的博客都是这样写,呵呵)

但是当我们需要一些额外的数据的时候,就要用上void* ptr;

我们可以自定义一种类型,例如my_data,然后让ptr指向它,以后取出来的时候就能用了;

最后,记住union的特性,它只会保存最后一个被赋值的成员,所以不要data.fd,data.ptr都赋值;通用的做法就是给ptr赋值,fd只是有些时候为了演示或怎么样罢了

所以个人的想法是,其实epoll_data完全可以就是一个void*,不过可能为了一些简单的场景,才设计成union,包含了fd,u32,u64

linux内核event原理,linux epoll epoll的原理;struct epoll_event 为什么要这样设计相关推荐

  1. linux内核 can总线,Linux Canbus调试笔记

    http://blog.csdn.net/flydream0/article/details/8161418 CAN总线在嵌入式Linux下驱动程序的实现 http://www.21ic.com/ap ...

  2. 【Linux 内核】编译 Linux 内核 ⑤ ( 查看 .config 编译配置文件 | 正式编译内核 )

    文章目录 一.查看 .config 编译配置文件 二.正式编译内核 一.查看 .config 编译配置文件 在上一篇博客 [Linux 内核]编译 Linux 内核 ④ ( 打开 Linux 内核编译 ...

  3. 【Linux 内核】编译 Linux 内核 ① ( 下载指定版本的 Linux 内核源码 | Linux 内核版本号含义 | 主版本号 | 次版本号 | 小版本号 | 稳定版本 )

    文章目录 一.下载 Linux 内核 1.下载最新版本 Linux 内核 2.下载指定版本 Linux 内核 二.Linux 内核版本号含义 一.下载 Linux 内核 1.下载最新版本 Linux ...

  4. 简述arm linux内核启动流程,Linux内核启动过程和Bootloader(总述)

    1.Linux内核启动过程概述 一个嵌入式 Linux 系统从软件角度看可以分为四个部分:引导加载程序(Bootloader),Linux 内核,文件系统,应用程序.其中 Bootloader是系统启 ...

  5. 武汉linux内核好找吗,Linux内核入门

    Linux内核入门 收藏 如何获取Linux内核源代码 下载Linux内核当然要去http://www.kernel.org/了,网站提供了两种文件下载,一种是完整的Linux内核,另一种是内核增量补 ...

  6. linux 内核优化实战,Linux编译优化必须掌握的几个姿势总结

    01.编译选项和内核编译 Linux内核(英语:linux kernel),是一种计算机操作系统内核,已C语言和汇编语言写成,匹配POSIX标准,以GNU通用公共许可证发布.从技术上说Linux只是一 ...

  7. 编译Linux内核没有zImage,Linux 编译系统的简单介绍与内核编译安装

    这里不只是讲怎样编译.安装Linux内核的,更主要的是介绍内核的编译系统和各个重要的文件.最后还利用学到的编译.安装Linux内核去修改Linux的01调度变成随机调度.如果你只是需要编译.安装内核的 ...

  8. Linux内核及主流Linux发行版对应关系汇总

    Linux内核及主流Linux发行版对应关系汇总 如需转载请标明出处:http://blog.csdn.net/itas109 QQ技术交流群:129518033 文章目录 Linux内核及主流Lin ...

  9. linux的头文件下载,Linux内核头文件(linux headers)

    更新 Linux 内核头文件(linux headers) 三 8th, 2013 2,474 views | 发表评论 | Trackback 一般来说,如果不是自己编译 kernel,那么更新头文 ...

  10. 【Linux 内核】编译 Linux 内核 ⑦ ( 安装内核模块 | 安装内核 | 重启系统 | 查看当前内核版本 )

    文章目录 一.安装内核模块 二.安装内核 三.重启系统 四.查看当前内核版本 一.安装内核模块 确保 Linux 内核编译完成 , 没有任何报错之后 ; 参考 [Linux 内核]编译 Linux 内 ...

最新文章

  1. MySQL的存储引擎与日志说明
  2. IOS-Core Data的使用
  3. php nl2br() 函数
  4. 十、从中缀向后缀转换表达式
  5. fatal error C1083: 无法打开预编译头文件:“Debug\a.pch”:No such file or directory
  6. 【数字逻辑】第四章 组合逻辑电路:端口设计 端口拓展的方法
  7. 高通骁龙888来了!新命名就是为了中国,小米11将全球首发
  8. 通过binlog恢复mysql备份之前的数据
  9. .eslintrc.js相关配置
  10. python 文本处理操作
  11. PSQL容器带脚本初始化
  12. 【UVA11059】Maximum Product(set+set默认从大到小排列---水题)
  13. 智能额温枪软件设计红外测温仪方案开发
  14. STC51单片机16——将输入信号2倍频
  15. 电感和磁珠有哪些区别
  16. 电线电缆很烫,都有哪些原因
  17. 【电力预测】基于matlab GUI灰色模型电力负荷预测【含Matlab源码 769期】
  18. 细胞穿透肽八精氨酸、 H2N-RRRRRRRR-OH、 148796-86-5
  19. postgis的扩展包fuzzystrmatch和postgis_tiger_geocoder的安装
  20. linux高并发开发视频教程,求视频教程- 基于linux百万级高并发框架Skynet-王桂林-专题视频课程...

热门文章

  1. android 命名空间解析,Android Bluetooth、Android AdapterView等命名空间-Android中文API文档...
  2. 计算机电缆执行标准是什么,DJYVP计算机电缆执行标准
  3. wps 模拟分析 规划求解_综合能源系统:规划及运行优化智慧决策平台介绍
  4. c语言rotl函数需要什么头文件,_rotl, _crotl, _lrotl
  5. c++ builder 2010论坛_CHiF中国血液创新论坛 | 领域大咖带您开启CLL的个体化治疗之门...
  6. matlab怎么调出来的,如何调出MATLAB内部函数的源程序?
  7. 【POJ2774】Long Long Message(求两个字符串的最长公共子串----后缀数组)
  8. android中横向滑动功能,Android开发基于ViewPager+GridView实现仿大众点评横向滑动功能...
  9. Java获取resin端口_线上解决Resin服务响应过慢的几个方法
  10. XGBoost 损失函数Loss Functions