1370 Chapter 63
Listing 63-8: Using pselect()
sigset_t emptyset, blockset;
struct sigaction sa;
sigemptyset(&blockset);
sigaddset(&blockset, SIGUSR1);
if (sigprocmask(SIG_BLOCK, &blockset, NULL) == -1)
errExit("sigprocmask");
sa.sa_sigaction = handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGUSR1, &sa, NULL) == -1)
errExit("sigaction");
sigemptyset(&emptyset);
ready = pselect(nfds, &readfds, NULL, NULL, NULL, &emptyset);
if (ready == -1)
errExit("pselect");
The ppoll() and epoll_pwait() system calls
Linux 2.6.16 also added a new, nonstandard system call, ppoll(), whose relationship
to poll() is analogous to the relationship of pselect() to select(). Similarly, starting with
kernel 2.6.19, Linux also includes epoll_pwait(), providing an analogous extension
to epoll_wait(). See the ppoll(2) and epoll_pwait(2) manual pages for details.
63.5.2 The Self-Pipe Trick
Since pselect() is not widely implemented, portable applications must employ other
strategies to avoid race conditions when simultaneously waiting for signals and call-
ing select() on a set of file descriptors. One common solution is the following:
- Create a pipe, and mark its read and write ends as nonblocking.
- As well as monitoring all of the other file descriptors that are of interest,
include the read end of the pipe in the readfds set given to select(). - Install a handler for the signal that is of interest. When this signal handler is
called, it writes a byte of data to the pipe. Note the following points about the
signal handler:- The write end of the pipe was marked as nonblocking in the first step to
prevent the possibility that signals arrive so rapidly that repeated invocations
of the signal handler fill the pipe, with the result that the signal handler’s
write() (and thus the process itself) is blocked. (It doesn’t matter if a write
to a full pipe fails, since the previous writes will already have indicated the
delivery of the signal.)
- The write end of the pipe was marked as nonblocking in the first step to