/****************************************************************
 *                                                              *
 *  LIBDIST V1.0						*
 *                                                              *
 *  sig.c -- signals                                            *
 *                                                              *
 *  Last changed: 17.02.96                                      *
 *  Author: Frank Kargl (frank.kargl@informatik.uni-ulm.de)     *
 *                                                              *
 *  Restrictions: works only for Solaris 2.6 or above           *
 *                                                              *
 ****************************************************************/

#include "libdist.h"
#include "config.h"

#include <synch.h>              /* for semaphores */

static sema_t dl_sig_lock = DL_SEM_UISEM;
			/* semaphore for shared access to bufferfield */
			/* initialized this way so we can determine */
			/* if we have done sema_init yet */

struct dl_sig_statuss {
    int catch;		/* is signal to be catched ? */
    void (*func)();		/* function to call */
} dl_sig_status[DL_SIG_MAXSIG];	/* global variable to determine */
				/* status of signal handlers */ 
/***
 *** void dl_sig_func(int what)
 ***
 *** Function: Just a wrapper around the function to be called
 *** Return  : -
 ***/

void dl_sig_func(int what) {

    /* first wait for semaphore */
    sema_wait(&dl_sig_lock);

    /* is this signal still to be catched ? */
    if (dl_sig_status[what].catch) {
	(dl_sig_status[what].func)(what);
	signal(what,dl_sig_func);
    }

    /* free semaphore again */
    sema_post(&dl_sig_lock);
}

/***
 *** void dl_sig_catch(int sig, void(*function)())
 ***
 *** Function: 'function' is called each time 'sig' is received
 ***           It isn't necessary to reinstall the
 ***           signal handler at the end
 *** Return  : -
 ***/

void dl_sig_catch(int sig, void(*function)(int)) {

    /* first lock up everything */
    if (dl_sig_lock.count!=1 && dl_sig_lock.count!=0) {
	sema_init(&dl_sig_lock, 1, USYNC_THREAD, NULL);
    }
    sema_wait(&dl_sig_lock);

    /* if out of range die silently */
    if (sig<0 || sig>DL_SIG_MAXSIG) { return; }

    /* Install the signal-handler */
    dl_sig_status[sig].catch=1;
    dl_sig_status[sig].func=function;
    signal(sig,dl_sig_func);

    /* free semaphore again */
    sema_post(&dl_sig_lock);

}

/***
 *** void dl_sig_free(int sig)
 ***
 *** Function: 'sig' isn't caught anymore
 *** Return  : -
 ***/

void dl_sig_free(int sig) {

    /* if out of range die silently */
    if(sig<0 || sig>DL_SIG_MAXSIG) { return; }

    /* reset signal mask */
    sema_wait(&dl_sig_lock);
    dl_sig_status[sig].catch=0;
    sema_post(&dl_sig_lock);

    /* reinstall default */
    signal(sig,SIG_DFL);
}
