[Nautilus-list] nautilus-throbber / BonoboEventSource refcounting
- From: Owen Taylor <otaylor redhat com>
- To: nautilus-list eazel com, gnome-components-list gnome org
- Subject: [Nautilus-list] nautilus-throbber / BonoboEventSource refcounting
- Date: 20 May 2001 10:11:15 -0400
I spent a chunk of time last night debugging why the throbber process
was often crashing for me when I closed windows; I have the problem
pretty well tracked down, but the best solution(s) is somewhat
less clear.
Here's what I found:
When a Nautilus window is closed, it is first unrealized, which
results in GTK+ peer of the embedded control being sent a
WM_DELETE_EVENT, and thus, destroyed. (GtkWidget::destroy)
When the GTK+ peer is destroyed, nautilus_throbber_destroy() calls
nautilus_bonobo_object_force_destroy_at_idle (throbber->details->control);
Which, results in the refcount the control being forced to zero when
control returns to the main loop; the resulting call to
bonobo_control_destroy() unrefs the control's property bag, which as a
consequence is also destroyed along with the aggregate EventSource
object.
bonobo_event_source_destroy() makes the assumption that no more
incoming calls will occur at that point - it walks the listener list
in a non-reentrant fashion and leaves the object in a junk state
(event_source->priv pointing to garbage.)
However, at this point, the event source object has NOT been
deactivated - this does not occur until the event source object
is finalized, which is a subsequent stage, so incoming
calls CAN happen. (with the forced destroy)
In fact, at the same time, the nautilus process has run along
to nautilus_window_destroy(), which does:
===
if (window->throbber != CORBA_OBJECT_NIL) {
CORBA_exception_init (&ev);
property_bag = Bonobo_Control_getProperties (window->throbber, &ev);
if (!BONOBO_EX (&ev) && property_bag != CORBA_OBJECT_NIL) {
bonobo_event_source_client_remove_listener
(property_bag,
window->details->throbber_location_change_request_listener_id,
&ev);
bonobo_object_release_unref (property_bag, NULL);
}
CORBA_exception_free (&ev);
bonobo_object_release_unref (window->throbber, NULL);
}
===
Which, in my tests usually gets serviced by the throbber in call to
Bonobo::Unknown::unref() in bonobo-event-source.c:desc_free().
resulting in a segfault when the above code calls
Bonobo::EventSource::removeListener.
So, that's the bug; what can be done to fix it?
1) Remove the call to nautilus_bonobo_force_destroy_at_idle(); the
root cause here is that the control thinks that nobody has a
reference to it, while on the other hand, Nautilus thinks it has a
reference to the control.
Yet, I'm not sure this is right. Distributed reference counting is
distinctly imperfect, and using the firm knowledge that the GTK+
peer has been destroyed to decide that the control should be
destroyed is not an unreasonable measure, despite the obvious and
clear evil-ness of releasing someone else's refcount.
1a) Change nautilus_bonobo_force_destroy_at_idle() to
nautilus_bonobo_force_destroy_later() with a timeout of say, 1
minute. This should still catch stale controls without being
nearly as vulnerable to race conditions.
2) Deactivate objects as the first step in destroying them, not when
they are finally destroyed. (In fact, you'd probably
want to deactivate all objects in an aggregate before starting
to destroy the aggregate)
I don't quite get how Bonobo is handling the distinction between
destroy and finalize in Bonobo, but there seems to be a general
idea that destruction is singular and results in an inoperable
object, so deactivation should generally be OK.
Deactivating doesn't work if destroy functions are allowed to
intentionally pass references to themselves back out again, and
then take incoming calls, but that seems like a dubious practice
at best.
3) Move the call to destroy the throbber in NautilusWindow to an
unrealize function so it gets executed prior to the child widgets
being unrealized. While this fixes the problem in a simple way,
it's not an obvious change, and I tend to suspect similar problems
occur elsewhere. So some combination of the above steps is
probably a good idea.
Regards,
Owen
[ There are various additional solutions involving changing
the destroy functions for Bonobo::Control and Bonobo::EventSource
to be more reentrant, but unless subsequent incoming calls are
really intended to happen, such changes don't seem appropriate. ]
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]