/*
 * $Header: /p/sss/cvs/OpenVM/src/native/common/eventmanager.c,v 1.22 2005/02/22 19:13:38 baker29 Exp $
 * eventmanager.c -- C-land code for the event manager.  this here code
 *                   helps facilitate our fast poll check that happens once
 *                   every couple instructions.  it also helps the VM
 *                   block for events whenever it needs to do so.
 * by Filip and David.
 */
#include <stdio.h>
#include <stdlib.h>
#include <mem.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include "util.h"

#if HAVE_PTHREAD
#include <pthread.h>
#endif

#define IN_EVENTMANAGER_C

#include "eventmanager.h"

#ifndef OLDE_STYLE_POLLCHECK

eventUnion_t eventUnion = {
    ._.notSignaled = 1,
    ._.notEnabled = 1
};

#else

/* anything the signal handler touches should be marked volatile
 * and really should be of type sig_atomic_t - DH */

/** set by the signal handler to indicate and event has occurred */
volatile sig_atomic_t eventSignaled=0;

/** flag to signal whether we're currently processing events */
volatile jboolean eventsEnabled=0;

#endif

/** the pointers */
volatile VOID_FPTR signal_event = NULL;
volatile VOID_FPTR signal_event_from_thread = NULL;

/** a standard and simple signal event implementation */
static void simple_signal_event(void) {
    SIGNAL_EVENT_FOR_POLL_CHECK();
}

/** a signal event implementation that indicates to the user that something
    is broken */
static void broken_signal_event(void) {
    fprintf(stderr,"broken_signal_event(void) called\n");
    abort();
}

void makeSignalEventSimple() {
    signal_event=simple_signal_event;
}

void makeSignalEventBroken() {
    signal_event=broken_signal_event;
}

void makeSignalEventFromThreadSimple() {
    signal_event_from_thread=simple_signal_event;
}

void makeSignalEventFromThreadBroken() {
    signal_event_from_thread=broken_signal_event;
}

/**
 * Blocks the current thread until an event has occurred.
 */
void waitForEvents() {
    sigset_t fullSet,oldSet,emptySet;
    sigfillset(&fullSet);
    sigemptyset(&emptySet);

    /* First we mask all signals */
#if HAVE_PTHREAD
    EXIT_ERRNO(pthread_sigmask(SIG_BLOCK,&fullSet,&oldSet),
               "pthread_sigmask failed");
#else
    EXIT_ERRNO(sigprocmask(SIG_BLOCK,&fullSet,&oldSet),
               "sigprocmask failed");
#endif

    /* next we check if there is an event pending */
    while (!CHECK_EVENT_SIGNALED()) {
        /* enable all signals while we suspend */
        sigsuspend(&emptySet);
    }
    /* clear the flag so that it is ready for next time */
    RESET_EVENTS();

    /* restore the original signal mask */
#if HAVE_PTHREAD
    EXIT_ERRNO(pthread_sigmask(SIG_SETMASK,&oldSet,NULL),
               "pthread_sigmask failed");
#else
    EXIT_ERRNO(sigprocmask(SIG_SETMASK,&oldSet,NULL),
               "sigprocmask failed");
#endif
}




