Epoll in modalità EPOLLET ritorno 2 EPOLLIN prima di leggere dalla presa
-
28-09-2019 - |
Domanda
La pagina del manuale epoll dice che un fd registrato con EPOLLET (fronte attivato) non dovresti avvisare EPOLLIN due volte se non di lettura è stato fatto.
Così, dopo un EPOLLIN è necessario svuotare il buffer prima epoll_wait essere in grado di restituire una nuova EPOLLIN su nuovi dati.
Comunque sto sperimentando problemi con questo approccio, come sto vedendo eventi EPOLLIN duplicati per FDS incontaminati.
Questa è l'uscita strace, 0x200 è EPOLLRDHUP che non è ancora definita nei miei intestazioni glibc ma definita nel 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
Quindi, dopo aver aggiunto il numero 9 fd io ricevono 2 eventi EPOLLIN consecutivi prima di avere recving il descrittore di file, le syscall traccia mostra come faccio a cancellare il fd prima di leggere, ma dovrebbe avvenire solo una volta, uno per ogni evento.
Quindi, o io non sto leggendo la pagina di manuale correttamente o qualcosa sta lavorando qui.
Soluzione
Credo che vi siete persi questa parte della pagina epoll
man:
Dal momento che anche con il bordo-triggered epoll più eventi possono essere generati al ricevimento di molteplici pezzi di i dati, il chiamante ha la possibilità di specificare il flag
EPOLLONESHOT
, a dire epoll per disabilitare il associato descrittore di file dopo il ricevimento un evento conepoll_wait(2)
. quando viene specificato il flagEPOLLONESHOT
, è responsabilità del chiamante riarmare il descrittore di file tramiteepoll_ctl(2)
conEPOLL_CTL_MOD
.
Questo è: hai due blocchi di dati che arrivano nella vostra coda di ricezione prima del primo read()
accaduto, il che significa che avete ottenuto due eventi epoll. Sembra EPOLLONESHOT
è quello che stai dopo, che atomicamente rimuovere il descrittore di file dal set sondaggio quando si verifica un evento su di essa (in modo che non sarà necessario fare il EPOLL_CTL_DEL
).
Altri suggerimenti
Bordo grilletto significa semplicemente (a meno che non hai EPOLLONESHOT usato) che si otterrà 1 evento quando qualcosa entra nella (kernel) tampone.
Quindi, se si ottiene 1 evento EPOLLIN e non fare nulla su di esso, si otterrà un altro EPOLLIN la prossima volta che alcuni dati che arriva sul descrittore - se non arrivano nuovi dati, non si ottiene un evento, però, anche se non ha letto i dati come indicato dal primo evento.
Bene, per dirla succintamente, EPOLLONESHOT significa solo che se non si leggono i dati che si suppone di leggere, saranno scartati.
In genere, devi essere avvisato con un evento per gli stessi dati, se non li leggono. Con EPOLLONESHOT, tuttavia, non la lettura dei dati è perfettamente legale e saranno semplicemente ignorato. Quindi, saranno generati ulteriori eventi.