Rb_gc_register_address() or rb_gc_mark()?

Hi, I’ve bad experiences with rb_gc_register_address(), it does never
work for me so I end using Ruby hashes and so.

Well, for my Ruby class defined in C I set a “alloc” method in which I
malloc and wrap a C struct:


struct my_cdata {
int active;
uv_udp_t *uv_handle;
}

VALUE MyClass_alloc(VALUE klass)
{
// Fill C struct:
struct my_cdata *cdata = ALLOC(struct my_cdata);
cdata->active = 0;
cdata->uv_handle = ALLOC(uv_udp_t);

// Get the created MyClass instance:
VALUE instance = Data_Wrap_Struct(klass, NULL, MyClass_free, cdata);

// Store the instance within the uv_handle->data field:
cdata->uv_handle->data = instace;

return instance;

}

When the UV UDP handle object receive data, UV async library calls a
callback passin gthe UV UDP handle, so in that callback I need to
retrieve the Ruby MyClass instance from the uv_handle:

VALUE instance = uv_handle->data;
// Run the Ruby callback and so…
rb_funcall(instance, xxxxxx, xxxxxx, xxxxxx);

Assuming that the created MyClass instance is not referenced in Ruby
land (it’s not in a hash, array, variable…) then this code would
crash since probably GC has freed “instance”. So there are (or could
be) 3 solutions:

  1. Storing the instance in a Ruby hash (and yes, it works, but it’s
    ugly).

  2. In the MyClass_alloc() function, before the “return” add:
    rb_gc_register_address(&instance);
    But this DOES NOT work for me, I get segmentfauls !

  3. Setting a mark function in Data_Wrap_Struct, and within such a mark
    function do:
    rb_gc_mark(uv_handle->data);

I’ve read point 3 in this thread:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/147514

So, is the choice 2 wrong and choice 3 is correct?

Thanks a lot.

2012/5/17 Iñaki Baz C. [email protected]:

  1. Setting a mark function in Data_Wrap_Struct, and within such a mark
    function do:
    rb_gc_mark(uv_handle->data);

I’ve read point 3 in this thread:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/147514

I would like to learn a bit more about rb_gc_mark(). In my experiments
such a function is never executed if the object is not assigned to a
variable or stored in a hash/array/whatever. But, in case it’s stored
somewhere, then the mark() function is executed multiple times by
Ruby.

Is it the normal behavior?

Ok, I’ll symplify my question, which basically is: WHAT is
rb_gc_mark() for? I see two options:

  1. rb_gc_mark(VALUE object) means that “object” will NEVER be GC’d by
    Ruby.

This is what I understand from here (point 1):

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/147514

  1. rb_gc_mark(VALUE object) is required for telling Ruby to GC
    “object” (which is stored within our wrapped DATA struct) when the
    owner Ruby object is GC’d.

This is what I understand from here:

http://stackoverflow.com/questions/970525/u-ruby-extensions-rb-gc-mark-and-instance-variables

So basically, what does “mark” mean??

Thanks a log. I’m getting crazy.

2012/5/17 Iñaki Baz C. [email protected]:

I would like to learn a bit more about rb_gc_mark(). In my experiments
such a function is never executed if the object is not assigned to a
variable or stored in a hash/array/whatever. But, in case it’s stored
somewhere, then the mark() function is executed multiple times by
Ruby.

Is it the normal behavior?

Forget this please, this happens because I’ve a thread running
GC.start every 0.1 seconds. I’ve understood how “mark” works:

When GC runs (Ruby decides when) it checks all the allocated VALUEs
and “marks” all the values that are in the current scope or are stored
in some attribute/array/hasy. If an object out of the current scope is
not referenced it’s not marked so, next to the “mark” action, Ruby
performs “sweep” action which frees all the non marked objects.

Hope this is correct :slight_smile:

Unfortunatelly I still don’t know how to translate this stuff to Ruby
C extensions. My question is very simple:

  • MyClass_alloc() function mallocs a C struct.
  • The C struct contains a “my_string” VALUE field and I assign there
    i.e. a Ruby String (which does not exist in Ruby land).
  • Of course MyClass_free() function should free the C struct.

But, what about “my_string” VALUE within the C struct?

  • Let’s say that I’ve an instance of MyClass in a global variable
    $my_class.

  • Then I run GC.start. Would it free my_string VALUE? (yes/no)

  • In case of yes, should then I provide a MyClass_mark() function
    which does this?:

    rb_gc_mark(data->my_string)

And then, what’s the meaning of rb_gc_(un)register_address(&VALUE)?
For me it means "this VALUE will never been GC’d even if it’s not
referenced in Ruby land.

Thanks a lot.

2012/5/17 Iñaki Baz C. [email protected]:

which does this?:

rb_gc_mark(data->my_string)

Ok, after some experiment I’m confused:

  • I run GC.startt every 0.1 seconds.

  • While my_class instance (which wraps the C struct referencing
    my_string VALUE) remains in the scope (or stored in a global variable)
    my_string is NOT GC’d. I know it because I’ve stored its object_id and
    used it in ObjectSpace._id2ref(id) and it returns my_string.

So… even if I’ve seen the usage of rb_gc_mark() in some C
extensions, in my experiments it does nothing. Any help would be
appreciated.

Thanks a lot.

i create an hash from the C-side, mark them with rb_global_variable and
then store my objects into them …

this protects my objects from being deleted.

2012/5/17 Hans M. [email protected]:

i create an hash from the C-side, mark them with rb_global_variable and
then store my objects into them …

this protects my objects from being deleted.

Hi, that’s strange since rb_global_variable() is:

void
rb_global_variable(VALUE *var)
{
rb_gc_register_address(var);
}

I can sure that rb_gc_register_address(&value) does not keep value
from being GC’d if value comes out of the scope. So, maybe
rb_gc_register_address() (which is the very same as
rb_global_variable()) is just useful when the VALUE is directly
created from C land?

2012/5/17 Iñaki Baz C. [email protected]:

extensions, in my experiments it does nothing. Any help would be
appreciated.

Forget it please! I was storing my_string in a class attribute :frowning:

Yes, rb_gc_mark() stuf is fully understood. Now I will investigate
what rb_gc_(un)register does, since in my experiments it does NOTHING.

because it needs a pointer the storeage value need to be C-global
i think in your way, the C-pointer of the VALUE object gets invalid

On May 17, 2012, at 12:24, Iaki Baz C. wrote:

So… even if I’ve seen the usage of rb_gc_mark() in some C
extensions, in my experiments it does nothing. Any help would be
appreciated.

Forget it please! I was storing my_string in a class attribute :frowning:

Yes, rb_gc_mark() stuf is fully understood. Now I will investigate
what rb_gc_(un)register does, since in my experiments it does NOTHING.

Correct.

You use rb_gc_mark() to mark ruby objects pointed-to by C structs that
are wrapped as ruby objects.

If you have

struct my_struct {
VALUE my_string;
}

And wrap that with Data_Wrap_Struct, then you must provide a mark
function that tells ruby about your string inside your struct (because
ruby does not otherwise know it exists).

To do this you use rb_gc_mark(the_struct->my_string). Without calling
rb_gc_mark the garbage collector may reclaim your string which can lead
to a crash the next time you try to use it.

On May 17, 2012, at 12:31, Hans M. wrote:

i create an hash from the C-side, mark them with rb_global_variable and
then store my objects into them

this protects my objects from being deleted.

This is probably wrong.

By using rb_global_variable the object can never be reclaimed by the
garbage collector.

You should either:

Return a ruby object to the user that stores your Hash.

Use Data_Wrap_Struct/Data_Make_Struct to store your Hash and use
rb_gc_mark to indicate it is still alive.

Use a constant, class or instance variable on a pre-defined class to
store your Hash.

2012/5/18 Eric H. [email protected]:

To do this you use rb_gc_mark(the_struct->my_string). Without calling
rb_gc_mark the garbage collector may reclaim your string which can lead to a crash
the next time you try to use it.

Sure, it’s fully understood now, and in fact, without the mark crashes
occur.

Now my other question is about the undocumented
rb_gc_register_address(VALUE object). As per my experience, this is
only valid for VALUE created within ruby code, and not for Ruby
objects that run in Ruby land. For example, in my C extension
XXXXX_init() function I create a Ruby String which I use within my C
code:

VALUE string_aaa = rb_str_new2(“aaa”);

So I must add:

rb_gc_register_address(&string_aaa);

Otherwhise it’s GC’d. But if I try to do the same with a previously
existing Ruby object (created in Ruby land or referenced in Ruby land)
then rb_gc_register_address does nothing. For example:

VALUE MyClass_do_domething(VALUE self)
{
rb_gc_register_address(&self);
return self;
}

This does NOTHING. The object (self) will be GC’d as usual.

On May 17, 2012, at 15:34, Iaki Baz C. wrote:

code:

VALUE MyClass_do_domething(VALUE self)
{
rb_gc_register_address(&self);
return self;
}

This does NOTHING. The object (self) will be GC’d as usual.

rb_gc_register_address is for use with fixed memory addresses like:

static VALUE string_aaa;

Using it on pointers to the heap or stack is going to result in
undefined behavior.

2012/5/18 Eric H. [email protected]:

rb_gc_register_address is for use with fixed memory addresses like:

static VALUE string_aaa;

Using it on pointers to the heap or stack is going to result in undefined
behavior.

Ok, that explains the behavior I’ve observed. This should be
documented somewhere, I will report it.

Thanks a lot.

On May 17, 2012, at 16:20 , Iaki Baz C. wrote:

Ok, that explains the behavior I’ve observed. This should be
documented somewhere, I will report it.

It’s documented in K&R’s C book. This is just a plain C idiom.

On May 18, 2012, at 00:20, Hans M. wrote:

By using rb_global_variable the object can never be reclaimed by the
store your Hash.

no its correct i want the control when the GC gets the object or not.
thats why i use a hash, when my binding removes the object out of the
hash, GC deleteds it. but no earlier

I was unclear, you should probably not use rb_global_variable on your
Hash. You should instead bind your Hash as a regular ruby constant,
wrap it in a struct, or return it as part of a regular ruby object.

no my hash should not go outside to the user, this hash is only for
internal use

Eric H. wrote in post #1061208:

On May 17, 2012, at 12:31, Hans M. wrote:

i create an hash from the C-side, mark them with rb_global_variable and
then store my objects into them

this protects my objects from being deleted.

This is probably wrong.

By using rb_global_variable the object can never be reclaimed by the
garbage collector.

You should either:

Return a ruby object to the user that stores your Hash.

Use Data_Wrap_Struct/Data_Make_Struct to store your Hash and use
rb_gc_mark to indicate it is still alive.

Use a constant, class or instance variable on a pre-defined class to
store your Hash.

no its correct i want the control when the GC gets the object or not.
thats why i use a hash, when my binding removes the object out of the
hash, GC deleteds it. but no earlier