Страница руководства epoll сообщает, что fd, зарегистрированный в EPOLLET (инициируемый край), не должен дважды уведомлять EPOLLIN, если не было выполнено чтение.
Поэтому после EPOLLIN вам нужно очистить буфер до того, как epoll_wait сможет вернуть новый EPOLLIN для новых данных.
Однако у меня возникают проблемы с этим подходом, так как я вижу дублированные события EPOLLIN для нетронутых fds.
Это вывод strace, 0x200 - это EPOLLRDHUP, который еще не определен в моих заголовках glibc, но определен в ядре.
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
Итак, после добавления fd номер 9 я получаю 2 последовательных события EPOLLIN до получения дескриптора файла, трассировка системного вызова показывает, как я удаляю fd перед чтением, но это должно происходить только один раз, по одному на событие.
Так что либо я не правильно читаю справочную страницу, либо что-то здесь работает.