[embedding] keeping track of non-exported global variables

problem:
Should I choose or to store objects in ?

thoughts:
PickAxe suggests that you push them on a global

VALUE objects = rb_ary_new();
rb_global_variable(objects);
rb_ary_push(objetcs, my_object);

But it seems that is trend to be used
everywhere. [mod_ruby, vim, …]

This make me wonder if there is something wrong
with using for this?

Have I missed something here?

what are your opinions about this?

···


Simon Strandgaard

No follow ups… Are you with me?

Im working on a tutorial on how to embed ruby into c++.

On the section of registering/unregistering global objects,
what should I write: Either that people should use an array
because this is what pickaxe says. Or that they should use a
hash because this is what [mod_ruby, vim, ruby++] uses.

problem:
Why does mod_ruby use a hash? why not array?

···

On Fri, 04 Apr 2003 05:37:33 +0200, Simon Strandgaard wrote:

problem:
Should I choose or to store objects in ?

thoughts:
PickAxe suggests that you push them on a global

VALUE objects = rb_ary_new();
rb_global_variable(objects);
rb_ary_push(objetcs, my_object);

But it seems that is trend to be used
everywhere. [mod_ruby, vim, …]

This make me wonder if there is something wrong
with using for this?

Have I missed something here?

what are your opinions about this?


Simon Strandgaard

On the section of registering/unregistering global objects,
what should I write: Either that people should use an array
because this is what pickaxe says. Or that they should use a
hash because this is what [mod_ruby, vim, ruby++] uses.

Just say that they can use an Hash or an Array : after if someone think
that it's easier (or faster) to manage an Hash (or an Array) he can do
what he want.

Why does mod_ruby use a hash? why not array?

Good question :slight_smile:

Probably only the author of mod_ruby know the response :slight_smile:

Guy Decoux

I tried mailing Shugo Maeda, but I haven’t got any replys… hmmm maybe I
should another of his mailing adresses?

Arrays works fine for me, but im still wondering why
both mod_ruby, vim, ruby++ uses hashes ???
It seems odd.

Objects::Objects() {
objects = rb_ary_new();
rb_global_variable(&objects);
}
Objects::~Objects() {
/* flush array in order to kill em
I do not think this is necessary at all.
I am assuming that calling ruby_finalize()
would effectivly kill all!
todo: is flushing necessary? */
}
void Objects::Register(VALUE object) {
cout << "objects += " << hex << object << endl;
rb_ary_push(objects, object);
}
void Objects::Unregister(VALUE object) {
cout << "objects -= " << hex << object << endl;
rb_ary_delete(objects, object);
}

···

On Sat, 05 Apr 2003 23:19:15 +0900, ts wrote:

On the section of registering/unregistering global objects,
what should I write: Either that people should use an array
because this is what pickaxe says. Or that they should use a
hash because this is what [mod_ruby, vim, ruby++] uses.

Just say that they can use an Hash or an Array : after if someone think
that it’s easier (or faster) to manage an Hash (or an Array) he can do
what he want.

Why does mod_ruby use a hash? why not array?

Good question :slight_smile:

Probably only the author of mod_ruby know the response :slight_smile:

Hi,

Arrays works fine for me, but im still wondering why
both mod_ruby, vim, ruby++ uses hashes ???
It seems odd.

I don’t know true reason, but I kind of guess it’s because
removing an object from a hash is faster than an array when
they have many elements.

Objects::~Objects() {
/* flush array in order to kill em
I do not think this is necessary at all.
I am assuming that calling ruby_finalize()
would effectivly kill all!
todo: is flushing necessary? */
}

Registered variable must not contain invalid VALUE - other than
object, Fixnum, Symbol, true, false and nil. If you’re really
sure that any “Objects” instances never get destructed until
ruby_finalize(), it would not be necessary. Otherwise, it
causes GC crashes at high possibility.

···

At Tue, 8 Apr 2003 02:49:23 +0900, Simon Strandgaard wrote:


Nobu Nakada

Hi,

Arrays works fine for me, but im still wondering why
both mod_ruby, vim, ruby++ uses hashes ???
It seems odd.

I don’t know true reason, but I kind of guess it’s because
removing an object from a hash is faster than an array when
they have many elements.

I’ve checked ruby-1.8.0’s array.c/rb_ary_delete and
hash.c/rb_hash_delete. The for loop in Array.delete appears
to iterate throught the whole array [linear time].
The Hash.delete doesn’t have any loops [constant time] :slight_smile:

Argh!! I now see why they all are using hashes. This problem
is now solved, thanks.

Objects::~Objects() {
/* flush array in order to kill em
I do not think this is necessary at all.
I am assuming that calling ruby_finalize()
would effectivly kill all!
todo: is flushing necessary? */
}

Registered variable must not contain invalid VALUE - other than
object, Fixnum, Symbol, true, false and nil. If you’re really
sure that any “Objects” instances never get destructed until
ruby_finalize(), it would not be necessary. Otherwise, it
causes GC crashes at high possibility.

Sorry I don’t understand, can you rephrase it ???

Yes, cleanup must be correct :slight_smile:

···

On Tue, 08 Apr 2003 12:33:38 +0900, nobu.nokad wrote:

At Tue, 8 Apr 2003 02:49:23 +0900, > Simon Strandgaard wrote:


Simon Strandgaard

Hi,

···

At Tue, 8 Apr 2003 12:52:21 +0900, Simon Strandgaard wrote:

Objects::~Objects() {
/* flush array in order to kill em
I do not think this is necessary at all.
I am assuming that calling ruby_finalize()
would effectivly kill all!
todo: is flushing necessary? */
}

Registered variable must not contain invalid VALUE - other than
object, Fixnum, Symbol, true, false and nil. If you’re really
sure that any “Objects” instances never get destructed until
ruby_finalize(), it would not be necessary. Otherwise, it
causes GC crashes at high possibility.

Sorry I don’t understand, can you rephrase it ???

rb_gc() expects valid VALUEs (as mentioned above) in registered
variables, and always tries to mark them. But if you discard a
variable still registered, the address is reused as another
variable, and an invalid VALUE may be stored there.


Nobu Nakada

Im still not getting you point. Sorry.

You mention some object which is OK to push on the array.
Is there some “kinds of object” which I must avoid storing
in the array ? Invalid values ?

What is an invalid value ???

The only objects I register is Data_Wrap_Struct’s.

Objects::~Objects() {
/*
question: will this flush the array ?
or do I have to do it manualy?
*/
rb_gc_unregister_address(objects);
}

···

On Tue, 08 Apr 2003 19:31:38 +0900, nobu.nokad wrote:

At Tue, 8 Apr 2003 12:52:21 +0900, > Simon Strandgaard wrote:

Objects::~Objects() {
/* flush array in order to kill em
I do not think this is necessary at all.
I am assuming that calling ruby_finalize()
would effectivly kill all!
todo: is flushing necessary? */
}

Registered variable must not contain invalid VALUE - other than
object, Fixnum, Symbol, true, false and nil. If you’re really
sure that any “Objects” instances never get destructed until
ruby_finalize(), it would not be necessary. Otherwise, it
causes GC crashes at high possibility.

Sorry I don’t understand, can you rephrase it ???

rb_gc() expects valid VALUEs (as mentioned above) in registered
variables, and always tries to mark them. But if you discard a
variable still registered, the address is reused as another
variable, and an invalid VALUE may be stored there.

Im still not getting you point. Sorry.

You mention some object which is OK to push on the array.
Is there some “kinds of object” which I must avoid storing
in the array ? Invalid values ?

Nope, just that when the memory position used to hold the VALUE is
reused anything could be there.

What is an invalid value ???

You have
class Objects {

Objects() {

rb_gc_register_address(&objects);
// now Ruby remembers the address of objects
}

~Objects() {

} // after the destructor is done, anything could
// be placed in the address where the attribute objects used to be.
// Ruby could think it is a real object (with a pointer to its klass,
// etc) and bomb
private:
VALUE objects;

};

The only objects I register is Data_Wrap_Struct’s.

Objects::~Objects() {
/*
question: will this flush the array ?
or do I have to do it manualy?
*/
rb_gc_unregister_address(objects);
}

Here’s my guess: suppose you don’t do rb_gc_unregister_address.
Then, Ruby keeps a pointer to the VALUE, even though you object is dead.
At some point later in time, another C++ object is living there, so at
the address where your VALUE used to live, you now have an int which
happens to be some pair number. When doing GC, Ruby will remember the
address of that VALUE, check whether it is a Fixnum, and then decide
that “it is a real object”, so it will ask it to mark all the objects it
holds references to. In order to do so it goes retrieve information
to wherever the VALUE points to, which is of course wrong.

See, in gc.c

void
rb_gc_mark_children(ptr)
VALUE ptr;
{
register RVALUE *obj = RANY(ptr);

  case T_DATA:
    if (obj->as.data.dmark) (*obj->as.data.dmark)(DATA_PTR(obj));

// ===== bad
break;

  case T_OBJECT:
    rb_mark_tbl(obj->as.object.iv_tbl);
    break;


}

everything will bomb as soon as Ruby does obj-> as it will be
following an invalid value.

···

On Wed, Apr 09, 2003 at 01:14:34AM +0900, Simon Strandgaard wrote:


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’ \
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

People disagree with me. I just ignore them.
– Linus Torvalds, regarding the use of C++ for the Linux kernel

Yes, dangling pointers is dangerous, because they ofthen result in
segfaults and those can be boring to debug :slight_smile:

Thus proper cleanup is important!

Objects::~Objects() {
rb_gc_unregister_address(&objects);
}

Unregistering all objects: Is this dtor sufficent ???

Should I manualy erase each element first ???
or is this unnecessary?

···

On Wed, 09 Apr 2003 02:53:13 +0900, Mauricio Fernández wrote:

Here’s my guess: suppose you don’t do rb_gc_unregister_address.
Then, Ruby keeps a pointer to the VALUE, even though you object is dead.


Simon Strandgaard

Here’s my guess: suppose you don’t do rb_gc_unregister_address.
Then, Ruby keeps a pointer to the VALUE, even though you object is dead.

Yes, dangling pointers is dangerous, because they ofthen result in
segfaults and those can be boring to debug :slight_smile:

But segfault is the best that could happen! Really!
I love when programs segfault, it’s so much easier to trace where things
went wrong. Now, if it just started to behave strangely…

Thus proper cleanup is important!

Objects::~Objects() {
rb_gc_unregister_address(&objects);
}

Unregistering all objects: Is this dtor sufficent ???

Should I manualy erase each element first ???
or is this unnecessary?

If I got it right, not. The GC won’t mark them, and they will be swept
away.

···

On Wed, Apr 09, 2003 at 07:56:43AM +0900, Simon Strandgaard wrote:

On Wed, 09 Apr 2003 02:53:13 +0900, Mauricio Fernández wrote:


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’ \
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

…Deep Hack Mode – that mysterious and frightening state of
consciousness where Mortal Users fear to tread.
– Matt Welsh

Me asking many silly questions and you answered them,
thanks 1000 times :slight_smile:

Finaly my class looks like this…

Objects::Objects() {
objects = rb_ary_new();
rb_gc_register_address(&objects);
}

Objects::~Objects() {
// dispose array and flush all elements
rb_gc_unregister_address(&objects);
/*
mass destrurction.
GC can no longer can mark the elements in
the Array and therefore they will all get swept.
*/
}

void Objects::Register(VALUE object) {
rb_ary_push(objects, object);
}

void Objects::Unregister(VALUE object) {
rb_ary_delete(objects, object);
}

···

On Wed, 09 Apr 2003 09:10:36 +0900, Mauricio Fernández wrote:

Objects::~Objects() {
rb_gc_unregister_address(&objects);
}

Unregistering all objects: Is this dtor sufficent ???

Should I manualy erase each element first ???
or is this unnecessary?

If I got it right, not. The GC won’t mark them, and they will be swept
away.