GDBusConnection: Avoid callbacks on finalized connection

Turns out that GDBusWorker will issue callbacks (in its own thread)
even after g_dbus_worker_stop() has been called. This would rarely
happen (and unreffing a connection is even rarer) so only saw this bug
occasionally when running the gdbus-connection test case in a loop.

Fix up this issue by maintaining a set of GDBusConnection objects that
are currently "alive" and do nothing in the callbacks if the passed
user_data pointer is not in this set.

Also attempted to fix up a race condition with
_g_object_wait_for_single_ref_do() and its use of GObject toggle
references - for now, just resort to busy waiting, thereby
sidestepping the toggle reference mess altogether.

Signed-off-by: David Zeuthen <davidz@redhat.com>
This commit is contained in:
David Zeuthen
2010-09-23 15:10:50 -04:00
parent c3c0e4d11d
commit f0b04acfd3
4 changed files with 115 additions and 22 deletions

View File

@@ -158,6 +158,40 @@ _g_bus_get_priv (GBusType bus_type,
/* ---------------------------------------------------------------------------------------------------- */
#if 1
/* toggle refs are not easy to use (maybe not even safe) when multiple
* threads are involved so implement this by busy-waiting for now
*/
gboolean
_g_object_wait_for_single_ref_do (gpointer object)
{
guint num_ms_elapsed;
gboolean timed_out;
timed_out = FALSE;
num_ms_elapsed = 0;
while (TRUE)
{
if (G_OBJECT (object)->ref_count == 1)
goto out;
if (num_ms_elapsed > 5000)
{
timed_out = TRUE;
goto out;
}
usleep (10 * 1000);
num_ms_elapsed += 10;
}
out:
return timed_out;
}
#else
typedef struct
{
GMainLoop *loop;
@@ -201,19 +235,31 @@ _g_object_wait_for_single_ref_do (gpointer object)
g_object_add_toggle_ref (G_OBJECT (object),
on_wait_for_single_ref_toggled,
&data);
/* the reference could have been removed between us checking the
* ref_count and the toggle ref being added
*/
if (G_OBJECT (object)->ref_count == 2)
goto single_ref_already;
g_object_unref (object);
g_main_loop_run (data.loop);
g_object_ref (object);
single_ref_already:
g_object_remove_toggle_ref (object,
on_wait_for_single_ref_toggled,
&data);
g_source_remove (timeout_id);
g_main_loop_unref (data.loop);
out:
if (data.timed_out)
{
g_printerr ("b ref_count is %d\n", G_OBJECT (object)->ref_count);
}
return data.timed_out;
}
#endif
/* ---------------------------------------------------------------------------------------------------- */