I'm currently adding sockfds created from accept to an epoll instance with the following events:
const int EVENTS = (
EPOLLET |
EPOLLIN |
EPOLLRDHUP |
EPOLLONESHOT |
EPOLLERR |
EPOLLHUP);
Once an event is triggered, I pass it off to a handler thread, read and then re-enable the sockfd through epoll_ctl
with the same flags. However, I only receive the EPOLLIN
event one time. Also, if I kill the client anytime after the first event is received, I do not get hangup events either. From reading the man pages, I thought I understood the correct approach with EdgeTriggered and OneShot.
Below is some pseudo code for the process I'm using:
const int EVENTS = (
EPOLLET |
EPOLLIN |
EPOLLRDHUP |
EPOLLONESHOT |
EPOLLERR |
EPOLLHUP);
void event_loop()
{
struct epoll_event event;
struct epoll_event *events;
events = calloc(100, sizeof event);
while (1)
{
int x;
int num_events = epoll_wait(epfd, events, 100, -1);
for (x = 0; x < num_events; x++)
{
another_thread(fd);
}
}
}
void another_thread(int fd)
{
// Read stuff until EAGAIN
struct epoll_event event;
event.data.fd = fd;
event.events = EVENTS;
epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &event);
}
When I do the EPOLL_CTL_MOD
operation, I do not receive any errors, but never get notified of other events. If I leave the read loop on repeat after the first event, it will read all subsequent data sent by client, so I know that the data is coming in and the fd is still open and working.
From checking strace
, threads are created from clone and have the flag CLONE_FILES
, so all threads share the same fd table.
What is the correct way to re-enable a fd for read events from a separate thread?
another_thread()
: doing the "Read stuff until EAGAIN" after the call toepoll_ctl()
to reactivate the edge trigger. There is a race condition otherwise: new data could enter the read buffer between the EAGAIN return from the I/Oread()
operation and the call toepoll_ctl()
, which would lose the edge trigger. – Charisecharisma