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 */