1% BEGIN LICENSE BLOCK
2% Version: CMPL 1.1
3%
4% The contents of this file are subject to the Cisco-style Mozilla Public
5% License Version 1.1 (the "License"); you may not use this file except
6% in compliance with the License.  You may obtain a copy of the License
7% at www.eclipse-clp.org/license.
8% 
9% Software distributed under the License is distributed on an "AS IS"
10% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
11% the License for the specific language governing rights and limitations
12% under the License. 
13% 
14% The Original Code is  The ECLiPSe Constraint Logic Programming System. 
15% The Initial Developer of the Original Code is  Cisco Systems, Inc. 
16% Portions created by the Initial Developer are
17% Copyright (C) 2006 Cisco Systems, Inc.  All Rights Reserved.
18% 
19% Contributor(s): 
20% 
21% END LICENSE BLOCK
22
23:- comment(alias, "Event Handling").
24:- comment(summary, "Built-ins to handle events and interrupts").
25:- comment(categories, ["Built-In Predicates"]).
26
27:- tool(error / 2).
28:- tool(error / 3).
29:- tool(event_create / 3).
30:- tool(set_event_handler / 2).
31:- tool(set_interrupt_handler / 2).
32
33:- comment(cancel_after_event / 2, [
34	summary:"Cancel all pending instances of after event Event",
35	amode:(cancel_after_event(+,-) is det),
36	desc:html("   All instances of the pending after event Event is 
37   cancelled so that the event will not be triggered. A pending after event 
38   is an event which is setup by either event_after/2, event_after/3 or 
39   event_after_every/2, and which is waiting to be raised 
40   (event_after_every/2 will always be pending as it is raised repeatedly).
41<P>
42   CancelledEvents is the list of after events that have been cancelled. 
43   Each element of CancelledEvents is of the form of an event specified
44   in Events of events_after / 1. As a result, CancelledEvents can be
45   reposted using events_after(CancelledEvents). If there was no event
46   to cancel, CancelledEvents will be bound to the empty list.
47<P>
48   Note that the processing of an already raised, but as yet unprocessed
49   event will not be cancelled by this predicate (but you can use
50   event_disable/1 to achieve this).
51"),
52	args:["Event" : "Atom or Handle", "CancelledEvents" : "Variable"],
53	exceptions:[5 : "Event is not an atom."],
54	eg:"
55    % setup an after event and cancel immediatedly
56    ?- event_create(writeln(hi), [], E),
57	event_after(E, 3.2),
58	cancel_after_event(E, Cancelled).
59    E = 'EVENT'(16'ed980a58)
60    Cancelled = ['EVENT'(16'ed980a58) - 3.1999999999999886]
61    Yes (0.00s cpu)
62
63    % no after-event requested, nothing to cancel
64    ?- event_create(writeln(hi), [], E),
65	cancel_after_event(E, Cancelled).
66    E = 'EVENT'(16'ed980a58)
67    Cancelled = []
68    Yes (0.00s cpu)
69
70    % setup an after event and cancel immediatedly
71    ?- event_create(writeln(hi), [], E1),
72	event_after_every(E1, 1),
73	event_create((cancel_after_event(E1, C1), writeln(cancelled(C1))), [], E2),
74	event_after(E2, 5),
75	repeat, fail.
76    hi
77    hi
78    hi
79    hi
80    cancelled(['EVENT'(16'edbc0cc0) - every(1)])
81
82",
83	see_also:[event_after / 2, event_after / 3, event_disable/1,
84                  event_after_every / 2, event / 1, set_event_handler / 2, 
85                  current_after_events / 1, event_create / 3, event_retrieve / 3]]).
86
87:- comment(current_error / 1, [
88	summary:"Succeeds if N unifies with a valid error number.
89
90",
91	amode:(current_error(+) is semidet),
92	amode:(current_error(-) is multi),
93	desc:html("   Used to generate on backtracking all the current valid error numbers.  N
94   is a variable.
95
96<P>
97   Also used to check that N is a valid error number.  N is an integer.
98
99<P>
100"),
101	args:["N" : "Positive integer or variable."],
102	fail_if:"Fails if N is not a valid error number.",
103	exceptions:[5 : "N is instantiated, but not to an integer."],
104	eg:"
105Success:
106      ?- current_error(N).
107      N = 1     More? (;)       % type `;'
108      N = 2     More? (;)
109      N = 4     More? (;)
110      N = 5     More? (;)       % carriage return typed
111      yes.
112
113      ?- [user].
114       list_error1(String, N, Message) :-
115              current_error(N),
116              error_id(N, Message),
117              substring(Message, String, _).
118       user compiled 208 bytes in 0.03 seconds
119
120      ?- list_error1(\"def\",N,M).
121      N = 21
122      M = \"undefined arithmetic expression\"     More? (;)
123      yes.
124
125Fail:
126      current_error(3).
127
128Error:
129      current_error(1.0).   (Error 5).
130
131
132
133",
134	see_also:[error_id / 2]]).
135
136:- comment(error_id / 2, [
137	summary:"Succeeds if Message unifies with the error message string defined for error
138number N.
139
140",
141	amode:(error_id(+,-) is det),
142	desc:html("   This predicate unifies Message with the message string defined for error
143   number N.
144
145<P>
146"),
147	args:["N" : "Positive integer.", "Message" : "String or variable."],
148	exceptions:[4 : "N is not instantiated.", 5 : "N is instantiated, but not to an integer.", 5 : "Message is instantiated, but not to a string."],
149	eg:"
150Success:
151      error_id(80,M).
152           (gives M=\"not a module\").
153      error_id(70,M).
154           (gives M=\"accessing an undefined dynamic procedure\").
155      error_id(60,M).
156           (gives M=\"accessing an undefined procedure\").
157      error_id(90,M).
158           (gives M=\"declaration not at module beginning\").
159
160      ?- [user].
161       warning_handler(X, Where) :-
162              write('(warning) '),
163              error_id(X, Message),
164              write(Message),
165              write(' in '),
166              write(Where).
167       user compiled 332 bytes in 0.05 seconds
168
169      ?- warning_handler(60,dummy).
170      (warning) accessing an undefined procedure in dummy
171      yes.
172
173      ?- [user].
174       fail_warning(N, Where) :-
175               write(\"Warning: Failure due to \"),
176               error_id(N, Errmsg),
177               write(Errmsg),
178               write(\":\"-Where),
179               fail.
180       user compiled 328 bytes in 0.00 seconds
181      yes.
182
183      ?- set_event_handler(68, fail_warning/2).
184      yes.
185
186      ?- p.
187      Warning: Failure due to calling an undefined procedure: - p
188      no.
189Fail:
190      error_id(60,\"procedure not defined\").
191Error:
192      error_id(N,\"not a module\").        (Error 4).
193      error_id(1.0,M).                   (Error 5).
194      error_id(1,atom).                  (Error 5).
195
196
197",
198	see_also:[]]).
199
200:- comment(current_after_events / 1, [
201	summary:"   Check or find currently pending after events.
202
203",
204	amode:(current_after_events(-) is det),
205	desc:html("\
206
207   If Events is a variable, then all the currently pending
208   events are returned as a list. The list elements are of the 
209   form due(EventName - PostTime, DueTime) for an event raised with
210   event_after/2 and event_after/3 and of the form
211   due(EventName - every(Interval), NextDueTime) for an event raised 
212   with event_after_every/2. An event will appear as many times as it
213   has been setup.   EventName is the name of the after event. PostTime is
214   the time at which the event was posted, and DueTime the time at which it 
215   is to be raised. For a repeating after event, Interval is the period
216   between events, and NextDueTime is the next time at which it is to be raised.
217
218<P>
219   Note that this predicate simply returns a snapshot of the current pending
220   after events. It is therefore possible that an after event returned in Events
221   has already been raised.
222<P>
223"),
224	args:["Events" : "List of due / 2 structures or variable"],
225	eg:"
226   setup :-
227      set_event_handler(hi, hi/0),
228      event_after_every(hi, 3.2).
229
230   hi :-
231      current_after_events(Es),
232      writeln(hi),
233      writeln('Pending events'-Es).
234
235   % just spinning after the setup for events to be raised.
236   ?- setup, repeat, fail.  
237    hi
238    Pending events - [due(hi - every(3.2), 30.51)]
239    hi
240    Pending events - [due(hi - every(3.2), 33.72)]
241    hi
242    Pending events - [due(hi - every(3.2), 36.93)]
243    ...
244",
245	see_also:[event_after / 2, event_after / 3, event_after_every / 2, 
246                  event / 1, set_event_handler / 2, event_create / 3, 
247                  event_retrieve / 3]]).
248
249
250:- comment(get_event_handler / 3, [
251	summary:"Returns the event handler for event/error Event and its home module Module.",
252	amode:(get_event_handler(+,-,-) is semidet),
253	desc:html("   Given the event name/error number Event, Predspec is unified with the specification
254   (i.e.  a term of the form name/arity) of the current handler for 
255   event; Module is unified with its home module.
256
257<p>
258   The events which exist are user defined; the errors which exist are
259   implementation defined. 
260
261
262<p>
263"),
264	args:["Event" : "atom or integer.", "Predspec" : "term which unifies with atom/integer.", "Module" : "atom or variable."],
265	fail_if:"Fails if Event is not an event",
266	exceptions:[4 : "Event is not instantiated.", 5 : "Event is not an atom nor integer.", 5 : "PredSpec is neither a variable nor of the form Atom/Integer."],
267	see_also:[set_event_handler / 2, event/ 1]]).
268
269:- comment(get_interrupt_handler / 3, [
270	summary:"Succeeds if PredSpec unifies with the specification of the current handler
271for interrupt IntId and Module unifies with its home module.
272
273",
274	amode:(get_interrupt_handler(+,-,-) is semidet),
275	desc:html("   Provided IntId is a valid interrupt identifier, unifies PredSpec with
276   the specification (i.e.  a term of the form name/arity) of the current
277   handler for interrupt IntId, and Module with the module in which it is
278   defined.
279<P>
280   The interrupts which exist are machine dependent.  The interrupts which
281   can be caught or trapped are implementation defined.
282
283<P>
284"),
285	args:["IntId" : "Integer or atom.", "PredSpec" : "Term which unifies with atom/integer.", "Module" : "Atom or variable."],
286	fail_if:"Fails if no handler has been set for the interrupt IntId",
287	exceptions:[4 : "IntId is not instantiated.", 5 : "IntId is not an atom or integer.", 5 : "PredSpec does not unify with atom/integer.", 6 : "IntId is not a valid interrupt name or number."],
288	eg:"
289Success:
290      ?- get_interrupt_handler(18,M,N).
291      M = pause/0
292      N = sepia_kernel
293      yes.
294
295      ?- set_interrupt_handler(18,true/0), kill(0, 18),
296      > get_interrupt_handler(18,true/0,sepia_kernel).
297      yes.
298Fail:
299      get_interrupt_handler(16, true/0, sepia_kernel).
300Error:
301      get_interrupt_handler(N,true/0,sepia_kernel).   (Error 4).
302      get_interrupt_handler(5.0,true/0,sepia_kernel). (Error 5).
303      get_interrupt_handler(-1,X,sepia_kernel).       (Error 6).
304",
305	see_also:[current_interrupt / 2, set_interrupt_handler / 2, kill/2]]).
306
307:- comment(reset_error_handlers / 0, [
308	summary:"All error handlers are reset, cancelling any redefinition.
309
310",
311	amode:(reset_error_handlers is det),
312	desc:html("   All error handlers are reset, cancelling any redefinition.
313
314<P>
315   The errors which exist are implementation defined.
316
317<P>
318"),
319	args:[],
320	eg:"
321Success:
322      ?- string_list(S,L).
323      instantiation fault in string_list(_g50, _g52)
324
325      ?- atom_length(\"atom\",L).
326      type error in atom_length(\"atom\", _g52).
327
328      ?- set_event_handler(4,fail/0), string_list(S,L).
329      no (more) solution.
330
331      ?- set_event_handler(5,abort/0),atom_length(\"atom\",L).
332      Aborting execution....
333
334      ?- reset_error_handlers, string_list(S,L).
335      instantiation fault in string_list(_g62, _g64)
336
337      ?- atom_length(\"atom\",L).
338      type error in atom_length(\"atom\", _g52).
339
340",
341	see_also:[reset_event_handler / 1]]).
342
343:- comment(event / 1, [
344	summary:"The event EventId is raised and the corresponding error handler is
345executed.
346
347",
348	amode:event(+),
349	desc:html("   The event EventId is raised and the corresponding error handler is
350   executed.
351
352<P>
353   Other ways to raise events are by
354<PRE>
355   - one of the builtins error/2 or error/3.
356   - posting an event from external code using ec_post_event().
357   - an interrupt whose handler has been specified as event/1.
358</PRE>
359   The latter two have the effect of dynamically inserting an event/1
360   goal into the current execution at the next synchronous point,
361   which is usually just before the next predicate call.
362
363<P>
364"),
365	args:["EventId" : "Atom or event Handle, or a list of atoms and/or event handles."],
366	resat:"Resatisfiable if the handler is resatisfiable",
367	fail_if:"Fails if the handler fails",
368	exceptions:[
369	    4 : "EventId is not ground",
370	    5 : "EventId is instantiated, but neither an atom nor an event handle, or a list of them",
371	    32 : "No handler is associated to an atomic EventId"],
372	eg:"
373    ?- event(hello).
374    warning: no handler for event in hello
375    yes.
376
377    ?- set_event_handler(hello, writeln/1).    
378    yes.
379
380    ?- event(hello).
381    hello
382    yes.
383
384    ?- event([hello,hello]).
385    hello
386    hello
387    Yes (0.00s cpu)
388
389",
390	see_also:[event_create/3, is_event/1, error / 2, error / 3, reset_event_handler / 1, set_event_handler / 2, set_interrupt_handler / 2]]).
391
392:- comment(reset_event_handler / 1, [
393	summary:"Resets the handler for the event EventId to its default value",
394	amode:(reset_event_handler(+) is det),
395	desc:html("   If EventId is an error number, the error handler is reset to
396   its default value, cancelling any previous redefinition.
397
398<P>
399   If EventId is an atom, any previously installed handler is uninstalled,
400   and future occurrences of the event will cause an error (32).
401
402<P>
403"),
404	args:["EventId" : "Atom or Integer."],
405	exceptions:[4 : "EventId is not instantiated.", 5 : "EventId is neither atom nor integer.", 6 : "EventId is integer, but not a valid error number."],
406	eg:"
407Success:
408    ?- event(hello).
409    warning: no handler for event in hello
410    yes.
411
412    ?- set_event_handler(hello, writeln/1).    
413    yes.
414
415    ?- event(hello).
416    hello
417
418    ?- reset_event_handler(hello).
419    yes.
420
421    ?- event(hello).
422    warning: no handler for event in hello
423    yes.
424
425",
426	see_also:[current_error / 1, get_event_handler / 3, error / 2, error / 3, event / 1, set_event_handler / 2]]).
427
428:- comment(set_event_handler / 2, [
429	summary:"Set an event handler PredSpec for the event EventId.
430
431",
432	amode:(set_event_handler(+, ++) is det),
433	desc:html("   Assigns the procedure specified by PredSpec as the event handler
434   for the event specified by EventId.  The event name can be either
435   an arbitrary atom or a valid error number (as returned by
436   current_error/1).
437
438<P>
439   An event handler which is used as an error handler can have 4
440   optional arguments:
441   <UL>
442       <LI>the 1st argument is the event number/identifier itself
443       <LI>the 2nd argument is the culprit (a structure corresponding to
444	   the call which caused it)
445       <LI>the 3rd argument is the context module (or the lookup module
446       	   if the context module is unknown)
447       <LI>the 4th argument is the lookup module for the call
448   </UL>
449   The error handler is free to use less than 4 arguments.
450   </UL>
451
452<P>
453   Handlers for events raised by event/1 or posted to the system from
454   the outside usually have no arguments or just the event name.
455
456<P>
457   Events can be raised by
458<PRE>
459   - one of the builtins event/1, error/2 or error/3.
460   - posting an event from external code using ec_post_event().
461   - an interrupt whose handler has been specified as event/1.
462</PRE>
463   The latter two have the effect of dynamically inserting an event/1
464   goal into the current execution at the next synchronous point,
465   which is usually just before the next predicate call.
466
467<P>
468   If the handler is specified as defers(Name/Arity), then the event has
469   the defer-property. This means that event handling is automatically
470   deferred on entering the event's handler, thus preventing other events
471   from interrupting the handler. Such handlers must always explicitly invoke
472   events_nodefer/0 before exiting in order to reenable event handling.
473<P>
474"),
475	args:["EventId" : "Atom or Integer.",
476		"PredSpec" : "Term of the form Atom/Integer, or defers(Atom/Integer)."],
477	exceptions:[4 : "Either EventId or PredSpec is not instantiated.",
478		5 : "EventId is neither atom nor integer.",
479		5 : "PredSpec is not of the form Atom/Integer or defers(Atom/Integer).",
480		6 : "EventId is integer, but not a valid error number.",
481		6 : "PredSpec specifies an illegal handler arity."
482		],
483	eg:"
484Success:
485    ?- event(hello).
486    warning: no handler for event in hello
487    yes.
488
489    ?- set_event_handler(hello, writeln/1).    
490    yes.
491
492    ?- event(hello).
493    hello
494    yes.
495",
496	see_also:[current_error / 1, get_event_handler / 3, error / 2, error / 3, event / 1, reset_event_handler / 1, events_nodefer/0]]).
497
498:- comment(current_interrupt / 2, [
499	summary:"Succeeds if N unifies with the number and IntID unifies with the mnemonic
500name of a valid interrupt.
501
502",
503	amode:(current_interrupt(-,-) is multi),
504	amode:(current_interrupt(+,-) is semidet),
505	amode:(current_interrupt(-,+) is semidet),
506	desc:html("   This predicate unifies N with the signal number and IntID with the
507   mnemonic name of an existing interrupt type.  This predicate can be used
508   to find the signal number related to a mnemonic interrupt name and vice
509   versa, or to return all valid interrupts on backtracking.
510
511<P>
512"),
513	args:["N" : "Positive integer or variable.", "IntID" : "Atom or variable."],
514	fail_if:"N or IntID do not unify with the interrupt number resp.  the mnemonic name of a valid interrupt",
515	exceptions:[5 : "N is instantiated, but not to an integer.", 5 : "IntID is instantiated, but not to an atom."],
516	eg:"
517Success:
518      current_interrupt(2, X)         (gives X = int)
519      current_interrupt(X, kill)      (gives X = 9)
520      current_interrupt(N, Int)
521Fail:
522      current_interrupt(43, Int)
523      current_interrupt(N, noint)
524Error:
525      current_interrupt(1.0, Int).    (Error 5).
526      current_interrupt(N, \"int\").    (Error 5).
527
528
529
530",
531	see_also:[current_error / 1, kill / 2]]).
532
533:- comment(error / 2, [
534	summary:"An error or event EventId is raised and the corresponding error handler is executed",
535	amode:error(+, ?),
536	desc:html("\
537   The event or error EventId with Culprit as its culprit goal is raised.
538   EventId is either an integer error number, or an atomic event name.
539   The error handler which is associated with EventId is invoked,
540   with its first argument set to EventId, its second argument to Culprit,
541   and its third argument and fourth argument are the context module in
542   which error/2 is invoked. If the handler has less than four arguments,
543   the extra information is lost.
544<P>
545   This simulates an occurrence of the error EventId inside a call
546   to Culprit.  The valid error numbers are those returned by
547   current_error/1.  Event names can be any atom as long as an event handler
548   has been defined for them.
549<P>
550   If EventId is a structure with functor default/1, the structure's argument
551   is taken as the error number and the default handler is executed, even
552   if the error handler has been redefined using set_event_handler/2.
553   This is useful for writing user error handlers.
554<P>
555   If the event handler succeeds, possibly binding some variables
556   inside Culprit, then error/2 succeeds as well. If the handler fails
557   or calls exit_block/1, then so does error/2.
558"),
559	args:["EventId" : "Atom, integer or structure with functor default/1.", "Culprit" : "Prolog term."],
560	resat:"Resatisfiable if the handler is resatisfiable",
561	fail_if:"Fails if the handler fails",
562	exceptions:[4 : "EventId is not instantiated.", 5 : "EventId is not an error specification.",
563		6 : "EventId is a number but not a valid error number.",
564		32 : "No handler is associated to EventId"],
565	eg:"
566Success:
567
568   % Writing a predicate with type checking
569    ?- [user].
570     is_positive(N) :-
571            number(N),
572            !,
573            N >= 0.
574     is_positive(N) :-
575            error(5, is_positive(N)).
576     user compiled 244 bytes in 0.02 seconds
577    yes.
578
579    ?- is_positive(a).
580    type error in is_positive(a)
581
582   % changing the behaviour of a built-in by redefining a handler
583    ?- //(1,0,X).       % change this behaviour
584    arithmetic exception in //(1, 0, X)
585
586    ?- [user].        % define the new handler
587     my_handler(_, //(_,_,Result)) :-
588            !,
589            Result = infinity.
590     my_handler(Err, Goal) :-
591            error(default(Err), Goal).
592     user compiled 212 bytes in 0.00 seconds
593    yes.
594
595    ?- set_event_handler(20, my_handler/2).
596    yes.
597
598    ?- //(1,0,X).      % check if it works
599    X = infinity
600    yes.
601
602    ?- sqrt(-1,X).   % other culprits: as before
603    arithmetic exception in sqrt(-1, _g36)
604
605Error:
606      error(N,dummy(1)).    (Error 4).
607      error(5.0,dummy(1)).  (Error 5).
608      error(-2,dummy(1)).   (Error 6).
609
610
611
612",
613	see_also:[error / 3, event/1, current_error / 1, error_id / 2, get_event_handler / 3, reset_event_handler / 1, reset_error_handlers / 0, set_event_handler / 2]]).
614
615:- comment(error / 3, [
616	summary:"An error EventId is raised with Culprit and context module Module, and the corresponding error handler is executed",
617	amode:error(++, ?, +),
618	desc:html("\
619   The event or error EventId with Culprit as its culprit goal is raised.
620   EventId is either an integer error number, or an atomic event name.
621   The error handler which is associated with EventId is invoked,
622   with its first argument set to EventId, its second argument to Culprit,
623   its third argument to Module, and its fourth argument to the context module
624   in which error/3 is invoked. If the handler has less than four arguments,
625   the extra information is lost.
626<P>
627   This simulates an occurrence of the error EventId inside a call
628   to Culprit in Module.  The valid error numbers are those returned by
629   current_error/1.  Event names can be any atom as long as an event handler
630   has been defined for them.
631<P>
632   If EventId is a structure with functor default/1, the structure argument
633   is taken as the error number and the default handler is executed, even
634   if the error handler has been redefined using set_event_handler/2.
635   This is useful for writing user error handlers.
636<P>
637   If the event handler succeeds, possibly binding some variables
638   inside Culprit, then error/3 succeeds as well. If the handler fails
639   or calls exit_block/1, then so does error/3.
640<P>
641   Not that when the error handler ignores the module (ie.  has arity less
642   than three), then error/2 and error/3 are equivalent.
643<P>
644"),
645	args:["EventId" : "Atom, integer or structure with functor default/1.", "Culprit" : "Prolog term.", "Module" : "Atom."],
646	resat:"Resatisfiable if the handler is resatisfiable",
647	fail_if:"Fails if the handler fails",
648	exceptions:[4 : "EventId is not instantiated.", 5 : "EventId is not an error specification.",
649		6 : "EventId is a number but not a valid error number.",
650		32 : "No handler is associated to EventId"],
651	eg:"
652Success:
653
654    ?- error(68, length(X, Y), lists).
655    calling an undefined procedure eclipse:length(X, Y) in module lists
656
657   % writing an alternative error handler for undefined predicates:
658    ?- arg(1,2).           % we want to change this
659    calling an undefined procedure arg(1, 2) in module eclipse
660
661    ?- [user].             % compile the new handler
662
663     undef_handler(_, Goal, _Context, Module) :-
664            functor(Goal, Name, BadArity),
665            (
666                current_predicate(Name/Arity)@Module
667            ;
668                current_built_in(Name/Arity)@Module
669            ),
670            !,
671            printf(\"%w does not exist, but there is %w\\n\",
672                               [Name/BadArity, Name/Arity]),
673            fail.
674     undef_handler(Err, Goal, Context, Module) :-
675            error(default(Err), Goal, Context, Module).
676     user compiled 592 bytes in 0.02 seconds
677    yes.
678
679    ?- set_event_handler(68, undef_handler/4).
680    yes.
681
682    ?- arg(1,2).            % check if it works
683    arg / 2 does not exist, but there is arg / 3
684
685    no.
686
687Error:
688      error(N,dummy(1),eclipse).    (Error 4).
689      error(5.0,dummy(1),eclipse).  (Error 5).
690      error(-2,dummy(1),eclipse).   (Error 6).
691      error(95,dummy(1),eclipse).   (Error 6).
692
693
694
695",
696	see_also:[error / 2, event/1, current_error / 1, error_id / 2, get_event_handler / 3, reset_event_handler / 1, reset_error_handlers / 0, set_event_handler / 2]]).
697
698:- comment(event_after / 2, [
699	summary:"   Set up an event Event which is triggered after Time seconds have
700   elapsed.
701
702",
703	amode:(event_after(+, +) is det),
704	desc:html("\
705   The event Event is raised after Time seconds of elapsed time from when
706   the predicate is executed. Every call to event_after/2 will cause exactly
707   one corresponding event, if the same event is requested several times, it
708   will be raised several times. The event mechanism is safe with respect to
709   backtracking: once an after-event has been requested, it will be raised,
710   even when execution fails across the point where it was requested.
711<P>
712   Time can be a real number, but the actual granularity of how fine
713   the elapsed time is measured is operating system dependent, and the
714   triggering condition is actually that at least Time seconds have
715   elapsed.
716<P>
717   In addition, the processing of an event may not happen immediately
718   upon the raising the event, as events are processed synchronously:
719   An event can only be handled at a point where an ECLiPSe goal can
720   be executed. This can delay the handling of an event when ECLiPSe is
721   performing some uninterruptible task, e.g. waiting for I/O, or executing
722   external code.
723<P>
724   The use of after-events requires some thought because after-events can
725   be raised at unpredictable (even though well-defined) points during
726   program execution. As long as the handlers succeed, this poses no
727   particular problem, because execution is allowed to continue after the
728   handler succeeds. By design, the possibilities of an event handler to
729   interact with the interrupted execution are limited (the handler can
730   access global data structures, use a symbolic trigger, etc).
731<P>
732   More problematic are applications where the handler is allowed to
733   abort using exit_block/1.  Due to the timed execution, the exact
734   program point where the abort happens is unpredictable.  It must be
735   made sure that the abort is safely caught in all cases, and that
736   nonlogical data is not left in an inconsistent state.  In such cases,
737   it is possible to use events_defer/0 and events_nodefer/0 to protect
738   critical code sequences from being interrupted by event handling.
739   Note that it never makes sense to let after-event handlers fail.
740<P>
741   Another problem that may occur with timed events is that a new
742   event may be raised while another one is still being handled.  To
743   stop event handlers from being interrupted by others, it is possible
744   to give events the defer-property.  This means that event handling
745   is automatically deferred on entering the event's handler, thus
746   preventing other events from interrupting the handler.  Such handlers
747   must always explicitly invoke events_nodefer/0 before exiting in order
748   to reenable event handling.
749<P>
750   The timer used by measuring elapsed time is specified by the environment
751   flag after_event_timer: virtual means that elapsed user cpu time is
752   used, real means elapsed real time. The default is real. On
753   systems that cannot support CPU time measurement, such as Microsoft
754   Windows, one may not set the timer to virtual: an error is raised
755   if this is attempted.  The time relevant for event handling can be
756   obtained by calling statistics(event_time, Now).
757"),
758	args:["Event" : "Atom or Handle", "Time" : "Positive number"],
759	exceptions:[5 : "Event is neither an atom nor a handle or Time is not a positive number."],
760	eg:"
761   ?- event_create(writeln(hi), [], E),
762      event_after(E, 3.2),
763      event_create(abort, [], E1),
764      event_after(E1, 5),
765      repeat, fail.
766   hi				% after 3.2 seconds
767   Aborting execution ...	% after 5 seconds
768   Abort
769",
770	see_also:[event_after / 3, event_after_every / 2,
771	cancel_after_event / 2, events_after/1, event / 1,
772	set_event_handler / 2, current_after_events / 1, 
773	event_create / 3, event_retrieve / 3, get_flag / 2, statistics/2]]).
774
775
776:- comment(event_after / 3, [
777	summary:"Set up an event Event which is triggered at DueTime, after Time seconds have elapsed",
778	amode:(event_after(+, +, -) is det),
779	desc:html("\
780   The event Event is raised after Time seconds of elapsed time from when
781   the predicate is executed.  This is identical to event_after/2, except
782   that DueTime gets bound to the time at which the event will be raised.
783   This time can be compared to the the current event_time as returned by
784   statistics/2.
785<P>
786   For more details, see event_after/2.
787"),
788	args:["Event" : "Atom or Handle", "Time" : "Positive number", 
789	      "DueTime" : "Variable, will be bound to a float"],
790	exceptions:[5 : "Event is neither an atom nor a handle or Time is not a positive number."],
791	eg:"
792    % With the following the handler definition
793    report_due(DueTime) :-
794	 Remaining is DueTime - statistics(event_time),
795	 printf(\"Event is due in %w seconds%n\", [Remaining]).
796
797    ?- event_create(abort, [], E1),
798	event_after(E1, 5, Due),
799	event_create(report_due(Due), [], E2),
800	event_after_every(E2, 1),
801	repeat, fail.
802    Event is due in 3.98999999999999 seconds
803    Event is due in 2.98 seconds
804    Event is due in 1.97 seconds
805    Event is due in 0.959999999999994 seconds
806    Aborting execution ...
807    Abort
808",
809	see_also:[event_after / 2, event_after_every / 2,
810	cancel_after_event / 2, events_after/1, event / 1,
811	set_event_handler / 2, current_after_events / 1, 
812	event_create / 3, event_retrieve / 3, get_flag / 2, statistics/2]]).
813
814
815:- comment(event_after_every / 2, [
816	summary:"   Set up an event Event which is triggered after every Time seconds have
817   elapsed.
818
819",
820	amode:(event_after_every(+, +) is det),
821	desc:html("\
822   The event Event is raised after every Time seconds of elapsed time from when
823   the predicate is executed.  The difference from event_after/2 and event_after/3
824   is that event_after_every/2 raises the event Event at regular Time intervals 
825   once it is initiated, whereas event_after/2 and event_after/3 
826   raise the event once (per event_after/2 and event_after/3) only.  The time
827   for the next event starts counting from the moment the previous event is
828   raised. This means that the time between the raising of two events will
829   never fall below the Time interval, even if there is a delay in raising
830   one of the events.  The event mechanism is safe with respect to
831   backtracking: once an after-event has been requested, it will be raised,
832   even when execution fails across the point where it was requested.
833   The only way to stop further after-every-events being raised is to cancel
834   them using cancel_after_event/2.
835<P>
836   Time can be a real number, but the actual granularity of how fine
837   the elapsed time is measured is operating system dependent, and the
838   triggering condition is actually that at least Time seconds have
839   elapsed.
840<P>
841   In addition, the processing of an event may not happen immediately
842   upon the raising the event, as events are processed synchronously:
843   An event can only be handled at a point where an ECLiPSe goal can
844   be executed. This can delay the handling of an event when ECLiPSe is
845   performing some uninterruptible task, e.g. waiting for I/O, or executing
846   external code.
847<P>
848   The use of after-events requires some thought because after-events can
849   be raised at unpredictable (even though well-defined) points during
850   program execution. As long as the handlers succeed, this poses no
851   particular problem, because execution is allowed to continue after the
852   handler succeeds. By design, the possibilities of an event handler to
853   interact with the interrupted execution are limited (the handler can
854   access global data structures, use a symbolic trigger, etc).
855<P>
856   More problematic are applications where the handler is allowed to
857   abort using exit_block/1.  Due to the timed execution, the exact
858   program point where the abort happens is unpredictable.  It must be
859   made sure that the abort is safely caught in all cases, and that
860   nonlogical data is not left in an inconsistent state.  In such cases,
861   it is possible to use events_defer/0 and events_nodefer/0 to protect
862   critical code sequences from being interrupted by event handling.
863   Note that it never makes sense to let after-event handlers fail.
864<P>
865   Another problem that may occur with timed events is that a new
866   event may be raised while another one is still being handled.  To
867   stop event handlers from being interrupted by others, it is possible
868   to give events the defer-property.  This means that event handling
869   is automatically deferred on entering the event's handler, thus
870   preventing other events from interrupting the handler.  Such handlers
871   must always explicitly invoke events_nodefer/0 before exiting in order
872   to reenable event handling.
873<P>
874   The timer used by measuring elapsed time is specified by the environment
875   flag after_event_timer: virtual means that elapsed user cpu time is
876   used, real means elapsed real time. The default is real. On
877   systems that cannot support CPU time measurement, such as Microsoft
878   Windows, one may not set the timer to virtual: an error is raised
879   if this is attempted.  The time relevant for event handling can be
880   obtained by calling statistics(event_time, Now).
881"),
882	args:["Event" : "Atom or Handle", "Time" : "Positive number"],
883	exceptions:[5 : "Event is neither an atom nor a handle or Time is not a positive number."],
884	eg:"
885    ?- event_create((statistics(event_time,T),writeln(now(T))), [], E),
886	event_after_every(E, 1),
887	repeat,fail.
888    now(4.61)	% after 1 second
889    now(5.62)	% after 2 seconds
890    now(6.63)
891    now(7.64)
892    now(8.65)
893    ...
894",
895	see_also:[event_after / 2, event_after / 3, events_after/1, 
896        cancel_after_event / 2, event / 1, set_event_handler / 2, 
897	current_after_events / 1, event_create / 3, event_retrieve / 3, 
898	get_flag / 2]]).
899
900
901:- comment(events_after / 1, [
902	summary:"   Set up a series of after events Events. 
903
904",
905	amode:(events_after(++) is det),
906	desc:html("\
907   Events is a list of after events where each element of the list
908   specifies one after event. Each element is either in the form of
909   EventName-Time or EventName-every(Time) where the first form is
910   equivalent to event_after(EventName, Time) and the second to
911   event_after_every(EventName, Time). The difference between using
912   a single events_after/1 and multiple calls to event_after/2, 
913   event_after/3 and event_after_every/2 to set up a series of after 
914   events is that with events_after/1, all the events are set up as a 
915   unit, and it is guaranteed that the relative orderings between the 
916   events are preserved, and that no after events will be raised until
917   all the specified events have been set up.
918<P>
919   The main use of events_after/1 is for restart event that have been
920   cancelled previously with cancel_after_event/2.
921<P>
922   See event_after/2, event_after/3 or event_after_every/2 for more details
923   on after events.
924"),
925	args:["Events" : "A list of the form Event-Time or Event-every(Time)"],
926	exceptions:[
927	   4 : "Events is not instantiated.",
928	   5 : "Events is not a list of after events of the form Event-Time or Event-every(Time), where Event is an atom or a handle and Time is a positive (non-breal) number."
929        ],
930	eg:"
931    % set event handlers to write the event name
932    ?- set_event_handler(e1, writeln/1),
933    	set_event_handler(e2, writeln/1).
934    Yes (0.00s cpu)
935
936    ?- events_after([e1-every(0.2), e2-0.5]),
937    	repeat,fail.
938    e1
939    e1
940    e2
941    e1
942    e1
943    e1
944    ^C
945    interruption: type a, b, c, e, or h for help : ? a
946    abort
947    Aborting execution ...
948    Abort
949
950    % cancel further e1 events
951    ?- cancel_after_event(e1, Cancelled).
952    Cancelled = [e1 - every(0.2)]
953    Yes (0.00s cpu)
954
955    % e2 was already raised, nothing to cancel
956    ?- cancel_after_event(e2, Cancelled).
957    Cancelled = []
958    Yes (0.00s cpu)
959
960    % restart the cancelled events
961    ?- events_after([e1 - every(0.2)]),
962	    repeat, fail.
963    e1
964    e1
965    e1
966    e1
967    ...
968",
969	see_also:[event_after / 2, event_after/3, event_after_every/2, 
970        cancel_after_event / 2, events_after/1, event / 1, 
971	set_event_handler / 2, current_after_events / 1, event_create / 3, 
972	event_retrieve / 3, get_flag / 2]
973]).
974
975:- comment(set_interrupt_handler / 2, [
976	summary:"Sets an interrupt handler PredSpec for the interrupt IntId",
977	amode:(set_interrupt_handler(+, ++) is det),
978	desc:html("
979   Assigns the procedure specified by PredSpec as the interrupt handler for
980   the interrupt whose name or number is given by IntId.
981<P>
982   See the ECLiPSe User Manual for details on the operation of
983   interrupt handlers.
984<P>
985   The interrupt handlers of the following interrupts cannot be modified,
986   since they cannot be caught by ECLiPSe .
987<PRE>
988    No. Code     Description  Example
989    9   SIGKILL  kill         kill process from keyboard
990    17  SIGSTOP  stop         cannot be caught, blocked, ignored
991</PRE>
992   The interrupts which can be caught or trapped are implementation
993   defined.
994<P>
995   The following interrupt handlers have a special meaning and can be
996   used even with the embedded library version of Eclipse:
997<PRE>
998    Handler     Meaning
999    -------     -------
1000    true/0      ignore the interrupt (SIG_IGN).
1001    default/0   take the default operating system action when the
1002                interrupt occurs (SIG_DFL).
1003    event/1     handle the signal by posting a (synchronous) event. The
1004                symbolic name of the interrupt will be used as the event name.
1005    throw/1     invoke exit_block/1 with the interrupt's symbolic name.
1006    abort/0     invoke exit_block(abort)
1007    halt/0      halt Eclipse and terminate the process
1008    internal/0  the signal is used by Eclipse to implement internal
1009                functionality (e.g. profiler)
1010</PRE>
1011    All other handler specifications cause the specified predicate to
1012    be called in a nested invocation of the Eclipse engine. This is
1013    not supported on some hardware/OS platforms, e.g. Windows.
1014"),
1015	args:["IntId" : "Integer or atom.", "PredSpec" : "Term of the form Atom/Integer."],
1016	exceptions:[4 : "Either IntId or PredSpec is not instantiated.",
1017	    5 : "IntId is not an atom or integer.",
1018	    5 : "PredSpec is neither a variable nor of the form Atom/Integer.",
1019	    6 : "IntId is not a valid interrupt name or number.",
1020	    6 : "PredSpec is of the form Atom/Integer, but the integer is greater than 3.",
1021	    60 : "PredSpec is of the form Atom/Integer, but no such predicate has been defined.",
1022	    170 : "The interrupt cannot be caught."],
1023	eg:"
1024Success:
1025    ?- get_interrupt_handler(alrm,M,N).
1026    M = event / 1
1027    N = sepia_kernel
1028    yes.
1029
1030    ?- set_interrupt_handler(alrm,true/0), interrupt(alrm).
1031    yes.
1032
1033    ?- kill(0, alrm).
1034    yes.
1035
1036    ?- get_interrupt_handler(alrm,M,N).
1037    M = true / 0
1038    N = sepia_kernel
1039    yes.
1040
1041    ?- [user].
1042     a :- write(log_output, \"interrupt 16\"), fail.
1043     user compiled 136 bytes in 0.00 seconds
1044
1045    ?- set_interrupt_handler(16,a/0).
1046    yes.
1047
1048    ?- kill(0, 16).
1049    interrupt 16
1050    yes.
1051
1052Error:
1053    set_interrupt_handler(N,true/0).    (Error 4).
1054    set_interrupt_handler(15,P).        (Error 4).
1055    set_interrupt_handler(15.0,true/0). (Error 5).
1056    set_interrupt_handler(1000,X).      (Error 6).
1057    set_interrupt_handler(-1,X).        (Error 6).
1058    set_interrupt_handler(6,a/4).       (Error 6).  % arity > 3.
1059    set_interrupt_handler(6,t/2).       (Error 60). % no t/2.
1060    set_interrupt_handler(9,true/0).    (Error 170).
1061    set_interrupt_handler(17,true/0).   (Error 170).
1062
1063
1064",
1065	see_also:[event / 1, set_event_handler / 2, current_interrupt / 2, get_interrupt_handler / 3]]).
1066
1067
1068:- comment(event_create / 3, [
1069    summary:"Create an ECLiPSe event from an arbitrary goal.",
1070    desc:html("\
1071	This creates an event from the goal provided, which can be raised 
1072	with the standard event handling predicates (e.g. event / 1, event_after / 2
1073	and event_after_every / 2) using the associated handle.
1074    <P>
1075	The event creation requires non-logical copying of the goal.
1076	As a result, if the goal contains variables, they lose their identity 
1077	and are replaced with fresh ones.
1078    <P>
1079	The intended use of such events are for localised event handling
1080	or when it is necessary to pass ground parameters to the event goal,
1081	i.e. when the use of a global event handler is unnecessary or does not suffice.
1082    <P>
1083	It should be noted that the event handle is the only way to uniquely
1084	identify a given event.  E.g. if an event has been scheduled as an
1085	after-event (using event_after/3 or events_after/2), it can only be
1086	cancelled by invoking cancel_after_event/2 with the correct handle.
1087    <P>
1088        The following options are recognised:
1089	<DL>
1090	<DT><B>defers</B></DT>
1091	    <DD>Give the event the defers-property.  This means that event
1092	    handling is automatically deferred on entering the event's handler,
1093	    thus preventing other events from interrupting the handler.
1094	    Such handlers must always explicitly invoke events_nodefer/0
1095	    before exiting in order to reenable event handling.</DD>
1096	</DL>
1097    "),
1098    amode:(event_create(+,++,-) is det),
1099    args:["Goal":"An arbitrary goal", "Options":"A list of atoms.", "EventHandle":"A free variable"],
1100    exceptions:[4: "Goal is not instantiated",
1101	5 : "Goal is not a valid goal",
1102	5 : "EventHandle is not a free variable",
1103	5 : "Options is not a list of atoms",
1104	6 : "Some element of Options is not a valid option"],
1105    eg:"\
1106    % Create and raise a single event
1107    ?-  event_create(writeln('Goodbye cruel world!'), [], Event),
1108    	writeln('Hello world!'),
1109	event(Event).
1110    Hello world!
1111    Goodbye cruel world!
1112    Event = 'EVENT'(16'503f0238)
1113    Yes (0.00s cpu)
1114
1115
1116    % Raise events via a timer
1117    ?-  event_create(writeln('e1'), [], E1Event),
1118	event_create(writeln('e2'), [], E2Event),
1119    	events_after([E1Event-every(0.2), E2Event-0.5]),
1120    	repeat, fail.
1121    e1
1122    e1
1123    e2
1124    e1
1125    e1
1126    ^C
1127    interruption: type a, b, c, e, or h for help : ? e1
1128    abort
1129    Aborting execution ...
1130
1131
1132    % By default, event handlers are allowed to interrupt each other,
1133    % which can make it seem that they are handled in reverse order:
1134    ?-  event_create(writeln('e1'), [], E1Event),
1135	event_create(writeln('e2'), [], E2Event),
1136	event([E1Event,E2Event]).	% raise both events together
1137    e2
1138    e1
1139    E1Event = 'EVENT'(16'ed9b0010)
1140    E2Event = 'EVENT'(16'ed770b20)
1141    Yes (0.00s cpu)
1142
1143
1144    % By default, event handlers are allowed to interrupt each other,
1145    % which can make it seem that they are handled in reverse order:
1146    ?-  event_create((writeln('e1'),events_nodefer), [defers], E1Event),
1147	event_create((writeln('e2'),events_nodefer), [defers], E2Event),
1148	event([E1Event,E2Event]).	% raise both events together
1149    e1
1150    e2
1151    E1Event = 'EVENT'(16'ed9b0010)
1152    E2Event = 'EVENT'(16'ed770b20)
1153    Yes (0.00s cpu)
1154    ",
1155    see_also:[event_retrieve / 3, event /1, event_after / 2, event_after / 3, 
1156	event_after_every / 2, set_event_handler / 2, current_after_events / 1,
1157	cancel_after_event / 2, is_event/1, events_nodefer/0]
1158    ]).
1159
1160
1161:- comment(event_retrieve / 3, [
1162    summary:"Given the handle with which an event is associated, retrieve the event goal and module",
1163    desc:html("\
1164	The goal associated with an event handle, created using event_create/3,
1165	is retrieved using this predicate. It also returns the context module
1166	in which the event was created (and where the goal should be called).
1167    <P>
1168	Like event creation, retrieval of the goal produces a copy of the
1169	goal. As a result, if the goal contains variables, they lose their
1170	identity and are replaced with fresh ones.
1171    <P>
1172        If the event was disabled, the goal 'true' is retrieved instead of the
1173	original goal.
1174    "),
1175    amode:(event_retrieve(+,-,-) is det),
1176    args:["EventHandle":"An event handle",
1177    	"Goal":"A free variable or goal to unify",
1178	"Module":"A free variable or module name"],
1179    exceptions:[4: "EventHandle is un-instantiated",
1180	5 : "EventHandle is not a handle"],
1181    eg:"\
1182    ?- event_create(writeln('Hello world!'), [], Event),
1183    	event_retrieve(Event, EventGoal, Module).
1184
1185    Event = 'EVENT'(16'50421bd0)
1186    EventGoal = writeln('Hello world!')
1187    Module = eclipse
1188    Yes (0.00s cpu)
1189    ",
1190    see_also:[event_create / 3, event /1, event_after / 2, event_after / 3, 
1191	event_after_every / 2, set_event_handler / 2, current_after_events / 1,
1192	cancel_after_event / 2, is_event/1, event_disable/1, event_enable/1]
1193    ]).
1194
1195
1196:- comment(event_disable / 1, [
1197    summary:"Disable the given event",
1198    desc:html("<P>\
1199	The given event is disabled.  A disabled events behaves as if its
1200	handler was the goal 'true':
1201	<UL>
1202	<LI>Retrieving the goal using event_retrieve/3 returns 'true'</LI>
1203	<LI>When the event is raised (e.g. posted via event/1), nothing happens</LI>
1204	<LI>If the event gets disabled after it was raised, but before its handler
1205	    execution has started, handler execution will be suppressed.</LI>
1206	</UL>
1207    </P><P>
1208	Note that disabling and enabling events are nonlogical operations
1209	which are not undone on backtracking.
1210    </P>
1211    "),
1212    amode:(event_disable(+) is det),
1213    args:["EventHandle":"An event handle"],
1214    exceptions:[4: "EventHandle is un-instantiated",
1215	5 : "EventHandle is not a handle"],
1216    eg:"\
1217    ?- event_create(writeln(hello), [], E),
1218       event_disable(E), writeln(disabled),
1219       event(E),	% does nothing
1220       event_enable(E), writeln(enabled),
1221       event(E).
1222    disabled
1223    enabled
1224    hello
1225    ",
1226    see_also:[event_create / 3, event /1, event_enable/1, event_retrieve/3]
1227    ]).
1228
1229
1230
1231:- comment(event_enable / 1, [
1232    summary:"Enable the given event",
1233    desc:html("<P>\
1234	The given event is (re-)enabled.  Since events are enabled by default,
1235	this only makes sense if the event had been previously disabled.
1236    </P><P>
1237	A disabled events behaves as if its handler was the goal 'true':
1238	<UL>
1239	<LI>Retrieving the goal using event_retrieve/3 returns 'true'</LI>
1240	<LI>When the event is raised (e.g. posted via event/1), nothing happens</LI>
1241	<LI>If the event gets disabled after it was raised, but before its handler
1242	    execution has started, handler execution will be suppressed.</LI>
1243	</UL>
1244    </P><P>
1245	Note that disabling and enabling events are nonlogical operations
1246	which are not undone on backtracking.
1247    </P>
1248    "),
1249    amode:(event_enable(+) is det),
1250    args:["EventHandle":"An event handle"],
1251    exceptions:[4: "EventHandle is un-instantiated",
1252	5 : "EventHandle is not a handle"],
1253    eg:"\
1254    ?- event_create(writeln(hello), [], E),
1255       event_disable(E), writeln(disabled),
1256       event(E),	% does nothing
1257       event_enable(E), writeln(enabled),
1258       event(E).
1259    disabled
1260    enabled
1261    hello
1262    ",
1263    see_also:[event_create / 3, event /1, event_disable/1, event_retrieve/3]
1264    ]).
1265
1266
1267
1268:- comment(events_defer / 0, [
1269    summary:"Defer event handling",
1270    amode:(events_defer is semidet),
1271    fail_if:"Fails iff event handling is already deferred",
1272    desc:html("<P>\
1273    	Defer event handling until a subsequent call to events_nodefer/0.
1274	The purpose of this feature is to
1275	<UL>
1276	    <LI>sequence event handlers so they don't interrupt each other</LI>
1277	    <LI>protect accesses to global data structures from being interrupted
1278		or preempted by events.</LI>
1279	</UL>
1280	Events whose handling will be deferred are:
1281	<UL>
1282	    <LI>events raised by the builtin event/1</LI>
1283	    <LI>events posted from external code using ec_post_event()</LI>
1284	    <LI>events raised by interrupts whose handler is event/1</LI>
1285	</UL>
1286	Events that are raised while event handling is deferred will be
1287	queued and handled later.
1288    </P><P>
1289	Event handling is also automatically deferred when entering the
1290	event handlers of events that have the defer-property set (see
1291	event_create/3 and set_event_handler/2).
1292    </P><P>
1293    	The predicate fails (and has no further effect) if event handling
1294	is already deferred. This feature should be used to make sure that
1295	event handling is not accidentally reenabled in a nested situation.
1296	E.g.
1297	<PRE>
1298	    ...,
1299	    ( events_defer ->
1300	        &lt;manipulate protected data&gt;
1301		events_nodefer
1302	    ;
1303		% events already deferred
1304	        &lt;manipulate protected data&gt;
1305	    ),
1306	    ...
1307	</PRE>
1308
1309    </P><P>
1310	CAUTION: events_defer/0 is a low-level primitive that must be
1311	used with great care. Part of ECLiPSe's functionality (e.g. timeout,
1312	branch-and-bound) relies on event handling and will not work
1313	properly while event handling is deferred. Deferring and undeferring
1314	events are nonlogical operations which are not undone on backtracking.
1315	The programmer must therefore make sure that every time event handling
1316	is deferred, it is eventually reenabled by a call to events_nodefer/0,
1317	even in case of failure or abort in the deferred code sequence.
1318    </P>
1319    "),
1320    eg:"\
1321    ?- event_create(writeln(hello), [], E),
1322	    event(E),
1323	    writeln(deferring),
1324	    events_defer,
1325	    event(E),
1326	    writeln(nodeferring),
1327	    events_nodefer.
1328    hello
1329    deferring
1330    nodeferring
1331    hello
1332    ",
1333    see_also:[event_create / 3, event /1, events_nodefer/0, set_event_handler/2]
1334    ]).
1335
1336
1337:- comment(events_nodefer / 0, [
1338    summary:"Allow event handling",
1339    amode:(events_nodefer is det),
1340    desc:html("<P>\
1341    	Reenable event handling after it was previously deferred by
1342        <UL>
1343	    <LI>entering the handler for an event with the defer-property
1344		(see event_create/3 and set_event_handler/2).</LI>
1345	    <LI>a call to events_defer/0</LI>
1346        </UL>
1347	The purpose of this feature is to
1348	<UL>
1349	    <LI>sequence event handlers so they don't interrupt each other</LI>
1350	    <LI>protect accesses to global data structures from being interrupted
1351		or preempted by events.</LI>
1352	</UL>
1353	Events whose handling will be deferred are:
1354	<UL>
1355	   <LI>events raised by the builtin event/1</LI>
1356	   <LI>events posted from external code using ec_post_event()</LI>
1357	   <LI>events raised by interrupts whose handler is event/1</LI>
1358	</UL>
1359	Events that are raised while event handling is deferred will be
1360	queued and handled later. A handler for an event with the defer-
1361	property must always call events_nodefer/0 before exiting, e.g.
1362	<PRE>
1363	deferring_event_handler :-
1364		writeln(\"This event handler\"),
1365		writeln(\"will not be interrupted\"),
1366		writeln(\"by other events!\"),
1367		events_nodefer.
1368	</PRE>
1369    </P><P>
1370	CAUTION: events_nodefer/0 is a low-level primitive that must be
1371	used with great care. Part of ECLiPSe's functionality (e.g. timeout,
1372	branch-and-bound) relies on event handling and will not work
1373	properly while event handling is deferred. Deferring and undeferring
1374	events are nonlogical operations which are not undone on backtracking.
1375	The programmer must therefore make sure that every time event handling
1376	is deferred, it is eventually reenabled by a call to events_nodefer/0,
1377	even in case of failure or abort in the deferred code sequence.
1378    </P>
1379    "),
1380    eg:"\
1381    % Without deferring, event handlers interrupt each other, which
1382    % makes it seem as if events were handled in reverse order:
1383
1384    simple_handler(E) :-
1385    	writeln(simple_handling(E)).
1386
1387    ?- set_event_handler(e1, simple_handler/1),
1388       set_event_handler(e2, simple_handler/1),
1389       set_event_handler(e3, simple_handler/1).
1390    Yes (0.00s cpu)
1391
1392    ?-  event([e1,e2,e3]).
1393    simple_handling(e3)
1394    simple_handling(e2)
1395    simple_handling(e1)
1396    Yes (0.00s cpu)
1397
1398
1399    % With deferring, event handlers are sequenced, i.e. every
1400    % handler is allowed to finish before the next one executes:
1401
1402    deferred_handler(E) :-
1403    	writeln(defered_handling(E)),
1404	events_nodefer.
1405
1406    ?- set_event_handler(e1, defers(deferred_handler/1)),
1407       set_event_handler(e2, defers(deferred_handler/1)),
1408       set_event_handler(e3, defers(deferred_handler/1)).
1409    Yes (0.00s cpu)
1410
1411    ?- event([e1,e2,e3]).
1412    defered_handling(e1)
1413    defered_handling(e2)
1414    defered_handling(e3)
1415    Yes (0.00s cpu)
1416    ",
1417    see_also:[event_create / 3, event /1, events_defer/0, set_event_handler/2]
1418    ]).
1419
1420