The documentation is unclear as to whether events are combined or not and my tests show that they are in some occasions but not always.
Consider man 7 epoll
:
Since even with edge-triggered epoll, multiple events can be generated upon receipt of multiple chunks of data, the caller has the option to specify the EPOLLONESHOT flag...
and the Q&A section:
Q7 If more than one event occurs between epoll_wait(2) calls, are they combined or reported separately?
A7 They will be combined.
I assume the first statement from the manual means that you can receive more than one EPOLLIN event in situations like reading from a socket, a packet arrives, you read it, then another packet arrives. And the answer from the Q&A section is talking about different events like EPOLLIN and EPOLLOUT. Please correct me if I'm wrong.
I was playing around with some code in order to understand better how epoll works and it appears to behave differently regarding the same kind of event based on whether another one is set or not. More precisely, if I'm waiting only for EPOLLIN, multiple inputs generate a single event, but if I'm waiting for both EPOLLIN and EPOLLOUT, multiple inputs generate multiple events.
Here's the code I used to test this:
#include <stdio.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
struct epoll_event ev = {EPOLLIN|EPOLLOUT|EPOLLET};
int epoll = epoll_create1(0);
epoll_ctl(epoll, EPOLL_CTL_ADD, 0, &ev);
//async stdin
int flags = fcntl(0, F_GETFL);
flags |= O_NONBLOCK;
fcntl(0, F_SETFL, flags);
while(1){
struct epoll_event events[64];
int n = epoll_wait(epoll, events, 64, -1);
printf("Event count: %d\n", n);
if(events[0].events == EPOLLIN)
printf("EPOLLIN only\n\n");
else
if(events[0].events == (EPOLLIN|EPOLLOUT))
printf("EPOLLIN and EPOLLOUT\n\n");
else
printf("EPOLLOUT only\n\n");
char buffer[256];
read(0, buffer, 256);
sleep(1);
}
return 0;
}
The output after pressing return shows that both EPOLLIN and EPOLLOUT are received, this message appears as many times as return was pressed, then it shows only EPOLLOUT being generated.
But if you compile the program without the EPOLLOUT flag and press return many times, a single event will be reported only once.
If I remove the read
call, EPOLLIN continues to be reported when EPOLLOUT is set, but doesn't when only EPOLLIN is set.
Is the behavior dependent on which events it's waiting for or there's something wrong with my test code? If it is dependent, can I rest assured it won't change in the future?