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

Phillip Suero philsuero at gmail.com
Tue Apr 27 16:09:34 EDT 2021


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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.iro.umontreal.ca/pipermail/gambit-list/attachments/20210427/2e2e2270/attachment.htm>


More information about the Gambit-list mailing list