Add Book to My BookshelfPurchase This Book Online

Chapter 10 - Signals

UNIX Systems Programming for SVR4
David A. Curry
 Copyright © 1996 O'Reilly & Associates, Inc.

Unreliable Signals
Signal handling in older versions of UNIX (Version 7, pre-SVR3 versions of System V, and pre-4.2BSD versions of Berkeley UNIX) was unreliable. Signals could get lost—a signal could occur and the process would never find out about it.
One of the most significant problems with these early implementations, though, is that they reset a caught signal's disposition to its default each time the signal was delivered. If the signal arrived a second time, the default disposition would be taken, instead of calling the signal handler. To see the problems that this can cause, start signal1 again and send it two SIGUSR1 signals. The first one is caught as intended, but the second one causes the program to terminate! This is because the default disposition for SIGUSR1 terminates the process.
The usual method to avoid this situation is to modify the handler function to reset the signal's disposition each time it is called, as shown in Example 10-2.
Example 10-2:  signal2
#include <signal.h>
#include <stdio.h>
void handler(int);
int
main(void)
{
    /*
     * Send SIGUSR1 and SIGUSR2 to the handler function.
     */
    if (signal(SIGUSR1, handler) == SIG_ERR) {
        fprintf(stderr, "cannot set handler for SIGUSR1\n");
        exit(1);
    }
    if (signal(SIGUSR2, handler) == SIG_ERR) {
        fprintf(stderr, "cannot set handler for SIGUSR2\n");
        exit(1);
    }
    /*
     * Now wait for signals to arrive.
     */
    for (;;)
        pause();
}
/*
* handler - handle a signal.
*/
void
handler(int sig)
{
    /*
     * Reset the signal's disposition.
     */
    signal(sig, handler);
    /*
     * Print out what we received.
     */
    psignal(sig, "Received signal");
}
    % signal2 &
    [1] 12345
    % kill -USR1 12345
    Received signal: Signal User 1
    % kill -USR2 12345
    Received signal: Signal User 2
    % kill -USR1 12345
    Received signal: Signal User 1
    % kill -USR2 12345
    Received signal: Signal User 2
    % kill 12345
    [1] + Terminated     signal2
Unfortunately, this solution is imperfect. There is a window of vulnerability between the time that the signal handler is called and the time it resets the signal's disposition during which the default disposition is still in effect. On very busy systems, or when signals are being sent rapid-fire to the process, it is possible for the signal to be missed by the signal handler, resulting in unintended behavior.
 NoteAs mentioned previously, the SIGCHLD signal is different from all the others. Because SIGCHLDs “reappear” as soon as the signal handler is reset, using the above approach of resetting the handler as soon as it is entered will not work. Instead, the following model should be used:
    void
    handler(int sig)
    {
        /* code */
·
·
·
          signal(SIGCHLD, handler);
    }
A second problem with the early implementations is that there was no way to turn a signal off when a process didn't want it to occur. The process could ignore the signal, but there was no way to say “don't deliver this signal right now, but save it for later when I'm ready.” To see the problems this can cause, consider the following code fragment:
    int flag = 0;
    void handler(int);
    
    int
    main(void)
    {
        ...
        signal(SIGALRM, handler);
    
        while (flag == 0)
            pause();
        ...
    }
    
    void
    handler(sig)
    {
        signal(SIGALRM, handler);
        flag = 1;
    }
This program continually sits in pause until an alarm signal occurs, at which point flag will become 1 and it will exit the while loop. But, consider the case where the alarm signal arrives after the test of flag, but before the call to pause. The program will enter pause and never return (unless the signal is generated a second time). The signal has been lost.

Previous SectionNext Section
Books24x7.com, Inc © 2000 –  Feedback