Node:Calling Prolog Asynchronously, Next:Exception Handling in C, Previous:Finding Multiple Solutions of a Call, Up:Calling Prolog
If you wish to call Prolog back from a signal handler or a thread other
than the thread that called SP_initialize
, that is, the main thread,
you cannot use SP_query()
etc. directly.
The call to Prolog has to be delayed until such time that the Prolog
execution can accept an interrupt and the call has to be performed from
the main thread (the Prolog execution thread). The function
SP_event()
serves this purpose, and installs the function
func
to be called from Prolog (in the main thread) when the
execution can accept a callback. It returns non-zero if and only if
installation succeeded. func
is called with arg
as first
argument.
A queue of functions, with corresponding arguments, is maintained; that
is, if several calls to SP_event()
occur before Prolog can accept
an interrupt, the functions are queued and executed in turn at the next
possible opportunity. A func
installed with SP_event()
will not be called until SICStus is actually running. One way of
ensuring that all pending functions installed with SP_event()
are
run is to call, from the main thread, some dummy goal, such as,
SP_query_cut_fail(SP_predicate("true",0,"user"))
.
While SP_event()
is safe to call from any thread, it is not safe
to call from arbitrary signal handlers. If you want to call
SP_event()
when a signal is delivered, you need to install your
signal handler with SP_signal()
(see below).
Note that SP_event()
is one of the very few functions in
the SICStus API that can safely be called from another thread than the
main thread.
Depending on the value returned from func
, the interrupted Prolog
execution will just continue (SP_SUCCESS
) or backtrack
(SP_FAILURE
or SP_ERROR
).
An exception raised by
func
, using SP_raise_exception
,
will be processed in the interrupted Prolog execution. If func
calls SP_fail
or SP_raise_exception
the return value from
func
is ignored and handled as if func
returned
SP_FAILURE
or SP_ERROR
, respectively.
In case of failure or exception, the event queue is flushed.
It is generally not robust to let func
raise an exception or
fail. The reason is that not all Prolog code is written such that it
gracefully handles being interrupted. If you want to interrupt some
long-running Prolog code, it is better to let your code test a flag in
some part of your code that is executed repeatedly.
int SP_event(int (*func)(void*), void *arg)