1374 Chapter 63
Further information
[Stevens et al., 2004] describes I/O multiplexing and signal-driven I/O, with partic-
ular emphasis on the use of these mechanisms with sockets. [Gammo et al, 2004] is
a paper comparing the performance of select(), poll(), and epoll.
A particularly interesting online resource is at http://www.kegel.com/c10k.html.
Written by Dan Kegel, and entitled “The C10K problem,” this web page explores
the issues facing developers of web servers designed to simultaneously serve tens of
thousands of clients. The web page includes a host of links to related information.
63.7 Exercises
63-1. Modify the program in Listing 63-2 (poll_pipes.c) to use select() instead of poll().
63-2. Write an echo server (see Sections 60.2 and 60.3) that handles both TCP and UDP
clients. To do this, the server must create both a listening TCP socket and a UDP
socket, and then monitor both sockets using one of the techniques described in
this chapter.
63-3. Section 63.5 noted that select() can’t be used to wait on both signals and file
descriptors, and described a solution using a signal handler and a pipe. A related
problem exists when a program needs to wait for input on both a file descriptor
and a System V message queue (since System V message queues don’t use file
descriptors). One solution is to fork a separate child process that copies each
message from the queue to a pipe included among the file descriptors monitored
by the parent. Write a program that uses this scheme with select() to monitor input
from both the terminal and a message queue.
63-4. The last step of the description of the self-pipe technique in Section 63.5.2 stated
that the program should first drain the pipe, and then perform any actions that
should be taken in response to the signal. What might happen if these substeps
were reversed?
63-5. Modify the program in Listing 63-9 (self_pipe.c) to use poll() instead of select().
63-6. Write a program that uses epoll_create() to create an epoll instance and then
immediately waits on the returned file descriptor using epoll_wait(). When, as in this
case, epoll_wait() is given an epoll file descriptor with an empty interest list, what
happens? Why might this be useful?
63-7. Suppose we have an epoll file descriptor that is monitoring multiple file descriptors,
all of which are always ready. If we perform a series of epoll_wait() calls in which
maxevents is much smaller than the number of ready file descriptors (e.g., maxevents
is 1), without performing all possible I/O on the ready descriptors between calls,
what descriptor(s) does epoll_wait() return in each call? Write a program to
determine the answer. (For the purposes of this experiment, it suffices to perform
no I/O between the epoll_wait() system calls.) Why might this behavior be useful?
63-8. Modify the program in Listing 63-3 (demo_sigio.c) to use a realtime signal instead of
SIGIO. Modify the signal handler to accept a siginfo_t argument and display the
values of the si_fd and si_code fields of this structure.