epoll API
执行一个类似的任务来poll
:监视多个文件描述符来查看是否有任何I / O
是可能的。 epoll API
既可以用作edge-triggered
的接口,也可以用作Level-triggered
的接口,并可以很好地扩展到大量的观察文件描述符。 提供以下系统调用来创建和管理epoll
实例:
* epoll_create
创建一个epoll实例并返回一个引用该实例的文件描述符。 (最近的epoll_create1
扩展了epoll_create
的功能。)
*对特定文件描述符的兴趣是通过epoll_ctl
注册的。 当前在epoll
实例上注册的文件描述符集有时被称为epoll集。
* epoll_wait
等待I / O事件,如果当前没有事件可用,则阻塞调用线程。
级别触发和边缘触发
Level-triggered and edge-triggered
#include <sys/epoll.h>
int epoll_create(int size);
int epoll_create1(int flags);
epoll_create()
创建一个epoll
实例。自从Linux 2.6.8,xize参数被忽略,但必须大于零;
epoll_create()
返回一个引用新的epoll
实例的文件描述符。此文件描述符用于所有后续对epoll
接口的调用。当不再需要时,epoll_create()
返回的文件描述符应该使用close
来关闭。当所有引用epoll
实例的文件描述符都被关闭时,内核将销毁实例并释放相关资源以供重用。
epoll_create1()
如果flags
为0,那么除了废弃大小参数被删除之外,epoll_create1()
与epoll_create()
相同。标志中可以包含以下值以获得不同的行为:
EPOLL_CLOEXEC
在新文件描述符上设置close-on-exec(FD_CLOEXEC)
标志。请参阅open
中O_CLOEXEC
标志的说明。
返回值
成功时,这个系统调用返回一个非负文件描述符。出错时,返回-1,并将errno
设置为指示错误。
错误:
EINVAL
size不正确
EINVAL (epoll_create1())
flags中指定的值无效。
在最初的epoll_create()
实现中,size
参数向内核通知了调用者期望添加到epoll实例的文件描述符的数量。 内核使用这个信息作为提示描述事件的内部数据结构中最初分配的空间量。 (如果需要的话,如果调用者的用法超出了给定的提示,内核将分配更多的空间)。现在,这个提示不再需要(内核动态地调整所需数据结构的大小,而不需要提示),但大小必须是 大于零,以确保在旧的内核上运行新的epoll应用程序时向后兼容。
epoll_ctl
: epoll描述符的控制接口
#include <sys/epoll.h>
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
该系统调用对文件描述符epfd
引用的epoll
实例执行控制操作。 它要求对目标文件描述符fd执行操作。
op
参数的有效值是:
EPOLL_CTL_ADD
在文件描述符epfd
引用的epoll
实例上注册目标文件描述符fd
,并将事件event
与链接到fd的内部文件相关联。
EPOLL_CTL_MOD
更改与目标文件描述符fd关联的事件event
。
EPOLL_CTL_DEL
从epfd
引用的epoll
实例中删除(注销)目标文件描述符fd
。 该事件被忽略,可以是NULL
(但请参阅下面的BUGS)。
event
参数描述链接到文件描述符fd的对象。 结构epoll_event被定义为:
typedef 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; /* 用户数据变量 */
};
events成员是使用以下可用事件类型组成的位掩码:
EPOLLIN
关联的文件可用于read
操作。
EPOLLOUT
关联的文件可用于write
操作。
EPOLLRDHUP (since Linux 2.6.17)
流套接字关闭连接,或关闭写入连接的一半。 (当使用Edge Triggered
监视时,这个标志对编写简单的代码来检测对等关闭特别有用。)
EPOLLPRI
紧急数据可用于read
操作。
EPOLLERR
错误情况发生在关联的文件描述符上。epoll_wait
将一直等待这个事件; 没有必要把它设置在事件中。
EPOLLHUP
挂起发生在关联的文件描述符上。 epoll_wait
将一直等待这个事件; 没有必要把它设置在事件中。 请注意,从管道或流套接字等通道读取时,此事件仅表示对等关闭了通道的末端。 只有在通道中所有未完成的数据被消耗之后,通道的后续读才会返回0(文件的结尾)。
EPOLLET
设置关联文件描述符的边缘触发行为。 epoll的默认行为是电平触发。
EPOLLONESHOT (since Linux 2.6.2)
设置关联文件描述符的一次性行为。 这意味着在事件被epoll_wait
pull out之后,关联的文件描述符被内部禁用,epoll接口不会报告其他事件。 用户必须使用
EPOLL_CTL_MOD
调用epoll_ctl()
以使用新的事件掩码重新装入文件描述符。
在2.6.9之前的内核版本中,EPOLL_CTL_DEL
操作在event
中需要一个非空指针,即使这个参数被忽略。 从Linux 2.6.9开始,使用EPOLL_CTL_DEL
时,event
可以指定为NULL
。 需要在2.6.9之前移植到内核的应用程序应该在event
中指定一个非空指针。
如果在flags
中指定EPOLLWAKEUP
,但调用者不具有CAP_BLOCK_SUSPEND
功能,则EPOLLWAKEUP
标志将被忽略。 这种不幸的行为是必要的,因为在原始实现中对flags参数没有进行有效性检查,并且在调用者没有CAP_BLOCK_SUSPEND
能力的情况下,通过检查导致调用失败的EPOLLWAKEUP
的添加至少导致了破坏 一个现有的用户空间应用程序发生随机(无用)指定此位。 因此,如果尝试使用EPOLLWAKEUP
标志,强健的应用程序应该仔细检查它是否具有CAP_BLOCK_SUSPEND
功能。
更多参数类型参照 man
文档。
epoll_pwait
- 等待epoll
文件描述符上的I / O
事件
#include <sys/epoll.h>
int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);
int epoll_pwait(int epfd, struct epoll_event *events,int maxevents, int timeout,const sigset_t *sigmask);
epoll_wait()
系统调用等待文件描述符epfd
引用的epoll
实例上的事件。 事件指向的内存区域将包含调用程序可用的事件。 epoll_wait()
返回最多的事件。 maxevents
参数必须大于零。
timeout
参数指定epoll_wait()
将阻塞的毫秒数。 该呼叫将阻止,直到:
*文件描述符传递一个事件;
*呼叫被信号处理程序中断;
*超时到期。
请注意,timeout
间隔将四舍五入到系统时钟粒度,并且内核调度延迟意味着阻塞间隔可能会超出一小部分。 指定-1的timeout
会导致epoll_wait()
无限期地被阻塞,同时指定一个等于零的timeout
会导致epoll_wait()立即返回,即使没有事件可用。
结构epoll_event
被定义为:
typedef 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 */
};
每个返回结构体的data
将包含用户使用epoll_ctl(EPOLL_CTL_ADD,EPOLL_CTL_MOD)
设置的相同数据,而events
成员将包含返回的事件位字段。
在2.6.37之前的内核中,超过大约LONG_MAX / HZ
毫秒的timeout
值被视为-1
(即,无穷大)。 因此,例如,在sizeof(long)
为4且kernel HZ
值为1000
的系统上,这意味着大于35.79
分钟的超时被视为无穷大。
C library/kernel differences
原始epoll_pwait()
系统调用具有第六个参数,size_t sigsetsize
,它指定了sigmask
参数的大小(以字节为单位)。glibc epoll_pwait()
包装函数将此参数指定为固定值(等于sizeof(sigset_t)
)。