[gnome-builder/wip/chergert/jsonrpc-gvariant] jsonrpc: fix async failures causing reference issues



commit fc0f9c811bc201359de19612c402986e0380b48c
Author: Christian Hergert <chergert redhat com>
Date:   Fri Mar 17 16:09:46 2017 -0700

    jsonrpc: fix async failures causing reference issues
    
    We need to be very careful about the ordering and how we dispatch callbacks
    so that ownership is preserved across the callback chain.

 contrib/jsonrpc-glib/jsonrpc-client.c |   43 +++++++++++++++++++++++----------
 libide/langserv/ide-langserv-client.c |   26 ++++++++++++++++++-
 2 files changed, 54 insertions(+), 15 deletions(-)
---
diff --git a/contrib/jsonrpc-glib/jsonrpc-client.c b/contrib/jsonrpc-glib/jsonrpc-client.c
index 3e58e46..6d834ce 100644
--- a/contrib/jsonrpc-glib/jsonrpc-client.c
+++ b/contrib/jsonrpc-glib/jsonrpc-client.c
@@ -474,26 +474,34 @@ jsonrpc_client_new (GIOStream *io_stream)
 }
 
 static void
-jsonrpc_client_call_notify_completed (GTask      *task,
-                                      GParamSpec *pspec,
-                                      gpointer    user_data)
+jsonrpc_client_remove_from_invocatoins (JsonrpcClient *self,
+                                        GTask         *task)
 {
-  JsonrpcClientPrivate *priv;
-  JsonrpcClient *self;
+  JsonrpcClientPrivate *priv = jsonrpc_client_get_instance_private (self);
   gpointer id;
 
+  g_assert (JSONRPC_IS_CLIENT (self));
   g_assert (G_IS_TASK (task));
-  g_assert (pspec != NULL);
-  g_assert (g_str_equal (pspec->name, "completed"));
 
-  self = g_task_get_source_object (task);
-  priv = jsonrpc_client_get_instance_private (self);
   id = g_task_get_task_data (task);
 
   g_hash_table_remove (priv->invocations, id);
 }
 
 static void
+jsonrpc_client_call_notify_completed (JsonrpcClient *self,
+                                      GParamSpec    *pspec,
+                                      GTask         *task)
+{
+  g_assert (JSONRPC_IS_CLIENT (self));
+  g_assert (pspec != NULL);
+  g_assert (g_str_equal (pspec->name, "completed"));
+  g_assert (G_IS_TASK (task));
+
+  jsonrpc_client_remove_from_invocatoins (self, task);
+}
+
+static void
 jsonrpc_client_call_write_cb (GObject      *object,
                               GAsyncResult *result,
                               gpointer      user_data)
@@ -501,12 +509,20 @@ jsonrpc_client_call_write_cb (GObject      *object,
   JsonrpcOutputStream *stream = (JsonrpcOutputStream *)object;
   g_autoptr(GTask) task = user_data;
   g_autoptr(GError) error = NULL;
+  JsonrpcClient *self;
 
   g_assert (JSONRPC_IS_OUTPUT_STREAM (stream));
+  g_assert (G_IS_ASYNC_RESULT (result));
   g_assert (G_IS_TASK (task));
 
+  self = g_task_get_source_object (task);
+  g_assert (JSONRPC_IS_CLIENT (self));
+
+  jsonrpc_client_remove_from_invocatoins (self, task);
+
   if (!jsonrpc_output_stream_write_message_finish (stream, result, &error))
     {
+      jsonrpc_client_panic (self, error);
       g_task_return_error (task, g_steal_pointer (&error));
       return;
     }
@@ -838,10 +854,11 @@ jsonrpc_client_call_async (JsonrpcClient       *self,
       return;
     }
 
-  g_signal_connect (task,
-                    "notify::completed",
-                    G_CALLBACK (jsonrpc_client_call_notify_completed),
-                    NULL);
+  g_signal_connect_object (task,
+                           "notify::completed",
+                           G_CALLBACK (jsonrpc_client_call_notify_completed),
+                           self,
+                           G_CONNECT_SWAPPED);
 
   id = ++priv->sequence;
 
diff --git a/libide/langserv/ide-langserv-client.c b/libide/langserv/ide-langserv-client.c
index 5493b0b..f2532cb 100644
--- a/libide/langserv/ide-langserv-client.c
+++ b/libide/langserv/ide-langserv-client.c
@@ -946,6 +946,19 @@ ide_langserv_client_start (IdeLangservClient *self)
 }
 
 static void
+ide_langserv_client_close_cb (GObject      *object,
+                              GAsyncResult *result,
+                              gpointer      user_data)
+{
+  g_autoptr(IdeLangservClient) self = user_data;
+  JsonrpcClient *client = (JsonrpcClient *)object;
+
+  g_assert (IDE_IS_LANGSERV_CLIENT (self));
+
+  jsonrpc_client_close_finish (client, result, NULL);
+}
+
+static void
 ide_langserv_client_shutdown_cb (GObject      *object,
                                  GAsyncResult *result,
                                  gpointer      user_data)
@@ -961,8 +974,11 @@ ide_langserv_client_shutdown_cb (GObject      *object,
 
   if (!jsonrpc_client_call_finish (client, result, NULL, &error))
     g_warning ("%s", error->message);
-
-  jsonrpc_client_close_async (client, NULL, NULL, NULL);
+  else
+    jsonrpc_client_close_async (client,
+                                NULL,
+                                ide_langserv_client_close_cb,
+                                g_object_ref (self));
 
   IDE_EXIT;
 }
@@ -1004,6 +1020,7 @@ ide_langserv_client_call_cb (GObject      *object,
 
   g_assert (JSONRPC_IS_CLIENT (client));
   g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (G_IS_TASK (task));
 
   if (!jsonrpc_client_call_finish (client, result, &return_value, &error))
     {
@@ -1040,6 +1057,11 @@ ide_langserv_client_call_async (IdeLangservClient   *self,
 
   IDE_ENTRY;
 
+  g_return_if_fail (IDE_IS_LANGSERV_CLIENT (self));
+  g_return_if_fail (method != NULL);
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+  g_return_if_fail (!priv->rpc_client || JSONRPC_IS_CLIENT (priv->rpc_client));
+
   task = g_task_new (self, cancellable, callback, user_data);
   g_task_set_source_tag (task, ide_langserv_client_call_async);
 


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