The Linux Programming Interface

(nextflipdebug5) #1

1330 Chapter 63


starve other file descriptors of attention if we perform a large amount of I/O
on one file descriptor. We consider this point in more detail when we describe
the edge-triggered notification model for epoll in Section 63.4.6.
z If the program employs a loop to perform as much I/O as possible on the file
descriptor, and the descriptor is marked as blocking, then eventually an I/O sys-
tem call will block when no more I/O is possible. For this reason, each monitored
file descriptor is normally placed in nonblocking mode, and after notification
of an I/O event, I/O operations are performed repeatedly until the relevant
system call (e.g., read() or write()) fails with the error EAGAIN or EWOULDBLOCK.

63.1.2 Employing Nonblocking I/O with Alternative I/O Models


Nonblocking I/O (the O_NONBLOCK flag) is often used in conjunction with the I/O
models described in this chapter. Some examples of why this can be useful are the
following:

z As explained in the previous section, nonblocking I/O is usually employed in con-
junction with I/O models that provide edge-triggered notification of I/O events.
z If multiple processes (or threads) are performing I/O on the same open file
descriptions, then, from a particular process’s point of view, a descriptor’s
readiness may change between the time the descriptor was notified as being
ready and the time of the subsequent I/O call. Consequently, a blocking I/O call
could block, thus preventing the process from monitoring other file descriptors.
(This can occur for all of the I/O models that we describe in this chapter, regard-
less of whether they employ level-triggered or edge-triggered notification.)
z Even after a level-triggered API such as select() or poll() informs us that a file
descriptor for a stream socket is ready for writing, if we write a large enough
block of data in a single write() or send(), then the call will nevertheless block.
z In rare cases, level-triggered APIs such as select() and poll() can return spurious
readiness notifications—they can falsely inform us that a file descriptor is ready.
This could be caused by a kernel bug or be expected behavior in an uncom-
mon scenario.

Section 16.6 of [Stevens et al., 2004] describes one example of spurious readi-
ness notifications on BSD systems for a listening socket. If a client connects to
a server’s listening socket and then resets the connection, a select() performed
by the server between these two events will indicate the listening socket as
being readable, but a subsequent accept() that is performed after the client’s
reset will block.

63.2 I/O Multiplexing


I/O multiplexing allows us to simultaneously monitor multiple file descriptors to
see if I/O is possible on any of them. We can perform I/O multiplexing using
either of two system calls with essentially the same functionality. The first of these,
select(), appeared along with the sockets API in BSD. This was historically the more
widespread of the two system calls. The other system call, poll(), appeared in System V.
Both select() and poll() are nowadays required by SUSv3.
Free download pdf