I found a very simple way to use callbacks in CFFI or in alien-lambda without
the performance and memory implications we discussed, at least for the case
that the callback doesn't call C again:
The callback given to C is just a delegator to a closure that is saved in a
the global variable *once-to-c-closure-callback*.
--------------------------------------------------------------------
(defvar *once-to-c-closure-callback* nil)
(defcallback delegating-callback :double ((x :double))
;; (callback-index :int))
(funcall *once-to-c-closure-callback* x))
(defun closure-callback (func)
(setq *once-to-c-closure-callback* func)
(callback delegating-callback))
--------------------------------------------------------------------
Here's an example with a C function executing the callback:
--------------------------------------------------------------------
// Compile with CF=testc && gcc -fPIC -c $CF.c && gcc -shared -Wl,-soname,$CF.so -o $CF.so $CF.o
#include <stdio.h>
double execute_callback (void* callback, double x) {
if (callback != NULL) {
printf("callback: %ld\n", (long)callback);
double (*callback1)();
callback1 = (double (*)())callback;
return (*callback1)(x);
} else {
printf("Callback is 0.\n");
}
}
--------------------------------------------------------------------
>From Lisp, you would use it this way:
(let ()
(define-foreign-library testc
(:unix "/home/daniel/pj/lisp/testc.so"))
(use-foreign-library testc)
(defcfun "execute_callback" :double (callback :pointer) (x :double)))
(defun test-closure-callback (a)
(execute-callback (closure-callback #'(lambda (x) (+ a x))) 10d0))
(test-closure-callback 5d0)
;; which gives 15d0.
(defun test-closure-callback2 (a)
(execute-callback (closure-callback #'(lambda (x) (* a x))) 10d0))
(test-closure-callback2 5d0)
;; which gives 50d0.
For callbacks that are allowed to call C again one would have to use a
self-expanding global array instead of *once-to-c-closure-callback* and pass
the index into the array where the closure is saved to the C function as well.
In order to let the garbage collector reclaim the closure's memory, the
following with-macro could be used instead of closure-callback. Since the
next call will overwrite *once-to-c-closure-callback* anyway, this doesn't
matter much, but in the above-mentioned array case, a similar implementation
would be necessary.
(defmacro with-closure-callback ((closure-var func) &body body)
`(unwind-protect
(let ((,closure-var (callback delegating-callback)))
(setq *once-to-c-closure-callback* ,func)
,@body)
(setq *once-to-c-closure-callback* nil)))
And here's a test for that:
(defun test-closure-callback (a)
(with-closure-callback (closure #'(lambda (x) (+ a x)))
(execute-callback closure 10d0)))
(test-closure-callback 5d0)
Best regards
Bruno Daniel
-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems? Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
Sbcl-help mailing list
Sbcl...@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sbcl-help
In case the C code receives another callback and wants to call both of them
interchangingly, one would have to use the array solution as well.
Viele Grüße