Alternative I/O Models 1371- The signal handler is installed after creating the pipe, in order to prevent
 the race condition that would occur if a signal was delivered before the
 pipe was created.
- It is safe to use write() inside the signal handler, because it is one of the
 async-signal-safe functions listed in Table 21-1, on page 426.
- Place the select() call in a loop, so that it is restarted if interrupted by a signal
 handler. (Restarting in this fashion is not strictly necessary; it merely means
 that we can check for the arrival of a signal by inspecting readfds, rather than
 checking for an EINTR error return.)
- On successful completion of the select() call, we can determine whether a signal
 arrived by checking if the file descriptor for the read end of the pipe is set in
 readfds.
- Whenever a signal has arrived, read all bytes that are in the pipe. Since multiple
 signals may arrive, employ a loop that reads bytes until the (nonblocking) read()
 fails with the error EAGAIN. After draining the pipe, perform whatever actions
 must be taken in response to delivery of the signal.
This technique is commonly known as the self-pipe trick, and code demonstrating
this technique is shown in Listing 63-9.
Variations on this technique can equally be employed with poll() and epoll_wait().
Listing 63-9: Using the self-pipe trick
–––––––––––––––––––––––––––––––––––––––––––––––––––––from altio/self_pipe.c
static int pfd[2]; / File descriptors for pipe /
static void
handler(int sig)
{
int savedErrno; / In case we change 'errno' /
savedErrno = errno;
if (write(pfd[1], "x", 1) == -1 && errno != EAGAIN)
errExit("write");
errno = savedErrno;
}
int
main(int argc, char argv[])
{
fd_set readfds;
int ready, nfds, flags;
struct timeval timeout;
struct timeval pto;
struct sigaction sa;
char ch;
