- Documentation
- Reference manual
- Foreign Language Interface
- The Foreign Include File
- Argument Passing and Control
- Atoms and functors
- Analysing Terms via the Foreign Interface
- Constructing Terms
- Unifying data
- Convenient functions to generate Prolog exceptions
- Serializing and deserializing Prolog terms
- BLOBS: Using atoms to store arbitrary binary data
- Exchanging GMP numbers
- Calling Prolog from C
- Discarding Data
- String buffering
- Foreign Code and Modules
- Prolog exceptions in foreign code
- Catching Signals (Software Interrupts)
- Miscellaneous
- Errors and warnings
- Environment Control from Foreign Code
- Querying Prolog
- Registering Foreign Predicates
- Foreign Code Hooks
- Storing foreign data
- Embedding SWI-Prolog in other applications
- The Foreign Include File
- Foreign Language Interface
- Packages
- Reference manual
If a C function implementing a predicate that calls Prolog should use
PL_open_query()
with the flag PL_Q_PASS_EXCEPTION
and make the function
return FALSE if PL_next_solution()
returns FALSE
and
PL_exception()
indicates an exception is pending.
Both for C functions implementing a predicate and when Prolog is
called while the main control of the process is in C, user code should
always check for exceptions. As explained above, C functions
implementing a predicate should normally cleanup and return with FALSE
.
If the C function whishes to continue it may call PL_clear_exception().
Note that this may cause any exception to be ignored, including time
outs and abort. Typically the user should check the
exception details before ignoring an exception (using PL_exception(0)
or
PL_exception(qid)
as appropriate). If the C code does not implement a predicate it
normally prints the exception and calls
PL_clear_exception()
to discard it. Exceptions may be printed by calling
print_message/2
through the C interface.
- int PL_raise_exception(term_t exception)
- Generate an exception (as throw/1)
and return
FALSE
. If there is already a pending exception, the most urgent exception is kept. Urgency of exceptions is defined as- abort (
'$aborted'
). time_limit_exceeded
(see call_with_time_limit/2).resource_error
exceptions.- Other
error(Formal, ImplDef)
exceptions. - Other exceptions.
This function is rarely used directly. Instead, errors are typically raised using the functions in section 12.4.6 or the C api functions that end in
_ex
such as PL_get_atom_ex(). Below we give an example returning an exception from a foreign predicate the verbose way. Note that the exception is raised in a sequence of actions connected using&&
. This ensures that a proper exception is raised should any of the calls used to build or raise the exception themselves raise an exception. In this simple case PL_new_term_ref() is guaranteed to succeed because the system guarantees at least 10 available term references before entering the foreign predicate. PL_unify_term() however may raise a resource exception for the global stack.foreign_t pl_hello(term_t to) { char *s; if ( PL_get_atom_chars(to, &s) ) { Sprintf("Hello \"%s\"\n", s); return TRUE; } else { term_t except; return ( (except=PL_new_term_ref()) && PL_unify_term(except, PL_FUNCTOR_CHARS, "type_error", 2, PL_CHARS, "atom", PL_TERM, to) && PL_raise_exception(except) ); } }
For reference, the preferred implementation of the above is below. The
CVT_EXCEPTION
tells the system to generate an exception if the conversion fails. The otherCVT_
flags define the admissible types andREP_MB
requests the string to be provided in the current locale representation. This implies that Unicode text is printed correctly if the current environment can represent it. If not, arepresentation_error
is raised.foreign_t pl_hello(term_t to) { char *s; if ( PL_get_chars(to, &s, CVT_ATOM|CVT_STRING|CVT_EXCEPTION|REP_MB) ) { Sprintf("Hello \"%s\"\n", s); return TRUE; } return FALSE; }
- abort (
- int PL_throw(term_t exception)
- Similar to PL_raise_exception(), but returns using the C longjmp() function to the innermost PL_next_solution(). This function is deprecated as it does not provide the opportunity to cleanup.
- term_t PL_exception(qid_t qid)
- Return the pending exception. Exceptions may be raised by most
of the API calls described in this chapter, a common possibility being
resource_error
exceptions. Some returntype_error
ordomain_error
exceptions. A call to Prolog using PL_next_solution() may return any exception, including those thrown by explicit calls to throw/1. If no exception is pending this function returns(term_t)0
.Normally qid should be
0
. An explicit qid must be used after a call to PL_next_solution() that returnsFALSE
when the query was created using thePL_Q_PASS_EXCEPTION
flag (see PL_open_query()).Note that an API may only raise an exception when it fails; if the API call succeeds, the result of
PL_exception(0)
will be 0.220Provided no exception was pending before calling the API function. As clients must deal with exceptions immediately after an API call raises one, this can not happen in a well behaved client. The implementation of a foreign predicate should normally cleanup and returnFALSE
after an exception is raised (and typically also after an API call failed for logical reasons; see PL_unify() for an elaboration on this topic). If the call to Prolog is not the implementation of a foreign predicate, e.g., when the overall process control is in some other language, exceptions may be printed by calling print_message/2 and should be discarded by calling PL_clear_exception(). - void PL_clear_exception(void)
- Tells Prolog that the encountered exception must be ignored. This function must be called if control remains in C after a previous API call fails with an exception.221This feature is non-portable. Other Prolog systems (e.g., YAP) have no facilities to ignore raised exceptions, and the design of YAP's exception handling does not support such a facility. If there is no pending exception, PL_clear_exception() does nothing.
12.4.16 Catching Signals (Software Interrupts)
SWI-Prolog offers both a C and Prolog interface to deal with software interrupts (signals). The Prolog mapping is defined in section 4.12. This subsection deals with handling signals from C.
If a signal is not used by Prolog and the handler does not call Prolog in any way, the native signal interface routines may be used.
Any handler that wishes to call one of the Prolog interface functions should call PL_sigaction() to install the handler. PL_signal() provides a deprecated interface that is notably not capable of properly restoring the old signal status if the signal was previously handled by Prolog.
- int PL_sigaction(int sig, pl_sigaction_t *act, pl_sigaction_t *oldact)
- Install or query the status for signal sig. The signal is an
integer between 1 and 64, where the where the signals up to 32 are
mapped to OS signals and signals above that are handled by Prolog's
synchronous signal handling. The
pl_sigaction_t
is a struct with the following definition:typedef struct pl_sigaction { void (*sa_cfunction)(int); /* traditional C function */ predicate_t sa_predicate; /* call a predicate */ int sa_flags; /* additional flags */ } pl_sigaction_t;
The
sa_flags
is a bitwise or ofPLSIG_THROW
,PLSIG_SYNC
andPLSIG_NOFRAME
. Signal handling is enabled ifPLSIG_THROW
is provided,sa_cfunction
orsa_predicate
is provided.sa_predicate
is a predicate handle for a predicate with arity 1. If no action is provided the signal handling for this signal is restored to the default before PL_initialise() was called.Finally, 0 (zero) may be passed for sig. In that case the system allocates a free signal in the Prolog range (32 ... 64). Such signal handler are activated using PL_thread_raise().
- void (*)() PL_signal(sig, func)
- This function is equivalent to the BSD-Unix signal() function,
regardless of the platform used. The signal handler is blocked while the
signal routine is active, and automatically reactivated after the
handler returns.
After a signal handler is registered using this function, the native signal interface redirects the signal to a generic signal handler inside SWI-Prolog. This generic handler validates the environment, creates a suitable environment for calling the interface functions described in this chapter and finally calls the registered user-handler.
By default, signals are handled asynchronously (i.e., at the time they arrive). It is inherently dangerous to call extensive code fragments, and especially exception related code from asynchronous handlers. The interface allows for synchronous handling of signals. In this case the native OS handler just schedules the signal using PL_raise(), which is checked by PL_handle_signals() at the call- and redo-port. This behaviour is realised by or-ing sig with the constant
PL_SIGSYNC
.222A better default would be to use synchronous handling, but this interface preserves backward compatibility.Signal handling routines may raise exceptions using PL_raise_exception(). The use of PL_throw() is not safe. If a synchronous handler raises an exception, the exception is delayed to the next call to PL_handle_signals();
- int PL_raise(int sig)
- Register sig for synchronous handling by Prolog. Synchronous signals are handled at the call-port or if foreign code calls PL_handle_signals(). See also thread_signal/2.
- int PL_handle_signals(void)
- Handle any signals pending from PL_raise(). PL_handle_signals()
is called at each pass through the call- and redo-port at a safe point.
Exceptions raised by the handler using PL_raise_exception()
are properly passed to the environment.
The user may call this function inside long-running foreign functions to handle scheduled interrupts. This routine returns the number of signals handled. If a handler raises an exception, the return value is -1 and the calling routine should return with
FALSE
as soon as possible. - int PL_get_signum_ex(term_t t, int *sig)
- Extract a signal specification from a Prolog term and store as an
integer signal number in sig. The specification is an
integer, a lowercase signal name without
SIG
or the full signal name. These refer to the same:9
,kill
andSIGKILL
. Leaves a typed, domain or instantiation error if the conversion fails.
12.4.17 Miscellaneous
12.4.17.1 Term Comparison
- int PL_compare(term_t t1, term_t t2)
- Compares two terms using the standard order of terms and returns -1, 0 or 1. See also compare/3.
- int PL_same_compound(term_t t1, term_t t2)
- Yields
TRUE
if t1 and t2 refer to physically the same compound term andFALSE
otherwise.
12.4.17.2 Recorded database
In some applications it is useful to store and retrieve Prolog terms from C code. For example, the XPCE graphical environment does this for storing arbitrary Prolog data as slot-data of XPCE objects.
Please note that the returned handles have no meaning at the Prolog level and the recorded terms are not visible from Prolog. The functions PL_recorded() and PL_erase() are the only functions that can operate on the stored term.
Two groups of functions are provided. The first group (PL_record() and friends) store Prolog terms on the Prolog heap for retrieval during the same session. These functions are also used by recorda/3 and friends. The recorded database may be used to communicate Prolog terms between threads.
- record_t PL_record(term_t +t)
- Record the term t into the Prolog database as recorda/3 and return an opaque handle to the term. The returned handle remains valid until PL_erase() is called on it. PL_recorded() is used to copy recorded terms back to the Prolog stack. Currently aborts the process with a fatal error on failu