C extension: VALUEs being collected too early

I'm writing a C extension which passes around structs that refer to
Ruby VALUEs. During the course of execution, these VALUEs are
assigned new Ruby strings, hashes or arrays (via the rb_{str,hash,ary)
_new functions) through a series of callbacks. The problem is that it
seems they're getting collected too early before I have a chance to
use the result.

I tried a few things to keep these VALUEs around (including calling
rb_gc_mark directly on these objects), but the only thing that seems
to prevent this early collection is by disabling the GC while my code
is executing.

Is there something I can use to prevent these VALUEs from getting re-
used without resorting to turning off the GC altogether?

Here's some pseudo code to help further illustrate the issue:

typedef struct {
  VALUE value;
  // some other fields
} MyStruct;

typedef struct {
  MyStruct **structs;
} MyOtherStruct;

VALUE my_rb_func(VALUE self) {
  MyOtherStruct *other;
  Data_Get_Struct(rb_iv_get(self, "@other"), MyOtherStruct, other);
  other->structs[0]->value = rb_hash_new();

  // This chain will allocate new MyStruct references and assign
  // new Ruby objects to MyStruct->value entries. The rb_hash_new()
  // won't be affected other than using rb_hash_aset().
  start_callback_chain(other);

   // without disabling gc, other->structs[0]->value is *not* the
original
   // hash this is true even if we don't assign anything to subsequent
   // MyStruct->value
}

eden li wrote:

I'm writing a C extension which passes around structs that refer to
Ruby VALUEs. During the course of execution, these VALUEs are
assigned new Ruby strings, hashes or arrays (via the rb_{str,hash,ary)
_new functions) through a series of callbacks. The problem is that it
seems they're getting collected too early before I have a chance to
use the result.

I tried a few things to keep these VALUEs around (including calling
rb_gc_mark directly on these objects), but the only thing that seems
to prevent this early collection is by disabling the GC while my code
is executing.

Is there something I can use to prevent these VALUEs from getting re-
used without resorting to turning off the GC altogether?

Here's some pseudo code to help further illustrate the issue:

typedef struct {
  VALUE value;
  // some other fields
} MyStruct;

typedef struct {
  MyStruct **structs;
} MyOtherStruct;

VALUE my_rb_func(VALUE self) {
  MyOtherStruct *other;
  Data_Get_Struct(rb_iv_get(self, "@other"), MyOtherStruct, other);
  other->structs[0]->value = rb_hash_new();

  // This chain will allocate new MyStruct references and assign
  // new Ruby objects to MyStruct->value entries. The rb_hash_new()
  // won't be affected other than using rb_hash_aset().
  start_callback_chain(other);

   // without disabling gc, other->structs[0]->value is *not* the
original
   // hash this is true even if we don't assign anything to subsequent
   // MyStruct->value
}

Why do not use ruby array (rb_array_new) as MyOtherStruct?
This may help (just need to keep one object instead of bunch of them...)

···

--
   WBR, Peter Zotov

See "3.3 Encapsulate C data into a Ruby object" in README.EXT in the ruby source distribution.

···

On Jun 13, 2009, at 21:39 , eden li wrote:

I'm writing a C extension which passes around structs that refer to
Ruby VALUEs. During the course of execution, these VALUEs are
assigned new Ruby strings, hashes or arrays (via the rb_{str,hash,ary)
_new functions) through a series of callbacks. The problem is that it
seems they're getting collected too early before I have a chance to
use the result.

I tried a few things to keep these VALUEs around (including calling
rb_gc_mark directly on these objects), but the only thing that seems
to prevent this early collection is by disabling the GC while my code
is executing.

I may end up doing that, but this is puzzling behavior, and I'd like
to figure out what's causing subsequent object allocations in the
callback chain to overwrite the original rb_hash_new(). I'd like to
know for future reference what's going on here.

···

On Jun 14, 6:41 am, Peter Zotov <whitequ...@whitequark.ru> wrote:

Why do not use ruby array (rb_array_new) as MyOtherStruct?
This may help (just need to keep one object instead of bunch of them...)