[gnome-builder] subprocess: add main context workarounds for dbus connection



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]