11.4.2.2 Full Support for Multiple SICStus Run-Times

To fully support multiple SICStus run-times, 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 run-times means that more than one SICStus run-time 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 run-time. 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 run-times 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 run-times:

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(long 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 long 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, then 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 Miscellaneous C API Functions, for details.

Most foreign resources that come with SICStus fully support multiple SICStus run-times. 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/.