[Openmcl-devel] should ccl allow ffi callbacks to be defined within closures

Ron Garret ron at flownet.com
Wed May 22 08:06:03 PDT 2024


The problem here is not that callbacks cannot be closures.  They can:

? (let ((x 1)) (defcallback foo () x))
FOO

The problem is that they have to be defined at the top level, not by a run-time call to DEFCALLBACK.  The reason for that is that DEFCALLBACK creates the callback function using CCL::NLAMBDA, which is like LAMBDA except that the created function has a name attached to it:

? (function-name (lambda () t))
NIL
? (function-name (ccl::nlambda foo () t))
FOO

The FFI needs that name to do its thing, and that name has to be a symbol.  The problem is that when NLAMBDA is called inside another function rather than at the top-level, the name of the function that gets created is a list, not a symbol:

? (defun baz () (function-name (ccl::nlambda foo () t)))
BAZ
? (baz)
(:INTERNAL FOO BAZ)

and the FFI doesn't know how to handle that.

rg

> On May 21, 2024, at 11:48 PM, Madhu <enometh at meer.net> wrote:
> 
> I came across a use of cffi callbacks which defines the callback
> within a function. In CCL the following
> 
> ```
> (defun barf ()
>  (ccl:defcallback CMPSTRINGP (:address p1 :address p2 :signed-int)
>      (ccl:external-call "strcmp" :address p1 :address p2 :signed-int)))
> (barf)
> 
> =>
> Condition of type TYPE-ERROR:
> 
> The value (:INTERNAL CMPSTRINGP BARF) is not of the expected type
> (AND SYMBOL (NOT (SATISFIES CONSTANTP)))
> ```
> 
> Is there any reason to disallow callbacks defined by defcallbacks from
> being closures which capture their environment?
> 
> I am attaching a patch which continues to use the name specified by
> DEFCALLBACK even if the defining function is a closure.
> 
> I'd very much appreciate it if other developers could review it and
> give feedback.
> 
> 
> From d6241c160cc42979da2629862f97c350615850a9 Mon Sep 17 00:00:00 2001
> From: Madhu <enometh at net.meer>
> Date: Sun, 12 May 2024 22:01:08 +0530
> Subject: [PATCH] allow ffi callbacks to be defined within closures.
> 
> * level-1/l1-callbacks.lisp: (define-callback-function): If the
> function-name is an internal-function of the form (:internal name) use
> the internal name instead.
> 
> After this patch, defcallbacks can be defined within internal
> functions. e.g. the following will work, instead of erroring out on
> the name.
> 
> ```
> (defun barf ()
>  (ccl:defcallback CMPSTRINGP (:address p1 :address p2 :signed-int)
>      (ccl:external-call "strcmp" :address p1 :address p2 :signed-int)))
> (barf)
> ```
> ---
> level-1/l1-callbacks.lisp | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/level-1/l1-callbacks.lisp b/level-1/l1-callbacks.lisp
> index 3f88041..f147f71 100644
> --- a/level-1/l1-callbacks.lisp
> +++ b/level-1/l1-callbacks.lisp
> @@ -25,7 +25,10 @@ (defstatic *callback-lock* (make-lock))
> (defun define-callback-function (lisp-function  &optional doc-string (without-interrupts t) info &aux name trampoline)
>   (unless (functionp lisp-function)
>     (setq lisp-function (require-type lisp-function 'function)))
> -  (unless (and (symbolp (setq name (function-name lisp-function)))
> +  (if (and (consp (setq name (function-name lisp-function)))
> +	   (eql (car name) :internal))
> +      (setq name (second name)))
> +  (unless (and (symbolp name)
>                ;;Might as well err out now before do any _Newptr's...
>                (not (constant-symbol-p name)))
>     (report-bad-arg name '(and symbol (not (satisfies constantp)))))
> -- 
> 2.39.2.101.g768bb238c4
> 



More information about the Openmcl-devel mailing list