[gnome-builder/wip/chergert/multi-process: 4/7] libide: add IdeWorker interface and plumbing



commit bd996d1a39a6ee239c1964204be6aac2aac93bbd
Author: Christian Hergert <chergert redhat com>
Date:   Mon Oct 19 21:20:49 2015 -0700

    libide: add IdeWorker interface and plumbing
    
    IdeWorker is designed to allow for a plugin to create a worker process
    where it will perform it's heavy work. Plugins that could potentially
    consume a lot of memory or resources should be pushed into a worker
    process so that we can recycle them based on future policies.
    
    The worker manager creates a GDBusServer that can be connected to by the
    worker process. It should export it's service via that bus, and connect
    to it from the UI process (using API to be added soon).
    
    The UI should handle for the potential that the connection and proxy are
    lost in the case that the worker process crashes, or is torn down due to
    overactive memory/cpu use.

 libide/Makefile.am          |    6 +
 libide/ide-worker-manager.c |  274 ++++++++++++++++++++++++++++++++
 libide/ide-worker-manager.h |   37 +++++
 libide/ide-worker-process.c |  364 +++++++++++++++++++++++++++++++++++++++++++
 libide/ide-worker-process.h |   44 +++++
 libide/ide-worker.c         |   58 +++++++
 libide/ide-worker.h         |   47 ++++++
 7 files changed, 830 insertions(+), 0 deletions(-)
---
diff --git a/libide/Makefile.am b/libide/Makefile.am
index 45b092c..881f5ad 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -176,6 +176,8 @@ libide_1_0_la_public_sources = \
        ide-vcs-uri.h \
        ide-vcs.c \
        ide-vcs.h \
+       ide-worker.c \
+       ide-worker.h \
        ide.c \
        ide.h \
        local/ide-local-device.c \
@@ -226,6 +228,10 @@ libide_1_0_la_SOURCES = \
        ide-source-view-movements.h \
        ide-vim-iter.c \
        ide-vim-iter.h \
+       ide-worker-manager.c \
+       ide-worker-manager.h \
+       ide-worker-process.c \
+       ide-worker-process.h \
        modelines/ide-modelines-file-settings.c \
        modelines/ide-modelines-file-settings.h \
        modelines/modeline-parser.c \
diff --git a/libide/ide-worker-manager.c b/libide/ide-worker-manager.c
new file mode 100644
index 0000000..12beda0
--- /dev/null
+++ b/libide/ide-worker-manager.c
@@ -0,0 +1,274 @@
+/* ide-worker-manager.c
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "ide-worker-manager"
+
+#include <gio/gio.h>
+#include <gio/gunixsocketaddress.h>
+#include <glib/gi18n.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "egg-counter.h"
+
+#include "ide-worker-process.h"
+#include "ide-worker-manager.h"
+
+struct _IdeWorkerManager
+{
+  GObject      parent_instance;
+
+  GMutex       mutex;
+
+  gchar       *argv0;
+  GHashTable  *workers_by_plugin_name;
+  GDBusServer *dbus_server;
+};
+
+G_DEFINE_TYPE (IdeWorkerManager, ide_worker_manager, G_TYPE_OBJECT)
+
+EGG_DEFINE_COUNTER (instances, "IdeWorkerManager", "Instances", "Number of IdeWorkerManager instances")
+
+enum {
+  PROP_0,
+  PROP_ARGV0,
+  LAST_PROP
+};
+
+static GParamSpec *gParamSpecs [LAST_PROP];
+
+static void
+ide_worker_manager_set_argv0 (IdeWorkerManager *self,
+                              const gchar      *argv0)
+{
+  g_return_if_fail (IDE_IS_WORKER_MANAGER (self));
+
+  if (argv0 == NULL)
+    argv0 = "gnome-builder";
+
+  if (g_strcmp0 (argv0, self->argv0) != 0)
+    {
+      g_free (self->argv0);
+      self->argv0 = g_strdup (argv0);
+      g_object_notify_by_pspec (G_OBJECT (self), gParamSpecs [PROP_ARGV0]);
+    }
+}
+
+static gboolean
+ide_worker_manager_new_connection_cb (IdeWorkerManager *self,
+                                      GDBusConnection  *connection,
+                                      GDBusServer      *server)
+{
+  GCredentials *credentials;
+  GHashTableIter iter;
+  gpointer key, value;
+  gboolean handled = FALSE;
+
+  g_assert (IDE_IS_WORKER_MANAGER (self));
+  g_assert (G_IS_DBUS_CONNECTION (connection));
+  g_assert (G_IS_DBUS_SERVER (server));
+
+  credentials = g_dbus_connection_get_peer_credentials (connection);
+  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);
+
+  while (g_hash_table_iter_next (&iter, &key, &value))
+    {
+      IdeWorkerProcess *process = value;
+
+      if (ide_worker_process_matches_credentials (process, credentials))
+        {
+          ide_worker_process_set_connection (process, connection);
+          handled = TRUE;
+        }
+    }
+
+  g_mutex_unlock (&self->mutex);
+
+  return handled;
+}
+
+static void
+ide_worker_manager_constructed (GObject *object)
+{
+  IdeWorkerManager *self = (IdeWorkerManager *)object;
+  g_autofree gchar *guid = NULL;
+  g_autofree gchar *address = NULL;
+  g_autofree gchar *tmpdir = NULL;
+  GError *error = NULL;
+
+  g_return_if_fail (IDE_IS_WORKER_MANAGER (self));
+
+  G_OBJECT_CLASS (ide_worker_manager_parent_class)->constructed (object);
+
+  if (g_unix_socket_address_abstract_names_supported ())
+    tmpdir = g_strdup_printf ("%s/gnome-builder-worker-%u",
+                              g_get_tmp_dir (), getpid ());
+  else
+    tmpdir = g_dir_make_tmp ("gnome-builder-worker-XXXXXX", NULL);
+
+  if (tmpdir == NULL)
+    {
+      g_error ("Failed to determine temporary directory for DBus.");
+      exit (EXIT_FAILURE);
+    }
+
+  address = g_strdup_printf ("unix:tmpdir=%s", tmpdir);
+  guid = g_dbus_generate_guid ();
+
+  self->dbus_server = g_dbus_server_new_sync (address,
+                                              G_DBUS_SERVER_FLAGS_NONE,
+                                              guid,
+                                              NULL,
+                                              NULL,
+                                              &error);
+
+  g_signal_connect_object (self->dbus_server,
+                           "new-connection",
+                           G_CALLBACK (ide_worker_manager_new_connection_cb),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  if (error != NULL)
+    {
+      g_printerr ("%s\n", error->message);
+      exit (EXIT_FAILURE);
+    }
+
+  g_assert (self->dbus_server != NULL);
+}
+
+static void
+ide_worker_manager_force_exit_worker (gpointer instance)
+{
+  IdeWorkerProcess *process = instance;
+
+  g_assert (IDE_IS_WORKER_PROCESS (process));
+
+  ide_worker_process_quit (process);
+  g_object_unref (process);
+}
+
+static void
+ide_worker_manager_finalize (GObject *object)
+{
+  IdeWorkerManager *self = (IdeWorkerManager *)object;
+
+  g_clear_pointer (&self->workers_by_plugin_name, g_hash_table_unref);
+  g_clear_object (&self->dbus_server);
+
+  G_OBJECT_CLASS (ide_worker_manager_parent_class)->finalize (object);
+
+  EGG_COUNTER_DEC (instances);
+}
+
+static void
+ide_worker_manager_set_property (GObject      *object,
+                                 guint         prop_id,
+                                 const GValue *value,
+                                 GParamSpec   *pspec)
+{
+  IdeWorkerManager *self = IDE_WORKER_MANAGER (object);
+
+  switch (prop_id)
+    {
+    case PROP_ARGV0:
+      ide_worker_manager_set_argv0 (self, g_value_get_string (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+ide_worker_manager_class_init (IdeWorkerManagerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->constructed = ide_worker_manager_constructed;
+  object_class->finalize = ide_worker_manager_finalize;
+  object_class->set_property = ide_worker_manager_set_property;
+
+  gParamSpecs [PROP_ARGV0] =
+    g_param_spec_string ("argv0",
+                         _("Argv0"),
+                         _("The path to the process to spawn."),
+                         "gnome-builder",
+                         (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, LAST_PROP, gParamSpecs);
+}
+
+static void
+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 =
+    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)
+{
+  IdeWorkerProcess *worker;
+
+  g_return_val_if_fail (IDE_IS_WORKER_MANAGER (self), NULL);
+  g_return_val_if_fail (plugin_name != NULL, NULL);
+
+  g_mutex_lock (&self->mutex);
+
+  worker = g_hash_table_lookup (self->workers_by_plugin_name, plugin_name);
+
+  if (worker == 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);
+    }
+
+  g_mutex_unlock (&self->mutex);
+
+  return ide_worker_process_create_proxy (worker, error);
+}
+
+IdeWorkerManager *
+ide_worker_manager_new (const gchar *argv0)
+{
+  g_return_val_if_fail (argv0 != NULL, NULL);
+
+  return g_object_new (IDE_TYPE_WORKER_MANAGER,
+                       "argv0", argv0,
+                       NULL);
+}
diff --git a/libide/ide-worker-manager.h b/libide/ide-worker-manager.h
new file mode 100644
index 0000000..3ad9faa
--- /dev/null
+++ b/libide/ide-worker-manager.h
@@ -0,0 +1,37 @@
+/* ide-worker-manager.h
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef IDE_WORKER_MANAGER_H
+#define IDE_WORKER_MANAGER_H
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_WORKER_MANAGER (ide_worker_manager_get_type())
+
+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);
+
+G_END_DECLS
+
+#endif /* IDE_WORKER_MANAGER_H */
diff --git a/libide/ide-worker-process.c b/libide/ide-worker-process.c
new file mode 100644
index 0000000..780443a
--- /dev/null
+++ b/libide/ide-worker-process.c
@@ -0,0 +1,364 @@
+/* ide-worker-process.c
+ *
+ * Copyright (C) 2015 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "ide-worker-process"
+
+#include <libpeas/peas.h>
+
+#include "egg-counter.h"
+
+#include "ide-debug.h"
+#include "ide-worker-process.h"
+#include "ide-worker.h"
+
+struct _IdeWorkerProcess
+{
+  GObject          parent_instance;
+
+  gchar           *argv0;
+  gchar           *dbus_address;
+  gchar           *plugin_name;
+  GSubprocess     *subprocess;
+  GDBusConnection *connection;
+
+  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")
+
+enum {
+  PROP_0,
+  PROP_ARGV0,
+  PROP_PLUGIN_NAME,
+  PROP_DBUS_ADDRESS,
+  LAST_PROP
+};
+
+static GParamSpec *gParamSpecs [LAST_PROP];
+
+IdeWorkerProcess *
+ide_worker_process_new (const gchar *argv0,
+                        const gchar *plugin_name,
+                        const gchar *dbus_address)
+{
+  IdeWorkerProcess *ret;
+
+  IDE_ENTRY;
+
+  g_return_val_if_fail (argv0 != NULL, NULL);
+  g_return_val_if_fail (plugin_name != NULL, NULL);
+  g_return_val_if_fail (dbus_address != NULL, NULL);
+
+  ret = g_object_new (IDE_TYPE_WORKER_PROCESS,
+                      "argv0", argv0,
+                      "plugin-name", plugin_name,
+                      "dbus-address", dbus_address,
+                      NULL);
+
+  IDE_RETURN (ret);
+}
+
+static void
+ide_worker_process_wait_check_cb (GObject      *object,
+                                  GAsyncResult *result,
+                                  gpointer      user_data)
+{
+  GSubprocess *subprocess = (GSubprocess *)object;
+  g_autoptr(IdeWorkerProcess) self = user_data;
+  GError *error = NULL;
+
+  IDE_ENTRY;
+
+  g_assert (G_IS_SUBPROCESS (subprocess));
+  g_assert (IDE_IS_WORKER_PROCESS (self));
+  g_assert (G_IS_ASYNC_RESULT (result));
+
+  if (!g_subprocess_wait_check_finish (subprocess, result, &error))
+    g_critical ("%s", error->message);
+
+  g_clear_object (&self->subprocess);
+
+  if (!self->quit)
+    ide_worker_process_respawn (self);
+
+  IDE_EXIT;
+}
+
+static void
+ide_worker_process_respawn (IdeWorkerProcess *self)
+{
+  g_autoptr(GSubprocessLauncher) launcher = NULL;
+  g_autoptr(GSubprocess) subprocess = NULL;
+  g_autofree gchar *type = NULL;
+  g_autofree gchar *dbus_address = NULL;
+  GError *error = NULL;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_WORKER_PROCESS (self));
+  g_assert (self->subprocess == NULL);
+
+  type = g_strdup_printf ("--type=%s", self->plugin_name);
+  dbus_address = g_strdup_printf ("--dbus-address=%s", self->dbus_address);
+
+  launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE);
+  subprocess = g_subprocess_launcher_spawn (launcher, &error, self->argv0, type, dbus_address, NULL);
+
+  if (subprocess == NULL)
+    {
+      g_warning ("Failed to spawn %s", error->message);
+      g_clear_error (&error);
+      IDE_EXIT;
+    }
+
+  self->subprocess = g_object_ref (subprocess);
+
+  g_subprocess_wait_check_async (subprocess,
+                                 NULL,
+                                 ide_worker_process_wait_check_cb,
+                                 g_object_ref (self));
+
+  IDE_EXIT;
+}
+
+void
+ide_worker_process_run (IdeWorkerProcess *self)
+{
+  g_return_if_fail (IDE_IS_WORKER_PROCESS (self));
+  g_return_if_fail (self->subprocess == NULL);
+
+  ide_worker_process_respawn (self);
+}
+
+void
+ide_worker_process_quit (IdeWorkerProcess *self)
+{
+  g_return_if_fail (IDE_IS_WORKER_PROCESS (self));
+
+  self->quit = TRUE;
+
+  if (self->subprocess != NULL)
+    {
+      if (!g_subprocess_get_if_exited (self->subprocess))
+        {
+          g_autoptr(GSubprocess) subprocess = self->subprocess;
+
+          self->subprocess = NULL;
+          g_subprocess_force_exit (subprocess);
+        }
+    }
+}
+
+static void
+ide_worker_process_dispose (GObject *object)
+{
+  IdeWorkerProcess *self = (IdeWorkerProcess *)object;
+
+  if (self->subprocess != NULL)
+    ide_worker_process_quit (self);
+
+  G_OBJECT_CLASS (ide_worker_process_parent_class)->dispose (object);
+}
+
+static void
+ide_worker_process_finalize (GObject *object)
+{
+  IdeWorkerProcess *self = (IdeWorkerProcess *)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_object (&self->connection);
+  g_clear_object (&self->subprocess);
+
+  G_OBJECT_CLASS (ide_worker_process_parent_class)->finalize (object);
+
+  EGG_COUNTER_DEC (instances);
+}
+
+static void
+ide_worker_process_get_property (GObject    *object,
+                                 guint       prop_id,
+                                 GValue     *value,
+                                 GParamSpec *pspec)
+{
+  IdeWorkerProcess *self = IDE_WORKER_PROCESS (object);
+
+  switch (prop_id)
+    {
+    case PROP_ARGV0:
+      g_value_set_string (value, self->argv0);
+      break;
+
+    case PROP_PLUGIN_NAME:
+      g_value_set_string (value, self->plugin_name);
+      break;
+
+    case PROP_DBUS_ADDRESS:
+      g_value_set_string (value, self->dbus_address);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+ide_worker_process_set_property (GObject      *object,
+                                 guint         prop_id,
+                                 const GValue *value,
+                                 GParamSpec   *pspec)
+{
+  IdeWorkerProcess *self = IDE_WORKER_PROCESS (object);
+
+  switch (prop_id)
+    {
+    case PROP_ARGV0:
+      self->argv0 = g_value_dup_string (value);
+      break;
+
+    case PROP_PLUGIN_NAME:
+      self->plugin_name = g_value_dup_string (value);
+      break;
+
+    case PROP_DBUS_ADDRESS:
+      self->dbus_address = g_value_dup_string (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+ide_worker_process_class_init (IdeWorkerProcessClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = ide_worker_process_dispose;
+  object_class->finalize = ide_worker_process_finalize;
+  object_class->get_property = ide_worker_process_get_property;
+  object_class->set_property = ide_worker_process_set_property;
+
+  gParamSpecs [PROP_ARGV0] =
+    g_param_spec_string ("argv0",
+                         "Argv0",
+                         "Argv0",
+                         NULL,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  gParamSpecs [PROP_PLUGIN_NAME] =
+    g_param_spec_string ("plugin-name",
+                         "plugin-name",
+                         "plugin-name",
+                         NULL,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  gParamSpecs [PROP_DBUS_ADDRESS] =
+    g_param_spec_string ("dbus-address",
+                         "dbus-address",
+                         "dbus-address",
+                         NULL,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, LAST_PROP, gParamSpecs);
+}
+
+static void
+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)
+{
+  g_autofree gchar *str = NULL;
+  const gchar *identifier;
+  pid_t pid;
+
+  g_return_val_if_fail (IDE_IS_WORKER_PROCESS (self), FALSE);
+  g_return_val_if_fail (G_IS_CREDENTIALS (credentials), FALSE);
+
+  if ((self->subprocess != NULL) &&
+      (identifier = g_subprocess_get_identifier (self->subprocess)) &&
+      (pid = g_credentials_get_unix_pid (credentials, NULL)))
+    {
+      str = g_strdup_printf ("%d", (int)pid);
+      if (g_strcmp0 (identifier, str) == 0)
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
+void
+ide_worker_process_set_connection (IdeWorkerProcess *self,
+                                   GDBusConnection  *connection)
+{
+  g_return_if_fail (IDE_IS_WORKER_PROCESS (self));
+  g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
+
+  g_set_object (&self->connection, connection);
+}
diff --git a/libide/ide-worker-process.h b/libide/ide-worker-process.h
new file mode 100644
index 0000000..73e3361
--- /dev/null
+++ b/libide/ide-worker-process.h
@@ -0,0 +1,44 @@
+/* ide-worker-process.h
+ *
+ * Copyright (C) 2015 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef IDE_WORKER_PROCESS_H
+#define IDE_WORKER_PROCESS_H
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_WORKER_PROCESS (ide_worker_process_get_type())
+
+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);
+
+G_END_DECLS
+
+#endif /* IDE_WORKER_PROCESS_H */
diff --git a/libide/ide-worker.c b/libide/ide-worker.c
new file mode 100644
index 0000000..ccf456a
--- /dev/null
+++ b/libide/ide-worker.c
@@ -0,0 +1,58 @@
+/* ide-worker.c
+ *
+ * Copyright (C) 2015 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "ide-worker"
+
+#include "ide-worker.h"
+
+G_DEFINE_INTERFACE (IdeWorker, ide_worker, G_TYPE_OBJECT)
+
+static void
+ide_worker_default_init (IdeWorkerInterface *iface)
+{
+}
+
+void
+ide_worker_register_service (IdeWorker       *self,
+                             GDBusConnection *connection)
+{
+  g_return_if_fail (IDE_IS_WORKER (self));
+  g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
+
+  IDE_WORKER_GET_IFACE (self)->register_service (self, connection);
+}
+
+/**
+ * ide_worker_create_proxy:
+ * @self: An #IdeWorker.
+ * @connection: A #GDBusConnection connected to the worker process.
+ *
+ * Creates a new proxy to be connected to the subprocess peer on the other
+ * end of @connection.
+ *
+ * Returns: (transfer full): A #GDBusProxy or %NULL.
+ */
+GDBusProxy *
+ide_worker_create_proxy (IdeWorker       *self,
+                         GDBusConnection *connection)
+{
+  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);
+}
diff --git a/libide/ide-worker.h b/libide/ide-worker.h
new file mode 100644
index 0000000..d44eecf
--- /dev/null
+++ b/libide/ide-worker.h
@@ -0,0 +1,47 @@
+/* ide-worker.h
+ *
+ * Copyright (C) 2015 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef IDE_WORKER_H
+#define IDE_WORKER_H
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_WORKER (ide_worker_get_type ())
+
+G_DECLARE_INTERFACE (IdeWorker, ide_worker, IDE, WORKER, GObject)
+
+struct _IdeWorkerInterface
+{
+  GTypeInterface parent;
+
+  GDBusProxy *(*create_proxy)     (IdeWorker       *self,
+                                   GDBusConnection *connection);
+  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);
+
+G_END_DECLS
+
+#endif /* IDE_WORKER_H */


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