[gambit-list] Moving a ___SCMOBJ that is ___STILL from Scm to C to Scm is fine?

Marc Feeley feeley at iro.umontreal.ca
Tue Apr 27 16:41:48 EDT 2021


Your approach may work for this case but I wouldn’t call it best practice.  You can’t (in general) copy a ___MOVABLE closure to a ___STILL closure with ##still-copy because a closure may contain a circular reference that will not be copied properly by the shallow ##still-copy.  For example :

> (define (foo x) (letrec ((bar (lambda (y) (list x y bar)))) bar))
> (define clo (foo 42))
> (eq? clo (##closure-ref clo 2))
#t

This shows that the closure’s structure contains a cycle in its environment.

The best practice is to store the reference to the closure in a still object, such as a still box.  It is also a good idea to increment this still object's reference count so that the GC knows that “the C world” has a pointer to that still object (in case the only way to reach the object is from C).  The reference count should be decremented when C no longer has a reference to the object.  This refcount management can be avoided if you can guarantee that the C world will only ever use the object while the Scheme world refers to the object.

Marc



> On Apr 27, 2021, at 4:09 PM, Phillip Suero <philsuero at gmail.com> wrote:
> 
> Dear Marc,
> 
> I ran this code:
> 
> (c-declare "___SCMOBJ storage;")
> 
> (define store! (c-lambda (scheme-object) void "storage = ___arg1;"))
> 
> (define get (c-lambda () scheme-object "___return(storage);"))
> 
> (define (gen-c)
>   (let ((abc #f))
>     (##still-copy
>       (lambda (v)
>          (define o v)
>          (set! abc v)
>          o))))
> 
> (define gen-i (eval '(lambda () (let ((abc #f))    (##still-copy (lambda (v) (define o v) (set! abc v) o))))))
> 
> To test the hypothesis that a ____STILL closure can be successfully passed as a ___SCMOBJ from Scheme to C, stay in C for a while and then be moved back to Scheme anytime.
> 
> A normal closure will not work, since it changes memory address. However, thanks to ##still-copy , I can get a closure that has a fixed memory address all up to collection, and such a closure's ___SCMOBJ can then be kept in C for as long as desired.
> 
> Also, this ___STILL closure will still be collected, so there is no memory leak problem.
> 
> The code above outputs:
> 
> > (load "test")
> "/path/to/test.o1"
> > (define x (gen-c)) (print x " ") (store! x) (##gc) (print (get) "\n")
> > #<procedure #2 x> > > > #<procedure #2 x>
> > 
> (define x (gen-i)) (print x " ") (store! x) (##gc) (print (get) "\n")
> > #<procedure #3 x> > > > #<procedure #3 x>
> 
> 
> The only operational requirement for the transfer of a ___SCMOBJ from C to Scheme is that the object is still alive. In the example code above, that is guaranteed by that a strong reference to the closure is kept in |x| up to that (get) has made the transfer from C to Scheme, which then produces a new strong reference to the closure, which is sufficient in itself.
> 
> Example to illustrate clean transfer of the strong reference:
> 
> (define x (gen-c)) ; Generate closure
> 
> (print x " ") 
> 
> (store! x) ; Store closure in C world, however still keep strong reference in |x|
> 
> (##gc) ; All non-___STILL/___FIXED allocated objects will change ___SCMOBJ, thus invalidating them
> 
> (define y (get)) ; We pick up the ___SCMOBJ from the C world and assign it to |y|. |x| above must be maintained as a strong reference up to the completion of this step.
> 
> ; |x| is no longer needed for (get) to work, here, since we have a separate strong reference to the object now, in |y|.
> 
> (set! x #f) (##gc)
> 
> ; All fine.
> 
> (print y "\n")
> 
> 
> The above example breaks, if the (##still-copy part is removed, in which case the closure will be ___MOVABLE, the ___SCMOBJ will be invalidated at GC, and therefore accessing the result of (get) produces SIGSEGV or similar unknown behavior, in my test it would print out #<unknown>.
> 
> Marc please confirm that what I do above here is a best practice and is all correct.
> 
> Phil
> _______________________________________________
> Gambit-list mailing list
> Gambit-list at iro.umontreal.ca
> https://mailman.iro.umontreal.ca/cgi-bin/mailman/listinfo/gambit-list




More information about the Gambit-list mailing list