I tried to pass a Scheme procedure to a C nonnull-function. The documentation says that the two types should be compatible:
http://www.iro.umontreal.ca/~gambit/doc/gambit-c.html#mapping-of-types
But I get the error that the conversion can not be done:
*** ERROR IN ##execute-program -- (Argument 1) Can't convert to C nonnull-function (call-func '#<procedure #2 proc>)
This is my test program:
;; Local Variables: ;; compile-command: "gsc -exe ffi-hello.scm" ;; End:
(c-declare #<<end-of-c-declare
typedef void(*func_t)(void);
void call_func (func_t func) { func(); }
end-of-c-declare )
(c-define-type func_t (nonnull-function () void))
(define call-func (c-lambda (func_t) void "call_func"))
(define proc (lambda () (display "Hello, World!")))
(write (procedure? proc))
(call-func proc)
Can anybody tell me whats wrong?
Afficher les réponses par date
Sorry for the mail. I found the answer in the docs:
Scheme procedures defined with the c-define special form can be passed where the function and nonnull-function types are expected. The value #f is also acceptable for a function type, and is converted to NULL. No other Scheme procedures are acceptable.
This version works:
;; Local Variables: ;; compile-command: "gsc -exe ffi-hello-2.scm" ;; End:
(c-declare #<<end-of-c-declare
typedef void(*func_t)(void);
void call_func (func_t func) { func(); }
end-of-c-declare )
(c-define-type func_t (nonnull-function () void))
(define call-func (c-lambda (func_t) void "call_func"))
(c-define (proc) () void "func" "" (display "Hello, World!"))
(write (procedure? proc))
(call-func proc)
But it is of limited use if it comes to Gtk callbacks. If one dynamically creates Gtk widgets it is necessary to be able to assign them callbacks. If the definition of the callback must be done on the Scheme top level and always requires a C name the whole code becomes quite static.
Gtk provides some infrastructure for callbacks called marshaller. Would it be possible to use that to write a gtk-lambda similar to c-define, which can be used to create callbacks for Gtk but without the limitations of c-define?
Hallo,
On Thu, Nov 3, 2011 at 1:58 PM, Vok Vojwo ceving@gmail.com wrote:
Gtk provides some infrastructure for callbacks called marshaller. Would it be possible to use that to write a gtk-lambda similar to c-define, which can be used to create callbacks for Gtk but without the limitations of c-define?
The GObject library certainly support dynamic, non-C callbacks:
http://developer.gnome.org/gobject/2.30/chapter-signal.html#id500726
Cheers,
2011/11/3 Alex Queiroz asandroq@gmail.com:
On Thu, Nov 3, 2011 at 1:58 PM, Vok Vojwo ceving@gmail.com wrote:
Gtk provides some infrastructure for callbacks called marshaller. Would it be possible to use that to write a gtk-lambda similar to c-define, which can be used to create callbacks for Gtk but without the limitations of c-define?
The GObject library certainly support dynamic, non-C callbacks:
http://developer.gnome.org/gobject/2.30/chapter-signal.html#id500726
Yes but this requires some knowledge about the things c-define does to export a Scheme function to C. Is this documented anywhere? I know a bit about C and Scheme but I am a Gambit noob. ;-)
Make a wrapper. Use the argument value you for sure can specify to the external API (a void* or alike) to pass back to you on callback, as id to your internal routine.
2011/11/3 Vok Vojwo ceving@gmail.com
But it is of limited use if it comes to Gtk callbacks. If one dynamically creates Gtk widgets it is necessary to be able to assign them callbacks. If the definition of the callback must be done on the Scheme top level and always requires a C name the whole code becomes quite static.
2011/11/3 Mikael mikael.rcv@gmail.com:
Make a wrapper. Use the argument value you for sure can specify to the external API (a void* or alike) to pass back to you on callback, as id to your internal routine.
I am not sure if I understood this correctly. Do you talk about a dispatching callback function which takes an continuation argument to execute the actual callback code?
Yes. The external representation is effectively an int. Btw any closure can be passed <-> the external world under the type representation scmobj which is effectively an int also, look it up in the manual.
I'm not clear right now if scmobj:s are persistent to GC iterations though, if you/anyone knows please let the ml know.
2011/11/3 Vok Vojwo ceving@gmail.com
2011/11/3 Mikael mikael.rcv@gmail.com:
Make a wrapper. Use the argument value you for sure can specify to the external API (a void* or alike) to pass back to you on callback, as id to your internal routine.
I am not sure if I understood this correctly. Do you talk about a dispatching callback function which takes an continuation argument to execute the actual callback code? _______________________________________________ Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
2011/11/3 Mikael mikael.rcv@gmail.com:
Yes. The external representation is effectively an int. Btw any closure can be passed <-> the external world under the type representation scmobj which is effectively an int also, look it up in the manual.
I'm not clear right now if scmobj:s are persistent to GC iterations though, if you/anyone knows please let the ml know.
I think I got it:
;; Local Variables: ;; compile-command: "gsc -exe ffi-hello-3.scm" ;; End:
(c-define (apply0 proc) (scheme-object) void "apply0" "" (proc))
(c-declare #<<end-of-c-declare
void call_scheme (___SCMOBJ proc) { apply0 (proc); }
end-of-c-declare )
(define call-scheme (c-lambda (scheme-object) void "call_scheme"))
(define (proc) (print "Hello, World!\n"))
(print (procedure? proc) "\n")
(call-scheme proc)
Now the C function call_scheme can call any Scheme procedure by using apply0.
With gc persistence you mean that the address of the scheme procedure might change because of a mark and compact gc? That would be a problem and will break the above code.
The Gambit documentation distinguishes movable and nonmovable objects in:
http://dynamo.iro.umontreal.ca/~gambit/wiki/index.php?title=Documentation:Pr...
But I can not find any description how to make an object nonmovable. Does anybody know how to make a closure nonmovable?
On 2011-11-03, at 10:16 AM, Vok Vojwo wrote:
2011/11/3 Mikael mikael.rcv@gmail.com:
Yes. The external representation is effectively an int. Btw any closure can be passed <-> the external world under the type representation scmobj which is effectively an int also, look it up in the manual.
I'm not clear right now if scmobj:s are persistent to GC iterations though, if you/anyone knows please let the ml know.
I think I got it:
;; Local Variables: ;; compile-command: "gsc -exe ffi-hello-3.scm" ;; End:
(c-define (apply0 proc) (scheme-object) void "apply0" "" (proc))
(c-declare #<<end-of-c-declare
void call_scheme (___SCMOBJ proc) { apply0 (proc); }
end-of-c-declare )
(define call-scheme (c-lambda (scheme-object) void "call_scheme"))
(define (proc) (print "Hello, World!\n"))
(print (procedure? proc) "\n")
(call-scheme proc)
Now the C function call_scheme can call any Scheme procedure by using apply0.
With gc persistence you mean that the address of the scheme procedure might change because of a mark and compact gc? That would be a problem and will break the above code.
Yes that's the problem with that approach.
Another approach is to have multiple instances of the function and "allocate" them dynamically. Check this message for that solution:
https://mercure.iro.umontreal.ca/pipermail/gambit-list/2009-January/002939.h...
The Gambit documentation distinguishes movable and nonmovable objects in:
http://dynamo.iro.umontreal.ca/~gambit/wiki/index.php?title=Documentation:Pr...
But I can not find any description how to make an object non movable.
Objects are either allocated as "movable" or as "still" (non-movable). Once allocated, you can't change their "movability". On the other hand you can use (##still-copy obj) to make a still copy of obj. The address of the copy will not change during its lifetime.
Like any other object, a still object will normally be reclaimed by the GC if it is not reachable from Scheme. So if you pass the only reference to the copy to C, it will be reclaimed at the next GC. On the other hand, you can force a still object to be considered live by the GC by incrementing its reference count:
(##still-obj-refcount-inc! obj)
When the C code is done with the object, it can decrement the reference count with the call:
___still_obj_refcount_dec(obj);
These things can be combined to safely pass closures to C. The idea is to use a still wrapper around the closure:
(define (wrap proc) (##still-obj-refcount-inc! (##still-copy (vector proc))))
(define (install-callback proc) ((c-lambda (scheme-object) void "... ___arg1 should be used as the callback data ...") (wrap proc)))
(c-define (scheme-callback wrapped-proc arg) (scheme-object char-string) void "scheme_callback" "" ((vector-ref wrapped-proc 0) arg))
The actual C callback needs to pass the "callback data" (the wrapped closure) to scheme-callback by calling scheme_callback.
Marc
2011/11/3 Marc Feeley feeley@iro.umontreal.ca:
The actual C callback needs to pass the "callback data" (the wrapped closure) to scheme-callback by calling scheme_callback.
Thanks for the information. It was very useful to understand the Scheme-C interaction.
But the problem is much bigger than I thought, because only simple Gtk callbacks require no parameters. There are many signals which want to pass arguments to the callback function. The delete-from-cursor of the entry widget is such a signal:
http://developer.gnome.org/gtk3/stable/GtkEntry.html#GtkEntry-delete-from-cu...
And because of that it would not help much to be able to call a Scheme function without arguments. It is necessary to convert all arguments to Scheme values and call a Scheme function from C. I think I have to follow the link Alex has posted. The problem can not be solved without the Gtk marshal functions.
On 2011-11-04, at 10:06 AM, Vok Vojwo wrote:
2011/11/3 Marc Feeley feeley@iro.umontreal.ca:
The actual C callback needs to pass the "callback data" (the wrapped closure) to scheme-callback by calling scheme_callback.
Thanks for the information. It was very useful to understand the Scheme-C interaction.
But the problem is much bigger than I thought, because only simple Gtk callbacks require no parameters. There are many signals which want to pass arguments to the callback function. The delete-from-cursor of the entry widget is such a signal:
http://developer.gnome.org/gtk3/stable/GtkEntry.html#GtkEntry-delete-from-cu...
And because of that it would not help much to be able to call a Scheme function without arguments. It is necessary to convert all arguments to Scheme values and call a Scheme function from C. I think I have to follow the link Alex has posted. The problem can not be solved without the Gtk marshal functions.
You are not obligated to use void functions. You can pass parameters and return results. There must be one type of "scheme_callback" function for each signature however.
Marc