YAP 7.1.0
signals.c
1/*************************************************************************
2 * *
3 * YAP Prolog *
4 * *
5 * Yap Prolog was developed at NCCUP - Universidade do Porto *
6 * *
7 * Copyright L.Damas, V. Santos Costa and Universidade do Porto 1985-- *
8 * *
9 **************************************************************************
10 * *
11 * File: signal.c *
12 * comments: Signal Handling & Debugger Support *
13 * *
14 * *
15 * *
16 *************************************************************************/
17#ifdef SCCS
18static char SccsId[] = "%W% %G%";
19#endif
20
21#define HAS_CACHE_REGS 1
22
23#include "Yap.h"
24#if HAVE_UNISTD_H
25#include <unistd.h>
26#endif
27#if _WIN32
28#include <io.h>
29#include <stdio.h>
30#endif
31#include "YapEval.h"
32#include "YapHeap.h"
33#include "Yatom.h"
34#include "yapio.h"
35#ifdef TABLING
36#include "tab.macros.h"
37#endif /* TABLING */
38#include <stdio.h>
39#include <stdlib.h>
40#if HAVE_STRING_H
41#include <string.h>
42#endif
43#if HAVE_STRINGS_H
44#include <strings.h>
45#endif
46#if HAVE_MALLOC_H
47#include <malloc.h>
48#endif
49#include <wchar.h>
50#ifdef LOW_LEVEL_TRACER
51#include <tracer.h>
52#endif
53
54/*
55 * The InteractSIGINT function is called after a normal interrupt had been
56 * caught.
57 * It allows 6 possibilities: abort, continue, trace, debug, help, exit.
58 */
59static yap_signals InteractSIGINT(int ch) {
60#ifdef HAVE_SETBUF
61 /* make sure we are not waiting for the end of line */
62 setbuf(stdin, NULL);
63#endif
64 switch (ch) {
65 case 'a':
66/* abort computation */
67#if PUSH_REGS
68 // restore_absmi_regs(&Yap_standard_regs);
69#endif
70 Yap_ThrowError(ABORT_EVENT,TermDAbort,NULL);
71 return YAP_ABORT_SIGNAL;
72 case 'b':
73 /* continue */
74 Yap_suspend_goal(TermBreak);
75 return YAP_BREAK_SIGNAL;
76 case 'c':
77 /* continue */
78 return YAP_NO_SIGNAL;
79 case 'd':
80 /* enter debug mode */
81 Yap_suspend_goal(TermDebug);
82 return YAP_DEBUG_SIGNAL;
83 case 'e':
84 /* exit */
85 Yap_exit(1);
86 return YAP_EXIT_SIGNAL;
87 case 'g':
88 /* stack dump */
89 return YAP_STACK_DUMP_SIGNAL;
90 case 't':
91 /* start tracing */
92 Yap_suspend_goal(TermTrace);
93 return YAP_TRACE_SIGNAL;
94#ifdef LOW_LEVEL_TRACER
95 case 'T':
96 toggle_low_level_trace();
97 return YAP_NO_SIGNAL;
98#endif
99 case 's':
100 /* show some statistics */
101 Yap_suspend_goal(TermStatistics);
102 return YAP_STATISTICS_SIGNAL;
103 case EOF:
104 return YAP_NO_SIGNAL;
105 case 'h':
106 case '?':
107 default:
108 /* show an helpful message */
109 fprintf(stderr, "Please press one of:\n");
110 fprintf(stderr, " a for abort\n c for continue\n d for debug\n");
111 fprintf(stderr, " e for exit\n g for stack dump\n s for statistics\n t "
112 "for trace\n");
113 fprintf(stderr, " b for break\n");
114 return YAP_NO_SIGNAL;
115 }
116}
117
124static yap_signals ProcessSIGINT(void) {
125 CACHE_REGS
126 int ch, out;
127
128#if _WIN32
129 if (!_isatty(0)) {
130 return YAP_INT_SIGNAL;
131 }
132#elif HAVE_ISATTY
133 if (!isatty(0)) {
134 return YAP_INT_SIGNAL;
135 }
136#endif
137 LOCAL_PrologMode |= AsyncIntMode;
138 do {
139 ch = Yap_GetCharForSIGINT();
140 } while (!(out = InteractSIGINT(ch)));
141 LOCAL_PrologMode &= ~AsyncIntMode;
142 return (out);
143}
144
145inline static void do_signal(int wid, yap_signals sig USES_REGS) {
146#if THREADS
147 __sync_fetch_and_or(&REMOTE(wid)->Signals_, SIGNAL_TO_BIT(sig));
148 if (!REMOTE_InterruptsDisabled(wid)) {
149 REMOTE_ThreadHandle(wid).current_yaam_regs->CreepFlag_ =
150 Unsigned(REMOTE_ThreadHandle(wid).current_yaam_regs->LCL0_);
151 }
152#else
153 if (!LOCAL_InterruptsDisabled) {
154 LOCAL_Signals |= SIGNAL_TO_BIT(sig);
155 CreepFlag = Unsigned(LCL0);
156 }
157#endif
158}
159
160inline static bool get_signal(yap_signals sig USES_REGS) {
161#if THREADS
162 uint64_t old;
163
164 // first, clear the Creep Flag, now if someone sets it it is their problem
165 CalculateStackGap(PASS_REGS1);
166 // reset the flag
167 if ((old = __sync_fetch_and_and(&LOCAL_Signals, ~SIGNAL_TO_BIT(sig))) !=
168 SIGNAL_TO_BIT(sig)) {
169 if (!LOCAL_InterruptsDisabled && LOCAL_Signals != 0) {
170 CreepFlag = (CELL)LCL0;
171 }
172 if (!(old & SIGNAL_TO_BIT(sig))) {
173 // not there?
174 return FALSE;
175 }
176 // more likely case, we have other interrupts.
177 return TRUE;
178 }
179 // success, we are good
180 return TRUE;
181// should we set the flag?
182#else
183 if (LOCAL_Signals & SIGNAL_TO_BIT(sig)) {
184 LOCAL_Signals &= ~SIGNAL_TO_BIT(sig);
185 if (!LOCAL_InterruptsDisabled && LOCAL_Signals != 0) {
186 CreepFlag = (CELL)LCL0;
187 } else {
188 CalculateStackGap(PASS_REGS1);
189 }
190 return TRUE;
191 } else {
192 return FALSE;
193 }
194#endif
195}
196
197bool Yap_DisableInterrupts(int wid) {
198 LOCAL_InterruptsDisabled = true;
199 LOCAL_debugger_state[DEBUG_DEBUG] = TermFalse;
200 LOCAL_InterruptsDisabled = true;
201 YAPEnterCriticalSection();
202 return true;
203}
204
205bool Yap_EnableInterrupts(int wid ) {
206 LOCAL_debugger_state[DEBUG_DEBUG]= getAtomicLocalPrologFlag(DEBUG_FLAG);
207 LOCAL_InterruptsDisabled = false;
208 YAPLeaveCriticalSection();
209 return true;
210}
211
215bool Yap_HandleSIGINT(void) {
216 CACHE_REGS
217 yap_signals sig;
218
219 do {
220 if ((sig = ProcessSIGINT()) != YAP_NO_SIGNAL)
221 LOCAL_PrologMode &= ~InterruptMode;
222 do_signal(worker_id, sig PASS_REGS);
223 return true;
224 } while (get_signal(YAP_INT_SIGNAL PASS_REGS));
225 return false;
226}
227
228
229void Yap_signal(yap_signals sig) {
230 CACHE_REGS
231 do_signal(worker_id, sig PASS_REGS);
232}
233
234
235#ifdef DEBUG
236static Int p_debug(USES_REGS1);
237#endif
238
239void Yap_external_signal(int wid, yap_signals sig) {
240#if THREADS
241 REGSTORE *regcache = REMOTE_ThreadHandle(wid).current_yaam_regs;
242#endif
243 do_signal(wid, sig PASS_REGS);
244 LOCAL_PrologMode &= ~InterruptMode;
245}
246
247int Yap_get_signal__(yap_signals sig USES_REGS) {
248 return get_signal(sig PASS_REGS);
249}
250
251// the caller holds the lock.
252int Yap_has_signals__(yap_signals sig1, yap_signals sig2 USES_REGS) {
253 return LOCAL_Signals & (SIGNAL_TO_BIT(sig1) | SIGNAL_TO_BIT(sig2));
254}
255
256int Yap_only_has_signals__(yap_signals sig1, yap_signals sig2 USES_REGS) {
257 uint64_t sigs = LOCAL_Signals;
258 return sigs & (SIGNAL_TO_BIT(sig1) | SIGNAL_TO_BIT(sig2)) &&
259 !(sigs & ~(SIGNAL_TO_BIT(sig1) | SIGNAL_TO_BIT(sig2)));
260}
261
262#ifdef DEBUG
263
264volatile int volat = 0;
265
266static Int p_debug(USES_REGS1) { /* $debug(+Flag) */
267 int i = IntOfTerm(Deref(ARG1));
268 while (volat == 0) {
269 }
270 if (i >= 'a' && i <= 'z')
271 GLOBAL_Option[i - 96] = !GLOBAL_Option[i - 96];
272 return 1;
273}
274void Yap_loop(void);
275void Yap_debug_end_loop(void);
276
277void Yap_loop(void) {
278 while (volat == 0)
279 ;
280}
281
282void Yap_debug_end_loop(void) { volat = 1; }
283#endif
284
285static Term sig_to_term(yap_signals sig)
286{
287 Atom at;
288 switch (sig) {
289 case YAP_INT_SIGNAL:
290 return TermSigInt;
291 case YAP_ABORT_SIGNAL:
292 return TermDAbort;
293 case YAP_CREEP_SIGNAL:
294 return TermSigCreep;
295 case YAP_TRACE_SIGNAL:
296 return TermSigTrace;
297 case YAP_DEBUG_SIGNAL:
298 return TermSigDebug;
299 case YAP_BREAK_SIGNAL:
300 return TermSigBreak;
301 case YAP_FAIL_SIGNAL:
302 return TermFail;
303 case YAP_STACK_DUMP_SIGNAL:
304 return TermSigStackDump;
305 case YAP_STATISTICS_SIGNAL:
306 return TermSigStatistics;
307 #ifdef SIGALRM
308 case YAP_ALARM_SIGNAL:
309#endif
310 case YAP_WINTIMER_SIGNAL:
311 return TermSigAlarm;
312 #ifdef SIGVTALRM
313 case YAP_VTALARM_SIGNAL:
314 return TermSigVTAlarm;
315 #endif
316 case YAP_EXIT_SIGNAL:
317 Yap_exit(1);
318 return FALSE;
319 case YAP_WAKEUP_SIGNAL:
320 return TermSigWakeUp;
321 case YAP_ITI_SIGNAL:
322 return TermSigIti;
323 #ifdef SIGPIPE
324 case YAP_PIPE_SIGNAL:
325 return TermSigPipe;
326 #endif
327#ifdef SIGHUP
328 case YAP_HUP_SIGNAL:
329 return TermSigHup;
330 #endif
331#ifdef SIGUSR1
332 case YAP_USR1_SIGNAL:
333 return TermSigUsr1;
334#endif
335#ifdef SIGUSR2
336 case YAP_USR2_SIGNAL:
337 return TermSigUsr2;
338#endif
339#ifdef SIGFPE
340 case YAP_FPE_SIGNAL:
341 return TermSigFPE;
342#endif
343 default:
344 return 0;
345 }
346 return MkAtomTerm(at);
347}
348
349
350Term Yap_next_signal( USES_REGS1 )
351{
352 yap_signals sig;
353 uint64_t mask = LOCAL_Signals;
354 if (mask == 0)
355 return FALSE;
356#if HAVE___BUILTIN_FFSLL
357 sig = __builtin_ffsll(mask);
358#elif HAVE_FFSLL
359 sig = ffsll(mask);
360#else
361 sig = Yap_msb(mask PASS_REGS) + 1;
362#endif
363 if (get_signal(sig PASS_REGS))
364 return sig_to_term(sig);
365 return 0;
366}
367
368
369
370
371static Int first_signal(USES_REGS1) {
372 Term t;
373
374 while((t = Yap_next_signal(PASS_REGS1))) {
375 if (t == TermSigInt) {
376 yap_signals sig = ProcessSIGINT();
377 if (sig == YAP_INT_SIGNAL) {
378 break;
379 }
380 if (sig != YAP_NO_SIGNAL)
381 continue;
382 return FALSE;
383 } else if (t == TermDAbort) {
384 /* abort computation */
385 LOCAL_PrologMode &= ~AsyncIntMode;
386 if (LOCAL_PrologMode & (GCMode | ConsoleGetcMode | CritMode)) {
387 LOCAL_PrologMode |= AbortMode;
388 return -1;
389 } else {
390 Yap_Error(ABORT_EVENT, TermNil, "abort from console");
391 }
392 Yap_RestartYap(1);
393 return FALSE;
394 } else {
395 break;
396 }
397 }
398 return Yap_unify(ARG1, t);
399}
400
401static Int continue_signals(USES_REGS1) { return first_signal(PASS_REGS1); }
402
403void Yap_InitSignalCPreds(void) {
404 /* Basic predicates for the debugger */
405 Yap_InitCPred("$first_signal", 1, first_signal, SafePredFlag | SyncPredFlag);
406 Yap_InitCPred("$continue_signals", 0, continue_signals,
407 SafePredFlag | SyncPredFlag);
408#ifdef DEBUG
409 Yap_InitCPred("sys_debug", 1, p_debug, SafePredFlag | SyncPredFlag);
410#endif
411}
412
413void * Yap_InitSignals(int wid) {
414 void *ptr = (void *)malloc(sizeof(UInt) * REMOTE_MaxActiveSignals(wid));
415 return ptr;
416}
Main definitions.