For the record, if anyone else tries to write a database driver, or any
C extension that has a graph of objects that have deallocation order
dependencies...

If you are integrating with mark and sweep, and provide free hooks for
your objects, be aware that at shutdown Ruby drops objects from its
object table in allocation order (table order). This means that once it
has called your free-hooks (defined in your calls to Data_Wrap_Struct),
afterwards ever after YOU CANNOT / MUST NOT, ***EVER*** call
Data_Get_Struct on a VALUE that has been visited/dropped from the Ruby
object table. Ruby will SEGV with a very hard to diagnose issue.

Your C structs should probably do something like this:

struct hierarchical_handle
{
    // the hook to the real C/C++ free code, never accessed
    // directly by Ruby GC, only via ref count decr routines
    RUBY_DATA_FUNC free_func;

    // increment this to 1 on allocation, children inc count
    // only free-hooks decr counts; in fact, your free-hooks
    // could simply be atomic_dec(handle*)
    rb_atomic_t atomic;

    // used by ref counting routines to pin C/C++ objects
    // in memory till the last one drops its reference
    nuodb_handle * parent_handle;

    // used to pin parents in memory via rb_gc_mark
    VALUE parent;
};

Like me, just steal atomic.[c|h] from Ruby. But N.B. There is a major
bug in them, somebody in the Ruby camp used the WRONG
GCC_ATOMIC_BUILTINS !@!!

Somebody ought to fix atomic.h, its screwed up badly.

Robert Buck wrote in post #1086203:
> I have a graph of objects in a C extension, and as such I maintain
> reference counts from children to parents as deallocations are order
> dependent (see struct definition below).
>
> While I run my program the reference counts match up, but when the
> program exits, when ruby dumps its entire object table calling free on
> every VALUE the parent's free functions are called before the children
> as the parents were allocated first and they appear in the ruby object
> table first (this was the whole reason for adding reference counting,
> because otherwise order dependent deallocations in C code causes a
> SEGV).
>
> Anyways, before shutdown here are my ref counts:
>
> [REFERENCE COUNT][O INCR] (child @ 00007fd6d0ddd5c0): 1 (parent @
> 00007fd6d2538460): 2
>
> n.b. 2 refs
>
> And after shutdown the ref counts are "magically" different:
>
> [REFERENCE COUNT][I DECR] (child @ 00007fd6d2538460): 1 (parent @
> 0000000000000000): -10
>
> n.b. -10 is just a sentinel marker, ignore that
> n.b. 1 refs though does not match 2 above
>
> The latter trace is for the root object, hence no parent. But notice the
> root object's reference count of 1. Take a look at its reference count
> before program termination, 2.
>
> This is saying that I have a case of memory corruption on my part,
> memory corruption on ruby's part, or my understanding of how to set up
> graphs of interrelated objects in C extensions is seriously flawed.
>
> Regarding the last option, all I am doing is maintaining a struct of:
>
> struct handle
> {
>     RUBY_DATA_FUNC free_func;
>     rb_atomic_t atomic;
>     VALUE parent;
> };
>
> Would someone have an idea of how to approach this, what could possibly
> be going on? I have been at this for three days now and I don't see any
> bug on my part.
>
> Bob

-- 
Posted via http://www.ruby-forum.com/.