From: elewis@kong.gsfc.nasa.gov (Ed Lewis - Code 522)
Subject: Trying to wait for SIGALRM and SIGINT
Keywords: POSIX, signals
Organization: Goddard Space Flight Center
Date: Tue, 7 Apr 92 17:37:26 GMT

I am trying to write a program that allows me to catch SIGALRM and SIGINT.
The following program, as written, does this (along with handling SIGUSR1 &
SIGUSR2), but it uses way to much CPU time.  I execute a semi-infinite
while loop (busy-waiting if you will) to wait for the occurance of
signals.  (Note: the only way to kill this from the same window is to
suspend the process and kill -9 %1 it.)

In the while loop I have four system calls that are designed to block until
arrival of a signal.  They are each commented out.  The problem is that
neither of the calls sucessfully waits for both SIGINT and SIGALRM.  The
first three (sigpause [yeah, I realize this isn't POSIX], pause, sigsuspend)
handle SIGALRM ok, but just kill the process when SIGINT arrives.  (The
arrival of SIGINT should not stop the process because I commented out the
flag assignment.)  The fourth (sleep) catches SIGINT correctly, but it
screws up the interval timer, so SIGALRM doesn't arrive.

My questions are: Is there "wait here" call that I should be using that I
don't know about?  Am I missing something in my own program?  What is
the capital of South Dakota?  Should I seek professional help?

To compile and run this program, you need only cc the file.  There are
no mysterious include files or libraries required.

Thanks in advance,
Ed Lewis
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Cut here~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* This program tests the trapping and handling of signals under POSIX
    restrictions.  Right now the program waits for the occurrance of a
    signal within a while loop.  There are four possibly ways to block
    the process so that it doesn't chew CPU, but they are all commented
    out, with a question.
*/
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>

/*
    Globals shared between the handler and the main routine
*/

int timetogo;
char message[80];
int have_message;

/* signal handler -- it sets a message to indicate what was caught and 
                    sets the have_messsage flag
                    It also would set the termination flag if it wasn't
                    commented out for the test, and it resets the alarm clock
*/
handle_break(sig)
{
    switch (sig)
    {
        case SIGINT:
            sprintf (message, "Interrupt handler called, sig = SIGINT\n");
            break;
        case SIGALRM:
            sprintf (message, "Interrupt handler called, sig = SIGALRM\n");
            break;
        case SIGUSR1:
            sprintf (message, "Interrupt handler called, sig = SIGUSR1\n");
            break;
        case SIGUSR2:
            sprintf (message, "Interrupt handler called, sig = SIGUSR2\n");
            break;
        default:
            sprintf (message, "Interrupt handler called, sig = %d\n", sig);
    }
    have_message = 1;
/*  if (sig == SIGINT) timetogo = 1;    Don't want to leave while testing */
    if (sig == SIGALRM) alarm(2);
}

main ()
{
    int                 i, ct1, ct2;
    sigset_t            empty,full;
    struct sigaction    action;

/* Set up utility variables */

    timetogo = 0;
    have_message = 0;
    message[0] = '\0';
    sigemptyset (&empty);
    sigfillset (&full);

/* Fill in the signal action structure --> tell signal to call the handler,
    and allow only SIGTSTP to interupt the handler
*/

    action.sa_handler = (void *)handle_break;
    sigfillset (&action.sa_mask);
    sigdelset (&action.sa_mask, SIGTSTP);
    action.sa_flags = 0;

/* Initialize signal handling */

    for (i = SIGHUP; i <= SIGUSR2; i++)
        if (i == SIGKILL || i == SIGSTOP || i == SIGTSTP)
            continue;
        else if (sigaction (i, &action, 0) == -1)
        {
            perror ("sigaction");
            printf ("           i is %d\n", i);
        }

/* Set variables for while loop */

    sigprocmask (SIG_SETMASK, &empty, 0);
    alarm (2);
    ct1 = 0; /* Just a dumb counter */
    ct2 = 0; /* Just a dumb counter */

    while(!timetogo)
    {
/*---------------------------------------------------------------------------*\
|What should I use here?  The first three don't handle the SIGINT correctly   |
|-- they just exit -- and the last doesn't handle the timer right.  If I use  |
|none, the program works correctly, but chews CPU.                            |
\*---------------------------------------------------------------------------*/

        /*if (sigsuspend (&sigset) == -1) perror ("sigsuspend");*/
        /*if (sigpause(0) == -1) perror ("sigpause");*/
        /*if (pause() == -1) perror ("pause");*/
        /*if (sleep(3) == -1) perror ("sleep");*/

/* Would be used to indicate the "number" of "wakeups." */

        /*printf ("."); fflush(stdout);*/

/* Periodically throw a SIGUSR1 */

        if (ct1++ == 33333)
        {
            kill (getpid(),SIGUSR1);
            ct1 = 0;
        }

/* Periodically throw a SIGUSR2 */

        if (ct2++ == 100000)
        {
            kill (getpid(),SIGUSR2);
            ct2 = 0;
        }

/* If the handler was called, print the message */

        if (have_message)
        {
            printf ("Message is : %s", message);
            fflush (stdout);
        }

/* Reset the globals, but don't permit any signals to be hit while doing so
    (atomic actions and all that jazz).
*/

        if (sigprocmask (SIG_SETMASK, &full, 0) == -1) perror ("sigproc/full");
        have_message = 0;
        message[0] = '\0';
        if (sigprocmask (SIG_SETMASK, &empty, 0) == -1) perror("sigproc/empty");
    }

    printf ("\n");
}