[gambit-list] References between 'foreign' objects.

Estevo euccastro at yahoo.com
Mon Mar 26 23:55:04 EDT 2012


I think I have finally built a mental model of how foreign objects work.  In order to confirm or correct this, I'll illustrate my current beliefs with an example.

Let's say I have these C structures somewhere visible to my Scheme code via c-declare:

typedef struct {int i, j;} child;
typedef struct {child c; int k;} parent;



And I wrap them like this:

(c-define-type child (struct "child" child "do_nothing"))

(c-define-type parent (struct "parent"))

(define make-parent
  (c-lambda () parent

    "___result_voidstar = ___EXT(___alloc_rc)(sizeof(parent));"))  ; [1]


Where the dummy `release-function` `do_nothing` is `c-declare`d:

___SCMOBJ do_nothing(void *p)
{
    return ___FIX(___NO_ERR);

}

Then I write an accessor:

(define (parent-c p)
  (let ((ret ((c-lambda (parent) child
                 "___result_voidstar = &(((parent*)___arg1_voidstar)->c);"))))
    ((c-lambda (child scheme-object) void
       "___EXT(___set_data_rc)(___arg1_voidstar, ___arg2);")  ; [2]

     ret parent)

    ret)


Let's say I have the above correctly compiled and say:

(define par (make-parent))
(define ch1 (parent-c p))
(define ch2 (parent-c p))


At this moment, I believe all the following sentences to be true:

  (i)   `par` is a Scheme foreign object that holds a pointer to the very memory I allocated in the line marked as [1], not to a copy of it.
  (ii) The pointer referred to in (i) is managed by Gambit, via reference counting (Gambit maintains some bookkeeping data in the address right before the pointer).  At this moment, its reference count is 1.

  (iii)  `ch1` is a Scheme foreign object that holds a pointer to the very position of the `c` member in the struct `par`, not to a copy of it.  As it happens, it points to the same memory as `par` itself.
  (iv)  the pointer mentioned in (iii) is, too, managed by Gambit.  Its reference count is, too, 1.
  (v)  additionally, the `data` field of the 'managed pointer' mentioned in (iii) holds, by virtue of [2], a root reference to `par` (the meaning of this will be made more explicit later).
  (vi) I haven't accessed memory in an illegal or undefined way in doing (v).

  (vii) (iii) to (vi) hold for `ch2` too.

Now I forget ch2:

(set! ch2 #f)

At this moment, I believe:

  (vii) `ch2` will be disposed of in the next garbage collection.
  (viii) the pointer wrapped by `ch2` will get a reference count of 0 and thus be disposed of at next opportunity.

  (ix) Gambit will not try and free any memory allocated in [1] when either of the above happens, because `ch2` has a bogus `release-function`.

Now I remove my only Scheme-visible reference to `par`:

(set! par #f)

At this moment, I believe:


  (x) `par` would not be garbage collected now.  The `data` reference from the `ch1` pointer is keeping it alive.
  (xi) the pointer wrapped by `par` will keep its reference count of 1.

Now I forget ch1:

(set! ch1 #f)

At this moment, I believe:

  (xii) (vii) and (viii) apply for `ch1` now.
  (xiii) nobody is holding a reference to `par` anymore, so `par` will be garbage collected at next opportunity.
  (xiv) when the above happens, the pointer referred to in (i) will be left with a reference count of 0, and thus it will be disposed of soon.
  (xv)  `par`s default `release-function` will free the memory allocated at [1].


My current implementation of the struct/union wrapping macro relies on these beliefs.  I have tested some of these, but I haven't yet figured out how to confirm or falsify others (e.g. how do you check whether a memory block has been deallocated?).  Anyway, if you know any of these to be false, I'd be grateful to hear from you.

Thanks in advance,

Estevo.



>________________________________
> De: Estevo <euccastro at yahoo.com>
>Para: Marc Feeley <feeley at iro.umontreal.ca> 
>Cc: "gambit-list at iro.umontreal.ca" <gambit-list at iro.umontreal.ca> 
>Enviadas: Sábado, 24 de Março de 2012 21:02
>Assunto: Re: [gambit-list] References between 'foreign' objects.
> 
>> This reminds me that Gambit provides a memory allocation function, ___alloc_rc, 
>
>> for allocating C objects on the C heap which have a back-pointer to a Scheme 
>> object, and also a reference count.  The API is:
>> 
>> void *___alloc_rc(unsigned long n);
>> void ___release_rc(void *ptr);
>> void ___addref_rc(void *ptr);
>> void ___set_data_rc(void *ptr, ___SCMOBJ val);
>> ___SCMOBJ ___data_rc(void *ptr);
>
>This might be just what I need, thanks!  Paradoxically enough, I was allocating my structs with ___alloc_rc, but I don't think I really understood how that works.
>
>I'll ping the list when I have something that I believe is solid, and/or I'll put it in the dumping grounds, just in case it might be of use for anyone else.
>
>Thanks again,
>
>Estevo.
>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.iro.umontreal.ca/pipermail/gambit-list/attachments/20120326/a3f6ae08/attachment.htm>


More information about the Gambit-list mailing list