Epoll in EPOLLET mode returns 2 EPOLLINs before reading from socket
The epoll man page states that a fd registered with EPOLLET (short-lived) should not notify EPOLLIN twice if a read has not been done.
So after EPOLLIN, you need to flush the buffer before epoll_wait can return a new EPOLLIN for new data.
However, I am having trouble with this approach as I see duplicate EPOLLIN events for untouched fds.
This is the output of strace, 0x200 is EPOLLRDHUP, which is not yet defined in my glibc headers, but is defined in the kernel.
30285 epoll_ctl(3, EPOLL_CTL_ADD, 9, {EPOLLIN|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET|0x2000, {u32=9, u64=9}}) = 0
30285 epoll_wait(3, {{EPOLLIN, {u32=9, u64=9}}}, 10, -1) = 1
30285 epoll_wait(3, {{EPOLLIN, {u32=9, u64=9}}}, 10, -1) = 1
30285 epoll_wait(3, <unfinished ...>
30349 epoll_ctl(3, EPOLL_CTL_DEL, 9, NULL) = 0
30306 recv(9, "7u\0\0\10\345\241\312\t\20\f\32\r\10\27\20\2\30\200\10 \31(C0\17\32\r\10\27\20\2\30"..., 20000, 0) = 20000
30349 epoll_ctl(3, EPOLL_CTL_DEL, 9, NULL) = -1 ENOENT (No such file or directory)
30305 recv(9, " \31(C0\17\32\r\10\27\20\2\30\200\10 \31(C0\17\32\r\10\27\20\2\30\200\10 \31("..., 20000, 0) = 10011
So after adding fd the number 9 I get 2 consecutive EPOLLIN events before uploading the file descriptor, the syscall trace shows me deleting fd before reading, but this should only happen once, one per event.
So either I am not reading the man page correctly, or something is working here now.
a source to share
I think you missed this part of the page epoll
:
Since even when an edge is fired, it is possible to generate multiple epoll events after receiving multiple chunks of data, the caller has the option to specify a flag
EPOLLONESHOT
to tell epoll to disable the associated file descriptor after receiving an event fromepoll_wait(2)
. when the flagEPOLLONESHOT
is specified, it is the responsibility of the caller to reverse the file descriptor usingepoll_ctl(2)
cEPOLL_CTL_MOD
.
That is: you have two pieces of data coming into your receive queue before your first happened read()
, which means you received two epoll events. This seems EPOLLONESHOT
to be what you want, which will automatically remove the file descriptor from the poll set when an event occurs on it (so you don't have to EPOLL_CTL_DEL
).
a source to share
An Edge trigger simply means (if you haven't used EPOLLONESHOT) that you will receive 1 event when something enters the buffer (kernel).
Thus, if you receive 1 EPOLLIN event and do nothing, you will get another EPOLLIN the next time some data enters that handle - if no new data arrives, you will not receive an event, although even if you have not read any data indicated by the first event.
a source to share
Well, okay, EPOLLONESHOT simply means that if you don't read the data you should be reading, it will be discarded.
Typically, you will be notified of an event for the same data if you are not reading it. However, with EPOLLONESHOT, not reading the data is perfectly legal and will simply be ignored. Therefore, there will be no additional events.
a source to share