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. |