[plt-scheme] Problem with FFI functions returning pointers to 'C' functions
On Sep 12, Tim Brown wrote:
> I've revisited my problem, and I have got a little further
> (in fact a solution I can work with).
>
> On 12/09/07 10:10, Tim Brown wrote:
> > A more concrete example is setting a signal(3C) call:
> >
> > (require (lib "foreign.ss"))
> > (unsafe!)
> > (define c-signal
> > (get-ffi-obj "signal" #f (_fun _int (_fun _int -> _void) ->
> > (_fun _int -> _void))))
> > (c-signal 15 (lambda (f) #f))
> >
> > However, when I run this on: MzScheme v370 [3m]
> > SunOS 5.10 x86 or even Linux
> >
> > I get the following error:
> > ffi-call: expects type <non-null-cpointer> as 1st argument, given: #f;
> > other arguments were: (#<ctype>) #<ctype>
>
> This error is caused by the signal function returning a NULL
> pointer. Since no signal handler is initially installed for 15 in
> this case, a NULL is returned.
Right. With pointers, #f stands for NULL, but not with functions.
> Why is the error reported by ffi-call, and not whatever it is that
> objected to the #f in the first place?
The `first place' is inside the implementation of `_cprocedure' which
just doesn't expect to deal with NULLs. It's easy to change the
library to do that, but I'm not sure that it's a good idea. If anyone
has a clear argument in favor then I'll do that, if not then at some
point in the future I'll make it possible to pass flags to `_fun' to
customize its behavior including allowing NULLs. (I'll need to add
such flags anyway, it's needed also to control the ABI that gets
used.)
But in the meanwhile, here is a solution that works for now:
* Your (_fun ...) type for signal gets expanded to:
(_cprocedure (list _int (_cprocedure (list _int) _void))
(_cprocedure (list _int) _void))
* You need a version of `_cprocedure' that can deal with NULLs, but
you can't do that with "foreign.ss" since it doesn't give you the
necessary primitives -- so grab them straight from the C level:
(require (only #%foreign ffi-callback ffi-call))
* Once you have that, you can implement the variant of `_cprocedure'
that just passes NULLs over (in both directrions):
(define (_cprocedure* itypes otype)
(make-ctype _fpointer
(lambda (x) (and x (ffi-callback x itypes otype)))
(lambda (x) (and x (ffi-call x itypes otype)))))
* Using this:
(define c-signal
(get-ffi-obj "signal" #f
(_cprocedure* (list _int (_cprocedure* (list _int) _void))
(_cprocedure* (list _int) _void))))
> Anyway, I am returning a _fpointer, and only casting it (with ptr-set)
> to an (_fun _int -> _void) if it is (not #f).
I'm pretty sure that doing such a cast will not work.
--
((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay:
http://www.barzilay.org/ Maze is Life!