The foreign function call interface allows a Lisp program to call many functions written in languages that use the C calling convention.
Lisp sets up various signal handling routines and other environment information when it first starts up, and expects these to be in place at all times. The C functions called by Lisp should not change the environment, especially the signal handlers: the signal handlers installed by Lisp typically have interesting flags set (e.g to request machine context information, or for signal delivery on an alternate stack) which the Lisp runtime relies on for correct operation. Precise details of how this works may change without notice between versions; the source, or the brain of a friendly SBCL developer, is the only documentation. Users of a Lisp built with the :sb-thread feature should also read the Threading section of this manual
(sb-alien:alien-funcall alien-function &rest arguments)
The alien-funcall function is the foreign function call primitive: alien-function is called with the supplied arguments and its C return value is returned as a Lisp value. The alien-function is an arbitrary run-time expression; to refer to a constant function, use extern-alien or a value defined by define-alien-routine.
The type of alien-function must be (alien (function ...)) or (alien (* (function ...))). The function type is used to determine how to call the function (as though it was declared with a prototype.) The type need not be known at compile time, but only known-type calls are efficiently compiled. Limitations:
Structure type return values are not implemented.
Passing of structures by value is not implemented.
Here is an example which allocates a (struct foo), calls a foreign function to initialize it, then returns a Lisp vector of all the (* (struct foo)) objects filled in by the foreign call:
;; Allocate a foo on the stack. (with-alien ((f (struct foo))) ;; Call some C function to fill in foo fields. (alien-funcall (extern-alien "mangle_foo" (function void (* foo))) (addr f)) ;; Find how many foos to use by getting the A field. (let* ((num (slot f 'a)) (result (make-array num))) ;; Get a pointer to the array so that we don't have to keep extracting it: (with-alien ((a (* (array (* (struct foo)) 100)) (addr (slot f 'b)))) ;; Loop over the first N elements and stash them in the result vector. (dotimes (i num) (setf (svref result i) (deref (deref a) i))) ;; Voila. result)))
(sb-alien:define-alien-routine} name result-type &rest arg-specifiers)
The define-alien-routine macro is a convenience for automatically generating Lisp interfaces to simple foreign functions. The primary feature is the parameter style specification, which translates the C pass-by-reference idiom into additional return values.
name is usually a string external symbol, but may also be a symbol Lisp name or a list of the foreign name and the Lisp name. If only one name is specified, the other is automatically derived as for extern-alien. result-type is the alien type of the return value.
Each element of the arg-specifiers list specifies an argument to the foreign function, and is of the form
(aname atype &optional style)aname is the symbol name of the argument to the constructed function (for documentation). atype is the alien type of corresponding foreign argument. The semantics of the actual call are the same as for alien-funcall. style specifies how this argument should be handled at call and return time, and should be one of the following
:inspecifies that the argument is passed by value. This is the default. :in arguments have no corresponding return value from the Lisp function.
:copy is similar to :in, but the argument is copied to a pre-allocated object and a pointer to this object is passed to the foreign routine.
:out specifies a pass-by-reference output value. The type of the argument must be a pointer to a fixed-sized object (such as an integer or pointer). :out and :in-out style cannot be used with pointers to arrays, records or functions. An object of the correct size is allocated on the stack, and its address is passed to the foreign function. When the function returns, the contents of this location are returned as one of the values of the Lisp function (and the location is automatically deallocated).
:in-out is a combination of :copy and :out. The argument is copied to a pre-allocated object and a pointer to this object is passed to the foreign routine. On return, the contents of this location is returned as an additional value.
Any efficiency-critical foreign interface function should be inline expanded, which can be done by preceding the define-alien-routine call with:
(declaim (inline lisp-name))In addition to avoiding the Lisp call overhead, this allows pointers, word-integers and floats to be passed using non-descriptor representations, avoiding consing.)
Consider the C function cfoo with the following calling convention:
void cfoo (str, a, i) char *str; char *a; /* update */ int *i; /* out */ { /* body of cfoo(...) */ }This can be described by the following call to define-alien-routine:
(define-alien-routine "cfoo" void (str c-string) (a char :in-out) (i int :out))The Lisp function cfoo will have two arguments (str and a) and two return values (a and i).
Calling Lisp functions from C is sometimes possible, but is extremely hackish and poorly supported as of SBCL 0.7.5. See funcall0 ... funcall3 in the runtime system. The arguments must be valid SBCL object descriptors (so that e.g. fixnums must be left-shifted by 2.) As of SBCL 0.7.5, the format of object descriptors is documented only by the source code and, in parts, by the old CMU CL "INTERNALS" documentation.
Note that the garbage collector moves objects, and won't be able to fix up any references in C variables. There are three mechanisms for coping with this:
The sb-ext:purify moves all live Lisp data into static or read-only areas such that it will never be moved (or freed) again in the life of the Lisp session
sb-sys:with-pinned-objects is a macro which arranges for some set of objects to be pinned in memory for the dynamic extent of its body forms. On ports which use the generational garbage collector (as of SBCL 0.8.3, only the x86) this has a page granularity - i.e. the entire 4k page or pages containing the objects will be locked down. On other ports it is implemented by turning off GC for the duration (so could be said to have a whole-world granularity).
Disable GC, using the without-gcing macro or gc-off call.