Macro | Package: ff | ToC | DocOverview | CGDoc | RelNotes | FAQ | Index | PermutedIndex
| Allegro CL version 10.1 Moderately revised from 10.0. 10.0 version

## defun-foreign-callable

Arguments: name arglist &rest body

This macro creates a function that can be called from non-lisp code. It is intended that such a function be callable from lisp as well, but such functionality has not yet been provided. (This macro replaces the obsolete defun-c-callable.)

name must be a symbol representing the name of the new function to install.

arglist is an argument list specification. Each argument is either a symbol representing the name of an argument of type `:long`, or it is a list of two elements containing the argument name and foreign-type, respectively. See The Syntax for Foreign Types in ftype.htm for information on pre-defined foreign types. Other foreign types can be defined with def-foreign-type. `(arg-name (:aligned ftype))` is not supported though `(arg-name :aligned)` is. The `:lisp` type is also supported (meaning a Lisp object is passed from the foreign code to Lisp) but see the warning below.

If the foreign type represents a `:struct`, `:union`, or `:class`, it creates possible pass-by-value semantics, based on the current value of `*pass-structs-by-value*` or the value given to the `:pass-structs-by-value` option.

### The :lisp argument type: signals a warning

If you specify an argument to be of type :lisp -- like `(arg-name :lisp)` -- a warning will be signaled because doing so casually is dangerous. Unless the Lisp value is an immediate (for example, a fixnum or a character), it is actually a pointer which is passed to Lisp. If that pointer happens to be to an object which has been moved by the garbage collector, then it will be invlaid and may cause Lisp to fail with a gc error.

The warning can be suppressed with the :lisp-args-will-not-move declaration:

    cl-user(3): (ff:defun-foreign-callable foo ((x :double) (y :lisp)))
    Warning: While defining foo: for foreign callback-arg named y,
             specifying :lisp as a foreign type for a transition from
             foreign to lisp space is dangerous because the object may move
             due to an intervening garbage collection. If the object is an
             aligned address consider instead using the :aligned
             specification.  Otherwise, if the object is static or if
             careful analysis shows that no movement can possibly occur,
             then add the :lisp-args-will-not-move option in the definition
             in order to remove this warning.
    foo
    cl-user(4): (ff:defun-foreign-callable foo ((x :double) (y :lisp))
                    (declare (:lisp-args-will-not-move t)))
    foo
    cl-user(5):

Specifying the type as `:aligned` will not signal a warning. Manipulating `:aligned` values (which look like fixnums to Lisp) is complicated and aligned pointers can also be moved, but that is uncommon. See Aligned Pointers and the :aligned type in ftype.htm.

### The body argument and its declaration

The first form in the body can be a declaration form, whose valid options are `:convention`, `:unwind`, and `:returning`; something like:

    (defun-foreign-callable my-callback ()
        (declare (:convention :c))
      ...)

The possible values of the options are:

- `:convention`: the convention provides for the specialization of calling conventions due to language or operating-system distinctions. The default convention is `:c`, and is adequate for most situations. `:fastcall` is also accepted. Other values are distinguished by MS Windows-based systems including `:stdcall`, `:method`, and `:fastcall`, but `:fastcall` is not supported and should not be specified. See Note 2: Possible Values for Convention on the page for def-foreign-call.
- `:unwind`: on MS Windows based systems, defaults to 0, and to `nil` on all other systems. May be `nil` or an integer.
- `:pass-structs-by-value`. This causes the `*pass-structs-by-value*` variable to be set (after it has been bound to its own value at the beginning of the macro call) to the value given. The valid values are `nil`, `:warn`, and `t`.
- `:returning`: this specifies the type of what is returned by the called function. It is ignored except when the declared value includes a foreign struct type (either a `:struct`, a `:union`, or a `:class`). Those can be passed by reference or by value depending on the value of `*pass-structs-by-value*` and the value given to the `:pass-structs-by-value` option. If passing is by reference, a hidden argument is provided and the structure is arranged to be copied back to the caller, according to the calling convention of the architecture. The general form is

      (ff:defun-foreign-callable foo (...)
         (declare (:returning <type>))
         ...)

  where `<type>` is a foreign type or its name specifying a structure. This declaration is intended to eventually replace the convert-to-c-types argument in register-foreign-callable, and cannot be used with it.

New C++ and other language based systems tend to establish exception handlers, and set up their own equivalent of unwind-protects in their own langage. Lisp knows nothing about such exception handlers, and thus tends to trash the handler chains that have been built up whenever lisp code throws over non-lisp code to a catch form in lisp code deeper in the stack. The non-lisp code had been expecting either its own exception handling system to remove the exception from the chain on the stack, or else normal functional returns to unwind the stack in a normal fashion.

When the `:unwind` value is `nil`, then no special unwinding takes place. When the argument is non-`nil` (e.g. 0), then a special "throw-by-returning-to-c" style of unwinding occurs; a throw occurs, not by removing the stack (including the foreign code which might have established handlers), but instead by returning the unwind-value to that code, which should then remove its own handler and return. When the foreign code returns, the lisp throw is again resumed until it is completed, or until the next lisp-to-nonlisp transition is encountered.

### Using a function defined by defun-foreign-callable

In order to use a function defined by defun-foreign-callable, the function must first be registered using register-foreign-callable.

What the foreign-callable function returns as a foreign value is controlled by the call to register-foreign-callable (which actually enables the foreign callable function). If the third (optional) argument to register-foreign-callable is `nil`, an unconverted Lisp value is returned in the foreign return register. Programmers must use the specifications in [Allegro directory]/misc/lisp.h to interpret this value. If the third argument is `t`, then the Lisp value of the function is converted to a foreign value according to the default conversion rules, and the resulting value is returned as the foreign value returned by the Lisp function.

The body of the foreign callable Lisp function must be carefully coded to return a Lisp value that will trigger an appropriate conversion so that the desired foreign value will actually appear at the interface.

### Strings passed as arguments

Consider this call to defun-foreign-callable:

    (defun-foreign-callable gdbm-error-handler ((string (* :char)))
      (error "gdbm error: ~a." (native-to-string string)))

The call native-to-string is necessary because the string argument in the callback to Lisp is done with no string conversion at callback time. The value of the string argument as passed will be an integer representing a C address. native-to-string does the necessary conversion.

See ftype.htm for information on foreign types in Allegro CL and foreign-functions.htm for general information on foreign functions in Allegro CL.

Copyright (c) 1998-2022, Franz Inc. Lafayette, CA., USA. All rights reserved.
This page has had moderate revisions compared to the 10.0 page.
Created 2019.8.20.

|  | ToC | DocOverview | CGDoc | RelNotes | FAQ | Index | PermutedIndex
| Allegro CL version 10.1 Moderately revised from 10.0. 10.0 version