YAP 7.1.0
signals.yap
1/*************************************************************************
2 * *
3 * YAP Prolog *
4 * *
5 * Yap Prolog was developed at NCCUP - Universidade do Porto *
6 * *
7 * Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
8 * *
9 **************************************************************************
10 * *
11 * File: signals.pl *
12 * Last rev: *
13 * mods: *
14 * comments: signal handling in YAP *
15 * *
16 *************************************************************************/
17
18%%! @addtogroup OS
19%% @{
20:- system_module( '$_signals', [alarm/3,
21 on_exception/3,
23 raise_exception/1,
24 read_sig/0], []).
25
26:- '$meta_call'/2use_system_module( '$_boot', []).
27
28:- '$trace'/1use_system_module( '$_debug', []).
29
30:- '$thread_gfetch'/1use_system_module( '$_threads', []).
31
32/** @pred alarm(+ _Seconds_,+ _Callable_,+ _OldAlarm_)
33
34
35 Arranges for YAP to be interrupted in _Seconds_ seconds, or in
36 [ _Seconds_| _MicroSeconds_]. When interrupted, YAP will execute
37 _Callable_ and then return to the previous execution. If
38 _Seconds_ is `0`, no new alarm is scheduled. In any event,
39 any previously set alarm is canceled.
40
41 The variable _OldAlarm_ unifies with the number of seconds remaining
42 until any previously scheduled alarm was due to be delivered, or with
43 `0` if there was no previously scheduled alarm.
44
45 Note that execution of _Callable_ will wait if YAP is
46 executing built-in predicates, such as Input/Output operations.
47
48 The next example shows how _alarm/3_ can be used to implement a
49 simple clock:
50
51 ~~~~~
52 loop :- loop.
53
54 ticker :- write('.'), flush_output,
55 get_value(tick, yes),
56 alarm(1,ticker,_).
57
58 :- set_value(tick, yes), alarm(1,ticker,_), loop.
59 ~~~~~
60
61 The clock, `ticker`, writes a dot and then checks the flag
62 `tick` to see whether it can continue ticking. If so, it calls
63 itself again. Note that there is no guarantee that the each dot
64 corresponds a second: for instance, if the YAP is waiting for
65 user input, `ticker` will wait until the user types the entry in.
66
67 The next example shows how alarm/3 can be used to guarantee that
68 a certain procedure does not take longer than a certain amount of time:
69
70 ~~~~~
71 loop :- loop.
72
73 :- catch((alarm(10, throw(ball), _),loop),
74 ball,
75 format('Quota exhausted.~n',[])).
76 ~~~~~
77 In this case after `10` seconds our `loop` is interrupted,
78 `ball` is thrown, and the handler writes `Quota exhausted`.
79 Execution then continues from the handler.
80
81 Note that in this case `loop/0` always executes until the alarm is
82 sent. Often, the code you are executing succeeds or fails before the
83 alarm is actually delivered. In this case, you probably want to disable
84 the alarm when you leave the procedure. The next procedure does exactly so:
85
86 ~~~~~
87 once_with_alarm(Time,Goal,DoOnAlarm) :-
88 catch(execute_once_with_alarm(Time, Goal), alarm, DoOnAlarm).
89
90 execute_once_with_alarm(Time, Goal) :-
91 alarm(Time, alarm, _),
92 ( call(Goal) -> alarm(0, alarm, _) ; alarm(0, alarm, _), fail).
93 ~~~~~
94
95 The procedure `once_with_alarm/3` has three arguments:
96 the _Time_ to wait before the alarm is
97 sent; the _Goal_ to execute; and the goal _DoOnAlarm_ to execute
98 if the alarm is sent. It uses catch/3 to handle the case the
99 `alarm` is sent. Then it starts the alarm, calls the goal
100 _Goal_, and disables the alarm on success or failure.
101
102
103*/
104/** @pred on_signal(+ _Signal_,? _OldAction_,+ _Callable_)
105
106
107 Set the interrupt handler for soft interrupt _Signal_ to be
108 _Callable_. _OldAction_ is unified with the previous handler.
109
110 Only a subset of the software interrupts (signals) can have their
111 handlers manipulated through on_signal/3.
112 Their POSIX names, YAP names and default behavior is given below.
113 The "YAP name" of the signal is the atom that is associated with
114 each signal, and should be used as the first argument to
115 on_signal/3. It is chosen so that it matches the signal's POSIX
116 name.
117
118 on_signal/3 succeeds, unless when called with an invalid
119 signal name or one that is not supported on this platform. No checks
120 are made on the handler provided by the user.
121
122 + sig_up (Hangup)
123 SIGHUP in Unix/Linux; Reconsult the initialization files
124 ~/.yaprc, ~/.prologrc and ~/prolog.ini.
125 + sig_usr1 and sig_usr2 (User signals)
126 SIGUSR1 and SIGUSR2 in Unix/Linux; Print a message and halt.
127
128
129 A special case is made, where if _Callable_ is bound to
130 `default`, then the default handler is restored for that signal.
131
132 A call in the form `on_signal( _S_, _H_, _H_)` can be used
133 to retrieve a signal's current handler without changing it.
134
135 It must be noted that although a signal can be received at all times,
136 the handler is not executed while YAP is waiting for a query at the
137
138 prompt. The signal will be, however, registered and dealt with as soon
139 as the user makes a query.
140
141 Please also note, that neither POSIX Operating Systems nor YAP guarantee
142 that the order of delivery and handling is going to correspond with the
143 order of dispatch.
144*/
145:- meta_predicate on_signal(0,?,:), alarm(+,0,-).
146
147:- dynamic prolog:'$signal_handler'/1.
148
149'$creep'(Sig) :-
150 '$signal_handler'(Sig).
151
152'$signal_handler'(sig_creep) :-
153 '$disable_debugging'.
154
155'$signal_handler'(sig_int) :-
156 '$signal_handler',
157 '$clear_input'(user_input),
158 prompt1('Action (h for help)'),
159 get_char(user_input,C),
160 int_action(C).
161'$signal_handler'(sig_iti) :-
162 '$thread_gfetch'(Goal),
163 % if more signals alive, set creep flag
164 '$current_module'(M0),
165 '$execute0'(Goal,M0).
166'$signal_handler'(sig_trace) :-
167 '$signal_handler'.
168'$signal_handler'(sig_debug) :-
169 '$signal_handler'.
170'$signal_handler'(sig_alarm) :-
171 throw(timeout).
172'$signal_handler'(sig_vtalarm) :-
173 throw(timeout).
174'$signal_handler'(sig_hup) :-
175 '$reload'.
176'$signal_handler'(sig_debug ) :-
177 '$signal_handler'.
178'$signal_handler'(sig_trace ) :-
179 '$signal_handler'.
180'$signal_handler'(sig_vtalarm) :-
181 throw(timeout).
182'$signal_handler'(sig_usr1) :-
183 throw(error(signal(usr1,[]),true)).
184'$signal_handler'(sig_usr2) :-
185 throw(error(signal(usr2,[]),true)).
186'$signal_handler'(sig_pipe) :-
187 throw(error(signal(pipe,[]),true)).
188'$signal_handler'(sig_fpe) :-
189 throw(error(signal(fpe,[]),true)).
190
191int_action(s) :-
192 int_action.
193int_action(t) :-
194 int_action,
195 '$creep'.
196
197
198'$start_creep'(Mod:G) :-
200 '$trace_goal'(G, Mod, outer ,_,CP).
201
202'$no_creep_call'('$execute_clause'(G,Mod,Ref,CP),_) :- '$no_creep_call',
203 '$enable_debugging',
204 '$execute_clause'(G,Mod,Ref,CP).
205'$no_creep_call'('$execute_nonstop'(G, M),_) :- '$no_creep_call',
206 '$enable_debugging',
207 '$execute_nonstop'(G, M).
208'$no_creep_call'(G, M) :-
209 '$enable_debugging',
210 '$execute_nonstop'(G, M).
211
212
213
214
215
216
217% reconsult init files. %
218'$reload' :-
219 (( exists('~/.yaprc') -> [-'~/.yaprc'] ; ),
220 ( exists('~/.prologrc') -> [-'~/.prologrc'] ; ),
221 ( exists('~/prolog.ini') -> [-'~/prolog.ini'] ; )).
222% die on signal default. %
223
224
225on_signal(Signal,OldAction,NewAction) :-
226 var(Signal), var,
227 (nonvar(OldAction) -> on_signal/3throw(error(instantiation_error,)) ; throw),
228 '$signal'(Signal),
229 on_signal(Signal, OldAction, NewAction).
230on_signal(Signal,OldAction,default) :-
231 '$reset_signal'(Signal, OldAction).
232on_signal(_Signal,_OldAction,Action) :-
233 var(Action), var,
234 throw(error('SYSTEM_ERROR_INTERNAL','Somehow the meta_predicate declarations of on_signal are subverted!')).
235on_signal(Signal,OldAction,Action) :-
236 OldAction == Action,
237 on_signal,
238 clause('$signal_handler'(Signal), OldAction).
239on_signal(Signal,_OldAction,Action) :-
240 ( Action = _M:Goal -> true ; on_signal/3throw(error(type_error(callable,Action),)) ),
241 % the following disagrees with 13211-2:6.7.1.4 which disagrees with 13211-1:7.12.2a %
242 % but the following agrees with 13211-1:7.12.2a %
243 ( nonvar(M) -> nonvar ; on_signal/3throw(error(instantiation_error,)) ),
244 ( atom(M) -> atom ; on_signal/3throw(error(type_error(callable,Action),)) ),
245 ( nonvar(Goal) -> nonvar ; on_signal/3throw(error(instantiation_error,)) ),
246 retractall('$signal_handler'(Signal)),
247 assert(('$signal_handler'(Signal) :- Action)).
248
249
250alarm(Interval, Goal, Left) :-
251 Interval == 0, alarm,
252 alarm(0, 0, Left0, _),
253 on_signal(sig_alarm, _, Goal),
254 Left = Left0.
255alarm(Interval, Goal, Left) :-
256 integer(Interval), integer,
257 on_signal(sig_alarm, _, Goal),
258 '$alarm'(Interval, 0, Left, _).
259alarm(Number, Goal, Left) :-
260 float(Number), float,
261 Secs is integer(Number),
262 USecs is integer((Number-Secs)*1000000) mod 1000000,
263 on_signal(sig_alarm, _, Goal),
264 alarm(Secs, USecs, Left, _).
265alarm([Interval|USecs], Goal, [Left|LUSecs]) :-
266 on_signal(sig_alarm, _, Goal),
267 alarm(Interval, USecs, Left, LUSecs).
268
269raise_exception(Ball) :- throw(Ball).
270
271on_exception(Pat, G, H) :- catch(G, Pat, H).
272
273catch :-
274 recorded('$signal_handler',X,_),
275 writeq(X),writeq,
276 writeq.
277writeq.
278
279 % %
280 % make thes predicates non-traceable. %
281
282:- '$set_no_trace'(current_choice_point(_DCP), prolog).
283:- '$set_no_trace'(cut_by(_DCP), prolog).
284:- '$set_no_trace'(true, prolog).
285:- '$set_no_trace'('$call'(_,_,_,_), prolog).
286:- '$set_no_trace'('$execute_nonstop'(_,_), prolog).
287:- '$set_no_trace'('$execute_clause'(_,_,_,_), prolog).
288:- '$set_no_trace'('$restore_regs'(_,_), prolog).
289:- '$set_no_trace'('$undefp'(_), prolog).
290:- '$set_no_trace'('$Error'(_), prolog).
291:- '$set_no_trace'('$LoopError'(_,_), prolog).
292%:- '$set_no_trace'('$TraceError'(_,_,_), prolog).
293%:- '$set_no_trace'('$handle_error'(_,_,_), prolog).
294
295
296%%! @}
297
alarm(+ Seconds,+ Callable,+ OldAlarm)
catch( : Goal,+ Exception,+ Action)
clause(+ H, B)
on_signal(+ Signal,? OldAction,+ Callable)
prompt1(+ _A__)
throw(+ Ball)
get_char(+ S,- C)
assert(+ C)
retractall(+ G)
exists(+ F)
atom( T)
current_choice_point( -CP )
float( T)
integer( T)
nonvar( T)
var( T)