epoll的原理及用法
英文源文件来自http://linux.die.net/man/4/epoll
名字
epoll-I/O事件消息通知器
包含文件
#include <sys/epoll.h>
描述
epoll是一个poll的变种,它可以用来作为边沿或者电平触发接口,可以很好的扩展到大量的监管的fds(文件描述符)。在建立和控制一个epoll
集合的过程中会有以下三个call: epoll_create, epoll_ctl, epoll_wait.
epoll_create建立一个连接到fd的epoll set. 至于对某个特定的fds,则是通过epoll_ctl, 最后,实际的等待是通过epoll_wait启动。
札记(Note)
这个epoll的事件分布接口都可以以边沿触发(Edge Triggered ( ET ) )和电平触发( Level Triggered ( LT ))的形式表现。ET和LT事件分布
机制的区别在于以下描述的几点。假设有如下情形发生:
1. fd代表的读管道(RFD)的读被加在了epoll 设备里。
2. 管道写者写了2Kb的数据在写管道。
3. epoll_wait 的调用完成,并将返回作为就绪df的RFD。
4. 管道读者从RFD读了1Kb的数据。
5. epoll_wait的调用完成。
如果RFD已经通过使用EPOLLET flag被加入了epoll设备,在步骤5完成的epoll_wait调用将很能挂住,这是因为现有的数据仍然存在于文件输入缓冲区,而远程对等的一方可能在等待对以已经发出的数据为基础的回应。导致这样的原因是ET事件分布只对发生在被监视的文件上的事件发布事件。所以,在步骤5时,调用者可能会对已经存在输入缓冲里的一些数据停止epoll_wait。在上面的这个例子中,由于步骤2的读完成,将会产生一个RFD的事件,这个事件在步骤3会被消耗掉。由于在步骤4完成的读操作没有消耗完所有的buffer data. 在步骤5完成的epoll_wait调用可能会无限期的锁住。使用EPOLLET flag的epoll 接口将使用非阻塞式的df来避免在操作fd的任务时发生读阻塞或者写饥饿。推荐作为ET接口使用的epoll方法如下,可以避免可能的缺陷:
i 使用 non-blocking fd。
ii 待等待一个事件完成后,才读或则写。
相反,当使用LT(电平触发)接口时,epoll不管如何都是一个更快的poll,只要后者可以使用LT就可以用,因为他们拥有相同的语义。由于即使使用ET(边沿触发)的epoll,多块数据的接受可以激发多个事件,调用者有可以选择指定EPOLLONESHOT flag的选项,来告诉epoll在收到epoll_wait的事件后可以disable关联的df。当EPOLLONESHOT flag被指定了,重整fd将是调用者的责任,通过使用EPOLL_CTL_MOD选项。
推荐使用的例子
struct epoll_event ev, *events; for(;;) { nfds = epoll_wait(kdpfd, events, maxevents, -1); for(n = 0; n < nfds; ++n) { if(events[n].data.fd == listener) { client = accept(listener, (struct sockaddr *) &local, &addrlen); if(client < 0){ perror("accept"); continue; } setnonblocking(client); ev.events = EPOLLIN | EPOLLET; ev.data.fd = client; if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, client, &ev) < 0) { fprintf(stderr, "epoll set insertion error: fd=%d0, client); return -1; } } else do_use_fd(events[n].data.fd); } }
Q&A (from linux-kernel)
Q1 : 如果往epoll_set里面添加了两次相同的fd会发生什么?
A1:你将和可能会得到EEXIST.然后,两个线程两次添加相同的fd是可能发生的。这是一种无害情形。
Q2:两个epoll set 可以等待相同的fd吗?如果这样,事件报告的是两个epoll sets fd 吗?
A2:是的。但是,不推荐这么使用。是,它对两个fd都会。
Q3:epoll fd 本身就是 poll/epoll/selectable吗?
A3: 是的。
Q4: 如果epoll fd被添加如到它自己的fd sets中会发生什么?
A4: 它将会失败。但是,你可以在另外一个epoll fd sets 里添加epoll fd。
Q5:我可以把epoll fd通过unix-socket送到另外一个进程吗?
A5: 不行。
Q6:关闭一个fd会导致它自动从所有的epoll sets中自动被移出来吗?
A6: 会。