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

469 lines
9.9 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-- *
* *
**************************************************************************
* *
* File: signal.c *
* comments: Signal Handling & Debugger Support *
* *
* *
* *
*************************************************************************/
2013-02-08 16:36:45 +00:00
#ifdef SCCS
static char SccsId[] = "%W% %G%";
#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 <stdio.h>
#include <io.h>
#endif
2013-02-08 16:36:45 +00:00
#include "Yatom.h"
#include "YapHeap.h"
#include "eval.h"
#include "yapio.h"
#ifdef TABLING
#include "tab.macros.h"
#endif /* TABLING */
2014-11-28 02:30:19 +00:00
#include <stdlib.h>
2013-02-08 16:36:45 +00:00
#include <stdio.h>
#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
2014-03-06 14:07:33 +00:00
/*
* 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 */
2015-06-19 01:30:13 +01:00
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 */
2014-09-08 23:13:39 +01:00
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);
}
2013-02-08 16:36:45 +00:00
inline static void
2014-03-06 02:09:48 +00:00
do_signal(int wid, yap_signals sig USES_REGS)
2013-02-08 16:36:45 +00:00
{
2014-03-06 14:07:33 +00:00
#if THREADS
__sync_fetch_and_or ( &REMOTE(wid)->Signals_, SIGNAL_TO_BIT(sig));
2014-03-06 02:09:48 +00:00
if (!REMOTE_InterruptsDisabled(wid)) {
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) {
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
}
2014-03-06 02:09:48 +00:00
inline static int
get_signal(yap_signals sig USES_REGS)
2013-02-08 16:36:45 +00:00
{
#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
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;
}
2014-09-03 17:02:28 +01:00
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;
// should we set the flag?
#else
2014-09-03 17:02:28 +01:00
if (LOCAL_Signals & SIGNAL_TO_BIT(sig)) {
LOCAL_Signals &= ~SIGNAL_TO_BIT(sig);
if (!LOCAL_InterruptsDisabled && LOCAL_Signals != 0) {
2014-09-03 17:02:28 +01:00
CreepFlag = (CELL)LCL0;
} else {
CalculateStackGap( PASS_REGS1 );
}
return TRUE;
} else {
return FALSE;
2014-03-06 02:09:48 +00:00
}
#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;
2013-02-08 16:36:45 +00:00
}
return 0;
2013-02-08 16:36:45 +00:00
}
static Int
p_creep( USES_REGS1 )
{
Atom at;
PredEntry *pred;
at = AtomCreep;
pred = RepPredProp(PredPropByFunc(Yap_MkFunctor(at, 1),0));
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;
}
2013-12-11 09:34:43 +00:00
static Int
p_creep_fail( USES_REGS1 )
{
Atom at;
PredEntry *pred;
at = AtomCreep;
pred = RepPredProp(PredPropByFunc(Yap_MkFunctor(at, 1),0));
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;
}
2015-07-06 11:59:50 +01:00
static Int stop_creeping( USES_REGS1 )
2013-02-08 16:36:45 +00:00
{
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
}
static Int
2015-09-21 23:05:36 +01:00
creep_allowed( USES_REGS1 )
2013-02-08 16:36:45 +00:00
{
if (PP != NULL) {
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
}
2015-09-21 23:05:36 +01:00
return false;
2013-02-08 16:36:45 +00:00
}
void
Yap_signal(yap_signals sig)
{
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
static Int
p_debug( USES_REGS1 );
2014-11-10 01:56:56 +00:00
#endif
2013-02-08 16:36:45 +00:00
void
2014-03-06 02:09:48 +00:00
Yap_external_signal(int wid, yap_signals sig)
2013-02-08 16:36:45 +00:00
{
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
}
int
Yap_get_signal__(yap_signals sig USES_REGS)
2014-03-06 02:09:48 +00:00
{
return get_signal(sig PASS_REGS);
2014-03-06 02:09:48 +00:00
}
// the caller holds the lock.
2014-03-06 02:09:48 +00:00
int
Yap_has_signals__(yap_signals sig1, yap_signals sig2 USES_REGS)
{
2014-09-03 17:02:28 +01:00
return LOCAL_Signals & (SIGNAL_TO_BIT(sig1)|SIGNAL_TO_BIT(sig2));
2014-03-06 02:09:48 +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)) &&
! (sigs & ~(SIGNAL_TO_BIT(sig1) | SIGNAL_TO_BIT(sig2))) ;
2013-02-08 16:36:45 +00:00
}
#ifdef DEBUG
volatile int volat = 0;
2013-02-08 16:36:45 +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];
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;
}
2013-02-08 16:36:45 +00:00
#endif
static Int
p_first_signal( USES_REGS1 )
{
2014-03-06 02:09:48 +00:00
Atom at;
yap_signals sig;
while (TRUE) {
uint64_t mask = LOCAL_Signals;
if (mask == 0)
return FALSE;
#if HAVE___BUILTIN_FFSLL
2015-01-18 03:47:44 +00:00
sig = __builtin_ffsll(mask);
#elif HAVE_FFSLL
sig = ffsll(mask);
#else
2015-06-19 01:30:13 +01:00
sig = Yap_msb( mask PASS_REGS)+1;
#endif
if (get_signal(sig PASS_REGS)) {
break;
}
2015-01-18 03:47:44 +00:00
}
loop:
2014-03-06 02:09:48 +00:00
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 {
2015-09-25 10:57:26 +01:00
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
case YAP_ALARM_SIGNAL:
2014-03-06 02:09:48 +00:00
#endif
case YAP_WINTIMER_SIGNAL:
at = AtomSigAlarm;
break;
2014-03-06 02:09:48 +00:00
#ifdef SIGVTALRM
case YAP_VTALARM_SIGNAL:
at = AtomSigVTAlarm;
break;
2014-03-06 02:09:48 +00:00
#endif
2014-09-08 23:13:39 +01: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
case YAP_PIPE_SIGNAL:
at = AtomSigPipe;
break;
2014-03-06 02:09:48 +00:00
#endif
#ifdef SIGHUP
case YAP_HUP_SIGNAL:
at = AtomSigHup;
break;
2014-03-06 02:09:48 +00:00
#endif
#ifdef SIGUSR1
case YAP_USR1_SIGNAL:
at = AtomSigUsr1;
break;
2014-03-06 02:09:48 +00:00
#endif
#ifdef SIGUSR2
case YAP_USR2_SIGNAL:
at = AtomSigUsr2;
break;
#endif
#ifdef SIGFPE
case YAP_FPE_SIGNAL:
at = AtomSigFPE;
break;
2014-03-06 02:09:48 +00:00
#endif
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
}
static Int
p_continue_signals( USES_REGS1 )
{
return p_first_signal( PASS_REGS1 );
2013-02-08 16:36:45 +00:00
}
void
Yap_InitSignalCPreds(void)
{
/* 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);
2015-07-06 11:59:50 +01:00
Yap_InitCPred("$stop_creeping", 0, stop_creeping, NoTracePredFlag|HiddenPredFlag|SafePredFlag);
Yap_InitCPred("$disable_debugging", 0, stop_creeping, NoTracePredFlag|HiddenPredFlag|SafePredFlag);
2013-02-08 16:36:45 +00:00
Yap_InitCPred ("$first_signal", 1, p_first_signal, SafePredFlag|SyncPredFlag);
Yap_InitCPred ("$continue_signals", 0, p_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
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
2014-03-08 00:03:58 +00:00
void *Yap_InitSignals(int wid)
2014-03-06 02:09:48 +00:00
{
2014-03-08 00:03:58 +00:00
void *ptr = (void *)malloc(sizeof(UInt)*REMOTE_MaxActiveSignals(wid));
return ptr;
2014-03-06 02:09:48 +00:00
}