In an embedded ECLiPSe, signals are usually handled by the host application. It is recommended to use the event mechanism (the ec_post_event() library function) when signals are meant to be handled by ECLiPSe code (via the event/1 default handler).
When an interrupt happens, the ECLiPSe system calls an interrupt handling routine in a manner very similar to the case of event handling. The only argument to the handler is the interrupt number. Just as event handlers may be user defined, so it is possible to define interrupt handlers. The goal
set_interrupt_handler(N, PredSpec)assigns the procedure specified by PredSpec as the interrupt handler for the interrupt identified by N (a number or a name). Some interrupts cannot be caught by the user (e.g. the kill signal), trying to establish a handler for them yields an error message. Note that in a standalone ECLiPSe, PredSpec can be a user defined predicate, but on embedded systems, PredSpec must be one of the predefined handlers.
To test interrupt handlers, the built-in kill/2 may be used to send a signal to the own process.
The predicate get_interrupt_handler/3 may be used to find the current interrupt handler for an interrupt N, in the same manner as get_event_handler:
get_interrupt_handler(N, PredSpec, HomeModule)
An interrupt handler has one optional argument, which is the interrupt number. There is no argument corresponding to the error culprit, since the interrupt has no relation to the currently executed predicate. A handler may be defined which takes no argument (such as when the handler is defined for only one interrupt type). If the handler has one argument, the identifier of the interrupt is passed to the handler when it is called.
When an interrupt occurs, the system halts what it is currently doing and calls the interrupt handler. Just as in the case with error handling, the interrupt handler can be any Prolog procedure. However, unlike the situation in the case of error handling, when the handler exits, be it with success or failure, the execution is resumed at the point where it was interrupted, the interrupt handling is in this case completely independent13.4. This ``resume and forget'' policy means that to the Prolog program, an interrupt is ``invisible'' -- providing the handler has no side effects, the program continues as if the interrupt had never happened. As a consequence it is not significant whether the handler succeeds or fails. However, again just as in the case of error handlers, a call to the predicate exit_block/1 may be made in order to escape from within the handler to the corresponding call of block/3. Obviously, in this case the interrupted execution can no longer be resumed.
There are a few special predefined interrupt handlers:
?- set_interrupt_handler(int, default/0)will exit the ECLiPSe system when
^
C is pressed.
Note that tkeclipse is an embedded ECLiPSe running under Tcl/Tk, so the general asynchronous interrupt handling is not supported on it.
timeout(Goal, Seconds, Timer, TimeOutGoal) :- % allows the user to set up different Timers set_event_handler(Timer, exit_block/1), start_timer(Timer, Seconds), block( (call(Goal) -> % need to make sure timer is stopped after executing TimeOutGoal stop_timer(Timer) ; stop_timer(Timer), fail ), Tag, handle_timeout(Tag, Timer, TimeOutGoal) ). start_timer(_, 0) :- !. % 0 means no timeout start_timer(Timer, Timeout) :- event_after(Timer, Timeout). stop_timer(Timer) :- ( cancel_after_event(Timer) -> true ; true ). handle_timeout(Tag, Timer, TimeOutGoal) :- (Tag == Timer -> call(TimeOutGoal) % timed out, call the TimeOutGoal ; stop_timer(Timer), % TimeOutGoal aborted for other reasons exit_block(Tag) ).