[gnome-builder: 37/139] libide-threading: add new threading static library



commit 884baf7358e75aee5fb11316164368c10153e98d
Author: Christian Hergert <chergert redhat com>
Date:   Wed Jan 9 16:20:27 2019 -0800

    libide-threading: add new threading static library
    
    The new threading static library moves subprocesses and tasks into a
    space to help plugins and Builder-core to manage multi-processing
    features.

 src/libide/subprocess/ide-breakout-subprocess.h    |  26 --
 src/libide/subprocess/meson.build                  |  25 --
 .../ide-flatpak-subprocess-private.h}              |  10 +-
 .../ide-flatpak-subprocess.c}                      | 330 ++++++++++-----------
 src/libide/threading/ide-gtask-private.h           |  37 +++
 src/libide/threading/ide-gtask.c                   | 180 +++++++++++
 .../ide-simple-subprocess-private.h}               |  10 +-
 .../ide-simple-subprocess.c                        |  10 +-
 .../ide-subprocess-launcher.c                      |  52 ++--
 .../ide-subprocess-launcher.h                      |  19 +-
 .../ide-subprocess-supervisor.c                    |   6 +-
 .../ide-subprocess-supervisor.h                    |  10 +-
 .../{subprocess => threading}/ide-subprocess.c     |   5 +-
 .../{subprocess => threading}/ide-subprocess.h     | 121 ++++----
 src/libide/threading/ide-task.c                    |  45 ++-
 src/libide/threading/ide-task.h                    |   8 +-
 src/libide/threading/ide-thread-pool.c             |  21 +-
 src/libide/threading/ide-thread-pool.h             |   9 +-
 src/libide/threading/ide-thread-private.h          |   1 +
 src/libide/threading/libide-threading.h            |  35 +++
 src/libide/threading/meson.build                   |  80 ++++-
 21 files changed, 659 insertions(+), 381 deletions(-)
---
diff --git a/src/libide/subprocess/ide-breakout-subprocess-private.h 
b/src/libide/threading/ide-flatpak-subprocess-private.h
similarity index 85%
rename from src/libide/subprocess/ide-breakout-subprocess-private.h
rename to src/libide/threading/ide-flatpak-subprocess-private.h
index ee414aed3..64628c69b 100644
--- a/src/libide/subprocess/ide-breakout-subprocess-private.h
+++ b/src/libide/threading/ide-flatpak-subprocess-private.h
@@ -1,4 +1,4 @@
-/* ide-breakout-subprocess-private.h
+/* ide-flatpak-subprocess-private.h
  *
  * Copyright 2016-2019 Christian Hergert <chergert redhat com>
  *
@@ -20,17 +20,21 @@
 
 #pragma once
 
-#include "subprocess/ide-breakout-subprocess.h"
+#include "ide-subprocess.h"
 
 G_BEGIN_DECLS
 
+#define IDE_TYPE_FLATPAK_SUBPROCESS (ide_flatpak_subprocess_get_type())
+
+G_DECLARE_FINAL_TYPE (IdeFlatpakSubprocess, ide_flatpak_subprocess, IDE, FLATPAK_SUBPROCESS, GObject)
+
 typedef struct
 {
   gint source_fd;
   gint dest_fd;
 } IdeBreakoutFdMapping;
 
-IdeSubprocess *_ide_breakout_subprocess_new (const gchar                 *cwd,
+IdeSubprocess *_ide_flatpak_subprocess_new (const gchar                 *cwd,
                                              const gchar * const         *argv,
                                              const gchar * const         *env,
                                              GSubprocessFlags             flags,
diff --git a/src/libide/subprocess/ide-breakout-subprocess.c b/src/libide/threading/ide-flatpak-subprocess.c
similarity index 82%
rename from src/libide/subprocess/ide-breakout-subprocess.c
rename to src/libide/threading/ide-flatpak-subprocess.c
index d628397fa..981dc185c 100644
--- a/src/libide/subprocess/ide-breakout-subprocess.c
+++ b/src/libide/threading/ide-flatpak-subprocess.c
@@ -14,31 +14,29 @@
  *          Ryan Lortie <desrt desrt ca>
  *          Alexander Larsson <alexl redhat com>
  *          Christian Hergert <chergert redhat com>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
  */
 
-#define G_LOG_DOMAIN "ide-breakout-subprocess"
+#define G_LOG_DOMAIN "ide-flatpak-subprocess"
 
 #include "config.h"
 
-#include <dazzle.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <gio/gunixinputstream.h>
 #include <gio/gunixoutputstream.h>
 #include <gio/gunixfdlist.h>
 #include <glib-unix.h>
+#include <libide-core.h>
 #include <stdio.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <unistd.h>
 
-#include "ide-debug.h"
-
-#include "application/ide-application.h"
-#include "subprocess/ide-breakout-subprocess.h"
-#include "subprocess/ide-breakout-subprocess-private.h"
-#include "util/ide-glib.h"
+#include "ide-flatpak-subprocess-private.h"
+#include "ide-gtask-private.h"
 
 #ifndef FLATPAK_HOST_COMMAND_FLAGS_CLEAR_ENV
 # define FLATPAK_HOST_COMMAND_FLAGS_CLEAR_ENV (1 << 0)
@@ -53,9 +51,7 @@
  * for all subprocesses so that we can have exit-on-close => false).
  */
 
-DZL_DEFINE_COUNTER (instances, "Subprocess", "HostCommand Instances", "Number of IdeBreakoutSubprocess 
instances")
-
-struct _IdeBreakoutSubprocess
+struct _IdeFlatpakSubprocess
 {
   GObject parent_instance;
 
@@ -172,12 +168,12 @@ enum {
   N_PROPS
 };
 
-static void              ide_breakout_subprocess_sync_complete        (IdeBreakoutSubprocess  *self,
+static void              ide_flatpak_subprocess_sync_complete        (IdeFlatpakSubprocess  *self,
                                                                        GAsyncResult          **result);
-static void              ide_breakout_subprocess_sync_done            (GObject                *object,
+static void              ide_flatpak_subprocess_sync_done            (GObject                *object,
                                                                        GAsyncResult           *result,
                                                                        gpointer                user_data);
-static CommunicateState *ide_breakout_subprocess_communicate_internal (IdeBreakoutSubprocess  *subprocess,
+static CommunicateState *ide_flatpak_subprocess_communicate_internal (IdeFlatpakSubprocess  *subprocess,
                                                                        gboolean                add_nul,
                                                                        GBytes                 *stdin_buf,
                                                                        GCancellable           *cancellable,
@@ -187,54 +183,54 @@ static CommunicateState *ide_breakout_subprocess_communicate_internal (IdeBreako
 static GParamSpec *properties [N_PROPS];
 
 static const gchar *
-ide_breakout_subprocess_get_identifier (IdeSubprocess *subprocess)
+ide_flatpak_subprocess_get_identifier (IdeSubprocess *subprocess)
 {
-  IdeBreakoutSubprocess *self = (IdeBreakoutSubprocess *)subprocess;
+  IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)subprocess;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
 
   return self->identifier;
 }
 
 static GInputStream *
-ide_breakout_subprocess_get_stdout_pipe (IdeSubprocess *subprocess)
+ide_flatpak_subprocess_get_stdout_pipe (IdeSubprocess *subprocess)
 {
-  IdeBreakoutSubprocess *self = (IdeBreakoutSubprocess *)subprocess;
+  IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)subprocess;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
 
   return self->stdout_pipe;
 }
 
 static GInputStream *
-ide_breakout_subprocess_get_stderr_pipe (IdeSubprocess *subprocess)
+ide_flatpak_subprocess_get_stderr_pipe (IdeSubprocess *subprocess)
 {
-  IdeBreakoutSubprocess *self = (IdeBreakoutSubprocess *)subprocess;
+  IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)subprocess;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
 
   return self->stderr_pipe;
 }
 
 static GOutputStream *
-ide_breakout_subprocess_get_stdin_pipe (IdeSubprocess *subprocess)
+ide_flatpak_subprocess_get_stdin_pipe (IdeSubprocess *subprocess)
 {
-  IdeBreakoutSubprocess *self = (IdeBreakoutSubprocess *)subprocess;
+  IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)subprocess;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
 
   return self->stdin_pipe;
 }
 
 static void
-ide_breakout_subprocess_wait_cb (GObject      *object,
+ide_flatpak_subprocess_wait_cb (GObject      *object,
                                  GAsyncResult *result,
                                  gpointer      user_data)
 {
-  IdeBreakoutSubprocess *self = (IdeBreakoutSubprocess *)object;
+  IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)object;
   gboolean *completed = user_data;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
   g_assert (completed != NULL);
 
   ide_subprocess_wait_finish (IDE_SUBPROCESS (self), result, NULL);
@@ -246,13 +242,13 @@ ide_breakout_subprocess_wait_cb (GObject      *object,
 }
 
 static gboolean
-ide_breakout_subprocess_wait (IdeSubprocess  *subprocess,
+ide_flatpak_subprocess_wait (IdeSubprocess  *subprocess,
                               GCancellable   *cancellable,
                               GError        **error)
 {
-  IdeBreakoutSubprocess *self = (IdeBreakoutSubprocess *)subprocess;
+  IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)subprocess;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
 
   g_object_ref (self);
 
@@ -277,7 +273,7 @@ ide_breakout_subprocess_wait (IdeSubprocess  *subprocess,
 
       ide_subprocess_wait_async (IDE_SUBPROCESS (self),
                                  cancellable,
-                                 ide_breakout_subprocess_wait_cb,
+                                 ide_flatpak_subprocess_wait_cb,
                                  &completed);
 
       while (!completed)
@@ -295,20 +291,20 @@ cleanup:
 }
 
 static void
-ide_breakout_subprocess_wait_async (IdeSubprocess       *subprocess,
+ide_flatpak_subprocess_wait_async (IdeSubprocess       *subprocess,
                                     GCancellable        *cancellable,
                                     GAsyncReadyCallback  callback,
                                     gpointer             user_data)
 {
-  IdeBreakoutSubprocess *self = (IdeBreakoutSubprocess *)subprocess;
+  IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)subprocess;
   g_autoptr(GTask) task = NULL;
   g_autoptr(GMutexLocker) locker = NULL;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
   g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
   task = g_task_new (self, cancellable, callback, user_data);
-  g_task_set_source_tag (task, ide_breakout_subprocess_wait_async);
+  g_task_set_source_tag (task, ide_flatpak_subprocess_wait_async);
   g_task_set_priority (task, G_PRIORITY_DEFAULT_IDLE);
 
   locker = g_mutex_locker_new (&self->waiter_mutex);
@@ -323,28 +319,28 @@ ide_breakout_subprocess_wait_async (IdeSubprocess       *subprocess,
 }
 
 static gboolean
-ide_breakout_subprocess_wait_finish (IdeSubprocess  *subprocess,
+ide_flatpak_subprocess_wait_finish (IdeSubprocess  *subprocess,
                                      GAsyncResult   *result,
                                      GError        **error)
 {
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (subprocess));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (subprocess));
   g_assert (G_IS_TASK (result));
 
   return g_task_propagate_boolean (G_TASK (result), error);
 }
 
 static void
-ide_breakout_subprocess_communicate_utf8_async (IdeSubprocess       *subprocess,
+ide_flatpak_subprocess_communicate_utf8_async (IdeSubprocess       *subprocess,
                                                 const char          *stdin_buf,
                                                 GCancellable        *cancellable,
                                                 GAsyncReadyCallback  callback,
                                                 gpointer             user_data)
 {
-  IdeBreakoutSubprocess *self = (IdeBreakoutSubprocess *)subprocess;
+  IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)subprocess;
   g_autoptr(GBytes) stdin_bytes = NULL;
   size_t stdin_buf_len = 0;
 
-  g_return_if_fail (IDE_IS_BREAKOUT_SUBPROCESS (subprocess));
+  g_return_if_fail (IDE_IS_FLATPAK_SUBPROCESS (subprocess));
   g_return_if_fail (stdin_buf == NULL || (self->flags & G_SUBPROCESS_FLAGS_STDIN_PIPE));
   g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
 
@@ -352,7 +348,7 @@ ide_breakout_subprocess_communicate_utf8_async (IdeSubprocess       *subprocess,
     stdin_buf_len = strlen (stdin_buf);
   stdin_bytes = g_bytes_new (stdin_buf, stdin_buf_len);
 
-  ide_breakout_subprocess_communicate_internal (self, TRUE, stdin_bytes, cancellable, callback, user_data);
+  ide_flatpak_subprocess_communicate_internal (self, TRUE, stdin_bytes, cancellable, callback, user_data);
 }
 
 static gboolean
@@ -398,7 +394,7 @@ communicate_result_validate_utf8 (const char            *stream_name,
 }
 
 static gboolean
-ide_breakout_subprocess_communicate_utf8_finish (IdeSubprocess  *subprocess,
+ide_flatpak_subprocess_communicate_utf8_finish (IdeSubprocess  *subprocess,
                                                  GAsyncResult   *result,
                                                  char          **stdout_buf,
                                                  char          **stderr_buf,
@@ -409,7 +405,7 @@ ide_breakout_subprocess_communicate_utf8_finish (IdeSubprocess  *subprocess,
 
   IDE_ENTRY;
 
-  g_return_val_if_fail (IDE_IS_BREAKOUT_SUBPROCESS (subprocess), FALSE);
+  g_return_val_if_fail (IDE_IS_FLATPAK_SUBPROCESS (subprocess), FALSE);
   g_return_val_if_fail (g_task_is_valid (result, subprocess), FALSE);
   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
@@ -434,14 +430,14 @@ ide_breakout_subprocess_communicate_utf8_finish (IdeSubprocess  *subprocess,
 }
 
 static gboolean
-ide_breakout_subprocess_communicate_utf8 (IdeSubprocess  *subprocess,
+ide_flatpak_subprocess_communicate_utf8 (IdeSubprocess  *subprocess,
                                           const char     *stdin_buf,
                                           GCancellable   *cancellable,
                                           char          **stdout_buf,
                                           char          **stderr_buf,
                                           GError        **error)
 {
-  IdeBreakoutSubprocess *self = (IdeBreakoutSubprocess *)subprocess;
+  IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)subprocess;
   g_autoptr(GAsyncResult) result = NULL;
   g_autoptr(GBytes) stdin_bytes = NULL;
   size_t stdin_buf_len = 0;
@@ -449,7 +445,7 @@ ide_breakout_subprocess_communicate_utf8 (IdeSubprocess  *subprocess,
 
   IDE_ENTRY;
 
-  g_return_val_if_fail (IDE_IS_BREAKOUT_SUBPROCESS (subprocess), FALSE);
+  g_return_val_if_fail (IDE_IS_FLATPAK_SUBPROCESS (subprocess), FALSE);
   g_return_val_if_fail (stdin_buf == NULL || (self->flags & G_SUBPROCESS_FLAGS_STDIN_PIPE), FALSE);
   g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
@@ -458,44 +454,44 @@ ide_breakout_subprocess_communicate_utf8 (IdeSubprocess  *subprocess,
     stdin_buf_len = strlen (stdin_buf);
   stdin_bytes = g_bytes_new (stdin_buf, stdin_buf_len);
 
-  ide_breakout_subprocess_communicate_internal (self,
+  ide_flatpak_subprocess_communicate_internal (self,
                                                 TRUE,
                                                 stdin_bytes,
                                                 cancellable,
-                                                ide_breakout_subprocess_sync_done,
+                                                ide_flatpak_subprocess_sync_done,
                                                 &result);
-  ide_breakout_subprocess_sync_complete (self, &result);
+  ide_flatpak_subprocess_sync_complete (self, &result);
   success = ide_subprocess_communicate_utf8_finish (subprocess, result, stdout_buf, stderr_buf, error);
 
   IDE_RETURN (success);
 }
 
 static gboolean
-ide_breakout_subprocess_get_successful (IdeSubprocess *subprocess)
+ide_flatpak_subprocess_get_successful (IdeSubprocess *subprocess)
 {
-  IdeBreakoutSubprocess *self = (IdeBreakoutSubprocess *)subprocess;
+  IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)subprocess;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
 
   return WIFEXITED (self->status) && WEXITSTATUS (self->status) == 0;
 }
 
 static gboolean
-ide_breakout_subprocess_get_if_exited (IdeSubprocess *subprocess)
+ide_flatpak_subprocess_get_if_exited (IdeSubprocess *subprocess)
 {
-  IdeBreakoutSubprocess *self = (IdeBreakoutSubprocess *)subprocess;
+  IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)subprocess;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
 
   return WIFEXITED (self->status);
 }
 
 static gint
-ide_breakout_subprocess_get_exit_status (IdeSubprocess *subprocess)
+ide_flatpak_subprocess_get_exit_status (IdeSubprocess *subprocess)
 {
-  IdeBreakoutSubprocess *self = (IdeBreakoutSubprocess *)subprocess;
+  IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)subprocess;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
   g_assert (self->client_has_exited);
 
   if (!WIFEXITED (self->status))
@@ -505,47 +501,47 @@ ide_breakout_subprocess_get_exit_status (IdeSubprocess *subprocess)
 }
 
 static gboolean
-ide_breakout_subprocess_get_if_signaled (IdeSubprocess *subprocess)
+ide_flatpak_subprocess_get_if_signaled (IdeSubprocess *subprocess)
 {
-  IdeBreakoutSubprocess *self = (IdeBreakoutSubprocess *)subprocess;
+  IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)subprocess;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
   g_assert (self->client_has_exited == TRUE);
 
   return WIFSIGNALED (self->status);
 }
 
 static gint
-ide_breakout_subprocess_get_term_sig (IdeSubprocess *subprocess)
+ide_flatpak_subprocess_get_term_sig (IdeSubprocess *subprocess)
 {
-  IdeBreakoutSubprocess *self = (IdeBreakoutSubprocess *)subprocess;
+  IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)subprocess;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
   g_assert (self->client_has_exited == TRUE);
 
   return WTERMSIG (self->status);
 }
 
 static gint
-ide_breakout_subprocess_get_status (IdeSubprocess *subprocess)
+ide_flatpak_subprocess_get_status (IdeSubprocess *subprocess)
 {
-  IdeBreakoutSubprocess *self = (IdeBreakoutSubprocess *)subprocess;
+  IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)subprocess;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
   g_assert (self->client_has_exited == TRUE);
 
   return self->status;
 }
 
 static void
-ide_breakout_subprocess_send_signal (IdeSubprocess *subprocess,
+ide_flatpak_subprocess_send_signal (IdeSubprocess *subprocess,
                                      gint           signal_num)
 {
-  IdeBreakoutSubprocess *self = (IdeBreakoutSubprocess *)subprocess;
+  IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)subprocess;
 
   IDE_ENTRY;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
 
   /* Signal delivery is not guaranteed, so we can drop this on the floor. */
   if (self->client_has_exited || self->connection == NULL)
@@ -567,15 +563,15 @@ ide_breakout_subprocess_send_signal (IdeSubprocess *subprocess,
 }
 
 static void
-ide_breakout_subprocess_force_exit (IdeSubprocess *subprocess)
+ide_flatpak_subprocess_force_exit (IdeSubprocess *subprocess)
 {
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (subprocess));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (subprocess));
 
-  ide_breakout_subprocess_send_signal (subprocess, SIGKILL);
+  ide_flatpak_subprocess_send_signal (subprocess, SIGKILL);
 }
 
 static void
-ide_breakout_subprocess_sync_complete (IdeBreakoutSubprocess  *self,
+ide_flatpak_subprocess_sync_complete (IdeFlatpakSubprocess  *self,
                                        GAsyncResult          **result)
 {
   g_autoptr(GMainContext) free_me = NULL;
@@ -583,7 +579,7 @@ ide_breakout_subprocess_sync_complete (IdeBreakoutSubprocess  *self,
 
   IDE_ENTRY;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
   g_assert (result != NULL);
   g_assert (*result == NULL || G_IS_ASYNC_RESULT (*result));
 
@@ -606,16 +602,16 @@ ide_breakout_subprocess_sync_complete (IdeBreakoutSubprocess  *self,
 }
 
 static void
-ide_breakout_subprocess_sync_done (GObject      *object,
+ide_flatpak_subprocess_sync_done (GObject      *object,
                                    GAsyncResult *result,
                                    gpointer      user_data)
 {
-  IdeBreakoutSubprocess *self = (IdeBreakoutSubprocess *)object;
+  IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)object;
   GAsyncResult **ret = user_data;
 
   IDE_ENTRY;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
   g_assert (ret != NULL);
   g_assert (*ret == NULL);
   g_assert (G_IS_ASYNC_RESULT (result));
@@ -671,7 +667,7 @@ ide_subprocess_communicate_made_progress (GObject      *source_object,
                                           gpointer      user_data)
 {
   CommunicateState *state;
-  IdeBreakoutSubprocess *subprocess;
+  IdeFlatpakSubprocess *subprocess;
   g_autoptr(GError) error = NULL;
   g_autoptr(GTask) task = user_data;
   gpointer source;
@@ -739,7 +735,7 @@ ide_subprocess_communicate_made_progress (GObject      *source_object,
 }
 
 static CommunicateState *
-ide_breakout_subprocess_communicate_internal (IdeBreakoutSubprocess *subprocess,
+ide_flatpak_subprocess_communicate_internal (IdeFlatpakSubprocess *subprocess,
                                               gboolean               add_nul,
                                               GBytes                *stdin_buf,
                                               GCancellable          *cancellable,
@@ -751,11 +747,11 @@ ide_breakout_subprocess_communicate_internal (IdeBreakoutSubprocess *subprocess,
 
   IDE_ENTRY;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (subprocess));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (subprocess));
   g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
   task = g_task_new (subprocess, cancellable, callback, user_data);
-  g_task_set_source_tag (task, ide_breakout_subprocess_communicate_internal);
+  g_task_set_source_tag (task, ide_flatpak_subprocess_communicate_internal);
   g_task_set_priority (task, G_PRIORITY_DEFAULT_IDLE);
 
   state = g_slice_new0 (CommunicateState);
@@ -816,22 +812,22 @@ ide_breakout_subprocess_communicate_internal (IdeBreakoutSubprocess *subprocess,
 }
 
 static void
-ide_breakout_subprocess_communicate_async (IdeSubprocess       *subprocess,
+ide_flatpak_subprocess_communicate_async (IdeSubprocess       *subprocess,
                                            GBytes              *stdin_buf,
                                            GCancellable        *cancellable,
                                            GAsyncReadyCallback  callback,
                                            gpointer             user_data)
 {
-  IdeBreakoutSubprocess *self = (IdeBreakoutSubprocess *)subprocess;
+  IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)subprocess;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
   g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
-  ide_breakout_subprocess_communicate_internal (self, FALSE, stdin_buf, cancellable, callback, user_data);
+  ide_flatpak_subprocess_communicate_internal (self, FALSE, stdin_buf, cancellable, callback, user_data);
 }
 
 static gboolean
-ide_breakout_subprocess_communicate_finish (IdeSubprocess  *subprocess,
+ide_flatpak_subprocess_communicate_finish (IdeSubprocess  *subprocess,
                                             GAsyncResult   *result,
                                             GBytes        **stdout_buf,
                                             GBytes        **stderr_buf,
@@ -843,7 +839,7 @@ ide_breakout_subprocess_communicate_finish (IdeSubprocess  *subprocess,
 
   IDE_ENTRY;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (subprocess));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (subprocess));
   g_assert (G_IS_TASK (task));
 
   g_object_ref (task);
@@ -873,31 +869,31 @@ ide_breakout_subprocess_communicate_finish (IdeSubprocess  *subprocess,
 }
 
 static gboolean
-ide_breakout_subprocess_communicate (IdeSubprocess  *subprocess,
+ide_flatpak_subprocess_communicate (IdeSubprocess  *subprocess,
                                      GBytes         *stdin_buf,
                                      GCancellable   *cancellable,
                                      GBytes        **stdout_buf,
                                      GBytes        **stderr_buf,
                                      GError        **error)
 {
-  IdeBreakoutSubprocess *self = (IdeBreakoutSubprocess *)subprocess;
+  IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)subprocess;
   g_autoptr(GAsyncResult) result = NULL;
   gboolean ret;
 
   IDE_ENTRY;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
   g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
-  ide_breakout_subprocess_communicate_internal (self,
+  ide_flatpak_subprocess_communicate_internal (self,
                                                 FALSE,
                                                 stdin_buf,
                                                 cancellable,
-                                                ide_breakout_subprocess_sync_done,
+                                                ide_flatpak_subprocess_sync_done,
                                                 &result);
-  ide_breakout_subprocess_sync_complete (self, &result);
+  ide_flatpak_subprocess_sync_complete (self, &result);
 
-  ret = ide_breakout_subprocess_communicate_finish (subprocess, result, stdout_buf, stderr_buf, error);
+  ret = ide_flatpak_subprocess_communicate_finish (subprocess, result, stdout_buf, stderr_buf, error);
 
   IDE_RETURN (ret);
 }
@@ -905,37 +901,37 @@ ide_breakout_subprocess_communicate (IdeSubprocess  *subprocess,
 static void
 subprocess_iface_init (IdeSubprocessInterface *iface)
 {
-  iface->get_identifier = ide_breakout_subprocess_get_identifier;
-  iface->get_stdout_pipe = ide_breakout_subprocess_get_stdout_pipe;
-  iface->get_stderr_pipe = ide_breakout_subprocess_get_stderr_pipe;
-  iface->get_stdin_pipe = ide_breakout_subprocess_get_stdin_pipe;
-  iface->wait = ide_breakout_subprocess_wait;
-  iface->wait_async = ide_breakout_subprocess_wait_async;
-  iface->wait_finish = ide_breakout_subprocess_wait_finish;
-  iface->get_successful = ide_breakout_subprocess_get_successful;
-  iface->get_if_exited = ide_breakout_subprocess_get_if_exited;
-  iface->get_exit_status = ide_breakout_subprocess_get_exit_status;
-  iface->get_if_signaled = ide_breakout_subprocess_get_if_signaled;
-  iface->get_term_sig = ide_breakout_subprocess_get_term_sig;
-  iface->get_status = ide_breakout_subprocess_get_status;
-  iface->send_signal = ide_breakout_subprocess_send_signal;
-  iface->force_exit = ide_breakout_subprocess_force_exit;
-  iface->communicate = ide_breakout_subprocess_communicate;
-  iface->communicate_utf8 = ide_breakout_subprocess_communicate_utf8;
-  iface->communicate_async = ide_breakout_subprocess_communicate_async;
-  iface->communicate_finish = ide_breakout_subprocess_communicate_finish;
-  iface->communicate_utf8_async = ide_breakout_subprocess_communicate_utf8_async;
-  iface->communicate_utf8_finish = ide_breakout_subprocess_communicate_utf8_finish;
+  iface->get_identifier = ide_flatpak_subprocess_get_identifier;
+  iface->get_stdout_pipe = ide_flatpak_subprocess_get_stdout_pipe;
+  iface->get_stderr_pipe = ide_flatpak_subprocess_get_stderr_pipe;
+  iface->get_stdin_pipe = ide_flatpak_subprocess_get_stdin_pipe;
+  iface->wait = ide_flatpak_subprocess_wait;
+  iface->wait_async = ide_flatpak_subprocess_wait_async;
+  iface->wait_finish = ide_flatpak_subprocess_wait_finish;
+  iface->get_successful = ide_flatpak_subprocess_get_successful;
+  iface->get_if_exited = ide_flatpak_subprocess_get_if_exited;
+  iface->get_exit_status = ide_flatpak_subprocess_get_exit_status;
+  iface->get_if_signaled = ide_flatpak_subprocess_get_if_signaled;
+  iface->get_term_sig = ide_flatpak_subprocess_get_term_sig;
+  iface->get_status = ide_flatpak_subprocess_get_status;
+  iface->send_signal = ide_flatpak_subprocess_send_signal;
+  iface->force_exit = ide_flatpak_subprocess_force_exit;
+  iface->communicate = ide_flatpak_subprocess_communicate;
+  iface->communicate_utf8 = ide_flatpak_subprocess_communicate_utf8;
+  iface->communicate_async = ide_flatpak_subprocess_communicate_async;
+  iface->communicate_finish = ide_flatpak_subprocess_communicate_finish;
+  iface->communicate_utf8_async = ide_flatpak_subprocess_communicate_utf8_async;
+  iface->communicate_utf8_finish = ide_flatpak_subprocess_communicate_utf8_finish;
 }
 
 static gboolean
 sigterm_handler (gpointer user_data)
 {
-  IdeBreakoutSubprocess *self = user_data;
+  IdeFlatpakSubprocess *self = user_data;
 
   IDE_ENTRY;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
 
   g_dbus_connection_call_sync (self->connection,
                                "org.freedesktop.Flatpak",
@@ -955,11 +951,11 @@ sigterm_handler (gpointer user_data)
 static gboolean
 sigint_handler (gpointer user_data)
 {
-  IdeBreakoutSubprocess *self = user_data;
+  IdeFlatpakSubprocess *self = user_data;
 
   IDE_ENTRY;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
 
   g_dbus_connection_call_sync (self->connection,
                                "org.freedesktop.Flatpak",
@@ -1031,14 +1027,14 @@ maybe_create_output_stream (GOutputStream **ret,
 }
 
 static void
-ide_breakout_subprocess_complete_command_locked (IdeBreakoutSubprocess *self,
+ide_flatpak_subprocess_complete_command_locked (IdeFlatpakSubprocess *self,
                                                  gint                   exit_status)
 {
   GList *waiting;
 
   IDE_ENTRY;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
   g_assert (G_IS_DBUS_CONNECTION (self->connection));
 
   self->client_has_exited = TRUE;
@@ -1052,8 +1048,8 @@ ide_breakout_subprocess_complete_command_locked (IdeBreakoutSubprocess *self,
   g_clear_pointer (&self->identifier, g_free);
 
   /* Remove our sources used for signal propagation */
-  dzl_clear_source (&self->sigint_id);
-  dzl_clear_source (&self->sigterm_id);
+  g_clear_handle_id (&self->sigint_id, g_source_remove);
+  g_clear_handle_id (&self->sigterm_id, g_source_remove);
 
   /* Complete async workers */
   waiting = g_steal_pointer (&self->waiting);
@@ -1090,8 +1086,8 @@ host_command_exited_cb (GDBusConnection *connection,
                         GVariant        *parameters,
                         gpointer         user_data)
 {
-  g_autoptr(IdeBreakoutSubprocess) finalize_protect = NULL;
-  IdeBreakoutSubprocess *self = user_data;
+  g_autoptr(IdeFlatpakSubprocess) finalize_protect = NULL;
+  IdeFlatpakSubprocess *self = user_data;
   g_autoptr(GMutexLocker) locker = NULL;
   guint32 client_pid = 0;
   guint32 exit_status = 0;
@@ -1099,7 +1095,7 @@ host_command_exited_cb (GDBusConnection *connection,
   IDE_ENTRY;
 
   g_assert (G_IS_DBUS_CONNECTION (connection));
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
 
   finalize_protect = g_object_ref (self);
 
@@ -1124,19 +1120,19 @@ host_command_exited_cb (GDBusConnection *connection,
       self->exited_subscription = 0;
     }
 
-  ide_breakout_subprocess_complete_command_locked (self, exit_status);
+  ide_flatpak_subprocess_complete_command_locked (self, exit_status);
 
   IDE_EXIT;
 }
 
 static void
-ide_breakout_subprocess_cancelled (IdeBreakoutSubprocess *self,
+ide_flatpak_subprocess_cancelled (IdeFlatpakSubprocess *self,
                                    GCancellable          *cancellable)
 {
   IDE_ENTRY;
 
   g_assert (G_IS_CANCELLABLE (cancellable));
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
 
   ide_subprocess_force_exit (IDE_SUBPROCESS (self));
 
@@ -1156,7 +1152,7 @@ maybe_close (gint *fd)
 }
 
 static void
-ide_breakout_subprocess_connection_closed (IdeBreakoutSubprocess *self,
+ide_flatpak_subprocess_connection_closed (IdeFlatpakSubprocess *self,
                                            gboolean               remote_peer_vanished,
                                            const GError          *error,
                                            GDBusConnection       *connection)
@@ -1165,7 +1161,7 @@ ide_breakout_subprocess_connection_closed (IdeBreakoutSubprocess *self,
 
   IDE_ENTRY;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
   g_assert (G_IS_DBUS_CONNECTION (connection));
 
   locker = g_mutex_locker_new (&self->waiter_mutex);
@@ -1173,17 +1169,17 @@ ide_breakout_subprocess_connection_closed (IdeBreakoutSubprocess *self,
   IDE_TRACE_MSG ("Synthesizing failure for client pid %u", (guint)self->client_pid);
 
   self->exited_subscription = 0;
-  ide_breakout_subprocess_complete_command_locked (self, -1);
+  ide_flatpak_subprocess_complete_command_locked (self, -1);
 
   IDE_EXIT;
 }
 
 static gboolean
-ide_breakout_subprocess_initable_init (GInitable     *initable,
+ide_flatpak_subprocess_initable_init (GInitable     *initable,
                                        GCancellable  *cancellable,
                                        GError       **error)
 {
-  IdeBreakoutSubprocess *self = (IdeBreakoutSubprocess *)initable;
+  IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)initable;
   g_autoptr(GVariantBuilder) fd_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{uh}"));
   g_autoptr(GVariantBuilder) env_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{ss}"));
   g_autoptr(GUnixFDList) fd_list = g_unix_fd_list_new ();
@@ -1200,7 +1196,7 @@ ide_breakout_subprocess_initable_init (GInitable     *initable,
 
   IDE_ENTRY;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
   g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
   /*
@@ -1459,7 +1455,7 @@ ide_breakout_subprocess_initable_init (GInitable     *initable,
   self->connection_closed_handler =
     g_signal_connect_object (self->connection,
                              "closed",
-                             G_CALLBACK (ide_breakout_subprocess_connection_closed),
+                             G_CALLBACK (ide_flatpak_subprocess_connection_closed),
                              self,
                              G_CONNECT_SWAPPED);
 
@@ -1512,11 +1508,11 @@ ide_breakout_subprocess_initable_init (GInitable     *initable,
     {
       g_signal_connect_object (cancellable,
                                "cancelled",
-                               G_CALLBACK (ide_breakout_subprocess_cancelled),
+                               G_CALLBACK (ide_flatpak_subprocess_cancelled),
                                self,
                                G_CONNECT_SWAPPED);
       if (g_cancellable_is_cancelled (cancellable) && !self->client_has_exited)
-        ide_breakout_subprocess_force_exit (IDE_SUBPROCESS (self));
+        ide_flatpak_subprocess_force_exit (IDE_SUBPROCESS (self));
     }
 
   ret = TRUE;
@@ -1541,19 +1537,19 @@ cleanup_fds:
 static void
 initiable_iface_init (GInitableIface *iface)
 {
-  iface->init = ide_breakout_subprocess_initable_init;
+  iface->init = ide_flatpak_subprocess_initable_init;
 }
 
-G_DEFINE_TYPE_EXTENDED (IdeBreakoutSubprocess, ide_breakout_subprocess, G_TYPE_OBJECT, 0,
+G_DEFINE_TYPE_EXTENDED (IdeFlatpakSubprocess, ide_flatpak_subprocess, G_TYPE_OBJECT, 0,
                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initiable_iface_init)
                         G_IMPLEMENT_INTERFACE (IDE_TYPE_SUBPROCESS, subprocess_iface_init))
 
 static void
-ide_breakout_subprocess_dispose (GObject *object)
+ide_flatpak_subprocess_dispose (GObject *object)
 {
-  IdeBreakoutSubprocess *self = (IdeBreakoutSubprocess *)object;
+  IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)object;
 
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (self));
 
   if (self->exited_subscription != 0)
     {
@@ -1569,16 +1565,16 @@ ide_breakout_subprocess_dispose (GObject *object)
   if (self->waiting != NULL)
     g_warning ("improper disposal while async operations are active!");
 
-  dzl_clear_source (&self->sigint_id);
-  dzl_clear_source (&self->sigterm_id);
+  g_clear_handle_id (&self->sigint_id, g_source_remove);
+  g_clear_handle_id (&self->sigterm_id, g_source_remove);
 
-  G_OBJECT_CLASS (ide_breakout_subprocess_parent_class)->dispose (object);
+  G_OBJECT_CLASS (ide_flatpak_subprocess_parent_class)->dispose (object);
 }
 
 static void
-ide_breakout_subprocess_finalize (GObject *object)
+ide_flatpak_subprocess_finalize (GObject *object)
 {
-  IdeBreakoutSubprocess *self = (IdeBreakoutSubprocess *)object;
+  IdeFlatpakSubprocess *self = (IdeFlatpakSubprocess *)object;
 
   IDE_ENTRY;
 
@@ -1614,20 +1610,18 @@ ide_breakout_subprocess_finalize (GObject *object)
     close (self->fd_mapping[i].source_fd);
   g_clear_pointer (&self->fd_mapping, g_free);
 
-  G_OBJECT_CLASS (ide_breakout_subprocess_parent_class)->finalize (object);
-
-  DZL_COUNTER_DEC (instances);
+  G_OBJECT_CLASS (ide_flatpak_subprocess_parent_class)->finalize (object);
 
   IDE_EXIT;
 }
 
 static void
-ide_breakout_subprocess_get_property (GObject    *object,
+ide_flatpak_subprocess_get_property (GObject    *object,
                                       guint       prop_id,
                                       GValue     *value,
                                       GParamSpec *pspec)
 {
-  IdeBreakoutSubprocess *self = IDE_BREAKOUT_SUBPROCESS (object);
+  IdeFlatpakSubprocess *self = IDE_FLATPAK_SUBPROCESS (object);
 
   switch (prop_id)
     {
@@ -1653,12 +1647,12 @@ ide_breakout_subprocess_get_property (GObject    *object,
 }
 
 static void
-ide_breakout_subprocess_set_property (GObject      *object,
+ide_flatpak_subprocess_set_property (GObject      *object,
                                       guint         prop_id,
                                       const GValue *value,
                                       GParamSpec   *pspec)
 {
-  IdeBreakoutSubprocess *self = IDE_BREAKOUT_SUBPROCESS (object);
+  IdeFlatpakSubprocess *self = IDE_FLATPAK_SUBPROCESS (object);
 
   switch (prop_id)
     {
@@ -1684,14 +1678,14 @@ ide_breakout_subprocess_set_property (GObject      *object,
 }
 
 static void
-ide_breakout_subprocess_class_init (IdeBreakoutSubprocessClass *klass)
+ide_flatpak_subprocess_class_init (IdeFlatpakSubprocessClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
-  object_class->dispose = ide_breakout_subprocess_dispose;
-  object_class->finalize = ide_breakout_subprocess_finalize;
-  object_class->get_property = ide_breakout_subprocess_get_property;
-  object_class->set_property = ide_breakout_subprocess_set_property;
+  object_class->dispose = ide_flatpak_subprocess_dispose;
+  object_class->finalize = ide_flatpak_subprocess_finalize;
+  object_class->get_property = ide_flatpak_subprocess_get_property;
+  object_class->set_property = ide_flatpak_subprocess_set_property;
 
   properties [PROP_CWD] =
     g_param_spec_string ("cwd",
@@ -1726,12 +1720,10 @@ ide_breakout_subprocess_class_init (IdeBreakoutSubprocessClass *klass)
 }
 
 static void
-ide_breakout_subprocess_init (IdeBreakoutSubprocess *self)
+ide_flatpak_subprocess_init (IdeFlatpakSubprocess *self)
 {
   IDE_ENTRY;
 
-  DZL_COUNTER_INC (instances);
-
   self->stdin_fd = -1;
   self->stdout_fd = -1;
   self->stderr_fd = -1;
@@ -1743,7 +1735,7 @@ ide_breakout_subprocess_init (IdeBreakoutSubprocess *self)
 }
 
 IdeSubprocess *
-_ide_breakout_subprocess_new (const gchar                 *cwd,
+_ide_flatpak_subprocess_new (const gchar                 *cwd,
                               const gchar * const         *argv,
                               const gchar * const         *env,
                               GSubprocessFlags             flags,
@@ -1756,12 +1748,12 @@ _ide_breakout_subprocess_new (const gchar                 *cwd,
                               GCancellable                *cancellable,
                               GError                     **error)
 {
-  g_autoptr(IdeBreakoutSubprocess) ret = NULL;
+  g_autoptr(IdeFlatpakSubprocess) ret = NULL;
 
   g_return_val_if_fail (argv != NULL, NULL);
   g_return_val_if_fail (argv[0] != NULL, NULL);
 
-  ret = g_object_new (IDE_TYPE_BREAKOUT_SUBPROCESS,
+  ret = g_object_new (IDE_TYPE_FLATPAK_SUBPROCESS,
                       "cwd", cwd,
                       "argv", argv,
                       "env", env,
diff --git a/src/libide/threading/ide-gtask-private.h b/src/libide/threading/ide-gtask-private.h
new file mode 100644
index 000000000..006e58759
--- /dev/null
+++ b/src/libide/threading/ide-gtask-private.h
@@ -0,0 +1,37 @@
+/* ide-gtask-private.h
+ *
+ * Copyright 2018-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+void ide_g_task_return_boolean_from_main (GTask          *task,
+                                          gboolean        value);
+void ide_g_task_return_int_from_main     (GTask          *task,
+                                          gint            value);
+void ide_g_task_return_pointer_from_main (GTask          *task,
+                                          gpointer        value,
+                                          GDestroyNotify  notify);
+void ide_g_task_return_error_from_main   (GTask          *task,
+                                          GError         *error);
+
+G_END_DECLS
diff --git a/src/libide/threading/ide-gtask.c b/src/libide/threading/ide-gtask.c
new file mode 100644
index 000000000..4373ab0fa
--- /dev/null
+++ b/src/libide/threading/ide-gtask.c
@@ -0,0 +1,180 @@
+/* ide-gtask.c
+ *
+ * Copyright 2016-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "ide-gtask"
+
+#include "config.h"
+
+#include "ide-gtask-private.h"
+
+typedef struct
+{
+  GType type;
+  GTask *task;
+  union {
+    gboolean v_bool;
+    gint v_int;
+    GError *v_error;
+    struct {
+      gpointer pointer;
+      GDestroyNotify destroy;
+    } v_ptr;
+  } u;
+} TaskState;
+
+static gboolean
+do_return (gpointer user_data)
+{
+  TaskState *state = user_data;
+
+  switch (state->type)
+    {
+    case G_TYPE_INT:
+      g_task_return_int (state->task, state->u.v_int);
+      break;
+
+    case G_TYPE_BOOLEAN:
+      g_task_return_boolean (state->task, state->u.v_bool);
+      break;
+
+    case G_TYPE_POINTER:
+      g_task_return_pointer (state->task, state->u.v_ptr.pointer, state->u.v_ptr.destroy);
+      state->u.v_ptr.pointer = NULL;
+      state->u.v_ptr.destroy = NULL;
+      break;
+
+    default:
+      if (state->type == G_TYPE_ERROR)
+        {
+          g_task_return_error (state->task, g_steal_pointer (&state->u.v_error));
+          break;
+        }
+
+      g_assert_not_reached ();
+    }
+
+  g_clear_object (&state->task);
+  g_slice_free (TaskState, state);
+
+  return G_SOURCE_REMOVE;
+}
+
+static void
+task_state_attach (TaskState *state)
+{
+  GMainContext *main_context;
+  GSource *source;
+
+  g_assert (state != NULL);
+  g_assert (G_IS_TASK (state->task));
+
+  main_context = g_task_get_context (state->task);
+
+  source = g_timeout_source_new (0);
+  g_source_set_callback (source, do_return, state, NULL);
+  g_source_set_name (source, "[ide] ide_g_task_return_from_main");
+  g_source_attach (source, main_context);
+  g_source_unref (source);
+}
+
+/**
+ * ide_g_task_return_boolean_from_main:
+ *
+ * This is just like g_task_return_boolean() except that it enforces
+ * that the current stack return to the main context before dispatching
+ * the callback.
+ *
+ * Since: 3.32
+ */
+void
+ide_g_task_return_boolean_from_main (GTask    *task,
+                                     gboolean  value)
+{
+  TaskState *state;
+
+  g_return_if_fail (G_IS_TASK (task));
+
+  state = g_slice_new0 (TaskState);
+  state->type = G_TYPE_BOOLEAN;
+  state->task = g_object_ref (task);
+  state->u.v_bool = !!value;
+
+  task_state_attach (state);
+}
+
+void
+ide_g_task_return_int_from_main (GTask *task,
+                                 gint   value)
+{
+  TaskState *state;
+
+  g_return_if_fail (G_IS_TASK (task));
+
+  state = g_slice_new0 (TaskState);
+  state->type = G_TYPE_INT;
+  state->task = g_object_ref (task);
+  state->u.v_int = value;
+
+  task_state_attach (state);
+}
+
+void
+ide_g_task_return_pointer_from_main (GTask          *task,
+                                     gpointer        value,
+                                     GDestroyNotify  notify)
+{
+  TaskState *state;
+
+  g_return_if_fail (G_IS_TASK (task));
+
+  state = g_slice_new0 (TaskState);
+  state->type = G_TYPE_POINTER;
+  state->task = g_object_ref (task);
+  state->u.v_ptr.pointer = value;
+  state->u.v_ptr.destroy = notify;
+
+  task_state_attach (state);
+}
+
+/**
+ * ide_g_task_return_error_from_main:
+ * @task: a #GTask
+ * @error: (transfer full): a #GError.
+ *
+ * Like g_task_return_error() but ensures we return to the main loop before
+ * dispatching the result.
+ *
+ * Since: 3.32
+ */
+void
+ide_g_task_return_error_from_main (GTask  *task,
+                                   GError *error)
+{
+  TaskState *state;
+
+  g_return_if_fail (G_IS_TASK (task));
+
+  state = g_slice_new0 (TaskState);
+  state->type = G_TYPE_ERROR;
+  state->task = g_object_ref (task);
+  state->u.v_error = error;
+
+  task_state_attach (state);
+}
diff --git a/src/libide/subprocess/ide-simple-subprocess.h 
b/src/libide/threading/ide-simple-subprocess-private.h
similarity index 87%
rename from src/libide/subprocess/ide-simple-subprocess.h
rename to src/libide/threading/ide-simple-subprocess-private.h
index d53b3040b..e1624830c 100644
--- a/src/libide/subprocess/ide-simple-subprocess.h
+++ b/src/libide/threading/ide-simple-subprocess-private.h
@@ -1,4 +1,4 @@
-/* ide-simple-subprocess.h
+/* ide-simple-subprocess-private.h
  *
  * Copyright 2016-2019 Christian Hergert <chergert redhat com>
  *
@@ -20,7 +20,7 @@
 
 #pragma once
 
-#include "subprocess/ide-subprocess.h"
+#include "ide-subprocess.h"
 
 G_BEGIN_DECLS
 
@@ -28,6 +28,12 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (IdeSimpleSubprocess, ide_simple_subprocess, IDE, SIMPLE_SUBPROCESS, GObject)
 
+struct _IdeSimpleSubprocess
+{
+  GObject      parent_instance;
+  GSubprocess *subprocess;
+};
+
 IdeSubprocess *ide_simple_subprocess_new (GSubprocess *subprocess);
 
 G_END_DECLS
diff --git a/src/libide/subprocess/ide-simple-subprocess.c b/src/libide/threading/ide-simple-subprocess.c
similarity index 98%
rename from src/libide/subprocess/ide-simple-subprocess.c
rename to src/libide/threading/ide-simple-subprocess.c
index 81f99dd77..d6d7a8f92 100644
--- a/src/libide/subprocess/ide-simple-subprocess.c
+++ b/src/libide/threading/ide-simple-subprocess.c
@@ -22,15 +22,9 @@
 
 #include "config.h"
 
-#include "ide-debug.h"
+#include <libide-core.h>
 
-#include "subprocess/ide-simple-subprocess.h"
-
-struct _IdeSimpleSubprocess
-{
-  GObject      parent_instance;
-  GSubprocess *subprocess;
-};
+#include "ide-simple-subprocess-private.h"
 
 static void subprocess_iface_init (IdeSubprocessInterface *iface);
 
diff --git a/src/libide/subprocess/ide-subprocess-launcher.c b/src/libide/threading/ide-subprocess-launcher.c
similarity index 96%
rename from src/libide/subprocess/ide-subprocess-launcher.c
rename to src/libide/threading/ide-subprocess-launcher.c
index 09a08c434..6e7f7aacf 100644
--- a/src/libide/subprocess/ide-subprocess-launcher.c
+++ b/src/libide/threading/ide-subprocess-launcher.c
@@ -22,9 +22,9 @@
 
 #include "config.h"
 
-#include <dazzle.h>
-#include <fcntl.h>
 #include <errno.h>
+#include <fcntl.h>
+#include <libide-core.h>
 #include <signal.h>
 #include <stdlib.h>
 #include <string.h>
@@ -33,15 +33,13 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include "ide-debug.h"
+#include "ide-environment.h"
+#include "ide-environment-variable.h"
+#include "ide-flatpak-subprocess-private.h"
+#include "ide-simple-subprocess-private.h"
+#include "ide-subprocess-launcher.h"
 
-#include "buildsystem/ide-environment-variable.h"
-#include "buildsystem/ide-environment.h"
-#include "subprocess/ide-breakout-subprocess.h"
-#include "subprocess/ide-breakout-subprocess-private.h"
-#include "subprocess/ide-simple-subprocess.h"
-#include "subprocess/ide-subprocess-launcher.h"
-#include "util/ide-flatpak.h"
+#define is_flatpak() (ide_get_process_kind() == IDE_PROCESS_KIND_FLATPAK)
 
 typedef struct
 {
@@ -145,7 +143,7 @@ ide_subprocess_launcher_kill_host_process (GCancellable  *cancellable,
   IDE_ENTRY;
 
   g_assert (G_IS_CANCELLABLE (cancellable));
-  g_assert (IDE_IS_BREAKOUT_SUBPROCESS (subprocess));
+  g_assert (IDE_IS_FLATPAK_SUBPROCESS (subprocess));
 
   g_signal_handlers_disconnect_by_func (cancellable,
                                         G_CALLBACK (ide_subprocess_launcher_kill_host_process),
@@ -165,19 +163,19 @@ ide_subprocess_launcher_new (GSubprocessFlags flags)
 }
 
 static gboolean
-should_use_breakout_process (IdeSubprocessLauncher *self)
+should_use_flatpak_process (IdeSubprocessLauncher *self)
 {
   IdeSubprocessLauncherPrivate *priv = ide_subprocess_launcher_get_instance_private (self);
 
   g_assert (IDE_IS_SUBPROCESS_LAUNCHER (self));
 
-  if (g_getenv ("IDE_USE_BREAKOUT_SUBPROCESS") != NULL)
+  if (g_getenv ("IDE_USE_FLATPAK_SUBPROCESS") != NULL)
     return TRUE;
 
   if (!priv->run_on_host)
     return FALSE;
 
-  return ide_is_flatpak ();
+  return is_flatpak ();
 }
 
 static void
@@ -223,7 +221,7 @@ ide_subprocess_launcher_spawn_host_worker (GTask        *task,
   if (priv->stderr_fd != -1)
     stderr_fd = dup (priv->stderr_fd);
 
-  process = _ide_breakout_subprocess_new (priv->cwd,
+  process = _ide_flatpak_subprocess_new (priv->cwd,
                                           (const gchar * const *)priv->argv->pdata,
                                           (const gchar * const *)priv->environ,
                                           priv->flags,
@@ -383,6 +381,8 @@ ide_subprocess_launcher_real_spawn (IdeSubprocessLauncher  *self,
 {
   IdeSubprocessLauncherPrivate *priv = ide_subprocess_launcher_get_instance_private (self);
   g_autoptr(GTask) task = NULL;
+  IdeSubprocess *ret;
+  GError *local_error = NULL;
 
   g_assert (IDE_IS_SUBPROCESS_LAUNCHER (self));
   g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
@@ -390,7 +390,7 @@ ide_subprocess_launcher_real_spawn (IdeSubprocessLauncher  *self,
   task = g_task_new (self, cancellable, NULL, NULL);
   g_task_set_source_tag (task, ide_subprocess_launcher_real_spawn);
 
-  if (priv->clear_env || (ide_is_flatpak () && priv->run_on_host))
+  if (priv->clear_env || (is_flatpak () && priv->run_on_host))
     {
       /*
        * Many things break without at least PATH, HOME, etc. being set.
@@ -404,12 +404,22 @@ ide_subprocess_launcher_real_spawn (IdeSubprocessLauncher  *self,
       ide_subprocess_launcher_setenv (self, "LANG", g_getenv ("LANG"), FALSE);
     }
 
-  if (should_use_breakout_process (self))
+  if (should_use_flatpak_process (self))
     ide_subprocess_launcher_spawn_host_worker (task, self, NULL, cancellable);
   else
     ide_subprocess_launcher_spawn_worker (task, self, NULL, cancellable);
 
-  return g_task_propagate_pointer (task, error);
+  ret = g_task_propagate_pointer (task, &local_error);
+
+  if (!ret && !local_error)
+    local_error = g_error_new (G_IO_ERROR,
+                               G_IO_ERROR_FAILED,
+                               "An unkonwn error occurred while spawning");
+
+  if (local_error != NULL)
+    g_propagate_error (error, g_steal_pointer (&local_error));
+
+  return g_steal_pointer (&ret);
 }
 
 static void
@@ -724,10 +734,10 @@ ide_subprocess_launcher_set_cwd (IdeSubprocessLauncher *self,
 
   g_return_if_fail (IDE_IS_SUBPROCESS_LAUNCHER (self));
 
-  if (dzl_str_empty0 (cwd))
+  if (ide_str_empty0 (cwd))
     cwd = ".";
 
-  if (!dzl_str_equal0 (priv->cwd, cwd))
+  if (!ide_str_equal0 (priv->cwd, cwd))
     {
       g_free (priv->cwd);
       priv->cwd = g_strdup (cwd);
@@ -766,7 +776,7 @@ ide_subprocess_launcher_overlay_environment (IdeSubprocessLauncher *self,
           key = ide_environment_variable_get_key (var);
           value = ide_environment_variable_get_value (var);
 
-          if (!dzl_str_empty0 (key))
+          if (!ide_str_empty0 (key))
             ide_subprocess_launcher_setenv (self, key, value ?: "", TRUE);
         }
     }
diff --git a/src/libide/subprocess/ide-subprocess-launcher.h b/src/libide/threading/ide-subprocess-launcher.h
similarity index 96%
rename from src/libide/subprocess/ide-subprocess-launcher.h
rename to src/libide/threading/ide-subprocess-launcher.h
index 8e8b41af7..7f64e8780 100644
--- a/src/libide/subprocess/ide-subprocess-launcher.h
+++ b/src/libide/threading/ide-subprocess-launcher.h
@@ -20,11 +20,15 @@
 
 #pragma once
 
-#include <gio/gio.h>
+#if !defined (IDE_THREADING_INSIDE) && !defined (IDE_THREADING_COMPILATION)
+# error "Only <libide-threading.h> can be included directly."
+#endif
 
-#include "ide-version-macros.h"
+#include <gio/gio.h>
+#include <libide-core.h>
 
-#include "ide-types.h"
+#include "ide-subprocess.h"
+#include "ide-environment.h"
 
 G_BEGIN_DECLS
 
@@ -42,14 +46,7 @@ struct _IdeSubprocessLauncherClass
                            GError                **error);
 
   /*< private >*/
-  gpointer _reserved1;
-  gpointer _reserved2;
-  gpointer _reserved3;
-  gpointer _reserved4;
-  gpointer _reserved5;
-  gpointer _reserved6;
-  gpointer _reserved7;
-  gpointer _reserved8;
+  gpointer _reserved[8];
 };
 
 IDE_AVAILABLE_IN_3_32
diff --git a/src/libide/subprocess/ide-subprocess-supervisor.c 
b/src/libide/threading/ide-subprocess-supervisor.c
similarity index 99%
rename from src/libide/subprocess/ide-subprocess-supervisor.c
rename to src/libide/threading/ide-subprocess-supervisor.c
index 1ce55d6f4..d6f72fce5 100644
--- a/src/libide/subprocess/ide-subprocess-supervisor.c
+++ b/src/libide/threading/ide-subprocess-supervisor.c
@@ -22,10 +22,10 @@
 
 #include "config.h"
 
-#include "ide-debug.h"
+#include <libide-core.h>
 
-#include "subprocess/ide-subprocess.h"
-#include "subprocess/ide-subprocess-supervisor.h"
+#include "ide-subprocess.h"
+#include "ide-subprocess-supervisor.h"
 
 /*
  * We will rate limit supervision to once per RATE_LIMIT_THRESHOLD_SECONDS
diff --git a/src/libide/subprocess/ide-subprocess-supervisor.h 
b/src/libide/threading/ide-subprocess-supervisor.h
similarity index 91%
rename from src/libide/subprocess/ide-subprocess-supervisor.h
rename to src/libide/threading/ide-subprocess-supervisor.h
index 80b412f79..7d69349c0 100644
--- a/src/libide/subprocess/ide-subprocess-supervisor.h
+++ b/src/libide/threading/ide-subprocess-supervisor.h
@@ -20,10 +20,14 @@
 
 #pragma once
 
-#include "ide-version-macros.h"
+#if !defined (IDE_THREADING_INSIDE) && !defined (IDE_THREADING_COMPILATION)
+# error "Only <libide-threading.h> can be included directly."
+#endif
 
-#include "subprocess/ide-subprocess.h"
-#include "subprocess/ide-subprocess-launcher.h"
+#include <libide-core.h>
+
+#include "ide-subprocess.h"
+#include "ide-subprocess-launcher.h"
 
 G_BEGIN_DECLS
 
diff --git a/src/libide/subprocess/ide-subprocess.c b/src/libide/threading/ide-subprocess.c
similarity index 99%
rename from src/libide/subprocess/ide-subprocess.c
rename to src/libide/threading/ide-subprocess.c
index eedcb2cda..c2af9c13f 100644
--- a/src/libide/subprocess/ide-subprocess.c
+++ b/src/libide/threading/ide-subprocess.c
@@ -23,10 +23,9 @@
 #include "config.h"
 
 #include <string.h>
+#include <libide-core.h>
 
-#include "ide-debug.h"
-
-#include "subprocess/ide-subprocess.h"
+#include "ide-subprocess.h"
 
 G_DEFINE_INTERFACE (IdeSubprocess, ide_subprocess, G_TYPE_OBJECT)
 
diff --git a/src/libide/subprocess/ide-subprocess.h b/src/libide/threading/ide-subprocess.h
similarity index 56%
rename from src/libide/subprocess/ide-subprocess.h
rename to src/libide/threading/ide-subprocess.h
index 45e65bfd9..583592a88 100644
--- a/src/libide/subprocess/ide-subprocess.h
+++ b/src/libide/threading/ide-subprocess.h
@@ -20,9 +20,12 @@
 
 #pragma once
 
-#include <gio/gio.h>
+#if !defined (IDE_THREADING_INSIDE) && !defined (IDE_THREADING_COMPILATION)
+# error "Only <libide-threading.h> can be included directly."
+#endif
 
-#include "ide-version-macros.h"
+#include <gio/gio.h>
+#include <libide-core.h>
 
 G_BEGIN_DECLS
 
@@ -93,85 +96,85 @@ struct _IdeSubprocessInterface
 };
 
 IDE_AVAILABLE_IN_3_32
-const gchar   *ide_subprocess_get_identifier     (IdeSubprocess *self);
+const gchar   *ide_subprocess_get_identifier          (IdeSubprocess        *self);
 IDE_AVAILABLE_IN_3_32
-GInputStream  *ide_subprocess_get_stdout_pipe    (IdeSubprocess *self);
+GInputStream  *ide_subprocess_get_stdout_pipe         (IdeSubprocess        *self);
 IDE_AVAILABLE_IN_3_32
-GInputStream  *ide_subprocess_get_stderr_pipe    (IdeSubprocess *self);
+GInputStream  *ide_subprocess_get_stderr_pipe         (IdeSubprocess        *self);
 IDE_AVAILABLE_IN_3_32
-GOutputStream *ide_subprocess_get_stdin_pipe     (IdeSubprocess *self);
+GOutputStream *ide_subprocess_get_stdin_pipe          (IdeSubprocess        *self);
 IDE_AVAILABLE_IN_3_32
-gboolean       ide_subprocess_wait               (IdeSubprocess        *self,
-                                                  GCancellable         *cancellable,
-                                                  GError              **error);
+gboolean       ide_subprocess_wait                    (IdeSubprocess        *self,
+                                                       GCancellable         *cancellable,
+                                                       GError              **error);
 IDE_AVAILABLE_IN_3_32
-gboolean       ide_subprocess_wait_check         (IdeSubprocess        *self,
-                                                  GCancellable         *cancellable,
-                                                  GError              **error);
+gboolean       ide_subprocess_wait_check              (IdeSubprocess        *self,
+                                                       GCancellable         *cancellable,
+                                                       GError              **error);
 IDE_AVAILABLE_IN_3_32
-void           ide_subprocess_wait_async         (IdeSubprocess        *self,
-                                                  GCancellable         *cancellable,
-                                                  GAsyncReadyCallback   callback,
-                                                  gpointer              user_data);
+void           ide_subprocess_wait_async              (IdeSubprocess        *self,
+                                                       GCancellable         *cancellable,
+                                                       GAsyncReadyCallback   callback,
+                                                       gpointer              user_data);
 IDE_AVAILABLE_IN_3_32
-gboolean       ide_subprocess_wait_finish        (IdeSubprocess        *self,
-                                                  GAsyncResult         *result,
-                                                  GError              **error);
+gboolean       ide_subprocess_wait_finish             (IdeSubprocess        *self,
+                                                       GAsyncResult         *result,
+                                                       GError              **error);
 IDE_AVAILABLE_IN_3_32
-void           ide_subprocess_wait_check_async   (IdeSubprocess        *self,
-                                                  GCancellable         *cancellable,
-                                                  GAsyncReadyCallback   callback,
-                                                  gpointer              user_data);
+void           ide_subprocess_wait_check_async        (IdeSubprocess        *self,
+                                                       GCancellable         *cancellable,
+                                                       GAsyncReadyCallback   callback,
+                                                       gpointer              user_data);
 IDE_AVAILABLE_IN_3_32
-gboolean       ide_subprocess_wait_check_finish  (IdeSubprocess        *self,
-                                                  GAsyncResult         *result,
-                                                  GError              **error);
+gboolean       ide_subprocess_wait_check_finish       (IdeSubprocess        *self,
+                                                       GAsyncResult         *result,
+                                                       GError              **error);
 IDE_AVAILABLE_IN_3_32
-gboolean       ide_subprocess_check_exit_status  (IdeSubprocess        *self,
-                                                  GError              **error);
+gboolean       ide_subprocess_check_exit_status       (IdeSubprocess        *self,
+                                                       GError              **error);
 IDE_AVAILABLE_IN_3_32
-gboolean       ide_subprocess_get_successful     (IdeSubprocess        *self);
+gboolean       ide_subprocess_get_successful          (IdeSubprocess        *self);
 IDE_AVAILABLE_IN_3_32
-gboolean       ide_subprocess_get_if_exited      (IdeSubprocess        *self);
+gboolean       ide_subprocess_get_if_exited           (IdeSubprocess        *self);
 IDE_AVAILABLE_IN_3_32
-gint           ide_subprocess_get_exit_status    (IdeSubprocess        *self);
+gint           ide_subprocess_get_exit_status         (IdeSubprocess        *self);
 IDE_AVAILABLE_IN_3_32
-gboolean       ide_subprocess_get_if_signaled    (IdeSubprocess        *self);
+gboolean       ide_subprocess_get_if_signaled         (IdeSubprocess        *self);
 IDE_AVAILABLE_IN_3_32
-gint           ide_subprocess_get_term_sig       (IdeSubprocess        *self);
+gint           ide_subprocess_get_term_sig            (IdeSubprocess        *self);
 IDE_AVAILABLE_IN_3_32
-gint           ide_subprocess_get_status         (IdeSubprocess        *self);
+gint           ide_subprocess_get_status              (IdeSubprocess        *self);
 IDE_AVAILABLE_IN_3_32
-void           ide_subprocess_send_signal        (IdeSubprocess        *self,
-                                                  gint                  signal_num);
+void           ide_subprocess_send_signal             (IdeSubprocess        *self,
+                                                       gint                  signal_num);
 IDE_AVAILABLE_IN_3_32
-void           ide_subprocess_force_exit         (IdeSubprocess        *self);
+void           ide_subprocess_force_exit              (IdeSubprocess        *self);
 IDE_AVAILABLE_IN_3_32
-gboolean       ide_subprocess_communicate        (IdeSubprocess        *self,
-                                                  GBytes               *stdin_buf,
-                                                  GCancellable         *cancellable,
-                                                  GBytes              **stdout_buf,
-                                                  GBytes              **stderr_buf,
-                                                  GError              **error);
+gboolean       ide_subprocess_communicate             (IdeSubprocess        *self,
+                                                       GBytes               *stdin_buf,
+                                                       GCancellable         *cancellable,
+                                                       GBytes              **stdout_buf,
+                                                       GBytes              **stderr_buf,
+                                                       GError              **error);
 IDE_AVAILABLE_IN_3_32
-gboolean       ide_subprocess_communicate_utf8   (IdeSubprocess        *self,
-                                                  const gchar          *stdin_buf,
-                                                  GCancellable         *cancellable,
-                                                  gchar               **stdout_buf,
-                                                  gchar               **stderr_buf,
-                                                  GError              **error);
+gboolean       ide_subprocess_communicate_utf8        (IdeSubprocess        *self,
+                                                       const gchar          *stdin_buf,
+                                                       GCancellable         *cancellable,
+                                                       gchar               **stdout_buf,
+                                                       gchar               **stderr_buf,
+                                                       GError              **error);
 IDE_AVAILABLE_IN_3_32
-void           ide_subprocess_communicate_async  (IdeSubprocess        *self,
-                                                  GBytes               *stdin_buf,
-                                                  GCancellable         *cancellable,
-                                                  GAsyncReadyCallback   callback,
-                                                  gpointer              user_data);
+void           ide_subprocess_communicate_async       (IdeSubprocess        *self,
+                                                       GBytes               *stdin_buf,
+                                                       GCancellable         *cancellable,
+                                                       GAsyncReadyCallback   callback,
+                                                       gpointer              user_data);
 IDE_AVAILABLE_IN_3_32
-gboolean       ide_subprocess_communicate_finish (IdeSubprocess        *self,
-                                                  GAsyncResult         *result,
-                                                  GBytes              **stdout_buf,
-                                                  GBytes              **stderr_buf,
-                                                  GError              **error);
+gboolean       ide_subprocess_communicate_finish      (IdeSubprocess        *self,
+                                                       GAsyncResult         *result,
+                                                       GBytes              **stdout_buf,
+                                                       GBytes              **stderr_buf,
+                                                       GError              **error);
 IDE_AVAILABLE_IN_3_32
 void           ide_subprocess_communicate_utf8_async  (IdeSubprocess        *self,
                                                        const gchar          *stdin_buf,
diff --git a/src/libide/threading/ide-task.c b/src/libide/threading/ide-task.c
index 185c92361..f32ebc460 100644
--- a/src/libide/threading/ide-task.c
+++ b/src/libide/threading/ide-task.c
@@ -21,11 +21,18 @@
 
 #include "config.h"
 
-#include <dazzle.h>
+#include <libide-core.h>
 
-#include "threading/ide-task.h"
-#include "threading/ide-thread-pool.h"
-#include "threading/ide-thread-private.h"
+#include "ide-task.h"
+#include "ide-thread-pool.h"
+#include "ide-thread-private.h"
+
+/* From GDK_PRIORITY_REDRAW */
+#define PRIORITY_REDRAW (G_PRIORITY_HIGH_IDLE + 20)
+
+#if 0
+# define ENABLE_TIME_CHART
+#endif
 
 /**
  * SECTION:ide-task
@@ -237,6 +244,11 @@ typedef struct
    */
   gpointer source_tag;
 
+#ifdef ENABLE_TIME_CHART
+  /* The time the task was created */
+  gint64 begin_time;
+#endif
+
   /*
    * Our priority for scheduling tasks in the particular workqueue.
    */
@@ -320,8 +332,6 @@ static void     ide_task_release        (IdeTask           *self,
 G_DEFINE_AUTOPTR_CLEANUP_FUNC (IdeTaskData, ide_task_data_free);
 G_DEFINE_AUTOPTR_CLEANUP_FUNC (IdeTaskResult, ide_task_result_free);
 
-DZL_DEFINE_COUNTER (instances, "Tasks", "Instances", "Number of active tasks")
-
 G_DEFINE_TYPE_WITH_CODE (IdeTask, ide_task, G_TYPE_OBJECT,
                          G_ADD_PRIVATE (IdeTask)
                          G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_RESULT, async_result_init_iface))
@@ -623,8 +633,6 @@ ide_task_finalize (GObject *object)
   g_mutex_clear (&priv->mutex);
 
   G_OBJECT_CLASS (ide_task_parent_class)->finalize (object);
-
-  DZL_COUNTER_DEC (instances);
 }
 
 static void
@@ -676,14 +684,12 @@ ide_task_init (IdeTask *self)
 {
   IdeTaskPrivate *priv = ide_task_get_instance_private (self);
 
-  DZL_COUNTER_INC (instances);
-
   g_mutex_init (&priv->mutex);
 
   priv->check_cancellable = TRUE;
   priv->release_on_propagate = TRUE;
   priv->priority = G_PRIORITY_DEFAULT;
-  priv->complete_priority = GDK_PRIORITY_REDRAW + 1;
+  priv->complete_priority = PRIORITY_REDRAW + 1;
   priv->main_context = g_main_context_ref_thread_default ();
   priv->global_link.data = self;
 
@@ -764,13 +770,16 @@ IdeTask *
   priv->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
   priv->callback = callback;
   priv->user_data = user_data;
+#ifdef ENABLE_TIME_CHART
+  priv->begin_time = g_get_monotonic_time ();
+#endif
 
   return g_steal_pointer (&self);
 }
 
 /**
  * ide_task_is_valid:
- * @self: (nullable) (type Ide.Task): a #IdeTask
+ * @self: (nullable) (type IdeTask): a #IdeTask
  * @source_object: (nullable): a #GObject or %NULL
  *
  * Checks if @source_object matches the object the task was created with.
@@ -979,6 +988,12 @@ ide_task_return_cb (gpointer user_data)
   self = g_steal_pointer (&result->task);
   priv = ide_task_get_instance_private (self);
 
+#ifdef ENABLE_TIME_CHART
+  g_message ("TASK-END: %s: duration=%lf",
+             priv->name,
+             (g_get_monotonic_time () - priv->begin_time) / (gdouble)G_USEC_PER_SEC);
+#endif
+
   g_mutex_lock (&priv->mutex);
 
   g_assert (priv->return_source != 0);
@@ -2061,6 +2076,10 @@ ide_task_set_name (IdeTask *self,
   g_mutex_lock (&priv->mutex);
   priv->name = name;
   g_mutex_unlock (&priv->mutex);
+
+#ifdef ENABLE_TIME_CHART
+  g_message ("TASK-BEGIN: %s", name);
+#endif
 }
 
 /**
@@ -2132,7 +2151,7 @@ async_result_init_iface (GAsyncResultIface *iface)
 }
 
 void
-ide_dump_tasks (void)
+_ide_dump_tasks (void)
 {
   guint i = 0;
 
diff --git a/src/libide/threading/ide-task.h b/src/libide/threading/ide-task.h
index fe6d939b4..b424edad7 100644
--- a/src/libide/threading/ide-task.h
+++ b/src/libide/threading/ide-task.h
@@ -19,9 +19,11 @@
 
 #pragma once
 
-#include <gio/gio.h>
+#if !defined (IDE_THREADING_INSIDE) && !defined (IDE_THREADING_COMPILATION)
+# error "Only <libide-threading.h> can be included directly."
+#endif
 
-#include "ide-version-macros.h"
+#include <gio/gio.h>
 
 G_BEGIN_DECLS
 
@@ -167,8 +169,6 @@ void          ide_task_report_new_error          (gpointer              source_o
                                                   gint                  code,
                                                   const gchar          *format,
                                                   ...) G_GNUC_PRINTF (7, 8);
-IDE_AVAILABLE_IN_3_32
-void          ide_dump_tasks                     (void);
 
 #ifdef __GNUC__
 # define ide_task_new(self, cancellable, callback, user_data)                      \
diff --git a/src/libide/threading/ide-thread-pool.c b/src/libide/threading/ide-thread-pool.c
index 934d18f26..d21579b9d 100644
--- a/src/libide/threading/ide-thread-pool.c
+++ b/src/libide/threading/ide-thread-pool.c
@@ -22,12 +22,10 @@
 
 #include "config.h"
 
-#include <dazzle.h>
+#include <libide-core.h>
 
-#include "ide-debug.h"
-
-#include "threading/ide-thread-pool.h"
-#include "threading/ide-thread-private.h"
+#include "ide-thread-pool.h"
+#include "ide-thread-private.h"
 
 typedef struct
 {
@@ -54,9 +52,6 @@ struct _IdeThreadPool
   gboolean           exclusive;
 };
 
-DZL_DEFINE_COUNTER (TotalTasks, "ThreadPool", "Total Tasks", "Total number of tasks processed.")
-DZL_DEFINE_COUNTER (QueuedTasks, "ThreadPool", "Queued Tasks", "Current number of pending tasks.")
-
 static IdeThreadPool thread_pools[] = {
   { NULL, IDE_THREAD_POOL_DEFAULT, 10, 1, FALSE },
   { NULL, IDE_THREAD_POOL_COMPILER, 2, 2, FALSE },
@@ -105,8 +100,6 @@ ide_thread_pool_push_task (IdeThreadPoolKind  kind,
   g_return_if_fail (G_IS_TASK (task));
   g_return_if_fail (func != NULL);
 
-  DZL_COUNTER_INC (TotalTasks);
-
   pool = ide_thread_pool_get_pool (kind);
 
   if (pool != NULL)
@@ -119,8 +112,6 @@ ide_thread_pool_push_task (IdeThreadPoolKind  kind,
       work_item->task.task = g_object_ref (task);
       work_item->task.func = func;
 
-      DZL_COUNTER_INC (QueuedTasks);
-
       g_thread_pool_push (pool, work_item, NULL);
     }
   else
@@ -174,8 +165,6 @@ ide_thread_pool_push_with_priority (IdeThreadPoolKind kind,
   g_return_if_fail (kind < IDE_THREAD_POOL_LAST);
   g_return_if_fail (func != NULL);
 
-  DZL_COUNTER_INC (TotalTasks);
-
   pool = ide_thread_pool_get_pool (kind);
 
   if (pool != NULL)
@@ -188,8 +177,6 @@ ide_thread_pool_push_with_priority (IdeThreadPoolKind kind,
       work_item->func.callback = func;
       work_item->func.data = func_data;
 
-      DZL_COUNTER_INC (QueuedTasks);
-
       g_thread_pool_push (pool, work_item, NULL);
     }
   else
@@ -208,8 +195,6 @@ ide_thread_pool_worker (gpointer data,
 
   g_assert (work_item != NULL);
 
-  DZL_COUNTER_DEC (QueuedTasks);
-
   if (work_item->type == TYPE_TASK)
     {
       gpointer source_object = g_task_get_source_object (work_item->task.task);
diff --git a/src/libide/threading/ide-thread-pool.h b/src/libide/threading/ide-thread-pool.h
index 0b2fa6016..2bc9bb99e 100644
--- a/src/libide/threading/ide-thread-pool.h
+++ b/src/libide/threading/ide-thread-pool.h
@@ -20,9 +20,12 @@
 
 #pragma once
 
-#include <gio/gio.h>
+#if !defined (IDE_THREADING_INSIDE) && !defined (IDE_THREADING_COMPILATION)
+# error "Only <libide-threading.h> can be included directly."
+#endif
 
-#include "ide-version-macros.h"
+#include <gio/gio.h>
+#include <libide-core.h>
 
 G_BEGIN_DECLS
 
@@ -41,6 +44,8 @@ typedef enum
  * IdeThreadFunc:
  * @user_data: (closure) (transfer full): The closure for the callback.
  *
+ *
+ * Since: 3.32
  */
 typedef void (*IdeThreadFunc) (gpointer user_data);
 
diff --git a/src/libide/threading/ide-thread-private.h b/src/libide/threading/ide-thread-private.h
index ca416a5a9..defe1fc7d 100644
--- a/src/libide/threading/ide-thread-private.h
+++ b/src/libide/threading/ide-thread-private.h
@@ -25,5 +25,6 @@
 G_BEGIN_DECLS
 
 void _ide_thread_pool_init (gboolean is_worker);
+void _ide_dump_tasks       (void);
 
 G_END_DECLS
diff --git a/src/libide/threading/libide-threading.h b/src/libide/threading/libide-threading.h
new file mode 100644
index 000000000..b321f06ab
--- /dev/null
+++ b/src/libide/threading/libide-threading.h
@@ -0,0 +1,35 @@
+/* ide-threading.h
+ *
+ * Copyright 2018-2019 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <libide-core.h>
+
+#define IDE_THREADING_INSIDE
+
+#include "ide-environment.h"
+#include "ide-environment-variable.h"
+#include "ide-subprocess-launcher.h"
+#include "ide-subprocess-supervisor.h"
+#include "ide-subprocess.h"
+#include "ide-task.h"
+#include "ide-thread-pool.h"
+
+#undef IDE_THREADING_INSIDE
diff --git a/src/libide/threading/meson.build b/src/libide/threading/meson.build
index 201e188e0..d38ddfb64 100644
--- a/src/libide/threading/meson.build
+++ b/src/libide/threading/meson.build
@@ -1,20 +1,78 @@
-threading_headers = [
-  'ide-thread-pool.h',
+libide_threading_header_subdir = join_paths(libide_header_subdir, 'threading')
+libide_include_directories += include_directories('.')
+
+#
+# Public API Headers
+#
+
+libide_threading_public_headers = [
+  'ide-environment.h',
+  'ide-environment-variable.h',
+  'ide-subprocess.h',
+  'ide-subprocess-launcher.h',
+  'ide-subprocess-supervisor.h',
   'ide-task.h',
+  'ide-thread-pool.h',
+  'libide-threading.h',
 ]
 
-threading_sources = [
-  'ide-thread-pool.c',
+install_headers(libide_threading_public_headers, subdir: libide_threading_header_subdir)
+
+#
+# Sources
+#
+
+libide_threading_private_headers = [
+  'ide-thread-private.h',
+  'ide-flatpak-subprocess-private.h',
+  'ide-gtask-private.h',
+  'ide-simple-subprocess-private.h',
+]
+
+libide_threading_private_sources = [
+  'ide-flatpak-subprocess.c',
+  'ide-simple-subprocess.c',
+]
+
+libide_threading_public_sources = [
+  'ide-environment-variable.c',
+  'ide-environment.c',
+  'ide-gtask.c',
+  'ide-subprocess-launcher.c',
+  'ide-subprocess-supervisor.c',
+  'ide-subprocess.c',
   'ide-task.c',
+  'ide-thread-pool.c',
 ]
 
-threading_enums = [
-  'ide-thread-pool.h',
-  'ide-task.h',
+libide_threading_sources = libide_threading_public_sources + libide_threading_private_sources
+
+#
+# Library Definitions
+#
+
+libide_threading_deps = [
+  libgio_dep,
+  libgiounix_dep,
+
+  libide_core_dep,
 ]
 
-libide_public_headers += files(threading_headers)
-libide_public_sources += files(threading_sources)
-libide_enum_headers += files(threading_enums)
+libide_threading = static_library('ide-threading-' + libide_api_version, libide_threading_sources,
+   dependencies: libide_threading_deps,
+         c_args: libide_args + release_args + ['-DIDE_THREADING_COMPILATION'],
+)
+
+libide_threading_dep = declare_dependency(
+              sources: libide_threading_private_headers,
+         dependencies: libide_threading_deps,
+           link_whole: libide_threading,
+  include_directories: include_directories('.'),
+)
 
-install_headers(threading_headers, subdir: join_paths(libide_header_subdir, 'threading'))
+gnome_builder_public_sources += files(libide_threading_public_sources)
+gnome_builder_public_headers += files(libide_threading_public_headers)
+gnome_builder_private_sources += files(libide_threading_private_sources)
+gnome_builder_private_headers += files(libide_threading_private_headers)
+gnome_builder_include_subdirs += libide_threading_header_subdir
+gnome_builder_gir_extra_args += ['--c-include=libide-threading.h', '-DIDE_THREADING_COMPILATION']


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