views:

23

answers:

1

man epoll:

The suggested way to use epoll as an edge-triggered (EPOLLET) interface is as follows:
    i   with nonblocking file descriptors; and
    ii  by waiting for an event only after read(2) or write(2) return EAGAIN.

Imagine we have two fds: the first is passive, data available only sometimes, the second is active, data only sometimes not available.

epoll_wait returned that we can read both. We read { the first, than the second } in a loop (without calls to epoll_wait because of it may suddenly block while the data is still available).

Now the first file descriptor returned EAGAIN on read.

What to do?

  1. If we go on reading the second fd in a loop (without calls to epoll_wait), we can miss that the data have become available on the first fd. It will just read and read and read without EAGAIN.
  2. If we will "consult" with epoll_wait before each read from the second fd, epoll_wait may SUDDENLY block because of nothing changed from the previous call (data still not available on the first FD and still available on the second FD).

How to continue processing of the second FD, but without forgetting about the first FD?

Update: Found one more thing: man epoll_wait:

while specifying timeout equal to zero makes epoll_wait() to return immediately even if no events are available

With this I can enumerate events for FDs even if there are no events.

A: 

If FD2 is constantly readable you might consider that epoll is not appropriate for it. It might be worth spinning off a thread just to sit and read it.

Otherwise, read FD2 in a loop until it is drained but in the loop have it attempt to read FD1 once every X times through. If FD1 has data, read it. If not you'll just get EAGAIN, reset the X counter and go back to reading FD2. When both are drained you are back to epoll_wait.

Something like:

count = 1;

while (true)
{
   read fd2;

   if (EAGAIN)
       break;
   else
       process data;

   count--;

   if (! count)
   {  
       while (true)
       {
           read fd1;

           if (EAGAIN)
               count = 10;
               break;
           else
               process data;
       }
   }
}
Duck
OK, instead of "attempt to read FD1" we can call epoll_wait with zero timeout. But too late: I've already implemented it without EPOLLET (with EPOLLONESHOT) and calling epoll_ctl here and there.
Vi