1 % (c) 2011-2024 Lehrstuhl fuer Softwaretechnik und Programmiersprachen,
2 % Heinrich Heine Universitaet Duesseldorf
3 % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html)
4
5 :- module(user_signal, [ user_interruptable_call_det/2
6 , protect_from_user_interrupt_det/1
7 , ignore_user_interrupt_det/1
8 , get_user_signal_ref/1
9 , init_user_signal/1]).
10
11 :- use_module('../../src/module_information.pl').
12
13 :- module_info(group,infrastructure).
14 :- module_info(description,'This is the interface to C code for interrupting Prolog runs with a UNIX signal.').
15
16 :- meta_predicate user_interruptable_call_det(0,-).
17 :- meta_predicate protect_from_user_interrupt_det(0).
18 :- meta_predicate ignore_user_interrupt_det(0).
19
20 :- load_files(library(system), [when(compile_time), imports([environ/2])]).
21 :- if((environ(no_interrupts,true) ; \+ predicate_property(load_foreign_resource(_), _))).
22 % turn off user interrupt handling: ctrl-c jumps into Prolog debugger
23
24 :- write('user interrupt handling for CTRL-C disabled'),nl.
25
26 user_interruptable_call_det(Call,Result) :- call(Call), Result=ok.
27 ignore_user_interrupt_det(Call) :- call(Call).
28 protect_from_user_interrupt_det(Call) :- call(Call).
29 get_user_signal_ref(off).
30 init_user_signal(ok).
31
32 :- else.
33 foreign_resource(user_signal, [set_user_signal_mode,get_user_signal_mode,user_signal_init,get_user_sig_reference]).
34 foreign(user_signal_init, user_signal_init).
35 foreign(set_user_signal_mode, set_user_signal_mode(+integer,+integer)).
36 foreign(get_user_signal_mode, get_user_signal_mode([-integer])).
37 foreign(get_user_sig_reference, get_user_sig_reference([-integer])).
38
39 :- dynamic loaded/1.
40
41 :- use_module(probsrc(pathes_lib),[safe_load_foreign_resource/2]).
42
43 init_user_signal(Res) :- catch((loadfr,(loaded(success) -> Res=ok ; Res=fail)), Exc, Res=Exc).
44
45 loadfr :-
46 ( loaded(_) -> true
47 ; safe_load_foreign_resource(user_signal,user_signal)
48 -> user_signal_init,
49 %write(user_signal_int),nl,
50 assertz(loaded(success))
51 ; format(user_output,"You can set the environment variable no_interrupts to true to avoid using the user_interrupt library~n",[]),
52 assertz(loaded(failure))
53 ).
54
55
56 % user signal mode can by
57 % status_ignore=0, status_protected=1, status_default=2
58 % mode 2: a received signal will raise a Prolog exception
59
60 :- meta_predicate catch_interrupt_exception(0,-).
61 catch_interrupt_exception(Call,Result) :-
62 ? catch( call(Call),
63 E,
64 (E==user_interrupt_signal -> Result=interrupted ; throw(E))),
65 (Result == interrupted -> true ; Result=ok).
66
67 %% user_interruptable_call_det(Call,Result) :- !,call(Call), Result=ok. % comment in to turn off CTRL-C
68 user_interruptable_call_det(Call,Result) :-
69 loadfr,
70 get_user_signal_mode(Mode),
71 call_cleanup( (set_user_signal_mode(1,2), % 2=status_default -> raise exceptions
72 catch_interrupt_exception(Call,Result),!),
73 set_user_signal_mode(1,Mode)). % look_for_queued=1 -> raise exception if one is queued
74
75 %% protect_from_user_interrupt_det(Call) :- !. % comment in to turn off CTRL-C
76 protect_from_user_interrupt_det(Call) :-
77 loadfr,
78 get_user_signal_mode(Mode),
79 call_cleanup( (set_user_signal_mode(0,1), call(Call), !), % look_for_queued=0, 1=status_protected; CTRL-C queued
80 set_user_signal_mode(1,Mode)). % look_for_queued=1 -> raise exception if one is queued
81
82 ignore_user_interrupt_det(Call) :-
83 loadfr,
84 get_user_signal_mode(Mode),
85 call_cleanup( (set_user_signal_mode(0,0), call(Call), !), % 0=status_ignore; CTRL-C completely ignored
86 set_user_signal_mode(0,Mode)).
87
88 get_user_signal_ref(Ref) :-
89 loadfr,
90 get_user_sig_reference(Ref).
91 :- endif.