Libev源码分析07:Linux下的eventfd简介
#include <sys/eventfd.h> int eventfd(unsigned int initval, int flags);
eventfd创建一个eventfd对象,该对象可用于用户空间的程序实现事件等待、通知机制,也可用于由内核向用户空间的应用进行事件的通知。eventfd对象在内核中包含了一个计数器,该计数器是64位的无符号整数(uint64_t),该计数器由eventfd函数的initval参数进行初始化。
在Linux2.6.26之前的版本,flags参数是无用的,必须置为0。从Linux2.6.27开始,可以在flags中指定下面的值以改变eventfd的行为:
EFD_NONBLOCK:在新建的文件描述符上设置O_NONBLOCK文件状态标志;
EFD_CLOEXEC:在新建的文件描述符上设置FD_CLOEXEC标志。
eventfd返回的文件描述符可以执行下面的操作:
read:如果eventfd的计数器的值非0,则read操作在一个8字节缓冲区中返回该值,并且将计数器重置为0,返回的值是主机字节序。如果计数器的值为0,若文件描述符设置为非阻塞的话,则read返回EAGAIN错误,否则,read一直阻塞,直到计数器非0。
如果提供给read的缓冲区长度小于8字节的话,read返回EINVAL错误。
write:write操作会将buffer中的8字节整数加到计数器上。计数器的最大值是64位无符号整数的最大值减1,也就是0xfffffffffffffffe。如果增加计数器的值会超过该最大值,若文件描述符设置成非阻塞的话,则write返回EAGAIN错误,否则,write操作会一直阻塞,直到在该文件描述符上执行了read操作。
如果write缓冲区的大小小于8字节,或者直接写0xffffffffffffffff的话,write将返回EINVAL错误。也就是说,下面的代码,不管计数器的当前值是多少,write操作都会返回EINVAL错误:
unsigned char buf[8] = {0};
memset(buf, 0xff, 8);
write(efd, buf, 8);
poll、select、epoll等:eventfd创建的文件描述符支持poll、epoll和select等操作:
如果计数器的值大于0,则该文件描述符可读;
如果在该描述符上至少能非阻塞的写入1,则该描述符就是可写的;
如果检测到计数器发生了溢出,则select会指示该文件描述符可读且可写;poll会返回POLLERR事件。上面提到的write操作不可能会使得计数器溢出。然而,KAIO子系统执行的2^64 eventfd “signal posts”操作会导致计数器溢出。这种情况,尽管理论上是可能的,但实际上却不太可能。如果确实发生了溢出,则read操作将会返回0xffffffffffffffff。
close:当不再需要该文件描述符时,应该使用close关闭。与其他文件描述符一样,如果底层eventfd对象关联的所有文件描述符都关闭之后,则该对象的资源就会被内核释放掉。
与其他文件描述符类似,fork之后,子进程拥有父进程的eventfd文件描述符的副本,它们指向相同的底层eventfd对象。执行execve之后,除非设置了close-on-exec标志,否则eventfd创建的描述符在子进程中依然保留。
eventfd调用成功,返回新的eventfd文件描述符,失败时返回-1,并设置相应的errno。
eventfd是linux特有的,自linux2.6.22才开始引入,在glibc的2.8版本中开始被支持。
在应用程序使用管道处理信号事件的所有场景中,可以用eventfd替换pipe。内核使用eventfd文件描述符的负载要比pipe低很多,并且仅仅使用一个描述符即可,而不是像pipe那样使用两个。
在内核中使用eventfd时,eventfd文件描述符起到了桥接内核和用户空间的作用,允许像KAIO(内核异步IO)这样的功能给一个文件描述符发送某些操作已经完成的信号。
eventfd文件描述符的关键优势在于它能够用于select、poll或者epoll。这样,应用程序可以同时监听常规文件和支持eventfd接口的其他内核机制的可读性。
例子:
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0) int main(int argc, char *argv[])
{
int efd, j;
uint64_t u;
ssize_t s; if (argc < 2)
{
fprintf(stderr, "Usage: %s <num1> <num2>...\n", argv[0]);
exit(EXIT_FAILURE);
} efd = eventfd(0, 0);
if (efd == -1)
handle_error("eventfd"); switch (fork())
{
case 0:
for (j = 1; j < argc; j++)
{
printf("Child writing %s to efd\n", argv[j]);
u = strtoull(argv[j], NULL, 0);
s = write(efd, &u, sizeof(uint64_t));
if (s != sizeof(uint64_t))
handle_error("write");
}
printf("Child completed write loop\n"); exit(EXIT_SUCCESS); default:
wait(); printf("Parent about to read\n");
s = read(efd, &u, sizeof(uint64_t));
if (s != sizeof(uint64_t))
handle_error("read"); printf("Parent read %llu (0x%llx) from efd\n",
(unsigned long long) u, (unsigned long long) u);
exit(EXIT_SUCCESS); case -1:
handle_error("fork");
}
}
结果:
# ./a.out 11 23 1
Child writing 11 to efd
Child writing 23 to efd
Child writing 1 to efd
Child completed write loop
Parent about to read
Parent read 35 (0x23) from efd
Libev源码分析07:Linux下的eventfd简介的更多相关文章
- [转]Libev源码分析 -- 整体设计
Libev源码分析 -- 整体设计 libev是Marc Lehmann用C写的高性能事件循环库.通过libev,可以灵活地把各种事件组织管理起来,如:时钟.io.信号等.libev在业界内也是广受好 ...
- QTimer源码分析(以Windows下实现为例)
QTimer源码分析(以Windows下实现为例) 分类: Qt2011-04-13 21:32 5026人阅读 评论(0) 收藏 举报 windowstimerqtoptimizationcallb ...
- Libev源码分析09:select突破处理描述符个数的限制
众所周知,Linux下的多路复用函数select采用描述符集表示处理的描述符.描述符集的大小就是它所能处理的最大描述符限制.通常情况下该值为1024,等同于每个进程所能打开的描述符个数. 增大描述符集 ...
- SpringAOP使用及源码分析(SpringBoot下)
一.SpringAOP应用 先搭建一个SpringBoot项目 <?xml version="1.0" encoding="UTF-8"?> < ...
- Spring AMQP 源码分析 07 - MessageListenerAdapter
### 准备 ## 目标 了解 Spring AMQP 如何用 POJO 处理消息 ## 前置知识 <Spring AMQP 源码分析 04 - MessageListener> ## 相 ...
- 内核源码分析之linux内核栈(基于3.16-rc4)
在3.16-rc4内核源码中,内核给每个进程分配的内核栈大小为8KB.这个内核栈被称为异常栈,在进程的内核空间运行时或者执行异常处理程序时,使用的都是异常栈,看下异常栈的代码(include/linu ...
- JDK源码分析(三)——HashMap 下(基于JDK8)
目录 概述 内部字段及构造方法 哈希值与索引计算 存储元素 扩容 删除元素 查找元素 总结 概述 在上文我们基于JDK7分析了HashMap的实现源码,介绍了HashMap的加载因子loadFac ...
- Libev源码分析01:Libev中的监视器结构(C结构体实现继承)
在Libev的源码中,用到了一种用C实现类似C++中继承的技巧,主要是用宏和结构体实现. 在Libev中,最关键的数据结构就是各种监视器,比如IO监视器,信号监视器等等.这些监视器的多数成员都是一样的 ...
- Libev源码分析06:异步信号同步化--sigwait、sigwaitinfo、sigtimedwait和signalfd
一:信号简述 信号是典型的异步事件.内核在某个信号出现时有三种处理方式: a:忽略信号,除了SIGKILL和SIGSTOP信号不能忽略外,其他大部分信号都可以被忽略: b:捕捉信号,也就是在信号发生时 ...
随机推荐
- Javaweb Form表单查询
1.表单(form),是一种可以由用户输入,并提交给服务器端的一个图形界面,有如下性质: (1)表单中可以输入一些内容,这些输入功能由控件提供,叫做表单元素 (2)表单中一般都有一个按钮负责提交 (3 ...
- centos 安装nginx + 多个tomcat负载均衡
今天在centos上安装了两个tomcat和nginx,进行配置.今天记录的只是最基本的实现测试.(不包含使用redis进行session共享) Nginx 是一款轻量级的Web 服务器/反向代理服务 ...
- 洛谷P1390 公约数的和 [2017年6月计划 数论12]
P1390 公约数的和 题目描述 有一天,TIBBAR和LXL比赛谁先算出1~N这N个数中每任意两个不同的数的最大公约数的和.LXL还在敲一个复杂而冗长的程序,争取能在100s内出解.而TIBBAR则 ...
- 2019阿里云开年Hi购季云通信分会场全攻略!
2019阿里云云上Hi购季活动已经于2月25日正式开启,从已开放的活动页面来看,活动分为三个阶段: 2月25日-3月04日的活动报名阶段.3月04日-3月16日的新购满返+5折抢购阶段.3月16日-3 ...
- 表格存储TableStore2.0重磅发布,提供更强大数据管理能力
表格存储TableStore是阿里云自研的面向海量结构化和半结构化数据存储的Serverless NoSQL多模型数据库,被广泛用于社交.物联网.人工智能.元数据和大数据等业务场景.表格存储Table ...
- 洛谷 1447 [NOI2010]能量采集——容斥/推式子
题目:https://www.luogu.org/problemnew/show/P1447 1.容斥原理 求 f [ i ] 表示 gcd==i 的对数,先 f [ i ] = (n/i) * (m ...
- Ubuntu的网络共享
实际场景 公司项目中遇到一个场景:Ubuntu的主机上装了个4G卡(USB模式),需要将这个4G网共享给一个AP,使得所有连接AP的移动设备都可以通过4G上外网 方法很简单: 1. 将4G网口之外的另 ...
- 【JZOJ5064】【GDOI2017第二轮模拟day2】友好城市 Kosarajo算法+bitset+ST表+分块
题面 在Byteland 一共有n 座城市,编号依次为1 到n,这些城市之间通过m 条单向公路连接. 对于两座不同的城市a 和b,如果a 能通过这些单向道路直接或间接到达b,且b 也能如此到达a,那么 ...
- Python3.7.4入门-6/7错误和异常/类
6 错误和异常 while True: try: x = int(input("Please enter a number: ")) break except ValueError ...
- Java.控制层.响应工具类.
Java.控制层.响应工具类. package cn.com.spdbccc.cds.index.web.base; public class ApiResponse { private int co ...