420 lines
9.2 KiB
C
Executable File
420 lines
9.2 KiB
C
Executable File
/*************************************************************************
|
|
* *
|
|
* YAP Prolog *
|
|
* *
|
|
* Yap Prolog was developed at NCCUP - Universidade do Porto *
|
|
* *
|
|
* Copyright L.Damas, V. Santos Costa and Universidade do Porto 1985-- *
|
|
* *
|
|
**************************************************************************
|
|
* *
|
|
* File: signal.c *
|
|
* comments: Signal Handling & Debugger Support *
|
|
* *
|
|
* *
|
|
* *
|
|
*************************************************************************/
|
|
#ifdef SCCS
|
|
static char SccsId[] = "%W% %G%";
|
|
#endif
|
|
|
|
#define HAS_CACHE_REGS 1
|
|
|
|
#include "Yap.h"
|
|
#include "Yatom.h"
|
|
#include "YapHeap.h"
|
|
#include "eval.h"
|
|
#include "yapio.h"
|
|
#ifdef TABLING
|
|
#include "tab.macros.h"
|
|
#endif /* TABLING */
|
|
#include <stdio.h>
|
|
#if HAVE_STRING_H
|
|
#include <string.h>
|
|
#endif
|
|
#if HAVE_MALLOC_H
|
|
#include <malloc.h>
|
|
#endif
|
|
#include <wchar.h>
|
|
|
|
#ifndef THREADS
|
|
#define worker_id 0
|
|
#endif
|
|
|
|
inline static void
|
|
do_signal(int wid, yap_signals sig USES_REGS)
|
|
{
|
|
#if THREADS
|
|
if (!REMOTE_InterruptsDisabled(wid)) {
|
|
REMOTE_ThreadHandle(wid).current_yaam_regs->CreepFlag_ =
|
|
Unsigned(REMOTE_ThreadHandle(wid).current_yaam_regs->LCL0_);
|
|
if (sig != YAP_CREEP_SIGNAL)
|
|
REMOTE_ThreadHandle(wid).current_yaam_regs->EventFlag_ =
|
|
Unsigned(REMOTE_ThreadHandle(wid).current_yaam_regs->LCL0_);
|
|
}
|
|
UInt i = REMOTE_FirstActiveSignal(wid);
|
|
if (REMOTE_FirstActiveSignal(wid) != REMOTE_LastActiveSignal(wid)) {
|
|
do {
|
|
if (sig == REMOTE_ActiveSignals(wid)[i]) {
|
|
return;
|
|
}
|
|
i++;
|
|
if (i == REMOTE_MaxActiveSignals(wid))
|
|
i = 0;
|
|
} while (i != REMOTE_LastActiveSignal(wid));
|
|
}
|
|
REMOTE_ActiveSignals(wid)[i] = sig;
|
|
REMOTE_LastActiveSignal(wid)++;
|
|
if (REMOTE_LastActiveSignal(wid) == REMOTE_MaxActiveSignals(wid))
|
|
REMOTE_LastActiveSignal(wid) = 0;
|
|
#else
|
|
if (!LOCAL_InterruptsDisabled) {
|
|
CreepFlag =
|
|
Unsigned(LCL0);
|
|
if (sig != YAP_CREEP_SIGNAL)
|
|
EventFlag =
|
|
Unsigned(LCL0);
|
|
}
|
|
UInt i = LOCAL_FirstActiveSignal;
|
|
if (LOCAL_FirstActiveSignal != LOCAL_LastActiveSignal) {
|
|
do {
|
|
if (sig == LOCAL_ActiveSignals[i]) {
|
|
return;
|
|
}
|
|
i++;
|
|
if (i == LOCAL_MaxActiveSignals)
|
|
i = 0;
|
|
} while (i != LOCAL_LastActiveSignal);
|
|
}
|
|
LOCAL_ActiveSignals[i] = sig;
|
|
LOCAL_LastActiveSignal++;
|
|
if (LOCAL_LastActiveSignal == LOCAL_MaxActiveSignals)
|
|
LOCAL_LastActiveSignal = 0;
|
|
#endif
|
|
}
|
|
|
|
inline static int
|
|
undo_signal(yap_signals sig USES_REGS)
|
|
{
|
|
UInt i = LOCAL_FirstActiveSignal;
|
|
if (LOCAL_FirstActiveSignal != LOCAL_LastActiveSignal) {
|
|
do {
|
|
if (sig == LOCAL_ActiveSignals[i])
|
|
break;
|
|
i++;
|
|
if (i == LOCAL_MaxActiveSignals)
|
|
i = 0;
|
|
} while (i != LOCAL_LastActiveSignal);
|
|
}
|
|
if (i == LOCAL_LastActiveSignal) {
|
|
return FALSE;
|
|
}
|
|
while ((i+1) % LOCAL_MaxActiveSignals != LOCAL_LastActiveSignal) {
|
|
LOCAL_ActiveSignals[i] = LOCAL_ActiveSignals[(i+1) % LOCAL_MaxActiveSignals];
|
|
i++;
|
|
}
|
|
if (LOCAL_LastActiveSignal == 0)
|
|
LOCAL_LastActiveSignal = LOCAL_MaxActiveSignals-1;
|
|
else
|
|
LOCAL_LastActiveSignal--;
|
|
if (LOCAL_FirstActiveSignal != LOCAL_LastActiveSignal) {
|
|
CalculateStackGap( PASS_REGS1 );
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static Int
|
|
p_creep( USES_REGS1 )
|
|
{
|
|
Atom at;
|
|
PredEntry *pred;
|
|
|
|
at = AtomCreep;
|
|
pred = RepPredProp(PredPropByFunc(Yap_MkFunctor(at, 1),0));
|
|
CreepCode = pred;
|
|
LOCK(LOCAL_SignalLock);
|
|
do_signal(worker_id, YAP_CREEP_SIGNAL PASS_REGS);
|
|
UNLOCK(LOCAL_SignalLock);
|
|
return TRUE;
|
|
}
|
|
|
|
static Int
|
|
p_creep_fail( USES_REGS1 )
|
|
{
|
|
Atom at;
|
|
PredEntry *pred;
|
|
|
|
at = AtomCreep;
|
|
pred = RepPredProp(PredPropByFunc(Yap_MkFunctor(at, 1),0));
|
|
CreepCode = pred;
|
|
LOCK(LOCAL_SignalLock);
|
|
do_signal(worker_id, YAP_CREEP_SIGNAL PASS_REGS);
|
|
UNLOCK(LOCAL_SignalLock);
|
|
return FALSE;
|
|
}
|
|
|
|
static Int
|
|
p_stop_creeping( USES_REGS1 )
|
|
{
|
|
LOCK(LOCAL_SignalLock);
|
|
undo_signal( YAP_CREEP_SIGNAL PASS_REGS );
|
|
UNLOCK(LOCAL_SignalLock);
|
|
return TRUE;
|
|
}
|
|
|
|
static Int
|
|
p_creep_allowed( USES_REGS1 )
|
|
{
|
|
LOCK(LOCAL_SignalLock);
|
|
if (PP != NULL) {
|
|
undo_signal(YAP_CREEP_SIGNAL PASS_REGS);
|
|
if (!LOCAL_InterruptsDisabled) {
|
|
if (LOCAL_FirstActiveSignal == LOCAL_LastActiveSignal)
|
|
CalculateStackGap( PASS_REGS1 );
|
|
}
|
|
UNLOCK(LOCAL_SignalLock);
|
|
return TRUE;
|
|
}
|
|
UNLOCK(LOCAL_SignalLock);
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
Yap_signal(yap_signals sig)
|
|
{
|
|
CACHE_REGS
|
|
do_signal(worker_id, sig PASS_REGS);
|
|
}
|
|
|
|
void
|
|
Yap_external_signal(int wid, yap_signals sig)
|
|
{
|
|
#if THREADS
|
|
REGSTORE *regcache = REMOTE_ThreadHandle(wid).current_yaam_regs;
|
|
#endif
|
|
do_signal(wid, sig PASS_REGS);
|
|
}
|
|
|
|
int
|
|
Yap_undo_signal__(yap_signals sig USES_REGS)
|
|
{
|
|
return undo_signal(sig PASS_REGS);
|
|
}
|
|
|
|
int
|
|
Yap_has_signal__(yap_signals sig USES_REGS)
|
|
{
|
|
UInt i = LOCAL_FirstActiveSignal;
|
|
if (LOCAL_FirstActiveSignal != LOCAL_LastActiveSignal) {
|
|
do {
|
|
if (sig == LOCAL_ActiveSignals[i]) {
|
|
return TRUE;
|
|
}
|
|
i++;
|
|
if (i == LOCAL_MaxActiveSignals)
|
|
i = 0;
|
|
} while (i != LOCAL_LastActiveSignal);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// the caller holds the lock.
|
|
int
|
|
Yap_has_signals__(yap_signals sig1, yap_signals sig2 USES_REGS)
|
|
{
|
|
UInt i = LOCAL_FirstActiveSignal;
|
|
if (LOCAL_FirstActiveSignal != LOCAL_LastActiveSignal) {
|
|
do {
|
|
if (sig1 == LOCAL_ActiveSignals[i] ||
|
|
sig2 == LOCAL_ActiveSignals[i]) {
|
|
return TRUE;
|
|
}
|
|
i++;
|
|
if (i == LOCAL_MaxActiveSignals)
|
|
i = 0;
|
|
} while (i != LOCAL_LastActiveSignal);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
int
|
|
Yap_only_has_signal__(yap_signals sig USES_REGS)
|
|
{
|
|
UInt i = LOCAL_FirstActiveSignal;
|
|
if (LOCAL_FirstActiveSignal != LOCAL_LastActiveSignal) {
|
|
do {
|
|
if (sig != LOCAL_ActiveSignals[i]) {
|
|
return FALSE;
|
|
}
|
|
i++;
|
|
if (i == LOCAL_MaxActiveSignals)
|
|
i = 0;
|
|
} while (i != LOCAL_LastActiveSignal);
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
int
|
|
Yap_only_has_signals__(yap_signals sig1, yap_signals sig2 USES_REGS)
|
|
{
|
|
UInt i = LOCAL_FirstActiveSignal;
|
|
if (LOCAL_FirstActiveSignal != LOCAL_LastActiveSignal) {
|
|
do {
|
|
if (sig1 != LOCAL_ActiveSignals[i] &&
|
|
sig2 != LOCAL_ActiveSignals[i]) {
|
|
return FALSE;
|
|
}
|
|
i++;
|
|
if (i == LOCAL_MaxActiveSignals)
|
|
i = 0;
|
|
} while (i != LOCAL_LastActiveSignal);
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
static Int
|
|
p_debug( USES_REGS1 )
|
|
{ /* $debug(+Flag) */
|
|
int i = IntOfTerm(Deref(ARG1));
|
|
|
|
if (i >= 'a' && i <= 'z')
|
|
GLOBAL_Option[i - 96] = !GLOBAL_Option[i - 96];
|
|
return (1);
|
|
}
|
|
#endif
|
|
|
|
static Int
|
|
p_first_signal( USES_REGS1 )
|
|
{
|
|
Atom at;
|
|
yap_signals sig;
|
|
|
|
LOCK(LOCAL_SignalLock);
|
|
/* always do wakeups first, because you don't want to keep the
|
|
non-backtrackable variable bad */
|
|
if (LOCAL_FirstActiveSignal != LOCAL_LastActiveSignal) {
|
|
sig = LOCAL_ActiveSignals[LOCAL_FirstActiveSignal];
|
|
LOCAL_FirstActiveSignal++;
|
|
if (LOCAL_FirstActiveSignal == LOCAL_MaxActiveSignals)
|
|
LOCAL_FirstActiveSignal = 0;
|
|
} else {
|
|
sig = YAP_NO_SIGNAL;
|
|
}
|
|
switch (sig) {
|
|
case YAP_INT_SIGNAL:
|
|
at = AtomSigInt;
|
|
break;
|
|
case YAP_CREEP_SIGNAL:
|
|
at = AtomSigCreep;
|
|
break;
|
|
case YAP_TRACE_SIGNAL:
|
|
at = AtomSigTrace;
|
|
break;
|
|
case YAP_DEBUG_SIGNAL:
|
|
at = AtomSigDebug;
|
|
break;
|
|
case YAP_BREAK_SIGNAL:
|
|
at = AtomSigBreak;
|
|
break;
|
|
case YAP_FAIL_SIGNAL:
|
|
at = AtomFail;
|
|
break;
|
|
case YAP_STACK_DUMP_SIGNAL:
|
|
at = AtomSigStackDump;
|
|
break;
|
|
case YAP_STATISTICS_SIGNAL:
|
|
at = AtomSigStatistics;
|
|
break;
|
|
#ifdef SIGALRM
|
|
case YAP_ALARM_SIGNAL:
|
|
#endif
|
|
case YAP_WINTIMER_SIGNAL:
|
|
at = AtomSigAlarm;
|
|
break;
|
|
#ifdef SIGVTALRM
|
|
case YAP_VTALARM_SIGNAL:
|
|
at = AtomSigVTAlarm;
|
|
break;
|
|
#endif
|
|
case YAP_WAKEUP_SIGNAL:
|
|
at = AtomSigWakeUp;
|
|
break;
|
|
case YAP_ITI_SIGNAL:
|
|
at = AtomSigIti;
|
|
break;
|
|
#ifdef SIGPIPE
|
|
case YAP_PIPE_SIGNAL:
|
|
at = AtomSigPipe;
|
|
break;
|
|
#endif
|
|
#ifdef SIGHUP
|
|
case YAP_HUP_SIGNAL:
|
|
at = AtomSigHup;
|
|
break;
|
|
#endif
|
|
#ifdef SIGUSR1
|
|
case YAP_USR1_SIGNAL:
|
|
at = AtomSigUsr1;
|
|
break;
|
|
#endif
|
|
#ifdef SIGUSR2
|
|
case YAP_USR2_SIGNAL:
|
|
at = AtomSigUsr2;
|
|
break;
|
|
#endif
|
|
default:
|
|
UNLOCK(LOCAL_SignalLock);
|
|
return FALSE;
|
|
}
|
|
UNLOCK(LOCAL_SignalLock);
|
|
return Yap_unify(ARG1, MkAtomTerm(at));
|
|
}
|
|
|
|
static Int
|
|
p_continue_signals( USES_REGS1 )
|
|
{
|
|
yap_signals sig;
|
|
/* hack to force the signal anew */
|
|
LOCK(LOCAL_SignalLock);
|
|
if (LOCAL_InterruptsDisabled) {
|
|
return TRUE;
|
|
}
|
|
if (LOCAL_FirstActiveSignal != LOCAL_LastActiveSignal) {
|
|
sig = LOCAL_ActiveSignals[LOCAL_FirstActiveSignal];
|
|
CreepFlag =
|
|
Unsigned(LCL0);
|
|
if (sig != YAP_CREEP_SIGNAL)
|
|
EventFlag =
|
|
Unsigned(LCL0);
|
|
}
|
|
UNLOCK(LOCAL_SignalLock);
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
Yap_InitSignalCPreds(void)
|
|
{
|
|
/* Basic predicates for the debugger */
|
|
Yap_InitCPred("$creep", 0, p_creep, SafePredFlag);
|
|
Yap_InitCPred("$creep_fail", 0, p_creep_fail, SafePredFlag);
|
|
Yap_InitCPred("$stop_creeping", 0, p_stop_creeping, SafePredFlag);
|
|
Yap_InitCPred ("$first_signal", 1, p_first_signal, SafePredFlag|SyncPredFlag);
|
|
Yap_InitCPred ("$continue_signals", 0, p_continue_signals, SafePredFlag|SyncPredFlag);
|
|
Yap_InitCPred("$creep_allowed", 0, p_creep_allowed, 0);
|
|
#ifdef DEBUG
|
|
Yap_InitCPred("$debug", 1, p_debug, SafePredFlag|SyncPredFlag);
|
|
#endif
|
|
}
|
|
|
|
void *Yap_InitSignals(int wid)
|
|
{
|
|
void *ptr = (void *)malloc(sizeof(UInt)*REMOTE_MaxActiveSignals(wid));
|
|
return ptr;
|
|
}
|