This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
yap-6.3/C/signals.c
2015-06-19 01:30:13 +01:00

469 lines
9.8 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"
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if _WIN32
#include <stdio.h>
#include <io.h>
#endif
#include "Yatom.h"
#include "YapHeap.h"
#include "eval.h"
#include "yapio.h"
#ifdef TABLING
#include "tab.macros.h"
#endif /* TABLING */
#include <stdlib.h>
#include <stdio.h>
#if HAVE_STRING_H
#include <string.h>
#endif
#if HAVE_STRINGS_H
#include <strings.h>
#endif
#if HAVE_MALLOC_H
#include <malloc.h>
#endif
#include <wchar.h>
#ifdef LOW_LEVEL_TRACER
#include <tracer.h>
#endif
/*
* The InteractSIGINT function is called after a normal interrupt had been caught.
* It allows 6 possibilities: abort, continue, trace, debug, help, exit.
*/
static yap_signals
InteractSIGINT(int ch) {
#ifdef HAVE_SETBUF
/* make sure we are not waiting for the end of line */
setbuf (stdin, NULL);
#endif
switch (ch) {
case 'a':
/* abort computation */
return YAP_ABORT_SIGNAL;
case 'b':
/* continue */
return YAP_BREAK_SIGNAL;
case 'c':
/* continue */
return YAP_NO_SIGNAL;
case 'd':
/* enter debug mode */
return YAP_DEBUG_SIGNAL;
case 'e':
/* exit */
Yap_exit(1);
return YAP_EXIT_SIGNAL;
case 'g':
/* stack dump */
return YAP_STACK_DUMP_SIGNAL;
case 't':
/* start tracing */
return YAP_TRACE_SIGNAL;
#ifdef LOW_LEVEL_TRACER
case 'T':
toggle_low_level_trace();
return YAP_NO_SIGNAL;
#endif
case 's':
/* show some statistics */
return YAP_STATISTICS_SIGNAL;
case EOF:
return YAP_NO_SIGNAL;
case 'h':
case '?':
default:
/* show an helpful message */
fprintf(stderr, "Please press one of:\n");
fprintf(stderr, " a for abort\n c for continue\n d for debug\n");
fprintf(stderr, " e for exit\n g for stack dump\n s for statistics\n t for trace\n");
fprintf(stderr, " b for break\n");
return YAP_NO_SIGNAL;
}
}
/*
This function talks to the user about a signal. We assume we are in
the context of the main Prolog thread (trivial in Unix, but hard in WIN32)
*/
static yap_signals
ProcessSIGINT(void)
{
CACHE_REGS
int ch, out;
#if _WIN32
if (!_isatty(0)) {
return YAP_INT_SIGNAL;
}
#elif HAVE_ISATTY
if (!isatty(0)) {
return YAP_INT_SIGNAL;
}
#endif
LOCAL_PrologMode |= AsyncIntMode;
do {
ch = Yap_GetCharForSIGINT();
} while (!(out = InteractSIGINT(ch)));
LOCAL_PrologMode &= ~AsyncIntMode;
return(out);
}
inline static void
do_signal(int wid, yap_signals sig USES_REGS)
{
#if THREADS
__sync_fetch_and_or ( &REMOTE(wid)->Signals_, SIGNAL_TO_BIT(sig));
if (!REMOTE_InterruptsDisabled(wid)) {
REMOTE_ThreadHandle(wid).current_yaam_regs->CreepFlag_ =
Unsigned(REMOTE_ThreadHandle(wid).current_yaam_regs->LCL0_);
}
#else
LOCAL_Signals |= SIGNAL_TO_BIT(sig);
if (!LOCAL_InterruptsDisabled) {
CreepFlag =
Unsigned(LCL0);
}
#endif
}
inline static int
get_signal(yap_signals sig USES_REGS)
{
#if THREADS
uint64_t old;
// first, clear the Creep Flag, now if someone sets it it is their problem
CalculateStackGap( PASS_REGS1 );
// reset the flag
if ( (old =__sync_fetch_and_and( &LOCAL_Signals, ~SIGNAL_TO_BIT(sig) ) ) !=
SIGNAL_TO_BIT(sig)) {
if (!LOCAL_InterruptsDisabled && LOCAL_Signals != 0) {
CreepFlag = (CELL)LCL0;
}
if (!(old & SIGNAL_TO_BIT(sig)) ) {
// not there?
return FALSE;
}
// more likely case, we have other interrupts.
return TRUE;
}
// success, we are good
return TRUE;
// should we set the flag?
#else
if (LOCAL_Signals & SIGNAL_TO_BIT(sig)) {
LOCAL_Signals &= ~SIGNAL_TO_BIT(sig);
if (!LOCAL_InterruptsDisabled && LOCAL_Signals != 0) {
CreepFlag = (CELL)LCL0;
} else {
CalculateStackGap( PASS_REGS1 );
}
return TRUE;
} else {
return FALSE;
}
#endif
}
/**
Function called to handle delayed interrupts.
*/
int
Yap_HandleInterrupts( void )
{
CACHE_REGS
yap_signals sig;
if ( get_signal( YAP_INT_SIGNAL PASS_REGS )) {
if ( (sig = ProcessSIGINT()) != YAP_NO_SIGNAL )
do_signal(worker_id, sig PASS_REGS);
LOCAL_PrologMode &= ~InterruptMode;
return 1;
}
return 0;
}
static Int
p_creep( USES_REGS1 )
{
Atom at;
PredEntry *pred;
at = AtomCreep;
pred = RepPredProp(PredPropByFunc(Yap_MkFunctor(at, 1),0));
CreepCode = pred;
do_signal(worker_id, YAP_CREEP_SIGNAL PASS_REGS);
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;
do_signal(worker_id, YAP_CREEP_SIGNAL PASS_REGS);
return FALSE;
}
static Int
p_stop_creeping( USES_REGS1 )
{
get_signal( YAP_CREEP_SIGNAL PASS_REGS );
return TRUE;
}
static Int
p_creep_allowed( USES_REGS1 )
{
if (PP != NULL) {
get_signal(YAP_CREEP_SIGNAL PASS_REGS);
return TRUE;
}
return FALSE;
}
void
Yap_signal(yap_signals sig)
{
CACHE_REGS
do_signal(worker_id, sig PASS_REGS);
}
#ifdef DEBUG
static Int
p_debug( USES_REGS1 );
#endif
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);
LOCAL_PrologMode &= ~InterruptMode;
}
int
Yap_get_signal__(yap_signals sig USES_REGS)
{
return get_signal(sig PASS_REGS);
}
// the caller holds the lock.
int
Yap_has_signals__(yap_signals sig1, yap_signals sig2 USES_REGS)
{
return LOCAL_Signals & (SIGNAL_TO_BIT(sig1)|SIGNAL_TO_BIT(sig2));
}
int
Yap_only_has_signals__(yap_signals sig1, yap_signals sig2 USES_REGS)
{
uint64_t sigs = LOCAL_Signals;
return sigs & (SIGNAL_TO_BIT(sig1) | SIGNAL_TO_BIT(sig2)) &&
! (sigs & ~(SIGNAL_TO_BIT(sig1) | SIGNAL_TO_BIT(sig2))) ;
}
#ifdef DEBUG
volatile int volat = 0;
static Int
p_debug( USES_REGS1 )
{ /* $debug(+Flag) */
int i = IntOfTerm(Deref(ARG1));
while (volat == 0) {
}
if (i >= 'a' && i <= 'z')
GLOBAL_Option[i - 96] = !GLOBAL_Option[i - 96];
return (1);
}
void Yap_loop(void);
void Yap_debug_end_loop(void);
void Yap_loop(void)
{
while (volat == 0);
}
void Yap_debug_end_loop(void)
{
volat = 1;
}
#endif
static Int
p_first_signal( USES_REGS1 )
{
Atom at;
yap_signals sig;
while (TRUE) {
uint64_t mask = LOCAL_Signals;
if (mask == 0)
return FALSE;
#if HAVE___BUILTIN_FFSLL
sig = __builtin_ffsll(mask);
#elif HAVE_FFSLL
sig = ffsll(mask);
#else
sig = Yap_msb( mask PASS_REGS)+1;
#endif
if (get_signal(sig PASS_REGS)) {
break;
}
}
loop:
switch (sig) {
case YAP_INT_SIGNAL:
sig = ProcessSIGINT();
if (sig == YAP_INT_SIGNAL) {
at = AtomSigInt;
break;
}
if (sig != YAP_NO_SIGNAL)
goto loop;
return FALSE;
case YAP_ABORT_SIGNAL:
/* abort computation */
LOCAL_PrologMode &= ~AsyncIntMode;
if (LOCAL_PrologMode & (GCMode|ConsoleGetcMode|CritMode)) {
LOCAL_PrologMode |= AbortMode;
return -1;
} else {
Yap_Error(PURE_ABORT, TermNil, "abort from console");
}
Yap_RestartYap( 1 );
return FALSE;
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_EXIT_SIGNAL:
Yap_exit(1);
return FALSE;
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
#ifdef SIGFPE
case YAP_FPE_SIGNAL:
at = AtomSigFPE;
break;
#endif
default:
return FALSE;
}
return Yap_unify(ARG1, MkAtomTerm(at));
}
static Int
p_continue_signals( USES_REGS1 )
{
return p_first_signal( PASS_REGS1 );
}
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("sys_debug", 1, p_debug, SafePredFlag|SyncPredFlag);
#endif
}
void *Yap_InitSignals(int wid)
{
void *ptr = (void *)malloc(sizeof(UInt)*REMOTE_MaxActiveSignals(wid));
return ptr;
}