To fully support multiple SICStus runtimes, a foreign resource
should be built with splfr --multi-sp-aware
.
C code compiled by splfr --multi-sp-aware
will have the C
pre-processor macro MULTI_SP_AWARE
defined to a non-zero value.
Full support for multiple SICStus runtimes means that more than one SICStus runtime can execute code in the foreign resource at the same time. This rules out the option to use any global variables for information that should be specific to each SICStus runtime. In particular, the SICStus dispatch vector cannot be stored in a global variable. Instead, the SICStus dispatch vector is passed as an extra first argument to each foreign function.
To ensure some degree of link time type checking, the name of each foreign
function will be changed (using #define
in the generated
header file).
The extra argument is used in the same way as when using multiple SICStus runtimes from an embedding application. It must be passed on to any function that needs access to the SICStus API.
To simplify the handling of this extra argument, several macros are defined so that the same foreign resource code can be compiled both with and without support for multiple SICStus runtimes:
SPAPI_ARG0
SPAPI_ARG
SPAPI_ARG_PROTO_DECL0
SPAPI_ARG_PROTO_DECL
Their use is easiest to explain with an example. Suppose the original foreign code looked like:
static int f1(void) { some SICStus API calls } static int f2(SP_term_ref t, int x) { some SICStus API calls } /* :- foreign(foreign_fun, c, foreign_pred(+integer)). */ void foreign_fun(SP_integer x) { ... some SICStus API calls ... f1(); ... f2(SP_new_term_ref(), 42); ... }
Assuming no global variables are used, the following change will ensure that the SICStus API dispatch vector is passed around to all functions:
static int f1(SPAPI_ARG_PROTO_DECL0) // _DECL<ZERO> for no-arg functions { some SICStus API calls } static int f2(SPAPI_ARG_PROTO_DECL SP_term_ref t, int x) // Note: no comma { some SICStus API calls } /* :- foreign(foreign_fun, c, foreign_pred([-integer])). */ void foreign_fun(SPAPI_ARG_PROTO_DECL SP_integer x) // Note: no comma { ... some SICStus API calls ... f1(SPAPI_ARG0); // ARG<ZERO> for no-arg functions ... f2(SPAPI_ARG SP_new_term_ref(), 42); // Note: no comma ... }
If MULTI_SP_AWARE
is not defined, i.e. --multi-sp-aware is
not specified to splfr, all these macros expand to nothing,
except SPAPI_ARG_PROTO_DECL0
, which will expand to void
.
You can use SP_foreign_stash()
to get access to a location,
initially set to NULL, where the foreign resource can store a
void*
. Typically this would be a pointer to a C struct that holds
all information that need to be stored in global variables. This struct
can be allocated and initialized by the foreign resource init
function. It should be deallocated by the foreign resource
deinit function. See OS Threads for
details.
Most foreign resources that come with SICStus fully support
multiple SICStus runtimes. For a particularly simple example, see the
code for library(random)
. For an example that hides the passing
of the extra argument by using the C pre-processor, see the files
in library/clpfd/.