Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why having to use non-blocking fd in a edge triggered epoll function?

I read document abount edge triggered epoll function in web as follows:

1. The file descriptor that represents the read side of a pipe (rfd) is registered on the epoll instance.
2. A pipe writer writes 2 kB of data on the write side of the pipe.
3. A call to epoll_wait(2) is done that will return rfd as a ready file descriptor.
4. The pipe reader reads 1 kB of data from rfd.
5. A call to epoll_wait(2) is done.
.......
.......

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

I understood 2, but I couldn't know why nonblocking file descriptors are used.

Could anyone explain the reason why nonblocking file descriptors are used? Why is it all right to use blocking file descriptors in a level triggered epoll function?

like image 703
user1804694 Avatar asked Feb 01 '13 09:02

user1804694


People also ask

What is edge-triggered Epoll?

In edge-triggered mode, a call to epoll_wait will return only when a new event is enqueued with the epoll object, while in level-triggered mode, epoll_wait will return as long as the condition holds.

What is epoll socket?

epoll_ctl() is a control function that allows us to add descriptors to a watch set, remove descriptors from a watch set, or reconfigure file descriptors already in the watch set. epoll_wait() waits for I/O events on the watch set, blocking the calling thread until one or more events are detected.

How do I make a non blocking socket?

To mark a socket as non-blocking, we use the fcntl system call. Here's an example: int flags = guard(fcntl(socket_fd, F_GETFL), "could not get file flags"); guard(fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK), "could not set file flags"); Here's a complete example.

How epoll works?

epoll monitors I/O events for multiple file descriptors. epoll supports edge trigger (ET) or level trigger (LT), which waits for I/O events via epoll_wait and blocks the calling thread if no events are currently available. select and poll only support LT working mode, and the default working mode of epoll is LT mode.


1 Answers

The idea is to try to completely drain the file descriptor when you have an edge-triggered notification that there is data to be had. So, once epoll() returns, you loop over the read() or write() until it returns -EAGAIN when there is no more data to be had.

If the fd was opened blocking, then this last read() or write() would also block, and you wouldn't have the chance to go back to the epoll() call to wait on the entire set of fds. When opened nonblocking, the last read()/write() does return, and you do have the chance to go back to polling.

This is not so much of a concern when using epoll() in a level-triggered fashion, since in this case epoll() will return immediately if there is any data to be had. So a (pseudocode) loop such as:

while (1) {
  epoll();
  do_read_write();
}

would work, as you're guaranteed to call do_read_write() as long as there is data. When using edge-triggered epoll, there is potential for the notification that new data is available to be missed, if it comes in between the finish of do_read_write() and the next call to epoll().

like image 104
sheu Avatar answered Sep 25 '22 09:09

sheu