Re: Atomic Reference Counts in GObject

On Thu, 28 Apr 2005, Jonas Bonn wrote:

Is there a concrete example of object resurrection somewhere, perhaps
in the GTK+ code itself?
I don't see why someone who might need the object wouldn't just keep
it alive by holding a reference to it instead of going to the trouble
of digging it out of the grave after it's already been dismembered...

that is a question of what exactly resurrection is.

older version of gtk dropped the last object references with the emission
of ::destroy, that wasn't too compatible with language bindings though,
so reference counting was introduced. that however allows anyone to
keep an object alive forever, of course also after ::destroy has been
now at any point, code like:
	void object_set_string (o, const gchar *s)
	{ g_free (o->str); o->str = g_strdup (s); }
can be executed. much of such object data (o->str) was taken down
in ::destroy handlers, rather than finalize (and for some non-string fields,
that is still teh case).
depending on your object use, get/set_string may already be "resurrecting"
certain object funcitonality.

so with reference counting, you need at least one of the following solutions:
1) you need to guard object_set_string() against invokations after ::destroy,
   this maybe very annoying for user code (either because you trigger an
   assertion or because set/get pairs don't match anymore).
2) you take down/cleanup o->str in finalize as well as destroy. this would/did
   involve lots of code changes and may not always be suitable.
3)  you make sure (another) emission of ::destroy directly preceedes invokation
   of finalize(), that way no intermediate user code "resurrects" your obejct.
   this may lead to multiple emissions of ::destroy though.

we obviously went for (3) but also (2) where it made sense.

My specific problem is the following.  I have a list of weak_refs,
which are weak because the thread using the list has no influence on
the object's life span -- it just needs to perform an action on the
objects that currently exist.  Hence, when an object is unref'ed, the
weak_ref will be removed from the list by the notifier.
Now, unfortunately, the dispose method begins to dismantle the
object... I can still pick it up in the other thread because it's
ref-count is 1, but the object is/may be incoherent.  Then, somewhere
near the end of 'disposing' of the victim, the ref-count is suddenly
set to 0 (see g_object_real_dispose)... now the weak notifiers are
called -- I can't resurrect the object in the weak notifiers because
the ref-count is 0.  This seems strange.  Why not?

weak notifiers were meant as only weak notifiers, i.e. you reset a pointer
and don't use them for resurrection. temporarily setting the ref_count to 0
is meant to enforce that, since you can neither ref() nor unref() an object
with ref_count=0.

 It's still in the
same bad shape it was in before, and who else is going to notice that
the object is being disposed of if not the weak-notifiers?
Then, it gets worse: the ref-count is suddenly raised again.

did you actually read the code portions that implements this? see:

static void
g_object_real_dispose (GObject *object)
  guint ref_count;

  g_signal_handlers_destroy (object);
  g_datalist_id_set_data (&object->qdata, quark_closure_array, NULL);

  /* yes, temporarily altering the ref_count is hackish, but that
   * enforces people not jerking around with weak_ref notifiers
  ref_count = object->ref_count;
  object->ref_count = 0;
  g_datalist_id_set_data (&object->qdata, quark_weak_refs, NULL);
  object->ref_count = ref_count;

so, these are not random changes to the ref count ;)

the weak notifiers have been called so I can hardly expect the object
to be coherent anymore, but if I am lucky, I can still get a reference

not sure what you mean with coherent here...

to the object (through the weak_refs, if I am devious and keep them
around after notification) and prevent it from being finalized.  At
this point we call in Dr. Frankenstein to bring it back to life...
Perhaps I am missing something and perhaps it's really obvious, but I
just do not see it.  My thinking is that the weak-notifiers should
probably be called just before the object-dispose method so that I
would know not to try to use the object anymore.

the idea was basically, if you wanted proper notification about obejct
destruction, you connect to ::destroy. if you use something GObject
derived, but not GtkObject derived, that is basically dispose() time
to which you can't connect. so such object prolly need to introduce their
own ::destroy like signal if you want to connect to them.

finally, part of the object destruction would be resetting remaining
object pointers, so weak refs were notified as part of the destruction
process after all signal handlers got disconnected.

 For example:
In g_object_last_unref:
1) call weak notifiers
2) if nobody has saved the object, call dispose (perhaps with
ref-count 1 because the weak-ref holders have been warned, allowing
for further life-saving measures somewhere -- in the dispose method
itself, I presume)
3) if still nobody has any partial remains, call finalize to make sure
the beast is really dead

if i were to move weak ref notification at all, i'd probably put it at the
start of dispose, so you're notified right before all object references
are released. that'd also be a proper point to allow resurrection (by
reference count increments), not a point to prevent disposal/destruction
though, since the code calling dispose() may have good reasons for telling
the object to release all references (which is what "dispose" really means
for a GObject lifetime).

Of course, I'm sure one of you could tell me why I'm wrong and I look
forward to your explanation!



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