[gnome-builder] worker: allow asynchronous creation of worker proxy



commit 4f458e337f9ebc4d4bd492f96256b30980a24ff3
Author: Christian Hergert <chergert redhat com>
Date:   Tue Oct 20 00:04:06 2015 -0700

    worker: allow asynchronous creation of worker proxy
    
    This allows the proxy to be requeste before the client process has
    completed starting up and connected back to the UI process.

 libide/ide-worker-manager.c |  103 +++++++++++++++++++++--------
 libide/ide-worker-manager.h |   13 +++-
 libide/ide-worker-process.c |  151 ++++++++++++++++++++++++++++++-------------
 libide/ide-worker-process.h |   29 +++++---
 libide/ide-worker.c         |    8 ++-
 libide/ide-worker.h         |   18 +++--
 6 files changed, 223 insertions(+), 99 deletions(-)
---
diff --git a/libide/ide-worker-manager.c b/libide/ide-worker-manager.c
index 12beda0..1076b99 100644
--- a/libide/ide-worker-manager.c
+++ b/libide/ide-worker-manager.c
@@ -34,11 +34,9 @@ struct _IdeWorkerManager
 {
   GObject      parent_instance;
 
-  GMutex       mutex;
-
   gchar       *argv0;
-  GHashTable  *workers_by_plugin_name;
   GDBusServer *dbus_server;
+  GHashTable  *plugin_name_to_worker;
 };
 
 G_DEFINE_TYPE (IdeWorkerManager, ide_worker_manager, G_TYPE_OBJECT)
@@ -88,9 +86,7 @@ ide_worker_manager_new_connection_cb (IdeWorkerManager *self,
   if ((credentials == NULL) || !g_credentials_get_unix_pid (credentials, NULL))
     return FALSE;
 
-  g_mutex_lock (&self->mutex);
-
-  g_hash_table_iter_init (&iter, self->workers_by_plugin_name);
+  g_hash_table_iter_init (&iter, self->plugin_name_to_worker);
 
   while (g_hash_table_iter_next (&iter, &key, &value))
     {
@@ -103,8 +99,6 @@ ide_worker_manager_new_connection_cb (IdeWorkerManager *self,
         }
     }
 
-  g_mutex_unlock (&self->mutex);
-
   return handled;
 }
 
@@ -174,7 +168,8 @@ ide_worker_manager_finalize (GObject *object)
 {
   IdeWorkerManager *self = (IdeWorkerManager *)object;
 
-  g_clear_pointer (&self->workers_by_plugin_name, g_hash_table_unref);
+  g_clear_pointer (&self->plugin_name_to_worker, g_hash_table_unref);
+  g_clear_pointer (&self->argv0, g_free);
   g_clear_object (&self->dbus_server);
 
   G_OBJECT_CLASS (ide_worker_manager_parent_class)->finalize (object);
@@ -225,42 +220,92 @@ ide_worker_manager_init (IdeWorkerManager *self)
 {
   EGG_COUNTER_INC (instances);
 
-  g_mutex_init (&self->mutex);
-
   self->argv0 = g_strdup ("gnome-builder");
 
-  self->workers_by_plugin_name =
+  self->plugin_name_to_worker =
     g_hash_table_new_full (g_str_hash,
                            g_str_equal,
                            g_free,
                            ide_worker_manager_force_exit_worker);
 }
 
-GDBusProxy *
-ide_worker_manager_get_worker (IdeWorkerManager  *self,
-                               const gchar       *plugin_name,
-                               GError           **error)
+static IdeWorkerProcess *
+ide_worker_manager_get_worker_process (IdeWorkerManager *self,
+                                       const gchar      *plugin_name)
 {
-  IdeWorkerProcess *worker;
-
-  g_return_val_if_fail (IDE_IS_WORKER_MANAGER (self), NULL);
-  g_return_val_if_fail (plugin_name != NULL, NULL);
+  IdeWorkerProcess *worker_process;
 
-  g_mutex_lock (&self->mutex);
+  g_assert (IDE_IS_WORKER_MANAGER (self));
+  g_assert (plugin_name != NULL);
 
-  worker = g_hash_table_lookup (self->workers_by_plugin_name, plugin_name);
+  worker_process = g_hash_table_lookup (self->plugin_name_to_worker, plugin_name);
 
-  if (worker == NULL)
+  if (worker_process == NULL)
     {
-      worker = ide_worker_process_new (self->argv0, plugin_name,
-                                       g_dbus_server_get_client_address (self->dbus_server));
-      g_hash_table_insert (self->workers_by_plugin_name, g_strdup (plugin_name), worker);
-      ide_worker_process_run (worker);
+      worker_process = ide_worker_process_new (self->argv0,
+                                               plugin_name,
+                                               g_dbus_server_get_client_address (self->dbus_server));
+      g_hash_table_insert (self->plugin_name_to_worker, g_strdup (plugin_name), worker_process);
+      ide_worker_process_run (worker_process);
     }
 
-  g_mutex_unlock (&self->mutex);
+  return worker_process;
+}
+
+static void
+ide_worker_manager_get_worker_cb (GObject      *object,
+                                  GAsyncResult *result,
+                                  gpointer      user_data)
+{
+  IdeWorkerProcess *worker_process = (IdeWorkerProcess *)object;
+  g_autoptr(GTask) task = user_data;
+  GDBusProxy *proxy;
+  GError *error = NULL;
+
+  g_assert (IDE_IS_WORKER_PROCESS (worker_process));
+  g_assert (G_IS_TASK (task));
+
+  proxy = ide_worker_process_get_proxy_finish (worker_process, result, &error);
+
+  if (proxy == NULL)
+    g_task_return_error (task, error);
+  else
+    g_task_return_pointer (task, proxy, g_object_unref);
+}
+
+void
+ide_worker_manager_get_worker_async (IdeWorkerManager    *self,
+                                     const gchar         *plugin_name,
+                                     GCancellable        *cancellable,
+                                     GAsyncReadyCallback  callback,
+                                     gpointer             user_data)
+{
+  IdeWorkerProcess *worker_process;
+  GTask *task;
+
+  g_return_if_fail (IDE_IS_WORKER_MANAGER (self));
+  g_return_if_fail (plugin_name != NULL);
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  task = g_task_new (self, cancellable, callback, user_data);
+  worker_process = ide_worker_manager_get_worker_process (self, plugin_name);
+  ide_worker_process_get_proxy_async (worker_process,
+                                      cancellable,
+                                      ide_worker_manager_get_worker_cb,
+                                      task);
+}
+
+GDBusProxy *
+ide_worker_manager_get_worker_finish (IdeWorkerManager  *self,
+                                      GAsyncResult      *result,
+                                      GError           **error)
+{
+  GTask *task = (GTask *)result;
+
+  g_return_val_if_fail (IDE_IS_WORKER_MANAGER (self), NULL);
+  g_return_val_if_fail (G_IS_TASK (task), NULL);
 
-  return ide_worker_process_create_proxy (worker, error);
+  return g_task_propagate_pointer (task, error);
 }
 
 IdeWorkerManager *
diff --git a/libide/ide-worker-manager.h b/libide/ide-worker-manager.h
index 3ad9faa..cd56aad 100644
--- a/libide/ide-worker-manager.h
+++ b/libide/ide-worker-manager.h
@@ -27,10 +27,15 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (IdeWorkerManager, ide_worker_manager, IDE, WORKER_MANAGER, GObject)
 
-IdeWorkerManager *ide_worker_manager_new        (const gchar       *argv0);
-GDBusProxy       *ide_worker_manager_get_worker (IdeWorkerManager  *self,
-                                                 const gchar       *plugin_name,
-                                                 GError           **error);
+IdeWorkerManager *ide_worker_manager_new               (const gchar          *argv0);
+void              ide_worker_manager_get_worker_async  (IdeWorkerManager     *self,
+                                                        const gchar          *plugin_name,
+                                                        GCancellable         *cancellable,
+                                                        GAsyncReadyCallback   callback,
+                                                        gpointer              user_data);
+GDBusProxy       *ide_worker_manager_get_worker_finish (IdeWorkerManager     *self,
+                                                        GAsyncResult         *result,
+                                                        GError              **error);
 
 G_END_DECLS
 
diff --git a/libide/ide-worker-process.c b/libide/ide-worker-process.c
index 780443a..4f7322b 100644
--- a/libide/ide-worker-process.c
+++ b/libide/ide-worker-process.c
@@ -35,12 +35,12 @@ struct _IdeWorkerProcess
   gchar           *plugin_name;
   GSubprocess     *subprocess;
   GDBusConnection *connection;
+  GPtrArray       *tasks;
+  IdeWorker       *worker;
 
   guint            quit : 1;
 };
 
-static void ide_worker_process_respawn (IdeWorkerProcess *self);
-
 G_DEFINE_TYPE (IdeWorkerProcess, ide_worker_process, G_TYPE_OBJECT)
 
 EGG_DEFINE_COUNTER (instances, "IdeWorkerProcess", "Instances", "Number of IdeWorkerProcess instances")
@@ -55,6 +55,8 @@ enum {
 
 static GParamSpec *gParamSpecs [LAST_PROP];
 
+static void ide_worker_process_respawn (IdeWorkerProcess *self);
+
 IdeWorkerProcess *
 ide_worker_process_new (const gchar *argv0,
                         const gchar *plugin_name,
@@ -137,6 +139,22 @@ ide_worker_process_respawn (IdeWorkerProcess *self)
                                  ide_worker_process_wait_check_cb,
                                  g_object_ref (self));
 
+  if (self->worker == NULL)
+    {
+      PeasEngine *engine;
+      PeasExtension *exten;
+      PeasPluginInfo *plugin_info;
+
+      engine = peas_engine_get_default ();
+      plugin_info = peas_engine_get_plugin_info (engine, self->plugin_name);
+
+      if (plugin_info != NULL)
+        {
+          exten = peas_engine_create_extension (engine, plugin_info, IDE_TYPE_WORKER, NULL);
+          self->worker = IDE_WORKER (exten);
+        }
+    }
+
   IDE_EXIT;
 }
 
@@ -187,8 +205,10 @@ ide_worker_process_finalize (GObject *object)
   g_clear_pointer (&self->argv0, g_free);
   g_clear_pointer (&self->plugin_name, g_free);
   g_clear_pointer (&self->dbus_address, g_free);
+  g_clear_pointer (&self->tasks, g_ptr_array_unref);
   g_clear_object (&self->connection);
   g_clear_object (&self->subprocess);
+  g_clear_object (&self->worker);
 
   G_OBJECT_CLASS (ide_worker_process_parent_class)->finalize (object);
 
@@ -289,47 +309,6 @@ ide_worker_process_init (IdeWorkerProcess *self)
   EGG_COUNTER_INC (instances);
 }
 
-gpointer
-ide_worker_process_create_proxy (IdeWorkerProcess  *self,
-                                 GError           **error)
-{
-  PeasEngine *engine;
-  PeasPluginInfo *plugin_info;
-  PeasExtension *exten;
-  GDBusProxy *proxy;
-
-  g_assert (IDE_IS_WORKER_PROCESS (self));
-  g_assert (self->plugin_name != NULL);
-
-  engine = peas_engine_get_default ();
-  plugin_info = peas_engine_get_plugin_info (engine, self->plugin_name);
-
-  if (plugin_info == NULL)
-    {
-      g_set_error (error,
-                   G_IO_ERROR,
-                   G_IO_ERROR_PROXY_FAILED,
-                   "The plugin named \"%s\" could not be found.",
-                   self->plugin_name);
-      return NULL;
-    }
-
-  if (self->connection == NULL)
-    {
-      g_set_error (error,
-                   G_IO_ERROR,
-                   G_IO_ERROR_PROXY_FAILED,
-                   "No connection has been established with the worker process");
-      return NULL;
-    }
-
-  exten = peas_engine_create_extension (engine, plugin_info, IDE_TYPE_WORKER, NULL);
-  proxy = ide_worker_create_proxy (IDE_WORKER (exten), self->connection);
-  g_clear_object (&exten);
-
-  return proxy;
-}
-
 gboolean
 ide_worker_process_matches_credentials (IdeWorkerProcess *self,
                                         GCredentials     *credentials)
@@ -353,6 +332,36 @@ ide_worker_process_matches_credentials (IdeWorkerProcess *self,
   return FALSE;
 }
 
+static void
+ide_worker_process_create_proxy_for_task (IdeWorkerProcess *self,
+                                          GTask            *task)
+{
+  GDBusProxy *proxy;
+  GError *error = NULL;
+
+  g_assert (IDE_IS_WORKER_PROCESS (self));
+  g_assert (G_IS_TASK (task));
+
+  if (self->worker == NULL)
+    {
+      g_task_return_new_error (task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_PROXY_FAILED,
+                               "Failed to create IdeWorker instance.");
+      return;
+    }
+
+  proxy = ide_worker_create_proxy (self->worker, self->connection, &error);
+
+  if (proxy == NULL)
+    {
+      g_task_return_error (task, error);
+      return;
+    }
+
+  g_task_return_pointer (task, proxy, g_object_unref);
+}
+
 void
 ide_worker_process_set_connection (IdeWorkerProcess *self,
                                    GDBusConnection  *connection)
@@ -360,5 +369,59 @@ ide_worker_process_set_connection (IdeWorkerProcess *self,
   g_return_if_fail (IDE_IS_WORKER_PROCESS (self));
   g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
 
-  g_set_object (&self->connection, connection);
+  if (g_set_object (&self->connection, connection))
+    {
+      if (self->tasks != NULL)
+        {
+          g_autoptr(GPtrArray) ar = NULL;
+          guint i;
+
+          ar = self->tasks;
+          self->tasks = NULL;
+
+          for (i = 0; i < ar->len; i++)
+            {
+              GTask *task = g_ptr_array_index (ar, i);
+              ide_worker_process_create_proxy_for_task (self, task);
+            }
+        }
+    }
+}
+
+void
+ide_worker_process_get_proxy_async (IdeWorkerProcess    *self,
+                                    GCancellable        *cancellable,
+                                    GAsyncReadyCallback  callback,
+                                    gpointer             user_data)
+{
+  g_autoptr(GTask) task = NULL;
+
+  g_return_if_fail (IDE_IS_WORKER_PROCESS (self));
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  task = g_task_new (self, cancellable, callback, user_data);
+
+  if (self->connection != NULL)
+    {
+      ide_worker_process_create_proxy_for_task (self, task);
+      return;
+    }
+
+  if (self->tasks == NULL)
+    self->tasks = g_ptr_array_new_with_free_func (g_object_unref);
+
+  g_ptr_array_add (self->tasks, g_object_ref (task));
+}
+
+GDBusProxy *
+ide_worker_process_get_proxy_finish (IdeWorkerProcess  *self,
+                                     GAsyncResult      *result,
+                                     GError           **error)
+{
+  GTask *task = (GTask *)result;
+
+  g_return_val_if_fail (IDE_IS_WORKER_PROCESS (self), NULL);
+  g_return_val_if_fail (G_IS_TASK (task), NULL);
+
+  return g_task_propagate_pointer (task, error);
 }
diff --git a/libide/ide-worker-process.h b/libide/ide-worker-process.h
index 73e3361..4133874 100644
--- a/libide/ide-worker-process.h
+++ b/libide/ide-worker-process.h
@@ -27,17 +27,24 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (IdeWorkerProcess, ide_worker_process, IDE, WORKER_PROCESS, GObject)
 
-IdeWorkerProcess *ide_worker_process_new                 (const gchar       *argv0,
-                                                          const gchar       *type,
-                                                          const gchar       *dbus_address);
-void              ide_worker_process_run                 (IdeWorkerProcess  *self);
-void              ide_worker_process_quit                (IdeWorkerProcess  *self);
-gpointer          ide_worker_process_create_proxy        (IdeWorkerProcess  *self,
-                                                          GError           **error);
-gboolean          ide_worker_process_matches_credentials (IdeWorkerProcess  *self,
-                                                          GCredentials      *credentials);
-void              ide_worker_process_set_connection      (IdeWorkerProcess  *self,
-                                                          GDBusConnection   *connection);
+IdeWorkerProcess *ide_worker_process_new                 (const gchar          *argv0,
+                                                          const gchar          *type,
+                                                          const gchar          *dbus_address);
+void              ide_worker_process_run                 (IdeWorkerProcess     *self);
+void              ide_worker_process_quit                (IdeWorkerProcess     *self);
+gpointer          ide_worker_process_create_proxy        (IdeWorkerProcess     *self,
+                                                          GError              **error);
+gboolean          ide_worker_process_matches_credentials (IdeWorkerProcess     *self,
+                                                          GCredentials         *credentials);
+void              ide_worker_process_set_connection      (IdeWorkerProcess     *self,
+                                                          GDBusConnection      *connection);
+void              ide_worker_process_get_proxy_async     (IdeWorkerProcess     *self,
+                                                          GCancellable         *cancellable,
+                                                          GAsyncReadyCallback   callback,
+                                                          gpointer              user_data);
+GDBusProxy       *ide_worker_process_get_proxy_finish    (IdeWorkerProcess     *self,
+                                                          GAsyncResult         *result,
+                                                          GError              **error);
 
 G_END_DECLS
 
diff --git a/libide/ide-worker.c b/libide/ide-worker.c
index ccf456a..9c1be12 100644
--- a/libide/ide-worker.c
+++ b/libide/ide-worker.c
@@ -41,6 +41,7 @@ ide_worker_register_service (IdeWorker       *self,
  * ide_worker_create_proxy:
  * @self: An #IdeWorker.
  * @connection: A #GDBusConnection connected to the worker process.
+ * @error: (allow-none): a location for a #GError, or %NULL.
  *
  * Creates a new proxy to be connected to the subprocess peer on the other
  * end of @connection.
@@ -48,11 +49,12 @@ ide_worker_register_service (IdeWorker       *self,
  * Returns: (transfer full): A #GDBusProxy or %NULL.
  */
 GDBusProxy *
-ide_worker_create_proxy (IdeWorker       *self,
-                         GDBusConnection *connection)
+ide_worker_create_proxy (IdeWorker        *self,
+                         GDBusConnection  *connection,
+                         GError          **error)
 {
   g_return_val_if_fail (IDE_IS_WORKER (self), NULL);
   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
 
-  return IDE_WORKER_GET_IFACE (self)->create_proxy (self, connection);
+  return IDE_WORKER_GET_IFACE (self)->create_proxy (self, connection, error);
 }
diff --git a/libide/ide-worker.h b/libide/ide-worker.h
index d44eecf..fd7278e 100644
--- a/libide/ide-worker.h
+++ b/libide/ide-worker.h
@@ -31,16 +31,18 @@ struct _IdeWorkerInterface
 {
   GTypeInterface parent;
 
-  GDBusProxy *(*create_proxy)     (IdeWorker       *self,
-                                   GDBusConnection *connection);
-  void        (*register_service) (IdeWorker       *self,
-                                   GDBusConnection *connection);
+  GDBusProxy *(*create_proxy)     (IdeWorker        *self,
+                                   GDBusConnection  *connection,
+                                   GError          **error);
+  void        (*register_service) (IdeWorker        *self,
+                                   GDBusConnection  *connection);
 };
 
-GDBusProxy *ide_worker_create_proxy     (IdeWorker       *self,
-                                         GDBusConnection *connection);
-void        ide_worker_register_service (IdeWorker       *self,
-                                         GDBusConnection *connection);
+GDBusProxy *ide_worker_create_proxy     (IdeWorker        *self,
+                                         GDBusConnection  *connection,
+                                         GError          **error);
+void        ide_worker_register_service (IdeWorker        *self,
+                                         GDBusConnection  *connection);
 
 G_END_DECLS
 


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