X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=doc%2Fffi.xml;fp=doc%2Fffi.xml;h=2efc11c12815793683d2b89e93000eaa9a226585;hb=3c5c2c265637357e88cb5bb36bcfdc5569bdea4c;hp=0000000000000000000000000000000000000000;hpb=1462adfb42f8eceade5a5493d5ab91ee7838d423;p=sbcl.git diff --git a/doc/ffi.xml b/doc/ffi.xml new file mode 100644 index 0000000..2efc11c --- /dev/null +++ b/doc/ffi.xml @@ -0,0 +1,1255 @@ + + +%myents; +]> + +The Foreign Function Interface + +This chapter describes &SBCL;'s interface to C programs and +libraries (and, since C interfaces are a sort of lingua +franca of the Unix world, to other programs and libraries in +general.) + +In the modern Lisp world, the usual term for this +functionality is Foreign Function Interface, or FFI, where +despite the mention of function in this term, FFI also +refers to direct manipulation of C data structures as well as +functions. The traditional &CMUCL; terminology is Alien Interface, and +while that older terminology is no longer used much in the system +documentation, it still reflected in names in the +implementation, notably in the name of the SB-ALIEN +package. + +Introduction to the Foreign Function Interface + + + +Because of Lisp's emphasis on dynamic memory allocation and garbage +collection, Lisp implementations use non-C-like memory representations +for objects. This representation mismatch creates friction when a Lisp +program must share objects with programs which expect C data. There +are three common approaches to establishing communication: + + The burden can be placed on the foreign program + (and programmer) by requiring the knowledge and use of the + representations used internally by the Lisp implementation. + This can require a considerable amount of glue code on the + C side, and that code tends to be sensitively dependent on the + internal implementation details of the Lisp system. + The Lisp system can automatically convert objects + back and forth between the Lisp and foreign representations. + This is convenient, but translation becomes prohibitively slow + when large or complex data structures must be shared. This approach + is supported by the &SBCL; FFI, and used automatically + by the when passing integers and strings. + The Lisp program can directly manipulate foreign + objects through the use of extensions to the Lisp language. + + + + +&SBCL;, like &CMUCL; before it, relies primarily on the +automatic conversion and direct manipulation approaches. The SB-ALIEN +package provices a facility wherein foreign values of simple scalar +types are automatically converted and complex types are directly +manipulated in their foreign representation. Additionally the +lower-level System Area Pointers (or SAPs) can be used where +necessary to provide untyped access to foreign memory. + +Any foreign objects that can't automatically be converted into +Lisp values are represented by objects of type alien-value. +Since Lisp is a dynamically typed language, even foreign objects must +have a run-time type; this type information is provided by +encapsulating the raw pointer to the foreign data within an +alien-value object. + +The type language and operations on foreign types are +intentionally similar to those of the C language. + + + +Foreign Types + + +Alien types have a description language based on nested list +structure. For example the C type +struct foo { + int a; + struct foo *b[100]; +}; +has the corresponding &SBCL; FFI type +(struct foo + (a int) + (b (array (* (struct foo)) 100))) + + +Defining Foreign Types + + +Types may be either named or anonymous. With structure and union +types, the name is part of the type specifier, allowing recursively +defined types such as: +(struct foo (a (* (struct foo)))) +An anonymous structure or union type is specified by using the name +nil. The with-alien macro defines a local +scope which captures any named type definitions. Other types +are not inherently named, but can be given named abbreviations using +the define-alien-type macro. + + + + +Foreign Types and Lisp Types + + +The foreign types form a subsystem of the &SBCL; type system. An +alien type specifier provides a way to use any foreign type as a +Lisp type specifier. For example, +(typep foo '(alien (* int))) +can be used to determine whether foo is a pointer to a foreign +int. alien type specifiers can be used in the same ways +as ordinary Lisp type specifiers (like string.) Alien type +declarations are subject to the same +precise type checking +as any other declaration. + + + +Note that the type identifiers used in the +foreign type system overlap with native Lisp type +specifiers in some cases. For example, the type specifier +(alien single-float) is identical to single-float, since +foreign floats are automatically converted to Lisp floats. When +type-of is called on an alien value that is not automatically +converted to a Lisp value, then it will return an alien type +specifier. + + + + +Foreign Type Specifiers + + +All foreign type names are exported from the sb-alien +package. Some foreign type names are also symbols in +the common-lisp package, in which case they are +reexported from the sb-alien package, so that +e.g. it is legal to refer to sb-alien:single-float. + + + +These are the basic foreign type specifiers: + + + + + The foreign type specifier (* foo) describes a + pointer to an object of type foo. A pointed-to type + foo of t indicates a pointer to anything, + similar to void * in ANSI C. A null alien pointer can + be detected with the sb-alien:null-alien + function. + + + + + The foreign type specifier (array foo &optional dimensions) + describes array of the specified dimensions, holding + elements of type foo. Note that (unlike in C) (* foo) + (array foo)} are considered to be different types when + type checking is done. If equivalence of pointer and array types + is desired, it may be explicitly coerced using + sb-alien:cast. + + + Arrays are accessed using sb-alien:deref, passing + the indices as additional arguments. Elements are stored in + column-major order (as in C), so the first dimension determines + only the size of the memory block, and not the layout of the + higher dimensions. An array whose first dimension is variable + may be specified by using nil as the first dimension. + Fixed-size arrays can be allocated as array elements, structure + slots or sb-alien:with-alien variables. Dynamic + arrays can only be allocated using sb-alien:make-alien. + + + + + The foreign type specifier + (sb-alien:struct name &rest fields) + describes a structure type with the specified name and + fields. Fields are allocated at the same offsets + used by the implementation's C compiler. If name + is nil then the structure is anonymous. + + + If a named foreign struct specifier is passed to + define-alien-type or with-alien, + then this defines, respectively, a new global or local foreign + structure type. If no fields are specified, then + the fields are taken from the current (local or global) alien + structure type definition of name. + + + + + The foreign type specifier + (sb-alien:union name &rest fields) + is similar to sb-alien:struct, but describes a union type. + All fields are allocated at the same offset, and the size of the + union is the size of the largest field. The programmer must + determine which field is active from context. + + + + + The foreign type specifier (sb-alien:enum name &rest specs) + describes an enumeration type that maps between integer values + and keywords. If name is nil, then the + type is anonymous. Each element of the specs + list is either a Lisp keyword, or a list (keyword value). + value is an integer. If value is not + supplied, then it defaults to one greater than the value for + the preceding spec (or to zero if it is the first spec.) + + + + + The foreign type specifier (sb-alien:signed &optional bits) + specifies a signed integer with the specified number of + bits precision. The upper limit on integer + precision is determined by the machine's word + size. If bits is not specified, the maximum + size will be used. + + + + + The foreign type specifier (integer &optional bits) is + equivalent to the corresponding type specifier using + sb-alien:signed instead of integer. + + + + + The foreign type specifier + (sb-alien:unsigned &optional bits) + is like corresponding type specifier using sb-alien:signed + except that the variable is treated as an unsigned integer. + + + + + The foreign type specifier (boolean &optional bits) is + similar to an enumeration type, but maps from Lisp nil + and t to C 0 and 1 + respectively. bits determines the amount of + storage allocated to hold the truth value. + + + + + The foreign type specifier single-float describes a + floating-point number in IEEE single-precision format. + + + + + The foreign type specifier double-float describes a + floating-point number in IEEE double-precision format. + + + + + The foreign type specifier + (function result-type &rest arg-types) + describes a foreign function that takes arguments of the specified + arg-types and returns a result of type result-type. + Note that the only context where a foreign function type + is directly specified is in the argument to + sb-alien:alien-funcall. + In all other contexts, foreign functions are represented by + foreign function pointer types: (* (function ...)). + + + + + The foreign type specifier sb-alien:system-area-pointer + describes a pointer which is represented in Lisp as a + system-area-pointer object. &SBCL; exports this type from + sb-alien because &CMUCL; did, but tentatively (as of + the first draft of this section of the manual, &SBCL; 0.7.6) it is + deprecated, since it doesn't seem to be required by user code. + + + + + The foreign type specifier sb-alien:void is + used in function types to declare that no useful value + is returned. Using alien-funcall + to call a void foreign function will return + zero values. + + + + + The foreign type specifier sb-alien:c-string + is similar to (* char), but is interpreted as a + null-terminated string, and is automatically converted into a + Lisp string when accessed; or if the pointer is C NULL + or 0, then accessing it gives Lisp nil. + Lisp strings are stored with a trailing NUL termination, so no + copying (either by the user or the implementation) is necessary + when passing them to foreign code. + + + Assigning a Lisp string to a c-string structure field or + variable stores the contents of the string to the memory already + pointed to by that variable. When a foreign object of type + (* char) is assigned to a c-string, then the + c-string pointer is assigned to. This allows + c-string pointers to be initialized. For example: + (cl:in-package "CL-USER") ; which USEs package "SB-ALIEN" + (define-alien-type nil (struct foo (str c-string))) + (defun make-foo (str) (let ((my-foo (make-alien (struct foo)))) + (setf (slot my-foo 'str) (make-alien char (length str)) + (slot my-foo 'str) str) my-foo)) + Storing Lisp NIL in a c-string writes C + NULL to the variable. + + + + + sb-alien also exports translations of these C type + specifiers as foreign type specifiers: + sb-alien:char, + sb-alien:short, + sb-alien:int, + sb-alien:long, + sb-alien:unsigned-char, + sb-alien:unsigned-short, + sb-alien:unsigned-int, + sb-alien:unsigned-long, + sb-alien:float, and + sb-alien:double. + + + + + + + + + + + +Operations On Foreign Values + + +This section describes how to read foreign values as Lisp +values, how to coerce foreign values to different kinds of foreign values, and +how to dynamically allocate and free foreign variables. + +Accessing Foreign Values + +(sb-alien:deref pointer-or-array &rest indices) + +The sb-alien:deref function returns the value pointed to by +a foreign pointer, or the value of a foreign array element. When +dereferencing a pointer, an optional single index can be specified to +give the equivalent of C pointer arithmetic; this index is scaled by +the size of the type pointed to. When dereferencing an array, the +number of indices must be the same as the number of dimensions in the +array type. deref can be set with setf to +assign a new value. + +(sb-alien:slot struct-or-union &rest slot-names) + +The sb-alien:slot function extracts the value of +the slot named slot-name from a foreign struct or +union. If struct-or-union is a pointer to a +structure or union, then it is automatically dereferenced. +sb-alien:slot can be set with setf to assign +a new value. Note that slot-name is evaluated, and need +not be a compile-time constant (but only constant slot accesses are +efficiently compiled.) + +Untyped memory + +As noted at the beginning of the chapter, the System Area +Pointer facilities allow untyped access to foreign memory. SAPs can +be converted to and from the usual typed foreign values using +sap-alien and alien-sap +(described elsewhere), and also to and from integers - raw machine +addresses. They should thus be used with caution; corrupting the Lisp +heap or other memory with SAPs is trivial. + +(sb-sys:int-sap machine-address) + +Creates a SAP pointing at the virtual address +machine-address. + +(sb-sys:sap-ref-32 sap offset) + +Access the value of the memory location at +offset bytes from sap. This form +may also be used with setf to alter the memory at +that location. + +(sb-sys:sap= sap1 sap2) + +Compare sap1 and sap2 for +equality. + +Similarly named functions exist for accessing other sizes of +word, other comparisons, and other conversions. The reader is invited +to use apropos and describe +for more details + +(apropos "sap" :sb-sys) + + + +Coercing Foreign Values + +(sb-alien:addr alien-expr) + + +The sb-alien:addr macro +returns a pointer to the location specified by +alien-expr, which must be either a foreign variable, a use of +sb-alien:deref, a use of sb-alien:slot, or a use of +sb-alien:extern-alien. + + +(sb-alien:cast foreign-value new-type) + +The sb-alien:cast +converts foreign-value to a new foreign value with the specified +new-type. Both types, old and new, must be foreign pointer, +array or function types. Note that the resulting Lisp +foreign variable object +is not eq to the +argument, but it does refer to the same foreign data bits. + +(sb-alien:sap-alien sap type) + +The sb-alien:sap-alien function converts sap +(a system area pointer) to a foreign value with the specified +type. type is not evaluated. + + +The type must be some foreign pointer, array, or +record type. + +(sb-alien:alien-sap foreign-value type) + +The sb-alien:alien-sap function +returns the SAP which points to alien-value's data. + + +The foreign-value must be of some foreign pointer, +array, or record type. + + + +Foreign Dynamic Allocation + +Lisp code can call the C standard library functions +malloc and free to dynamically allocate and +deallocate foreign variables. The Lisp code shares the same allocator +with foreign C code, so it's OK for foreign code to call +free on the result of Lisp +sb-alien:make-alien, or for Lisp code to call +sb-alien:free-alien on foreign objects allocated by C +code. + +(sb-alien:make-alien type size) + +The sb-alien:make-alien macro +returns a dynamically allocated foreign value of the specified +type (which is not evaluated.) The allocated memory is not +initialized, and may contain arbitrary junk. If supplied, +size is an expression to evaluate to compute the size of the +allocated object. There are two major cases: + + + When type is a foreign array type, an array of + that type is allocated and a pointer to it is returned. Note that you + must use deref to change the result to an array before you + can use deref to read or write elements: + + (cl:in-package "CL-USER") ; which USEs package "SB-ALIEN" + (defvar *foo* (make-alien (array char 10))) + (type-of *foo*) => (alien (* (array (signed 8) 10))) + (setf (deref (deref foo) 0) 10) => 10 + If supplied, size is used as the first dimension for the + array. + + + When type is any other foreign type, then an + object for that type is allocated, and a pointer to it is + returned. So (make-alien int) returns a (* int). + If size is specified, then a block of that many + objects is allocated, with the result pointing to the first one. + + + + +(sb-alien:free-alien foreign-value) + +The sb-alien:free-alien function +frees the storage for foreign-value, +which must have been allocated with Lisp make-alien +or C malloc. + +See also the sb-alien:with-alien macro, which +allocates foreign values on the stack. + + + + + +Foreign Variables + + + +Both local (stack allocated) and external (C global) foreign variables are +supported. + + +Local Foreign Variables + +(sb-alien:with-alien var-definitions &body body) + +The with-alien +macro establishes local +foreign variables +with the specified +alien types and names. +This form is analogous to defining a local variable in C: additional +storage is allocated, and the initial value is copied. +This form is less +analogous to LET-allocated Lisp variables, since the variables +can't be captured in closures: they live only for the dynamic extent +of the body, and referring to them outside is a gruesome error. + + +The var-definitions argument is a list of +variable definitions, each of the form +(name type &optional initial-value) +The names of the variables are established as symbol-macros; the bindings have +lexical scope, and may be assigned with setq +or setf. + + +The with-alien macro also establishes +a new scope for named structures +and unions. Any type specified for a variable may contain +named structure or union types with the slots specified. Within the +lexical scope of the binding specifiers and body, a locally defined +foreign structure type foo can be referenced by its name using +(struct foo). + + + + +External Foreign Variables + + +External foreign names are strings, and Lisp names are symbols. When +an external foreign value is represented using a Lisp variable, there +must be a way to convert from one name syntax into the other. The +macros extern-alien, define-alien-variable and +define-alien-routine use this conversion heuristic: + + Alien names are converted to Lisp names by uppercasing and + replacing underscores with hyphens. + Conversely, Lisp names are converted to alien names by + lowercasing and replacing hyphens with underscores. + Both the Lisp symbol and alien string names may be + separately specified by using a list of the form + (alien-string lisp-symbol) + + + +(sb-alien:define-alien-variable name type) + + +The define-alien-variable macro +defines name as an external foreign variable of the +specified foreign type. name and type are not +evaluated. The Lisp name of the variable (see above) becomes a +global alien variable. Global alien variables +are effectively ``global symbol macros''; a reference to the +variable fetches the contents of the external variable. Similarly, +setting the variable stores new contents---the new contents must be +of the declared type. Someday, they may well be implemented +using the &ANSI; define-symbol-macro mechanism, but +as of &SBCL; 0.7.5, they are still implemented using an older +more-or-less parallel mechanism inherited from &CMUCL;. + + + +For example, to access a C-level counter foo, one could +write + +(define-alien-variable "foo" int) +;; Now it is possible to get the value of the C variable foo simply by +;; referencing that Lisp variable: +(print foo) +(setf foo 14) +(incf foo) + + +(sb-alien:get-errno) + + +Since in modern C libraries, the errno "variable" is typically +no longer a variable, but some bizarre artificial construct +which behaves superficially like a variable within a given thread, +it can no longer reliably be accessed through the ordinary +define-alien-variable mechanism. Instead, &SBCL; provides +the operator sb-alien:get-errno to allow Lisp code to read it. + + +(sb-alien:extern-alien name type) + + +The extern-alien macro +returns an alien with the specified type which +points to an externally defined value. name is not evaluated, +and may be either a string or a symbol. type is +an unevaluated alien type specifier. + + + + + + +Foreign Data Structure Examples + + + +Now that we have alien types, operations and variables, we can manipulate +foreign data structures. This C declaration + +struct foo { + int a; + struct foo *b[100]; +}; +can be translated into the following alien type: +(define-alien-type nil + (struct foo + (a int) + (b (array (* (struct foo)) 100)))) + + + +Once the foo alien type has been defined as above, +the C expression + +struct foo f; +f.b[7].a +can be translated in this way: + +(with-alien ((f (struct foo))) + (slot (deref (slot f 'b) 7) 'a) + ;; + ;; Do something with f... + ) + + + +Or consider this example of an external C variable and some accesses: + +struct c_struct { + short x, y; + char a, b; + int z; + c_struct *n; +}; +extern struct c_struct *my_struct; +my_struct->x++; +my_struct->a = 5; +my_struct = my_struct->n; +which can be manipulated in Lisp like this: + +(define-alien-type nil + (struct c-struct + (x short) + (y short) + (a char) + (b char) + (z int) + (n (* c-struct)))) +(define-alien-variable "my_struct" (* c-struct)) +(incf (slot my-struct 'x)) +(setf (slot my-struct 'a) 5) +(setq my-struct (slot my-struct 'n)) + + + + +Loading Unix Object Files + + +Foreign object files can be loaded into the running Lisp process by +calling the functions load-foreign or +load-1-foreign. + + + The sb-alien:load-1-foreign function is the more +primitive of the two operations. It loads a single object file. into +the currently running Lisp. The external symbols defining routines and +variables are made available for future external references (e.g. by +extern-alien). Forward references to foreign symbols +aren't supported: load-1-foreign must be run before any +of the defined symbols are referenced. + + +sb-alien:load-foreign is built in terms of +load-1-foreign and some other machinery +like sb-ext:run-program. +It accepts a list of files and libraries, +and runs the linker on the files and +libraries, creating an absolute Unix object file which is then +processed by load-1-foreign. + +As of &SBCL; 0.7.5, all foreign code (code loaded +with load-1-function or load-function) is +lost when a Lisp core is saved with +sb-ext:save-lisp-and-die, and no attempt is made to +restore it when the core is loaded. Historically this has been an +annoyance both for &SBCL; users and for &CMUCL; users. +It's hard to solve this problem completely cleanly, but some +generally-reliable partial solution might be useful. Once someone in +either camp gets sufficiently annoyed to create it, &SBCL; is +likely to adopt some mechanism for automatically restoring foreign +code when a saved core is loaded. + + + +Foreign Function Calls + + +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 + +The <function>alien-funcall</function> Primitive + +(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))) + + + + +The <function>define-alien-routine</function> Macro + +(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.) + + + + + +<function>define-alien-routine</function> Example + + +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 From C + + +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 &CMUCL; "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. + + + + + + + + + + +Step-By-Step Example of the Foreign Function Interface + + +This section presents a complete example of an interface to a somewhat +complicated C function. + + + +Suppose you have the following C function which you want to be able to +call from Lisp in the file test.c + +struct c_struct +{ + int x; + char *s; +}; + +struct c_struct *c_function (i, s, r, a) + int i; + char *s; + struct c_struct *r; + int a[10]; +{ + int j; + struct c_struct *r2; + + printf("i = %d\n", i); + printf("s = %s\n", s); + printf("r->x = %d\n", r->x); + printf("r->s = %s\n", r->s); + for (j = 0; j < 10; j++) printf("a[%d] = %d.\n", j, a[j]); + r2 = (struct c_struct *) malloc (sizeof(struct c_struct)); + r2->x = i + 5; + r2->s = "a C string"; + return(r2); +}; + + + +It is possible to call this C function from Lisp using the file +test.lisp containing + +(cl:defpackage "TEST-C-CALL" (:use "CL" "SB-ALIEN" "SB-C-CALL")) +(cl:in-package "TEST-C-CALL") + +;;; Define the record C-STRUCT in Lisp. +(define-alien-type nil + (struct c-struct + (x int) + (s c-string))) + +;;; Define the Lisp function interface to the C routine. It returns a +;;; pointer to a record of type C-STRUCT. It accepts four parameters: +;;; I, an int; S, a pointer to a string; R, a pointer to a C-STRUCT +;;; record; and A, a pointer to the array of 10 ints. +;;; +;;; The INLINE declaration eliminates some efficiency notes about heap +;;; allocation of alien values. +(declaim (inline c-function)) +(define-alien-routine c-function + (* (struct c-struct)) + (i int) + (s c-string) + (r (* (struct c-struct))) + (a (array int 10))) + +;;; a function which sets up the parameters to the C function and +;;; actually calls it +(defun call-cfun () + (with-alien ((ar (array int 10)) + (c-struct (struct c-struct))) + (dotimes (i 10) ; Fill array. + (setf (deref ar i) i)) + (setf (slot c-struct 'x) 20) + (setf (slot c-struct 's) "a Lisp string") + + (with-alien ((res (* (struct c-struct)) + (c-function 5 "another Lisp string" (addr c-struct) ar))) + (format t "~&back from C function~%") + (multiple-value-prog1 + (values (slot res 'x) + (slot res 's)) + + ;; Deallocate result. (after we are done referring to it: + ;; "Pillage, *then* burn.") + (free-alien res))))) + + + +To execute the above example, it is necessary to compile the C routine, +e.g.: +cc -c test.c +(In order to enable incremental loading with some linkers, you may need +to say +cc -G 0 -c test.c) + + + +Once the C code has been compiled, you can start up Lisp and load it in: +sbcl. +Lisp should start up with its normal prompt. + + +Within Lisp, +compile the Lisp file. (This step can be done separately. You don't +have to recompile every time.) +(compile-file "test.lisp") + + + +Within Lisp, load the foreign object file to define the necessary +symbols: +(load-foreign "test.o"). +This must be done before loading any code that refers +to these symbols. + + + +Now you can load the compiled Lisp ("fasl") file into Lisp: +(load "test.fasl") +And once the Lisp file is loaded, you can call the +Lisp routine that sets up the parameters and calls the C +function: +(test-c-call::call-cfun) + + + +The C routine should print the following information to standard output: + +i = 5 +s = another Lisp string +r->x = 20 +r->s = a Lisp string +a[0] = 0. +a[1] = 1. +a[2] = 2. +a[3] = 3. +a[4] = 4. +a[5] = 5. +a[6] = 6. +a[7] = 7. +a[8] = 8. +a[9] = 9. +After return from the C function, +the Lisp wrapper function should print the following output: +back from C function +And upon return from the Lisp wrapper function, +before the next prompt is printed, the +Lisp read-eval-print loop should print the following return values: + + +10 +"a C string" + + + + + +