The Linux Programming Interface

(nextflipdebug5) #1
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.



  1. 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.)

  2. 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.

  3. 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;

Free download pdf