SoupSessionAsync: don't queue idles from dispose()
authorDan Winship <danw@gnome.org>
Tue, 14 Feb 2012 03:05:43 +0000 (22:05 -0500)
committerDan Winship <danw@gnome.org>
Tue, 14 Feb 2012 03:05:43 +0000 (22:05 -0500)
SoupSession does a soup_session_abort() from dispose(), which had the
effect in SoupSessionAsync of queueing an idle (to check if new
messages could be sent now that old connections had been closed). This
causes problems if the session was disposed from a thread other than
the one that its GMainContext is running in, which is weird, and also
incompatible with some garbage-collected runtimes. So fix that.

https://bugzilla.gnome.org/show_bug.cgi?id=667364

libsoup/soup-session-async.c
tests/misc-test.c

index 9baa78e..eaadd58 100644 (file)
@@ -69,13 +69,16 @@ soup_session_async_init (SoupSessionAsync *sa)
 }
 
 static void
-finalize (GObject *object)
+dispose (GObject *object)
 {
        SoupSessionAsyncPrivate *priv = SOUP_SESSION_ASYNC_GET_PRIVATE (object);
 
-       g_hash_table_destroy (priv->idle_run_queue_sources);
+       if (priv->idle_run_queue_sources) {
+               g_hash_table_destroy (priv->idle_run_queue_sources);
+               priv->idle_run_queue_sources = NULL;
+       }
 
-       G_OBJECT_CLASS (soup_session_async_parent_class)->finalize (object);
+       G_OBJECT_CLASS (soup_session_async_parent_class)->dispose (object);
 }
 
 static void
@@ -94,7 +97,7 @@ soup_session_async_class_init (SoupSessionAsyncClass *soup_session_async_class)
        session_class->auth_required = auth_required;
        session_class->kick = kick;
 
-       object_class->finalize = finalize;
+       object_class->dispose = dispose;
 }
 
 
@@ -483,6 +486,9 @@ idle_run_queue (gpointer sa)
 {
        SoupSessionAsyncPrivate *priv = SOUP_SESSION_ASYNC_GET_PRIVATE (sa);
 
+       if (!priv->idle_run_queue_sources)
+               return FALSE;
+
        g_hash_table_remove (priv->idle_run_queue_sources,
                             soup_session_get_async_context (sa));
        run_queue (sa);
@@ -494,6 +500,9 @@ do_idle_run_queue (SoupSession *session)
 {
        SoupSessionAsyncPrivate *priv = SOUP_SESSION_ASYNC_GET_PRIVATE (session);
 
+       if (!priv->idle_run_queue_sources)
+               return;
+
        if (!g_hash_table_lookup (priv->idle_run_queue_sources,
                                  soup_session_get_async_context (session))) {
                GMainContext *async_context = soup_session_get_async_context (session);
index 321d41f..82d2d73 100644 (file)
@@ -1272,6 +1272,38 @@ do_ipv6_test (void)
        soup_test_server_quit_unref (ipv6_server);
 }
 
+static void
+do_idle_on_dispose_test (void)
+{
+       SoupSession *session;
+       SoupMessage *msg;
+       GMainContext *async_context;
+
+       debug_printf (1, "\nTesting SoupSessionAsync dispose behavior\n");
+
+       async_context = g_main_context_new ();
+       session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
+                                        SOUP_SESSION_ASYNC_CONTEXT, async_context,
+                                        NULL);
+
+       msg = soup_message_new_from_uri ("GET", base_uri);
+       soup_session_send_message (session, msg);
+       g_object_unref (msg);
+
+       while (g_main_context_iteration (async_context, FALSE))
+               ;
+
+       g_object_run_dispose (G_OBJECT (session));
+
+       if (g_main_context_iteration (async_context, FALSE)) {
+               debug_printf (1, "  idle was queued!\n");
+               errors++;
+       }
+
+       g_object_unref (session);
+       g_main_context_unref (async_context);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -1311,6 +1343,7 @@ main (int argc, char **argv)
        do_non_persistent_connection_test ();
        do_dot_dot_test ();
        do_ipv6_test ();
+       do_idle_on_dispose_test ();
 
        soup_uri_free (base_uri);
        soup_uri_free (ssl_base_uri);