chicken-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Chicken-users] newbie: foreign pointers that depend on Scheme objects


From: Alejandro Forero Cuervo
Subject: [Chicken-users] newbie: foreign pointers that depend on Scheme objects
Date: Mon, 15 Dec 2008 22:34:15 +0100
User-agent: Mutt/1.5.13 (2006-08-11)

I have a question about what the best way to achieve something with
Chicken's FFI might be.  This is based on problems I'm having with the
svn-client egg (so the actual code is more complex, this is just a
simplification) for some modifications that I'm making to implement
some new functionality in Svnwiki.

Lets say I have the following C structure:

  struct closure {
    void *data;
    void *proc(void *data);
  };

Lets say I have a function that builds one such structure and returns
it:

  void create_closure(void *data, void *proc (void *));

(Please ignore syntax errors in the above C code; the intention should
be clear.)

Now, if I want to make create_closure callable from Scheme, I'm doing
the following:

  (define-record c-closure ptr)

  (define (make-c-closure-with-finalizer x)
    (set-finalizer! x (foreign-lambda void "free_closure" (pointer "closure")))
    (make-c-closure x))
  
  (define-foreign-type
    c-closure-type
    (pointer "closure")
    c-closure-ptr
    make-c-closure-with-finalizer)

  (define-external (call_the_proc (scheme-object proc)) scheme-object
    (proc))

  (define create-closure
    (foreign-lambda* c-closure ((scheme-object proc))
      "return(create_closure(proc, call_the_proc));"))

This, evidently, has problems.  If the programmer does

  (create-closure (lambda () (foobar))) ,

the dependency of the resulting c-closure on the parameter passed to
create-closure is not registered anywhere.  So it may get GCed.  And,
furthermore, IIRC, it may get moved to a different address so the C
pointer data will be rendered invalid.

So what's the best way to solve this?

One idea I had was to do the following (plus tweaks to call_the_proc
to de-ref the GC root):

  (define create-closure
    (let ((obj ((foreign-lambda* c-closure ((scheme-object proc))
  #<<EOF
       void *root = CHICKEN_new_gc_root();
       CHICKEN_gc_root_set(root, proc);
       return(create_closure(root, call_the_proc));
  EOF     
                ) proc)))
      (set-finalizer! (c-closure-ptr obj)
        (foreign-lambda* void ((c-closure obj))
          "CHICKEN_delete_gc_root(obj->data);"))
      obj))

I actually don't think this would work: there could be loops if the
Scheme-level closure depends on an object that is eventually modified
to depend on the C-level closure object (the object returned by
create-closure) so even if there are no other references to these
objects, they won't be GCed.

So how should I solve this problem?

Thanks.

Alejo.
http://azul.freaks-unidos.net/




reply via email to

[Prev in Thread] Current Thread [Next in Thread]