I'm writing an Ruby extension for a physics engine. This physics engine has bodies that are linked to a world, so my Ruby objects are World
and Body
. A body is constructed (in C++) with world->CreateBody
and destroyed with world->DestroyBody
.
The problem is that the Ruby GC is destroying the world before the bodies. So, when the GC destroy the bodies, the world no longer exists and I get a segmentation fault. I know that I need to mark something somewhere for the GC (using rb_gc_mark
), but I don't know where.
The World
class is pretty standard, it looks like this:
extern "C" void world_free(void *w)
{
static_cast<World*>(w)->~World();
ruby_xfree(w);
}
extern "C" void world_mark(void *w)
{
// ???
}
extern "C" VALUE world_alloc(VALUE klass)
{
return Data_Wrap_Struct(klass, world_mark, world_free, ruby_xmalloc(sizeof(World)));
}
extern "C" VALUE world_initialize(VALUE self)
{
World* w;
Data_Get_Struct(self, World, w);
new (w) World();
return self;
}
The Body
class is a little different, since it needs to be created from a World object (I can't simply new
it). So it looks like this:
extern "C" void body_free(void* b)
{
Body* body = static_cast<Body*>(b);
World* world = body->GetWorld();
world->DestroyBody(body);
}
extern "C" void body_mark(void* b)
{
// ???
}
extern "C" VALUE body_alloc(VALUE klass)
{
return Data_Wrap_Struct(klass, body_mark, body_free, 0);
}
extern "C" VALUE static_obj_initialize(VALUE self, VALUE world)
{
Body* b;
World* w;
Data_Get_Struct(self, Body, b);
Data_Get_Struct(world, World, w);
b = w->CreateBody();
DATA_PTR(self) = b;
return self;
}
So my questions are:
- Which of the two objects should I mark on the GC?
- How do I do it? Do I simply mark with
rb_gc_mark
, or should I do it only under some conditions? Which ones? - What should I mark? The mark functions receive only a naked pointer to my struct, but the
rb_gc_mark
function expects aVALUE
.