local/signal.c

///////////////////////////////////////////////////////////////////////////////
// Filename: signal.c
///////////////////////////////////////////////////////////////////////////////
// Purpose: demonstrates the use of signals
///////////////////////////////////////////////////////////////////////////////
// History:
// ========
//
// Date     Time     Name      Description   
// -------- -------- --------  ------------------------------------------------
// 96/03/19 01:11:12 muellerg: created
//
///////////////////////////////////////////////////////////////////////////////


// Feature test switches ///////////////////////////// Feature test switches //
    /* NONE */



// System headers /////////////////////////////////////////// System headers //

#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

 
// Local headers ///////////////////////////////////////////// Local headers //

#include "../common.h"



// Macros /////////////////////////////////////////////////////////// Macros //
    /* NONE */



// File scope objects /////////////////////////////////// File scope objects //
    /* NONE */



// External variables, functions, and classes ///////////// External objects //
    /* NONE */



// Signal catching functions ///////////////////// Signal catching functions //

static void signalhandler(int signo)
{
    cout << "Signal " << signo << " recognized!" << endl << flush;
    return;
}



// Structures, unions, and class definitions /////////////////// Definitions //
    /* NONE */



// Functions and class implementation /// Functions and class implementation //
    /* NONE */



// Main /////////////////////////////////////////////////////////////// Main //

/* This example program shows how to protect the interrupt signal
 * to be delivered in a critical region of code 
 */

int
main(int argc, char *argv[])
{
    error.set_program_name(argv[0]);    

    // signal masks
    sigset_t newmask, oldmask, zeromask, testmask;
    bool interrupted = false;

    // set up signal handler

    struct sigaction handle_sig;
    handle_sig.sa_handler = &signalhandler; // function to call
    sigemptyset(&handle_sig.sa_mask);       // no need to block other signals
    handle_sig.sa_flags   = 0;              // no special flags. 

    // set new handler into action
    if(sigaction(SIGINT, &handle_sig, NULL) != 0)
                error.system("sigaction error: can't install signal handler");

    sigemptyset(&zeromask);                 // clear all signals in signal mask

    sigemptyset(&newmask);                  // generate signal mask with SIGINT
    sigaddset(&newmask, SIGINT);    


    // ...

    // the program is doing some non-critical things
    cout << "The program can be interrupted here with CTRL-C" << endl;
    cout << "(sleeping for 5 seconds)" << endl;
    sleep(5);

    // ...

    // now the program wants to make sure that it is not interrupted
    // via the SIGINT signal: the SIGINT signal is blocked and the
    // current signal mask saved
    
    if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
        error.system("can't block signal");

    cout << "Entering critical section... CTRL-C is not delivered..." << endl;
    // now the program can do all the critical work...
    sleep(5);
    // ...

    // We can test for a pending signal like this:
    if(sigpending(&testmask) <0)
        error.system("sigpending error");

    if(sigismember(&testmask, SIGINT))
    {
        cout << "You have pressed CTRL-C in the critical section" 
             << " without the signal beeing delivered to the process yet"
             << endl;
        interrupted = true;
    }

    // The program might now want to wait for any signal

    // sigsuspend() is used to atomically swap out the signal mask,
    // while waiting for a signal.

    cout << "Now all signals are delivered." << endl;

    if(interrupted == false)
    {
        cout << "Please generate a signal for this process (e.g. by"
             << " pressing CTRL-C) to continue" << endl;
    }

    if(sigsuspend(&zeromask) != -1)
        error.system("sigsuspend error");


    // now reset signal mask which unblocks SIGINT

    if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)    
        error.system("SIG_SETMASK error");

    cout << "Now CTRL-C is recognized again. Sleeping for 5 seconds." << endl;

    sleep(5);

    // ...

    return(EXIT_SUCCESS);
}