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

451 lines
10 KiB
C
Raw Normal View History

2013-02-08 16:36:45 +00:00
/*************************************************************************
* *
* YAP Prolog *
* *
* Yap Prolog was developed at NCCUP - Universidade do Porto *
* *
* Copyright L.Damas, V. Santos Costa and Universidade do Porto 1985-- *
* *
**************************************************************************
* *
2016-01-03 02:06:09 +00:00
* File: signal.c *
* comments: Signal Handling & Debugger Support *
* *
* *
* *
*************************************************************************/
2013-02-08 16:36:45 +00:00
#ifdef SCCS
2016-01-03 02:06:09 +00:00
static char SccsId[] = "%W% %G%";
2013-02-08 16:36:45 +00:00
#endif
#define HAS_CACHE_REGS 1
#include "Yap.h"
2015-06-19 01:30:13 +01:00
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if _WIN32
#include <io.h>
2016-11-24 04:35:39 +00:00
#include <stdio.h>
#endif
2013-02-08 16:36:45 +00:00
#include "YapHeap.h"
2016-11-24 04:35:39 +00:00
#include "Yatom.h"
2013-02-08 16:36:45 +00:00
#include "eval.h"
#include "yapio.h"
#ifdef TABLING
#include "tab.macros.h"
#endif /* TABLING */
#include <stdio.h>
2016-11-24 04:35:39 +00:00
#include <stdlib.h>
2013-02-08 16:36:45 +00:00
#if HAVE_STRING_H
#include <string.h>
#endif
2014-11-28 02:30:19 +00:00
#if HAVE_STRINGS_H
#include <strings.h>
#endif
2013-02-08 16:36:45 +00:00
#if HAVE_MALLOC_H
#include <malloc.h>
#endif
#include <wchar.h>
#ifdef LOW_LEVEL_TRACER
#include <tracer.h>
#endif
2013-02-08 16:36:45 +00:00
/*
2016-01-03 02:06:09 +00:00
* The InteractSIGINT function is called after a normal interrupt had been
* caught.
* It allows 6 possibilities: abort, continue, trace, debug, help, exit.
*/
2016-01-03 02:06:09 +00:00
static yap_signals InteractSIGINT(int ch) {
#ifdef HAVE_SETBUF
/* make sure we are not waiting for the end of line */
2016-01-03 02:06:09 +00:00
setbuf(stdin, NULL);
#endif
switch (ch) {
2016-01-03 02:06:09 +00:00
case 'a':
2016-11-24 04:35:39 +00:00
/* abort computation */
#if PUSH_REGS
// restore_absmi_regs(&Yap_standard_regs);
#endif
siglongjmp(LOCAL_RestartEnv, 4);
2016-01-03 02:06:09 +00:00
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
2016-01-03 02:06:09 +00:00
case 'T':
toggle_low_level_trace();
return YAP_NO_SIGNAL;
#endif
2016-01-03 02:06:09 +00:00
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)
*/
2016-01-03 02:06:09 +00:00
static yap_signals ProcessSIGINT(void) {
CACHE_REGS
int ch, out;
#if _WIN32
if (!_isatty(0)) {
2016-01-03 02:06:09 +00:00
return YAP_INT_SIGNAL;
}
#elif HAVE_ISATTY
if (!isatty(0)) {
2016-01-03 02:06:09 +00:00
return YAP_INT_SIGNAL;
}
#endif
LOCAL_PrologMode |= AsyncIntMode;
do {
2016-01-03 02:06:09 +00:00
ch = Yap_GetCharForSIGINT();
} while (!(out = InteractSIGINT(ch)));
LOCAL_PrologMode &= ~AsyncIntMode;
2016-01-03 02:06:09 +00:00
return (out);
}
2016-01-03 02:06:09 +00:00
inline static void do_signal(int wid, yap_signals sig USES_REGS) {
2014-03-06 14:07:33 +00:00
#if THREADS
2016-01-03 02:06:09 +00:00
__sync_fetch_and_or(&REMOTE(wid)->Signals_, SIGNAL_TO_BIT(sig));
2014-03-06 02:09:48 +00:00
if (!REMOTE_InterruptsDisabled(wid)) {
2016-01-03 02:06:09 +00:00
REMOTE_ThreadHandle(wid).current_yaam_regs->CreepFlag_ =
Unsigned(REMOTE_ThreadHandle(wid).current_yaam_regs->LCL0_);
2014-03-06 14:07:33 +00:00
}
#else
LOCAL_Signals |= SIGNAL_TO_BIT(sig);
2014-03-06 14:07:33 +00:00
if (!LOCAL_InterruptsDisabled) {
2016-01-03 02:06:09 +00:00
CreepFlag = Unsigned(LCL0);
2014-03-06 02:09:48 +00:00
}
2014-03-06 14:07:33 +00:00
#endif
2013-02-08 16:36:45 +00:00
}
2016-01-03 02:06:09 +00:00
inline static bool get_signal(yap_signals sig USES_REGS) {
#if THREADS
uint64_t old;
2015-01-18 01:32:13 +00:00
// first, clear the Creep Flag, now if someone sets it it is their problem
2016-01-03 02:06:09 +00:00
CalculateStackGap(PASS_REGS1);
// reset the flag
2016-01-03 02:06:09 +00:00
if ((old = __sync_fetch_and_and(&LOCAL_Signals, ~SIGNAL_TO_BIT(sig))) !=
SIGNAL_TO_BIT(sig)) {
2016-01-03 02:06:09 +00:00
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;
2014-03-06 02:09:48 +00:00
}
// success, we are good
return TRUE;
2016-01-03 02:06:09 +00:00
// should we set the flag?
#else
2014-09-03 17:02:28 +01:00
if (LOCAL_Signals & SIGNAL_TO_BIT(sig)) {
2016-01-03 02:06:09 +00:00
LOCAL_Signals &= ~SIGNAL_TO_BIT(sig);
if (!LOCAL_InterruptsDisabled && LOCAL_Signals != 0) {
CreepFlag = (CELL)LCL0;
} else {
CalculateStackGap(PASS_REGS1);
}
return TRUE;
} else {
2016-01-03 02:06:09 +00:00
return FALSE;
2014-03-06 02:09:48 +00:00
}
#endif
}
2016-11-24 04:35:39 +00:00
bool Yap_DisableInterrupts(int wid) {
2016-03-29 01:55:12 +01:00
LOCAL_InterruptsDisabled = true;
YAPEnterCriticalSection();
return true;
}
2016-11-24 04:35:39 +00:00
bool Yap_EnableInterrupts(int wid) {
2016-03-29 01:55:12 +01:00
LOCAL_InterruptsDisabled = false;
YAPLeaveCriticalSection();
return true;
}
/**
2016-01-03 02:06:09 +00:00
Function called to handle delayed interrupts.
*/
2016-11-24 04:35:39 +00:00
bool Yap_HandleSIGINT(void) {
CACHE_REGS
yap_signals sig;
2016-11-24 04:35:39 +00:00
do {
2016-01-03 02:06:09 +00:00
if ((sig = ProcessSIGINT()) != YAP_NO_SIGNAL)
do_signal(worker_id, sig PASS_REGS);
LOCAL_PrologMode &= ~InterruptMode;
2016-11-24 04:35:39 +00:00
return true;
} while (get_signal(YAP_INT_SIGNAL PASS_REGS));
return false;
2013-02-08 16:36:45 +00:00
}
2016-01-03 02:06:09 +00:00
static Int p_creep(USES_REGS1) {
Atom at;
PredEntry *pred;
2013-02-08 16:36:45 +00:00
at = AtomCreep;
2016-01-03 02:06:09 +00:00
pred = RepPredProp(PredPropByFunc(Yap_MkFunctor(at, 1), 0));
2013-02-08 16:36:45 +00:00
CreepCode = pred;
2014-03-06 02:09:48 +00:00
do_signal(worker_id, YAP_CREEP_SIGNAL PASS_REGS);
2013-02-08 16:36:45 +00:00
return TRUE;
}
2016-01-03 02:06:09 +00:00
static Int p_creep_fail(USES_REGS1) {
Atom at;
PredEntry *pred;
2013-12-11 09:34:43 +00:00
at = AtomCreep;
2016-01-03 02:06:09 +00:00
pred = RepPredProp(PredPropByFunc(Yap_MkFunctor(at, 1), 0));
2013-12-11 09:34:43 +00:00
CreepCode = pred;
2014-03-06 02:09:48 +00:00
do_signal(worker_id, YAP_CREEP_SIGNAL PASS_REGS);
2013-12-11 09:34:43 +00:00
return FALSE;
}
2016-01-03 02:06:09 +00:00
static Int stop_creeping(USES_REGS1) {
if (get_signal(YAP_CREEP_SIGNAL PASS_REGS)) {
return Yap_unify(ARG1, TermTrue);
}
return Yap_unify(ARG1, TermFalse);
}
static Int disable_debugging(USES_REGS1) {
get_signal(YAP_CREEP_SIGNAL PASS_REGS);
2015-09-21 23:05:36 +01:00
return true;
2013-02-08 16:36:45 +00:00
}
2016-01-03 02:06:09 +00:00
static Int creep_allowed(USES_REGS1) {
2013-02-08 16:36:45 +00:00
if (PP != NULL) {
2016-01-03 02:06:09 +00:00
get_signal(YAP_CREEP_SIGNAL PASS_REGS);
return true;
2013-02-08 16:36:45 +00:00
}
2015-09-21 23:05:36 +01:00
return false;
2013-02-08 16:36:45 +00:00
}
2016-01-03 02:06:09 +00:00
void Yap_signal(yap_signals sig) {
2013-02-08 16:36:45 +00:00
CACHE_REGS
do_signal(worker_id, sig PASS_REGS);
2013-02-08 16:36:45 +00:00
}
2014-11-10 01:56:56 +00:00
#ifdef DEBUG
2016-01-03 02:06:09 +00:00
static Int p_debug(USES_REGS1);
2014-11-10 01:56:56 +00:00
#endif
2016-01-03 02:06:09 +00:00
void Yap_external_signal(int wid, yap_signals sig) {
2014-03-06 14:07:33 +00:00
#if THREADS
2014-03-06 02:09:48 +00:00
REGSTORE *regcache = REMOTE_ThreadHandle(wid).current_yaam_regs;
2014-03-06 14:07:33 +00:00
#endif
2014-03-06 02:09:48 +00:00
do_signal(wid, sig PASS_REGS);
LOCAL_PrologMode &= ~InterruptMode;
2014-03-06 02:09:48 +00:00
}
2016-01-03 02:06:09 +00:00
int Yap_get_signal__(yap_signals sig USES_REGS) {
return get_signal(sig PASS_REGS);
2014-03-06 02:09:48 +00:00
}
// the caller holds the lock.
2016-01-03 02:06:09 +00:00
int Yap_has_signals__(yap_signals sig1, yap_signals sig2 USES_REGS) {
return LOCAL_Signals & (SIGNAL_TO_BIT(sig1) | SIGNAL_TO_BIT(sig2));
2014-03-06 02:09:48 +00:00
}
2016-01-03 02:06:09 +00:00
int Yap_only_has_signals__(yap_signals sig1, yap_signals sig2 USES_REGS) {
uint64_t sigs = LOCAL_Signals;
2014-09-03 17:02:28 +01:00
return sigs & (SIGNAL_TO_BIT(sig1) | SIGNAL_TO_BIT(sig2)) &&
2016-01-03 02:06:09 +00:00
!(sigs & ~(SIGNAL_TO_BIT(sig1) | SIGNAL_TO_BIT(sig2)));
2013-02-08 16:36:45 +00:00
}
#ifdef DEBUG
volatile int volat = 0;
2016-01-03 02:06:09 +00:00
static Int p_debug(USES_REGS1) { /* $debug(+Flag) */
int i = IntOfTerm(Deref(ARG1));
while (volat == 0) {
}
2013-02-08 16:36:45 +00:00
if (i >= 'a' && i <= 'z')
GLOBAL_Option[i - 96] = !GLOBAL_Option[i - 96];
2016-01-03 02:06:09 +00:00
return 1;
2013-02-08 16:36:45 +00:00
}
void Yap_loop(void);
void Yap_debug_end_loop(void);
2016-01-03 02:06:09 +00:00
void Yap_loop(void) {
while (volat == 0)
;
}
2016-01-03 02:06:09 +00:00
void Yap_debug_end_loop(void) { volat = 1; }
2013-02-08 16:36:45 +00:00
#endif
2016-01-03 02:06:09 +00:00
static Int first_signal(USES_REGS1) {
2014-03-06 02:09:48 +00:00
Atom at;
yap_signals sig;
while (TRUE) {
2016-01-03 02:06:09 +00:00
uint64_t mask = LOCAL_Signals;
if (mask == 0)
return FALSE;
#if HAVE___BUILTIN_FFSLL
2016-01-03 02:06:09 +00:00
sig = __builtin_ffsll(mask);
#elif HAVE_FFSLL
2016-01-03 02:06:09 +00:00
sig = ffsll(mask);
#else
2016-01-03 02:06:09 +00:00
sig = Yap_msb(mask PASS_REGS) + 1;
#endif
2016-01-03 02:06:09 +00:00
if (get_signal(sig PASS_REGS)) {
break;
}
2015-01-18 03:47:44 +00:00
}
2016-01-03 02:06:09 +00:00
loop:
2014-03-06 02:09:48 +00:00
switch (sig) {
2016-01-03 02:06:09 +00:00
case YAP_INT_SIGNAL:
sig = ProcessSIGINT();
if (sig == YAP_INT_SIGNAL) {
at = AtomSigInt;
break;
2016-01-03 02:06:09 +00:00
}
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(ABORT_EVENT, 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;
2014-03-06 02:09:48 +00:00
#ifdef SIGALRM
2016-01-03 02:06:09 +00:00
case YAP_ALARM_SIGNAL:
2014-03-06 02:09:48 +00:00
#endif
2016-01-03 02:06:09 +00:00
case YAP_WINTIMER_SIGNAL:
at = AtomSigAlarm;
break;
2014-03-06 02:09:48 +00:00
#ifdef SIGVTALRM
2016-01-03 02:06:09 +00:00
case YAP_VTALARM_SIGNAL:
at = AtomSigVTAlarm;
break;
2014-03-06 02:09:48 +00:00
#endif
2016-01-03 02:06:09 +00:00
case YAP_EXIT_SIGNAL:
Yap_exit(1);
return FALSE;
case YAP_WAKEUP_SIGNAL:
at = AtomSigWakeUp;
break;
case YAP_ITI_SIGNAL:
at = AtomSigIti;
break;
2014-03-06 02:09:48 +00:00
#ifdef SIGPIPE
2016-01-03 02:06:09 +00:00
case YAP_PIPE_SIGNAL:
at = AtomSigPipe;
break;
2014-03-06 02:09:48 +00:00
#endif
#ifdef SIGHUP
2016-01-03 02:06:09 +00:00
case YAP_HUP_SIGNAL:
at = AtomSigHup;
break;
2014-03-06 02:09:48 +00:00
#endif
#ifdef SIGUSR1
2016-01-03 02:06:09 +00:00
case YAP_USR1_SIGNAL:
at = AtomSigUsr1;
break;
2014-03-06 02:09:48 +00:00
#endif
#ifdef SIGUSR2
2016-01-03 02:06:09 +00:00
case YAP_USR2_SIGNAL:
at = AtomSigUsr2;
break;
#endif
#ifdef SIGFPE
2016-01-03 02:06:09 +00:00
case YAP_FPE_SIGNAL:
at = AtomSigFPE;
break;
2014-03-06 02:09:48 +00:00
#endif
2016-01-03 02:06:09 +00:00
default:
return FALSE;
2013-02-08 16:36:45 +00:00
}
2014-03-06 02:09:48 +00:00
return Yap_unify(ARG1, MkAtomTerm(at));
2013-02-08 16:36:45 +00:00
}
2016-01-03 02:06:09 +00:00
static Int continue_signals(USES_REGS1) { return first_signal(PASS_REGS1); }
2013-02-08 16:36:45 +00:00
2016-01-03 02:06:09 +00:00
void Yap_InitSignalCPreds(void) {
2013-02-08 16:36:45 +00:00
/* Basic predicates for the debugger */
Yap_InitCPred("$creep", 0, p_creep, SafePredFlag);
2013-12-11 09:34:43 +00:00
Yap_InitCPred("$creep_fail", 0, p_creep_fail, SafePredFlag);
2016-01-03 02:06:09 +00:00
Yap_InitCPred("$stop_creeping", 1, stop_creeping,
NoTracePredFlag | HiddenPredFlag | SafePredFlag);
Yap_InitCPred("$disable_debugging", 0, disable_debugging,
NoTracePredFlag | HiddenPredFlag | SafePredFlag);
Yap_InitCPred("$first_signal", 1, first_signal, SafePredFlag | SyncPredFlag);
Yap_InitCPred("$continue_signals", 0, continue_signals,
SafePredFlag | SyncPredFlag);
2015-09-21 23:05:36 +01:00
Yap_InitCPred("creep_allowed", 0, creep_allowed, 0);
2013-02-08 16:36:45 +00:00
#ifdef DEBUG
2016-01-03 02:06:09 +00:00
Yap_InitCPred("sys_debug", 1, p_debug, SafePredFlag | SyncPredFlag);
2013-02-08 16:36:45 +00:00
#endif
}
2014-03-06 02:09:48 +00:00
2016-01-03 02:06:09 +00:00
void *Yap_InitSignals(int wid) {
void *ptr = (void *)malloc(sizeof(UInt) * REMOTE_MaxActiveSignals(wid));
2014-03-08 00:03:58 +00:00
return ptr;
2014-03-06 02:09:48 +00:00
}