The Linux Programming Interface

(nextflipdebug5) #1

1366 Chapter 63


insignificant compared to the time required for the system call to monitor N
descriptors. Table 63-9 doesn’t include the times for the inspection step.

Very roughly, we can say that for large values of N (the number of file descriptors
being monitored), the performance of select() and poll() scales linearly with N. We
start to see this behavior for the N = 100 and N = 1000 cases in Table 63-9. By the
time we reach N = 10000, the scaling has actually become worse than linear.
By contrast, epoll scales (linearly) according to the number of I/O events that
occur. The epoll API is thus particularly efficient in a scenario that is common in
servers that handle many simultaneous clients: of the many file descriptors being
monitored, most are idle; only a few descriptors are ready.

63.4.6 Edge-Triggered Notification


By default, the epoll mechanism provides level-triggered notification. By this, we
mean that epoll tells us whether an I/O operation can be performed on a file
descriptor without blocking. This is the same type of notification as is provided by
poll() and select().
The epoll API also allows for edge-triggered notification—that is, a call to
epoll_wait() tells us if there has been I/O activity on a file descriptor since the previous
call to epoll_wait() (or since the descriptor was opened, if there was no previous call).
Using epoll with edge-triggered notification is semantically similar to signal-driven
I/O, except that if multiple I/O events occur, epoll coalesces them into a single
notification returned via epoll_wait(); with signal-driven I/O, multiple signals may
be generated.
To employ edge-triggered notification, we specify the EPOLLET flag in ev.events
when calling epoll_ctl():

struct epoll_event ev;

ev.data.fd = fd
ev.events = EPOLLIN | EPOLLET;
if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, ev) == -1)
errExit("epoll_ctl");

We illustrate the difference between level-triggered and edge-triggered epoll notifi-
cation using an example. Suppose that we are using epoll to monitor a socket for
input (EPOLLIN), and the following steps occur:


  1. Input arrives on the socket.

  2. We perform an epoll_wait(). This call will tell us that the socket is ready, regard-
    less of whether we are employing level-triggered or edge-triggered notification.

  3. We perform a second call to epoll_wait().


If we are employing level-triggered notification, then the second epoll_wait() call
will inform us that the socket is ready. If we are employing edge-triggered notifica-
tion, then the second call to epoll_wait() will block, because no new input has
arrived since the previous call to epoll_wait().
Free download pdf