[gnome-builder] subprocess: add main context workarounds for dbus connection
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] subprocess: add main context workarounds for dbus connection
- Date: Wed, 14 Sep 2016 02:24:44 +0000 (UTC)
commit c7fbd48fcd3e47d16950da62076b2c512d48d132
Author: Christian Hergert <chergert redhat com>
Date: Tue Sep 13 19:24:35 2016 -0700
subprocess: add main context workarounds for dbus connection
We need to ensure the main context for the connection is progressed when
communicating so we can get the closed or HostCommandExited signals.
libide/subprocess/ide-breakout-subprocess.c | 55 ++++++++++++++++++++-------
1 files changed, 41 insertions(+), 14 deletions(-)
---
diff --git a/libide/subprocess/ide-breakout-subprocess.c b/libide/subprocess/ide-breakout-subprocess.c
index 1d1aa8b..5c67ccc 100644
--- a/libide/subprocess/ide-breakout-subprocess.c
+++ b/libide/subprocess/ide-breakout-subprocess.c
@@ -64,6 +64,9 @@ struct _IdeBreakoutSubprocess
GSubprocessFlags flags;
+ /* No reference */
+ GThread *spawn_thread;
+
gchar **argv;
gchar **env;
gchar *cwd;
@@ -74,6 +77,8 @@ struct _IdeBreakoutSubprocess
GInputStream *stdout_pipe;
GInputStream *stderr_pipe;
+ GMainContext *main_context;
+
guint sigint_id;
guint sigterm_id;
guint exited_subscription;
@@ -158,7 +163,8 @@ enum {
};
static void ide_breakout_subprocess_sync_setup (void);
-static void ide_breakout_subprocess_sync_complete (GAsyncResult **result);
+static void ide_breakout_subprocess_sync_complete (IdeBreakoutSubprocess *self,
+ GAsyncResult **result);
static void ide_breakout_subprocess_sync_done (GObject *object,
GAsyncResult *result,
gpointer user_data);
@@ -392,7 +398,7 @@ ide_breakout_subprocess_communicate_utf8 (IdeSubprocess *subprocess,
cancellable,
ide_breakout_subprocess_sync_done,
&result);
- ide_breakout_subprocess_sync_complete (&result);
+ ide_breakout_subprocess_sync_complete (self, &result);
success = ide_subprocess_communicate_utf8_finish (subprocess, result, stdout_buf, stderr_buf, error);
IDE_RETURN (success);
@@ -508,26 +514,21 @@ ide_breakout_subprocess_force_exit (IdeSubprocess *subprocess)
static void
ide_breakout_subprocess_sync_setup (void)
{
- if (IDE_IS_MAIN_THREAD ())
- g_main_context_push_thread_default (g_main_context_ref (g_main_context_default ()));
- else
- g_main_context_push_thread_default (g_main_context_new ());
}
static void
-ide_breakout_subprocess_sync_complete (GAsyncResult **result)
+ide_breakout_subprocess_sync_complete (IdeBreakoutSubprocess *self,
+ GAsyncResult **result)
{
- GMainContext *context = g_main_context_get_thread_default ();
-
IDE_ENTRY;
+ g_assert (IDE_IS_BREAKOUT_SUBPROCESS (self));
+ g_assert (self->main_context != NULL);
g_assert (result != NULL);
g_assert (*result == NULL || G_IS_ASYNC_RESULT (*result));
while (*result == NULL)
- g_main_context_iteration (context, TRUE);
- g_main_context_pop_thread_default (context);
- g_main_context_unref (context);
+ g_main_context_iteration (self->main_context, TRUE);
IDE_EXIT;
}
@@ -675,6 +676,7 @@ ide_breakout_subprocess_communicate_internal (IdeBreakoutSubprocess *subprocess,
IDE_ENTRY;
g_assert (IDE_IS_BREAKOUT_SUBPROCESS (subprocess));
+ g_assert (subprocess->main_context != NULL);
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
task = g_task_new (subprocess, cancellable, callback, user_data);
@@ -686,12 +688,23 @@ ide_breakout_subprocess_communicate_internal (IdeBreakoutSubprocess *subprocess,
state->cancellable = g_cancellable_new ();
state->add_nul = add_nul;
+ /*
+ * If we are running from another thread than we were spawned, then we need
+ * to iterate another main context than the context that will be completing
+ * the GDBusConnection signals.
+ */
+ if (g_thread_self () != subprocess->spawn_thread)
+ {
+ g_clear_pointer (&subprocess->main_context, g_main_context_unref);
+ subprocess->main_context = g_main_context_new ();
+ }
+
if (cancellable)
{
state->cancellable_source = g_cancellable_source_new (cancellable);
/* No ref held here, but we unref the source from state's free function */
g_source_set_callback (state->cancellable_source, ide_subprocess_communicate_cancelled, state, NULL);
- g_source_attach (state->cancellable_source, g_main_context_get_thread_default ());
+ g_source_attach (state->cancellable_source, subprocess->main_context);
}
if (subprocess->stdin_pipe)
@@ -810,7 +823,7 @@ ide_breakout_subprocess_communicate (IdeSubprocess *subprocess,
cancellable,
ide_breakout_subprocess_sync_done,
&result);
- ide_breakout_subprocess_sync_complete (&result);
+ ide_breakout_subprocess_sync_complete (self, &result);
ret = ide_breakout_subprocess_communicate_finish (subprocess, result, stdout_buf, stderr_buf, error);
@@ -1099,6 +1112,7 @@ ide_breakout_subprocess_initable_init (GInitable *initable,
g_autoptr(GUnixFDList) fd_list = g_unix_fd_list_new ();
g_autoptr(GVariant) reply = NULL;
g_autoptr(GVariant) params = NULL;
+ GMainContext *main_context;
guint32 client_pid = 0;
gint stdout_pair[2] = { -1, -1 };
gint stderr_pair[2] = { -1, -1 };
@@ -1114,6 +1128,18 @@ ide_breakout_subprocess_initable_init (GInitable *initable,
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
/*
+ * We need to know the GMainContext that the GDBusConnection will use because
+ * we have to pump it if we are doing ide_breakout_subprocess_communicate()
+ * from the same thread. If we communicate from another thread, we will just
+ * iterate another main context until we complete.
+ */
+ self->spawn_thread = g_thread_self ();
+ if (NULL == (main_context = g_main_context_get_thread_default ()))
+ self->main_context = g_main_context_ref (g_main_context_default ());
+ else
+ self->main_context = g_main_context_ref (main_context);
+
+ /*
* FIXME:
*
* Because we are seeing a rather difficult to track down bug where we lose
@@ -1459,6 +1485,7 @@ ide_breakout_subprocess_finalize (GObject *object)
g_clear_pointer (&self->cwd, g_free);
g_clear_pointer (&self->argv, g_strfreev);
g_clear_pointer (&self->env, g_strfreev);
+ g_clear_pointer (&self->main_context, g_main_context_unref);
g_clear_object (&self->stdin_pipe);
g_clear_object (&self->stdout_pipe);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]