[libsoup] SoupSessionAsync: fix the GMainContext tracking



commit dc498831f5fb9740047ac9bfe023809a1b801a5c
Author: Dan Winship <danw gnome org>
Date:   Wed Apr 11 13:17:15 2012 -0400

    SoupSessionAsync: fix the GMainContext tracking
    
    Using (non-reffed) GMainContexts as hash keys can mess up when a
    context gets freed and then a new one is created at the same location
    (in which case the session might think it has an idle_run_queue
    queued, but it doesn't really). Reorganize the way this works to avoid
    that problem.

 libsoup/soup-session-async.c |   51 +++++++++++++++++++-----------------------
 1 files changed, 23 insertions(+), 28 deletions(-)
---
diff --git a/libsoup/soup-session-async.c b/libsoup/soup-session-async.c
index eaadd58..a58439e 100644
--- a/libsoup/soup-session-async.c
+++ b/libsoup/soup-session-async.c
@@ -47,25 +47,18 @@ static void  auth_required   (SoupSession *session, SoupMessage *msg,
 G_DEFINE_TYPE (SoupSessionAsync, soup_session_async, SOUP_TYPE_SESSION)
 
 typedef struct {
-	GHashTable *idle_run_queue_sources;
+	SoupSessionAsync *sa;
+	gboolean disposed;
 
 } SoupSessionAsyncPrivate;
 #define SOUP_SESSION_ASYNC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_SESSION_ASYNC, SoupSessionAsyncPrivate))
 
 static void
-destroy_unref_source (gpointer source)
-{
-	g_source_destroy (source);
-	g_source_unref (source);
-}
-
-static void
 soup_session_async_init (SoupSessionAsync *sa)
 {
 	SoupSessionAsyncPrivate *priv = SOUP_SESSION_ASYNC_GET_PRIVATE (sa);
 
-	priv->idle_run_queue_sources =
-		g_hash_table_new_full (NULL, NULL, NULL, destroy_unref_source);
+	priv->sa = sa;
 }
 
 static void
@@ -73,10 +66,7 @@ dispose (GObject *object)
 {
 	SoupSessionAsyncPrivate *priv = SOUP_SESSION_ASYNC_GET_PRIVATE (object);
 
-	if (priv->idle_run_queue_sources) {
-		g_hash_table_destroy (priv->idle_run_queue_sources);
-		priv->idle_run_queue_sources = NULL;
-	}
+	priv->disposed = TRUE;
 
 	G_OBJECT_CLASS (soup_session_async_parent_class)->dispose (object);
 }
@@ -482,16 +472,17 @@ run_queue (SoupSessionAsync *sa)
 }
 
 static gboolean
-idle_run_queue (gpointer sa)
+idle_run_queue (gpointer user_data)
 {
-	SoupSessionAsyncPrivate *priv = SOUP_SESSION_ASYNC_GET_PRIVATE (sa);
+	SoupSessionAsyncPrivate *priv = user_data;
 
-	if (!priv->idle_run_queue_sources)
+	if (priv->disposed)
 		return FALSE;
 
-	g_hash_table_remove (priv->idle_run_queue_sources,
-			     soup_session_get_async_context (sa));
-	run_queue (sa);
+	/* Ensure that the source is destroyed before running the queue */
+	g_source_destroy (g_main_current_source ());
+
+	run_queue (priv->sa);
 	return FALSE;
 }
 
@@ -499,18 +490,22 @@ static void
 do_idle_run_queue (SoupSession *session)
 {
 	SoupSessionAsyncPrivate *priv = SOUP_SESSION_ASYNC_GET_PRIVATE (session);
+	GMainContext *async_context = soup_session_get_async_context (session);
+	GSource *source;
 
-	if (!priv->idle_run_queue_sources)
+	if (priv->disposed)
 		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);
-		GSource *source = soup_add_completion (async_context, idle_run_queue, session);
+	/* We use priv rather than session as the source data, because
+	 * other parts of libsoup (or the calling app) may have sources
+	 * using the session as the source data.
+	 */
 
-		g_hash_table_insert (priv->idle_run_queue_sources,
-				     async_context, g_source_ref (source));
-	}
+	source = g_main_context_find_source_by_user_data (async_context, priv);
+	if (source)
+		return;
+
+	source = soup_add_completion (async_context, idle_run_queue, priv);
 }
 
 static void



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