[Openmcl-devel] Calling a callback & closures

Gary Byers gb at clozure.com
Mon May 2 04:33:39 PDT 2005



On Mon, 2 May 2005, David Steuber wrote:

> Hello,
>
> I'm trying to see if I can use DEFCALLBACK to close over lexical variables so 
> that when a C function calls into lisp, the correct value will be in the 
> variable.  I'm not clear how closures work, so I don't even know if the idea 
> is sane.  To start testing the idea, I tried using %ff-call to call my 
> callback.  I landed in the kernel debugger, so I'm doing something very 
> wrong.  Can someone show me how to get this bit to work?
>
> $ openmcl
> Welcome to OpenMCL Version (Beta: Darwin) 0.14.3-050429!
> ? (%ff-call (let (fn)
>                     (declare (special fn))
>                     (defcallback fn (:integer)
>                       1)) :integer)
> Unhandled exception 4 at 0x0639eeec, context->regs at #xf01356d8
> Illegal instruction (0x0639ef06) at 0x0639eeec In foreign code at address 
> 0x0639eeec
> ? for help
> [1019] OpenMCL kernel debugger:
>
> I was hoping to get a 1 back.

The form:

(defcallback fn (:integer) 1)

a) has the effect of setting the (special) value of the symbol FN to a
    pointer (to a little piece of foreign code) that jumps into the lisp
    kernel; code in the kernel jumps out to a lisp function.
b) retuns the symbol FN (as do other defining forms, like DEFUN/DEFMACRO.)

If we moved things around:

? (defcallback fn (:int) 1)
1
? (%ff-call 'fn :signed-fullword)

and the kernel debugger tells us (somewhat cryptically ...) that %FF-CALL
doesn't do much typechecking and is perfectly happy to try to jump into
a symbol.  (The pointer to the symbol's pname probably isn't a valid
machine instruction.)

(%ff-call (let (fn)
               (declare (special fn))
               (defcallback fn (:int)
                 1)
               fn)
            :signed-fullword)

returns 1.

>
> Now imagine that I declared foo in the let expression (but not as a special). 
> Could the value of foo be used in the callback fn?
>
> eg (if the above worked):
>
> (%ff-call (let (fn (foo 1))
>   (declare (special fn))
>     (defcallback fn (:integer) foo)) :integer)
>

I'm not sure that I understand the question, so here are a couple
of (not-necessarily relevant) answers:.

The functions that DEFCALLBACK defines are defined in the current
lexical environment, so you can do things like:

? (let* ((x 17))
     (defcallback fn (:int) x)
     (defun set-x (val)
       (setq x val)))
SET-X
? (set-x 12)
12
? (ff-call fn :signed-integer)
12

DEFCALLBACK has an (often, but not always) useful side-effect: namely,
setting a special variable's value to point to the little piece of
trampoline code.  (Using DEFCALLBACK to redefine an existing callback
preserves that pointer but redefines the lisp code associated with
that foreign pointer.)

It's certainly handy to be able to manipulate globally named callback
pointers, but it seems (both philosophically and practically) like
it'd also be handy to be able to create anonymous callback functions
as well (that the actions of manipulating the callback pointer and
generating a lisp function that handles the foreign argument/return
value coercions should/could be separated.)



More information about the Openmcl-devel mailing list