[telepathy-mission-control/master] McdDispatchOperation: track channels' life-cycles here, not in McdDispatcherContext

Simon McVittie simon.mcvittie at collabora.co.uk
Mon Nov 2 06:41:33 PST 2009


This is a step towards having mcd_dispatcher_context_unref not have
unwanted side-effects.
---
 src/mcd-dispatch-operation.c |   40 +++++++++++++++++++++++++++++-
 src/mcd-dispatcher.c         |   56 +----------------------------------------
 2 files changed, 41 insertions(+), 55 deletions(-)

diff --git a/src/mcd-dispatch-operation.c b/src/mcd-dispatch-operation.c
index edc92d5..34ae9c5 100644
--- a/src/mcd-dispatch-operation.c
+++ b/src/mcd-dispatch-operation.c
@@ -578,6 +578,32 @@ error:
 }
 
 static void
+mcd_dispatch_operation_channel_aborted_cb (McdChannel *channel,
+                                           McdDispatchOperation *self)
+{
+    const GError *error;
+
+    g_object_ref (self);    /* FIXME: use a GObject closure or something */
+
+    DEBUG ("Channel %p aborted while in a dispatch operation", channel);
+
+    /* if it was a channel request, and it was cancelled, then the whole
+     * context should be aborted */
+    error = mcd_channel_get_error (channel);
+    if (error && error->code == TP_ERROR_CANCELLED)
+        _mcd_dispatch_operation_set_cancelled (self);
+
+    _mcd_dispatch_operation_lose_channel (self, channel);
+
+    if (_mcd_dispatch_operation_peek_channels (self) == NULL)
+    {
+        DEBUG ("Nothing left in this context");
+    }
+
+    g_object_unref (self);
+}
+
+static void
 mcd_dispatch_operation_set_property (GObject *obj, guint prop_id,
                                      const GValue *val, GParamSpec *pspec)
 {
@@ -626,9 +652,16 @@ mcd_dispatch_operation_set_property (GObject *obj, guint prop_id,
                            "Account?!");
             }
 
-            /* reference the channels */
+            /* reference the channels and connect to their signals */
             for (list = priv->channels; list != NULL; list = list->next)
+            {
                 g_object_ref (list->data);
+
+                g_signal_connect_after (list->data, "abort",
+                    G_CALLBACK (mcd_dispatch_operation_channel_aborted_cb),
+                    operation);
+
+            }
         }
         break;
 
@@ -706,7 +739,12 @@ mcd_dispatch_operation_dispose (GObject *object)
     if (priv->channels)
     {
         for (list = priv->channels; list != NULL; list = list->next)
+        {
+            g_signal_handlers_disconnect_by_func (list->data,
+                mcd_dispatch_operation_channel_aborted_cb, object);
             g_object_unref (list->data);
+        }
+
         g_list_free (priv->channels);
         priv->channels = NULL;
     }
diff --git a/src/mcd-dispatcher.c b/src/mcd-dispatcher.c
index 7798e2e..e5e81f1 100644
--- a/src/mcd-dispatcher.c
+++ b/src/mcd-dispatcher.c
@@ -1237,33 +1237,6 @@ _mcd_dispatcher_context_abort (McdDispatcherContext *context,
 }
 
 static void
-on_channel_abort_context (McdChannel *channel, McdDispatcherContext *context)
-{
-    const GError *error;
-
-    DEBUG ("Channel %p aborted while in a dispatcher context", channel);
-
-    /* if it was a channel request, and it was cancelled, then the whole
-     * context should be aborted */
-    error = mcd_channel_get_error (channel);
-    if (error && error->code == TP_ERROR_CANCELLED)
-        _mcd_dispatch_operation_set_cancelled (context->operation);
-
-    /* Losing the channel might mean we get freed, which would make some of
-     * the operations below very unhappy */
-    mcd_dispatcher_context_ref (context, "CTXREF08");
-
-    _mcd_dispatch_operation_lose_channel (context->operation, channel);
-
-    if (_mcd_dispatch_operation_peek_channels (context->operation) == NULL)
-    {
-        DEBUG ("Nothing left in this context");
-    }
-
-    mcd_dispatcher_context_unref (context, "CTXREF08");
-}
-
-static void
 on_operation_finished (McdDispatchOperation *operation,
                        McdDispatcherContext *context)
 {
@@ -1339,8 +1312,6 @@ _mcd_dispatcher_enter_state_machine (McdDispatcher *dispatcher,
 {
     McdDispatcherContext *context;
     McdDispatcherPrivate *priv;
-    GList *list;
-    McdChannel *channel;
     McdAccount *account;
 
     g_return_if_fail (MCD_IS_DISPATCHER (dispatcher));
@@ -1377,9 +1348,8 @@ _mcd_dispatcher_enter_state_machine (McdDispatcher *dispatcher,
      * bundle? */
 
     context->operation = _mcd_dispatch_operation_new (priv->clients,
-        !requested, g_list_copy (channels),
-        (const gchar * const *) possible_handlers);
-    /* the copy of @channels is stolen, but the GObject references are not */
+        !requested, channels, (const gchar * const *) possible_handlers);
+    /* ownership of @channels is stolen, but the GObject references are not */
 
     if (!requested)
     {
@@ -1395,17 +1365,6 @@ _mcd_dispatcher_enter_state_machine (McdDispatcher *dispatcher,
                           G_CALLBACK (on_operation_finished), context);
     }
 
-    for (list = channels; list != NULL; list = list->next)
-    {
-        channel = MCD_CHANNEL (list->data);
-
-        g_signal_connect_after (channel, "abort",
-                                G_CALLBACK (on_channel_abort_context),
-                                context);
-    }
-
-    g_list_free (channels);
-
     DEBUG ("entering state machine for context %p", context);
 
     sp_timestamp ("invoke internal filters");
@@ -2053,7 +2012,6 @@ mcd_dispatcher_context_unref (McdDispatcherContext * context,
                               const gchar *tag)
 {
     McdDispatcherPrivate *priv;
-    GList *list;
 
     /* FIXME: check for leaks */
     g_return_if_fail (context);
@@ -2065,16 +2023,6 @@ mcd_dispatcher_context_unref (McdDispatcherContext * context,
     {
         DEBUG ("freeing the context %p", context);
 
-        for (list = _mcd_dispatch_operation_dup_channels (context->operation);
-             list != NULL;
-             list = g_list_delete_link (list, list))
-        {
-            McdChannel *channel = MCD_CHANNEL (list->data);
-
-            g_signal_handlers_disconnect_by_func (channel,
-                G_CALLBACK (on_channel_abort_context), context);
-            g_object_unref (channel);
-        }
         g_signal_handlers_disconnect_by_func (context->operation,
                                               on_operation_finished,
                                               context);
-- 
1.5.6.5




More information about the telepathy-commits mailing list