[telepathy-mission-control/master] McdDispatchOperation: if not finished, queue up Claim() calls, and reply to all of them when allowed to do so

Simon McVittie simon.mcvittie at collabora.co.uk
Wed Oct 28 11:44:18 PDT 2009


---
 src/mcd-dispatch-operation.c |   91 +++++++++++++++++++++++++++++++-----------
 1 files changed, 68 insertions(+), 23 deletions(-)

diff --git a/src/mcd-dispatch-operation.c b/src/mcd-dispatch-operation.c
index c2018c5..0325e25 100644
--- a/src/mcd-dispatch-operation.c
+++ b/src/mcd-dispatch-operation.c
@@ -85,13 +85,33 @@ typedef enum {
 
 typedef struct {
     ApprovalType type;
-    /* will later include DBusGMethodInvocation etc. */
+    /* NULL unless type is CLAIM */
+    DBusGMethodInvocation *context;
 } Approval;
 
 static Approval *
+approval_new_claim (DBusGMethodInvocation *context)
+{
+    Approval *approval = g_slice_new0 (Approval);
+
+    g_assert (context != NULL);
+    approval->type = APPROVAL_TYPE_CLAIM;
+    approval->context = context;
+    return approval;
+}
+
+static Approval *
 approval_new (ApprovalType type)
 {
-    Approval *approval = g_slice_new (Approval);
+    Approval *approval = g_slice_new0 (Approval);
+
+    switch (type)
+    {
+        case APPROVAL_TYPE_CLAIM:
+            g_assert_not_reached ();
+        default:
+            {} /* do nothing */
+    }
 
     approval->type = type;
     return approval;
@@ -100,6 +120,9 @@ approval_new (ApprovalType type)
 static void
 approval_free (Approval *approval)
 {
+    /* we should have replied to the method call by now */
+    g_assert (approval->context == NULL);
+
     g_slice_free (Approval, approval);
 }
 
@@ -122,8 +145,6 @@ struct _McdDispatchOperationPrivate
     gboolean wants_to_finish;
     gchar *handler;
     gint64 handle_with_time;
-    gchar *claimer;
-    DBusGMethodInvocation *claim_context;
 
     /* queue of Approval */
     GQueue *approvals;
@@ -301,6 +322,8 @@ static void mcd_dispatch_operation_set_channel_handled_by (
 static void
 _mcd_dispatch_operation_check_client_locks (McdDispatchOperation *self)
 {
+    Approval *approval;
+
     /* we may not continue until we've called all the Observers, and they've
      * all replied "I'm ready" */
     if (!self->priv->invoked_observers_if_needed ||
@@ -349,29 +372,34 @@ _mcd_dispatch_operation_check_client_locks (McdDispatchOperation *self)
         return;
     }
 
+    approval = g_queue_peek_head (self->priv->approvals);
+
     /* if we've been claimed, respond, then do not call HandleChannels */
-    if (self->priv->claim_context != NULL)
+    if (approval != NULL && approval->type == APPROVAL_TYPE_CLAIM)
     {
         const GList *list;
+        const gchar *caller = dbus_g_method_get_sender (approval->context);
+
+        /* remove this approval from the list, so it won't be treated as a
+         * failure */
+        g_queue_pop_head (self->priv->approvals);
 
         g_assert (!self->priv->channels_handled);
         self->priv->channels_handled = TRUE;
 
-        g_assert (self->priv->claimer != NULL);
-
         for (list = self->priv->channels; list != NULL; list = list->next)
         {
             McdChannel *channel = MCD_CHANNEL (list->data);
 
             mcd_dispatch_operation_set_channel_handled_by (self, channel,
-                self->priv->claimer);
+                caller);
         }
 
-        DEBUG ("Replying to Claim call from %s", self->priv->claimer);
+        DEBUG ("Replying to Claim call from %s", caller);
 
         tp_svc_channel_dispatch_operation_return_from_claim (
-            self->priv->claim_context);
-        self->priv->claim_context = NULL;
+            approval->context);
+        approval->context = NULL;
 
         _mcd_dispatch_operation_finish (self);
 
@@ -573,6 +601,12 @@ static void
 _mcd_dispatch_operation_finish (McdDispatchOperation *operation)
 {
     McdDispatchOperationPrivate *priv = operation->priv;
+    Approval *approval;
+    /* FIXME: if we're finishing because there are no channels left, this
+     * should be replaced by the invalidated reason for the last channel
+     * to close */
+    GError not_yours = { TP_ERRORS, TP_ERROR_NOT_YOURS,
+        "Channel handled by someone else (or all channels were lost)" };
 
     if (priv->wants_to_finish)
     {
@@ -582,6 +616,26 @@ _mcd_dispatch_operation_finish (McdDispatchOperation *operation)
 
     priv->wants_to_finish = TRUE;
 
+    for (approval = g_queue_pop_head (priv->approvals);
+         approval != NULL;
+         approval = g_queue_pop_head (priv->approvals))
+    {
+        switch (approval->type)
+        {
+            case APPROVAL_TYPE_CLAIM:
+                /* someone else got it - either another Claim() or a handler */
+                g_assert (approval->context != NULL);
+                DEBUG ("denying Claim call from %s",
+                       dbus_g_method_get_sender (approval->context));
+                dbus_g_method_return_error (approval->context, &not_yours);
+                approval->context = NULL;
+                break;
+
+            default:
+                {} /* do nothing */
+        }
+    }
+
     if (mcd_dispatch_operation_may_signal_finished (operation))
     {
         DEBUG ("%s/%p has finished", priv->unique_name, operation);
@@ -640,11 +694,10 @@ dispatch_operation_claim (TpSvcChannelDispatchOperation *cdo,
     McdDispatchOperation *self = MCD_DISPATCH_OPERATION (cdo);
     McdDispatchOperationPrivate *priv = self->priv;
 
-    if (self->priv->wants_to_finish ||
-        !g_queue_is_empty (self->priv->approvals))
+    if (self->priv->channels_handled)
     {
         GError *error = g_error_new (TP_ERRORS, TP_ERROR_NOT_YOURS,
-                                     "CDO already finished or approved");
+                                     "CDO already finished");
         DEBUG ("Giving error to %s: %s", dbus_g_method_get_sender (context),
                error->message);
         dbus_g_method_return_error (context, error);
@@ -652,14 +705,7 @@ dispatch_operation_claim (TpSvcChannelDispatchOperation *cdo,
         return;
     }
 
-    g_assert (priv->claimer == NULL);
-    g_assert (priv->claim_context == NULL);
-    priv->claimer = dbus_g_method_get_sender (context);
-    priv->claim_context = context;
-    DEBUG ("Claiming on behalf of %s", priv->claimer);
-
-    g_queue_push_tail (priv->approvals,
-                       approval_new (APPROVAL_TYPE_CLAIM));
+    g_queue_push_tail (priv->approvals, approval_new_claim (context));
     _mcd_dispatch_operation_check_client_locks (self);
 }
 
@@ -949,7 +995,6 @@ mcd_dispatch_operation_finalize (GObject *object)
 
     g_free (priv->handler);
     g_free (priv->object_path);
-    g_free (priv->claimer);
 
     G_OBJECT_CLASS (_mcd_dispatch_operation_parent_class)->finalize (object);
 }
-- 
1.5.6.5




More information about the telepathy-commits mailing list