Re: instance-private-data issue



On 2 Aug 2003, Owen Taylor wrote:

> So, say you have classes MyA, MyB, MyB deriving from MyA. And
> you have an instance init function for My:
>
> static void
> my_a_init (MyA *a)
> {
>   MyAPrivate *priv =  G_TYPE_INSTANCE_GET_PRIVATE (a,
>                                                    MY_TYPE_A,
>                                                    MyA);
>
>   /* use priv */
>
> }
>
> All fine, right? Well, actually no. The problem is that
> g_type_instance_get_private() looks at:
>
>  a->g_class->g_type
>
> to find out the type of a, and thus the offset to the private
> data. Well, the way GObject works, a->g_class->g_type is
> always MY_TYPE_A in my_a_instance_init(), even when we are
> really initializing a MY_TYPE_B.

have you written a glib-only test case for this already?

> For those not in the know, the reason it works like this is that
> the idea is to avoid ever accessing the virtual functions for
> MyB until the instance_init for MyB is called. [*]
>
> So, how do we fix the problem? Two ideas I can come up with:
>
>  - increase GTypeInstance from 4 bytes to 8 bytes (on
>    32 bits), caching the real type *before* the public g_class field.

i have to side with Mathieu here. i think this is an exceptionally
good example for a bad trade-off. not only is private-data a
recently introduced non-essential feature that hasn't correctly
worked at all yet, the work-around is only required for a very short
moment in an objects lifetime. yet, you're willing to sacrifice
an extra pointer per every GObject used out there.


>  - Use thread-private data to keep track of a stack of
>    currently-being-initialized objects with their real types, and
>    have g_type_instance_get_private() check that.

while that's an interesting idea, and i'd definitely like to get
into the problematics of using __thread with glib, i don't think
we have to resort to this kind of hackery for solving the private-data
issue.

we can simply store object pointers around init() in a lookup table
and have g_type_instance_get_private() test that before resorting
to its usual lookup. this will also work for szenarios where
objects are passed around between threads during init().
considering that most object trees don't create the majority of
their children during init(), using a list as lookup table is
probably good enough, though we could use a binary array if you
expect more than 8 objects to show up there at a time.

for the common case (no object in init()), this means an additional
!NULL lookup-table-pointer check for g_type_instance_get_private(),
and in case of an object being in init(), the performance hit boils
down to a read-lock plus the table lookup.
to give an idea, that's roughly as fast as some
  g_type_is_a (OBJECT_TYPE, INTERFACE_TAPE);
check, which every function does on entry.

> I don't think not fixing the issue is an option; you could easily
> have MyA < MyB < MyC situation where my_b_init() calls a function
> in MyA that tries to access IPD.
>
> Regards,
> 						Owen
>
> [*] This is sort of screwy; while calling vfuncs on a partially
> initially object is undesirable, calling overridden vfuncs is even
> more so. But it isn't something we can change
> after 5 years.

you make it sound like we went for the way things now are only
accidentally. we did not. instead, we changed things to the
current way because previously we had much more breakage, and
because other languages intialize objects the same way, e.g. C++.

---
ciaoTJ





[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]