[Openmcl-devel] Calling a callback & closures

David Steuber david at david-steuber.com
Mon May 2 13:01:32 PDT 2005


Hello Gary & list,

On May 2, 2005, at 7:33 AM, Gary Byers wrote:
> On Mon, 2 May 2005, David Steuber wrote:
>> 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.

Ah!  Thanks for correcting the syntax for me.

>> 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:.

I was asking about making a closure in a clumsy sort of way...

> 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.)

Yes.  Here is what I'm trying to do (in concept) and it looks like it 
may work:

$ openmcl
Welcome to OpenMCL Version (Beta: Darwin) 0.14.3-050429!
? (defun make-ff (ret)
   (let (fn)
     (declare (special fn))
     (defcallback fn (:int) ret)
     fn))
MAKE-FF
? (defvar ff-foo (make-ff 10))
FF-FOO
? (defvar ff-bar (make-ff 20))
FF-BAR
? (%ff-call ff-foo :signed-fullword)
10
? (%ff-call ff-bar :signed-fullword)
20
? (quit)

The idea is to make a callback that uses a closure to associate the 
function pointer with a CLOS object that can then be used by the 
callback function.  This would get rid of an ugly hack in some Carbon 
event handler code I have and also allow me to abstract the notion of 
Carbon callbacks as other APIs want different callbacks with different 
function signatures (in the C sense of the word).





More information about the Openmcl-devel mailing list