ORBit2 r2063 - in trunk/linc2: . src



Author: michael
Date: Thu May 22 15:44:47 2008
New Revision: 2063
URL: http://svn.gnome.org/viewvc/ORBit2?rev=2063&view=rev

Log:
2008-05-22  Michael Meeks  <michael meeks novell com>

        * src/linc-connection.c (link_connection_broken_idle),
        (add_idle_broken_for_cnx_T, link_connection_state_changed_T_R): 
        don't add one idle handler per cnx; share a global idle handler.
        don't inhibit reconnection while emitting 'broken' if we are
        already emitting broken callbacks. bug #534351#



Modified:
   trunk/linc2/ChangeLog
   trunk/linc2/src/linc-connection.c

Modified: trunk/linc2/src/linc-connection.c
==============================================================================
--- trunk/linc2/src/linc-connection.c	(original)
+++ trunk/linc2/src/linc-connection.c	Thu May 22 15:44:47 2008
@@ -149,29 +149,67 @@
 	g_slist_free (callbacks);
 }
 
+/*
+ * Unfortunate to have a global list, but we need to know
+ * if this is being processed in the main thread & if so
+ * simply append to it.
+ */
+static GSList *idle_broken_cnxs = NULL;
+
 static gboolean
-link_connection_broken_idle (gpointer data)
+link_connection_broken_idle (gpointer dummy)
 {
 	GSList *callbacks;
-	LinkConnection *cnx = data;
+	LinkConnection *cnx;
 
 	d_printf ("Connection %p broken idle ...\n", data);
 
-	CNX_LOCK (cnx);
-	callbacks = cnx->idle_broken_callbacks;
-	cnx->idle_broken_callbacks = NULL;
-	cnx->inhibit_reconnect = FALSE;
-	link_signal ();
-	CNX_UNLOCK (cnx);
-
-	link_connection_emit_broken (cnx, callbacks);
+	do {
+		link_lock();
+		cnx = NULL;
+		if (idle_broken_cnxs != NULL) {
+			cnx = idle_broken_cnxs->data;
+			idle_broken_cnxs = g_slist_delete_link (idle_broken_cnxs, idle_broken_cnxs);
+		}
+		if (cnx) {
+			callbacks = cnx->idle_broken_callbacks;
+			cnx->idle_broken_callbacks = NULL;
+			cnx->inhibit_reconnect = FALSE;
+			link_signal ();
+		}
+		link_unlock ();
 
-	link_connection_unref (cnx);
+		if (cnx) {
+			link_connection_emit_broken (cnx, callbacks);
+			link_connection_unref (cnx);
+		}
+	} while (cnx != NULL);
 
 	return FALSE;
 }
 
 static void
+add_idle_broken_for_cnx_T (LinkConnection *cnx)
+{
+	if (idle_broken_cnxs != NULL) {
+		fprintf (stderr, "Deadlock potential - avoiding evil bug!\n");
+		/*
+		 * just append ourself & exit - we don't want to
+		 * inhibit re-connection because of the horrendous
+		 * deadlock possible, cf. g#534351#
+		 */
+		if (g_slist_find (idle_broken_cnxs, cnx) != NULL)
+			return;
+	} else {
+		/* inhibit reconnect while we emit 'broken' */
+		cnx->inhibit_reconnect = TRUE;
+		g_idle_add (link_connection_broken_idle, NULL);
+	}
+	link_connection_ref_T (cnx);
+	idle_broken_cnxs = g_slist_prepend (idle_broken_cnxs, cnx);
+}
+
+static void
 link_source_remove (LinkConnection *cnx)
 {
 	if (cnx->priv->tag) {
@@ -314,10 +352,7 @@
 					dispatch_callbacks_drop_lock (cnx);
 				} else {
 					d_printf ("Queuing broken callbacks at idle\n");
-
-					cnx->inhibit_reconnect = TRUE;
-					link_connection_ref_T (cnx);
-					g_idle_add (link_connection_broken_idle, cnx);
+					add_idle_broken_for_cnx_T (cnx);
 				}
 			}
 		}



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