common/synchronize.c

///////////////////////////////////////////////////////////////////////////////
// Filename: synchronize.c
///////////////////////////////////////////////////////////////////////////////
// Purpose: functions that makes it possible for two processes to
//          synchronize themselves
///////////////////////////////////////////////////////////////////////////////
// History:
// ========
//
// Date     Time     Name      Description   
// -------- -------- --------  ------------------------------------------------
// 96/02/26 22:53:51 muellerg: created
// 96/02/29 01:07:55 muellerg: added synchronization_reset
///////////////////////////////////////////////////////////////////////////////


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



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

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


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

#include "../common.h"



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



// File scope objects /////////////////////////////////// File scope objects //

static volatile sig_atomic_t sigflag;       // set to nonzero by signal handler
static sigset_t newmask, oldmask, zeromask;




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



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

static void
sig_usr(int)    /* one signal handler for SIGUSR1 and SIGUSR2 */
{
    sigflag = 1;
    return;
}




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



// Functions and class implementation /// Functions and class implementation //

/* These functions enable it for two unrelated processes to synchronize.
 * This implementation uses signals (SIGUSR1 and SIGUSR2), but it would
 * also be possible to use e.g. pipes. 
 *
 * To destinguish the two processes one is called the parent, the
 * other one the child. This must not be true in reality.
 *
 * The processes to use the following functions have to decide which 
 * one is the parent and which one is the child. This decision can be
 * changed while the program is running.
 *
 * The following functions are available:
 *
 * void synchronization_init(void): initialize everything,
 *      has to be called before any of the other functions can be used
 *
 *
 * void synchronization_signal_parent(pid_t pid): send signal SIGUSR2
 *      to pid
 *
 * void synchronization_signal_child(pid_t pid): send signal SIGUSR1
 *      to pid
 *
 * void synchronization_wait(void): wait for signal (either from
 *      child or parent)
 *
 * void synchronization_reset(void): reset signal mask to how it was when 
 *      calling synchronization_init()
 */



/*
 * Initialize everything
 */

void
synchronization_init(void)
{
    // set up signal handler

    struct sigaction handle_sigusr;
    handle_sigusr.sa_handler = &sig_usr;
    sigemptyset(&handle_sigusr.sa_mask);   // no need to block other signals
    handle_sigusr.sa_flags   = 0;

    if(sigaction(SIGUSR1, &handle_sigusr, NULL) != 0)
        error.system("synchronization_init(): sigaction() error");

    if(sigaction(SIGUSR2, &handle_sigusr, NULL) != 0)
        error.system("synchronization_init(): sigaction() error");


    sigemptyset(&zeromask);

    sigemptyset(&newmask);
    sigaddset(&newmask, SIGUSR1);
    sigaddset(&newmask, SIGUSR2);

    // block SIGUSR1 and SIGUSR2, and save current signal mask 

    if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
        error.system("synchronization_init(): SIG_BLOCK error");
}


/*
 * Send signal from child to parent process
 */

void
synchronization_signal_parent(pid_t pid)
{
    kill(pid, SIGUSR2);
}



/*
 * Send signal from parent to child
 */

void
synchronization_signal_child(pid_t pid)
{
    kill(pid, SIGUSR1); 
}



/*
 * wait for signal (from parent or child) 
 */

void
synchronization_wait(void)
{
    while (sigflag == 0)
        sigsuspend(&zeromask);  // wait for signal

    sigflag = 0;    // reset signal mask to original value 
}


/*
 * reset signal mask to how it was when calling synchronization_init()
 */

void
synchronization_reset(void)
{
    if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
        error.system("synchronization_reset(): SIG_SETMASK error");
}


// Main /////////////////////////////////////////////////////////////// Main //
    /* NONE */