Re: should ccl allow ffi callbacks to be defined within closures

Ron Garret <[email protected]> Wed, 22 May 2024 08:06:03 -0700
Newsgroups gmane.lisp.openmcl.devel
Message-ID <[email protected]>
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 <[email protected]> wrote:
>=20
> I came across a use of cffi callbacks which defines the callback
> within a function. In CCL the following
>=20
> ```
> (defun barf ()
>  (ccl:defcallback CMPSTRINGP (:address p1 :address p2 :signed-int)
>      (ccl:external-call "strcmp" :address p1 :address p2 =
:signed-int)))
> (barf)
>=20
> =3D>
> Condition of type TYPE-ERROR:
>=20
> The value (:INTERNAL CMPSTRINGP BARF) is not of the expected type
> (AND SYMBOL (NOT (SATISFIES CONSTANTP)))
> ```
>=20
> Is there any reason to disallow callbacks defined by defcallbacks from
> being closures which capture their environment?
>=20
> I am attaching a patch which continues to use the name specified by
> DEFCALLBACK even if the defining function is a closure.
>=20
> I'd very much appreciate it if other developers could review it and
> give feedback.
>=20
>=20
> =46rom d6241c160cc42979da2629862f97c350615850a9 Mon Sep 17 00:00:00 =
2001
> From: Madhu <[email protected]>
> Date: Sun, 12 May 2024 22:01:08 +0530
> Subject: [PATCH] allow ffi callbacks to be defined within closures.
>=20
> * 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.
>=20
> After this patch, defcallbacks can be defined within internal
> functions. e.g. the following will work, instead of erroring out on
> the name.
>=20
> ```
> (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(-)
>=20
> 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)))))
> --=20
> 2.39.2.101.g768bb238c4
>=20