是Epoll与边沿触发和单稳只有一次报告 [英] Epoll with edge triggered and oneshot only reports once
问题描述
我目前正在增加从创建sockfds接受以一个epoll的实例以下事件:
const int的活动=(
EPOLLET |
EPOLLIN |
EPOLLRDHUP |
EPOLLONESHOT |
EPOLLERR |
EPOLLHUP);
一旦事件被触发,我将其传递给一个处理线程,读,然后重新启用通过 epoll_ctl
具有相同的标志的sockfd。不过,我只收到 EPOLLIN
事件一次。另外,如果我杀了接收第一个事件后,可随时在客户端,我不明白挂断事件无论是。从阅读手册页,我想我明白与EdgeTriggered和ONESHOT正确的做法。
下面是一些伪code为我使用的过程:
const int的活动=(
EPOLLET |
EPOLLIN |
EPOLLRDHUP |
EPOLLONESHOT |
EPOLLERR |
EPOLLHUP);无效event_loop()
{
结构epoll_event事件;
结构epoll_event *事件;
事件=释放calloc(100,sizeof的事件);
而(1)
{
INT X;
INT NUM_EVENTS = epoll_wait(epfd的,事件,100,-1);
为(X = 0; X&下; NUM_EVENTS; X ++)
{
another_thread(FD);
}
}
}无效another_thread(INT FD)
{
//读取的东西,直到EAGAIN 结构epoll_event事件;
event.data.fd = FD;
event.events =活动;
epoll_ctl(epfd的,EPOLL_CTL_MOD,FD&安培;事件);
}
当我做 EPOLL_CTL_MOD
的操作,我没有收到任何错误,但从来没有得到通知的其他事件。如果我离开重复读取循环的第一个事件之后,它会读取客户端发送的所有后续数据,所以我知道数据是进来和FD仍处于打开状态和工作。
从检查 strace的
,从的克隆并有标志 CLONE_FILES
,因此所有线程共享相同的fd表。
什么是正确的方式,从一个单独的线程重新启用读事件FD?
不过,我只收到EPOLLIN事件一次。另外,如果我杀了接收第一个事件后,可随时在客户端,我不明白挂断事件无论是。
块引用>有关epoll_ctl手册页(2)说:
EPOLLONESHOT(因为Linux 2.6.2)
设置相关联的文件描述符单触发行为。
这意味着,一个事件后与拉出
epoll_wait(2)关联的文件描述符是内部
残疾并没有其他事件将被epoll的报告
接口。用户必须调用epoll_ctl()与EPOLL_CTL_MOD
再装一个新的事件掩码的文件描述符。
块引用>
块引用>在你的情况,当你得到第一个事件,epoll的禁用你的sockfd。
使用EPOLL_CTL_MOD
,将通知由内核收到的所有事件当您重新启用的sockfd 的之后的的重新注册。因此,首先通知和重新注册之间的任何事件都将丢失。这可能是原因没有得到任何挂起的事件或数据。删除
EPOLLONESHOT
从事件会纠正你的code,最终你不也需要重新启用的sockfd。此外,由于使用的是
EPOLLET
,将不会有任何性能问题也。I'm currently adding sockfds created from accept to an epoll instance with the following events:
const int EVENTS = ( EPOLLET | EPOLLIN | EPOLLRDHUP | EPOLLONESHOT | EPOLLERR | EPOLLHUP);
Once an event is triggered, I pass it off to a handler thread, read and then re-enable the sockfd through
epoll_ctl
with the same flags. However, I only receive theEPOLLIN
event one time. Also, if I kill the client anytime after the first event is received, I do not get hangup events either. From reading the man pages, I thought I understood the correct approach with EdgeTriggered and OneShot.Below is some pseudo code for the process I'm using:
const int EVENTS = ( EPOLLET | EPOLLIN | EPOLLRDHUP | EPOLLONESHOT | EPOLLERR | EPOLLHUP); void event_loop() { struct epoll_event event; struct epoll_event *events; events = calloc(100, sizeof event); while (1) { int x; int num_events = epoll_wait(epfd, events, 100, -1); for (x = 0; x < num_events; x++) { another_thread(fd); } } } void another_thread(int fd) { // Read stuff until EAGAIN struct epoll_event event; event.data.fd = fd; event.events = EVENTS; epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &event); }
When I do the
EPOLL_CTL_MOD
operation, I do not receive any errors, but never get notified of other events. If I leave the read loop on repeat after the first event, it will read all subsequent data sent by client, so I know that the data is coming in and the fd is still open and working.From checking
strace
, threads are created from clone and have the flagCLONE_FILES
, so all threads share the same fd table.What is the correct way to re-enable a fd for read events from a separate thread?
解决方案However, I only receive the EPOLLIN event one time. Also, if I kill the client anytime after the first event is received, I do not get hangup events either.
man page for epoll_ctl(2) says that:
EPOLLONESHOT (since Linux 2.6.2) Sets the one-shot behavior for the associated file descriptor. This means that after an event is pulled out with epoll_wait(2) the associated file descriptor is internally disabled and no other events will be reported by the epoll interface. The user must call epoll_ctl() with EPOLL_CTL_MOD to rearm the file descriptor with a new event mask.
In your case, when you get the first event, epoll disables your sockfd. When you re-enable your sockfd using
EPOLL_CTL_MOD
, it will notify all the events that are received by kernel after the re-registration. So any event between first notification and re-registration will be lost. This can be reason for not getting any hangup events or data.Removing
EPOLLONESHOT
from events will correct your code, eventually you don't need to re-enable sockfd also.And since you are using
EPOLLET
, there won't be any performance issue also.这篇关于是Epoll与边沿触发和单稳只有一次报告的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!