Epoll в режиме EPOLLET, возвращающий 2 EPOLLIN перед чтением из сокета - PullRequest
2 голосов
/ 20 апреля 2010

Страница руководства 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 перед чтением, но это должно происходить только один раз, по одному на событие. Так что либо я не правильно читаю справочную страницу, либо что-то здесь работает.

Ответы [ 3 ]

7 голосов
/ 20 апреля 2010

Я думаю, что вы пропустили эту часть epoll справочной страницы:

Так как даже с запущенным фронтом epoll несколько событий могут быть сгенерированы при получении нескольких кусков данные, вызывающая сторона имеет возможность укажите флаг EPOLLONESHOT, чтобы скажите epoll, чтобы отключить связанный дескриптор файла после получения событие с epoll_wait(2). когда указан флаг EPOLLONESHOT, это обязанность звонящего перезапустите дескриптор файла, используя epoll_ctl(2) с EPOLL_CTL_MOD.

То есть: у вас есть две порции данных, поступающих в вашу очередь на получение до того, как произошла ваша первая read(), что означает, что вы получили два события epoll. Похоже, что EPOLLONESHOT - это то, что вам нужно, которое атомарно удалит дескриптор файла из набора опроса, когда с ним произойдет событие (поэтому вам не нужно будет делать EPOLL_CTL_DEL).

2 голосов
/ 20 апреля 2010

Триггер Edge просто означает (если вы не использовали EPOLLONESHOT), что вы получите 1 событие, когда что-то попадет в (ядро) буфер.

Таким образом, если вы получаете 1 событие EPOLLIN и ничего не делаете с ним, вы получите еще один EPOLLIN, когда в следующий раз некоторые данные поступят по этому дескриптору - если новые данные не поступят, вы не получите событие, даже если вы не прочитал данные, указанные первым событием.

0 голосов
/ 20 июля 2011

Говоря кратко, EPOLLONESHOT просто означает, что если вы не прочитаете данные, которые должны прочитать, они будут отброшены.

Как правило, вы будете уведомлены с событием для тех же данных, если вы не читаете их. С EPOLLONESHOT, однако, не чтение данных совершенно законно, и они будут просто проигнорированы. Следовательно, дальнейшие события не будут генерироваться.

...