概要
#include <sys/eventfd.h>
int eventfd(unsigned int initval, int flags);
描述
eventfd()创建一个“eventfd对象”,这个对象能被用户空间应用用作一个事件等待/响应机制,靠内核去响应用户空间应用事件。这个对象包含一个由内核保持的无符号64位整型计数器。这个计数器由参数initval说明的值来初始化。
从linux2.6.27开始,下面的值可以在flags中被 OR 来改变eventfd()的行为:
EFD_NONBLOCK
在新打开的文件描述符中设置O_NONBLOCK文件状态标示。使用这个标示节省了对fcntl的额外调
用。
EFD_CLOEXEC
在新打开的文件描述符中设置close-on-exec(FD_CLOEXEC)标示。
在linux2.6.26版本以下,flags参数都是不能够使用的,必须为0.
eventfd()返回一个新的与eventfd对象关联的文件描述符。下面的操作能在这个文件描述符上执行:
read
如果eventfd计数器为一个非0值,read返回包含这个值的8个字节,并且这个计数器的值被重置为0.(返回的值为主机字节序)。
如果read的时候计数器为0,调用要么阻塞直到计数器变为非0,要么失败返回EAGAIN,如果文件描述符是非阻塞的话。
read会失败返回EINVAL,如果提供的buffer大小小于8字节的话。
write
write调用向计数器增加一个由它的buffer提供的8字节整型值。计数器能存储的最大值是最大的无符号64位整型值少1(0xfffffffffffffffe)。如果增加导致计时器的值超过了最大值,write要么阻塞直到一个read在这个文件描述符上执行,要么返回EAGAIN,如果文件描述法是非阻塞的。
write会失败返回EINVAL,如果提供的buffer大小小于8字节的话,或者如果试图写入值0xffffffffffffff。
poll,select(等)
返回的文件描述符支持poll和select,如下:
文件描述符是可读的(seceltreadfds参数;)如果计数器值大于0.
文件描述符是可写的,如果它可以被写入一个至少为1的值而不会被阻塞。
如果计数器值被检测到溢出了,select会指示这个文件描述符为可读可写。如上所提醒的,write决不能溢出计数器。
eventfd文件描述符也支持其他文件多路转接API:pselcet,ppoll,epoll。
close
当文件描述符不再被需要的时候它要被关闭。当所有和同一个eventfd对象相联系的文件描述符被关系时,对象的资源就被内核清空。
由eventfd()创建的文件描述符拷贝被子进程通过fork所继承。文件描述符的副本是同同一个eventfd对象相联系的。由eventfd()创建的文件描述符在execve时被保留。
返回值
成功时,eventfd()返回一个新的eventfd文件描述符。失败时,返回-1,errno指出错误情况。
错误
EINVAL
标示不合法;在linux2.6.26或更早版本中,flags非0。
EMFILE
到达进程最大打开文件描述符限制。
ENFILE
到达系统总共能打开的文件数。
ENODEV
不能挂载匿名节点设备。
ENOMEM
没有创建一个新eventfd文件描述符的足够内存。
版本
eventfd()自从2.6.22开始可用。glibc版本2.8开始提供支持。eventfd2()系统调用从linux2.6.27开始可用。自从2.9开始,glibc eventfd()用evnetfd2()系统调用封装,如果内核支持的话。
注意
应用可以使用一个eventfd文件描述符来取代一个管道,在所有管道用来作为事件通知的情况下。内核消耗在一个eventfd文件描述符上的远比在一个管道上的少,并且仅需要一个文件描述符(管道需要2个)。
当使用在内核中时,一个eventfd文件描述符能提供一个内核-用户空间的桥梁。
一个关于eventfd要指出的地方是它能像其他文件描述符一样用select,poll。epoll来监控。这意味着一个应用能同时监控:传统“文件的读端,和其他支持eventfd接口的内核机制的读端。
Linux 新api eventfd
eventfd 在内核版本,2.6.22以后有效。查看内核版本可以用命令 uname -r 。
这个函数会创建一个 事件对象 (eventfd object), 用来实现,进程(线程)间 的 等待/通知(wait/notify) 机制. 内核会为这个对象维护一个64位的计数器(uint64_t)。
并且使用第一个参数(initval)初始化这个计数器。调用这个函数就会返回一个新的文件描述符(event object)。2.6.27版本开始可以按位设置第二个参数(flags)。
有如下的一些宏可以使用:
EFD_NONBLOCK , 功能同open(2) 的O_NONBLOCK,设置对象为非阻塞状态,如果没有设置这个状态的话,read(2)读eventfd,并且计数器的值为0 就一直堵塞在read调用当中,要是设置了这个标志, 就会返回一个 EAGAIN 错误(errno = EAGAIN)。效果也如同 额外调用select(2)达到的效果。
EFD_CLOEXEC 我的理解是,这个标识被设置的话,调用exec后会自动关闭文件描述符,防止泄漏。
如果是2.6.26或之前版本的内核,flags 必须设置为0。
创建这个对象后,可以对其做如下操作。
write 将缓冲区写入的8字节整形值加到内核计数器上。
read 读取8字节值, 并把计数器重设为0. 如果调用read的时候计数器为0, 要是eventfd是阻塞的, read就一直阻塞在这里,否则就得到 一个EAGAIN错误。
如果buffer的长度小于8那么read会失败, 错误代码被设置成 EINVAL。
poll select epoll
close 当不需要eventfd的时候可以调用close关闭, 当这个对象的所有句柄都被关闭的时候,内核会释放资源。 为什么不是close就直接释放呢, 如果调用fork 创建
进程的时候会复制这个句柄到新的进程,并继承所有的状态。
下面是一个例子
这个API还是很有用的, 当你想要编写并发型服务器的时候,aventfd 可以完美取代 pipe去通知(唤醒)其他的进程(线程)。比如经典的异步IO reactor/selector
应用场景,去唤醒select的调用。他的缓冲区处理非常方便, 规定只有8字节。
<!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--> 1 #include <sys/eventfd.h>
int eventfd(unsigned int initval, int flags);
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--> 1 #include <sys/eventfd.h>
int eventfd(unsigned int initval, int flags);
这个函数会创建一个 事件对象 (eventfd object), 用来实现,进程(线程)间 的 等待/通知(wait/notify) 机制. 内核会为这个对象维护一个64位的计数器(uint64_t)。
并且使用第一个参数(initval)初始化这个计数器。调用这个函数就会返回一个新的文件描述符(event object)。2.6.27版本开始可以按位设置第二个参数(flags)。
有如下的一些宏可以使用:
EFD_NONBLOCK , 功能同open(2) 的O_NONBLOCK,设置对象为非阻塞状态,如果没有设置这个状态的话,read(2)读eventfd,并且计数器的值为0 就一直堵塞在read调用当中,要是设置了这个标志, 就会返回一个 EAGAIN 错误(errno = EAGAIN)。效果也如同 额外调用select(2)达到的效果。
EFD_CLOEXEC 我的理解是,这个标识被设置的话,调用exec后会自动关闭文件描述符,防止泄漏。
如果是2.6.26或之前版本的内核,flags 必须设置为0。
创建这个对象后,可以对其做如下操作。
write 将缓冲区写入的8字节整形值加到内核计数器上。
read 读取8字节值, 并把计数器重设为0. 如果调用read的时候计数器为0, 要是eventfd是阻塞的, read就一直阻塞在这里,否则就得到 一个EAGAIN错误。
如果buffer的长度小于8那么read会失败, 错误代码被设置成 EINVAL。
poll select epoll
close 当不需要eventfd的时候可以调用close关闭, 当这个对象的所有句柄都被关闭的时候,内核会释放资源。 为什么不是close就直接释放呢, 如果调用fork 创建
进程的时候会复制这个句柄到新的进程,并继承所有的状态。
下面是一个例子
<!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--> 1 #include < sys / eventfd.h >
2 #include < unistd.h >
3 #include < stdio.h >
4 #include < stdint.h >
5 #include < stdlib.h >
6 #include < errno.h >
7
8 #define handle_error(msg) \
9 do { perror(msg); exit( 1 ); } while ( 0 )
10
11 int main( int argc, char ** argv )
12 {
13 uint64_t u;
14 ssize_t s;
15 int j;
16 if ( argc < 2 ) {
17 fprintf(stderr, " input <num> in command argument " );
18 exit( 1 );
19 }
20
21 int efd;
22 if ( (efd = eventfd( 0 , EFD_NONBLOCK)) == - 1 )
23 handle_error( " eventfd failed " );
24
25
26 switch (fork()) {
27 case 0 :
28 for ( j = 1 ; j < argc; j ++ ) {
29 printf( " Child writing %s to efd\n " , argv[j] );
30
31 u = strtoull(argv[j], NULL, 0 ); /* analogesly atoi */
32 s = write(efd, & u, sizeof (uint64_t)); /* append u to counter */
33 if ( s != sizeof (uint64_t) )
34 handle_error( " write efd failed " );
35
36 }
37 printf( " child completed write loop\n " );
38
39 exit( 0 );
40 default :
41 sleep ( 2 );
42
43 printf( " parent about to read\n " );
44 s = read(efd, & u, sizeof (uint64_t));
45 if ( s != sizeof (uint64_t) ) {
46 if (errno = EAGAIN) {
47 printf( " Parent read value %d\n " , s);
48 return 1 ;
49 }
50 handle_error( " parent read failed " );
51 }
52 printf( " parent read %d , %llu (0x%llx) from efd\n " ,
53 s, (unsigned long long )u, (unsigned long long ) u);
54 exit( 0 );
55
56 case - 1 :
57 handle_error( " fork " );
58 }
59 return 0 ;
60 }
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--> 1 #include < sys / eventfd.h >
2 #include < unistd.h >
3 #include < stdio.h >
4 #include < stdint.h >
5 #include < stdlib.h >
6 #include < errno.h >
7
8 #define handle_error(msg) \
9 do { perror(msg); exit( 1 ); } while ( 0 )
10
11 int main( int argc, char ** argv )
12 {
13 uint64_t u;
14 ssize_t s;
15 int j;
16 if ( argc < 2 ) {
17 fprintf(stderr, " input <num> in command argument " );
18 exit( 1 );
19 }
20
21 int efd;
22 if ( (efd = eventfd( 0 , EFD_NONBLOCK)) == - 1 )
23 handle_error( " eventfd failed " );
24
25
26 switch (fork()) {
27 case 0 :
28 for ( j = 1 ; j < argc; j ++ ) {
29 printf( " Child writing %s to efd\n " , argv[j] );
30
31 u = strtoull(argv[j], NULL, 0 ); /* analogesly atoi */
32 s = write(efd, & u, sizeof (uint64_t)); /* append u to counter */
33 if ( s != sizeof (uint64_t) )
34 handle_error( " write efd failed " );
35
36 }
37 printf( " child completed write loop\n " );
38
39 exit( 0 );
40 default :
41 sleep ( 2 );
42
43 printf( " parent about to read\n " );
44 s = read(efd, & u, sizeof (uint64_t));
45 if ( s != sizeof (uint64_t) ) {
46 if (errno = EAGAIN) {
47 printf( " Parent read value %d\n " , s);
48 return 1 ;
49 }
50 handle_error( " parent read failed " );
51 }
52 printf( " parent read %d , %llu (0x%llx) from efd\n " ,
53 s, (unsigned long long )u, (unsigned long long ) u);
54 exit( 0 );
55
56 case - 1 :
57 handle_error( " fork " );
58 }
59 return 0 ;
60 }
http://www.cppblog.com/peija/archive/2010/10/07/128941.html?opt=admin
这个API还是很有用的, 当你想要编写并发型服务器的时候,aventfd 可以完美取代 pipe去通知(唤醒)其他的进程(线程)。比如经典的异步IO reactor/selector
应用场景,去唤醒select的调用。他的缓冲区处理非常方便, 规定只有8字节。
6439

被折叠的 条评论
为什么被折叠?



