[gnome-builder] libide: use setsid() and kill(-pid, SIGKILL) to kill process group



commit 1aa54dbc1a4bafdea39f5c4e728038c2b1262abb
Author: Christian Hergert <chergert redhat com>
Date:   Mon Feb 15 18:20:58 2016 -0800

    libide: use setsid() and kill(-pid, SIGKILL) to kill process group
    
    We had an issue where "gmake", despite getting SIGKILL, would not cause
    the build process to exit. This seems to be caused by the descendent
    processes not dying with the parent.
    
    To allow us to kill all of the processes, we first create a new session
    group with setsid() in our child setup function. If the process should
    be cancelled (via g_cancellable_cancel()), then we send SIGKILL to all
    members of the session group with kill(-pid, SIGKILL). Specifying a
    negated(pid) indicates delivery to all members of the group.
    
    We probably need to verify that this works on FreeBSD, but it seems
    plausible that will.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=760874

 libide/ide-subprocess-launcher.c |   58 ++++++++++++++++++++++++++++++++++++++
 1 files changed, 58 insertions(+), 0 deletions(-)
---
diff --git a/libide/ide-subprocess-launcher.c b/libide/ide-subprocess-launcher.c
index 345c7bb..052f5dd 100644
--- a/libide/ide-subprocess-launcher.c
+++ b/libide/ide-subprocess-launcher.c
@@ -16,7 +16,10 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <signal.h>
+#include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #include "ide-debug.h"
 #include "ide-environment.h"
@@ -46,6 +49,50 @@ enum {
 
 static GParamSpec *properties [N_PROPS];
 
+static void
+child_setup_func (gpointer data)
+{
+#ifdef G_OS_UNIX
+  /*
+   * TODO: Check on FreeBSD to see if the process group id is the same as
+   *       the owning process. If not, our kill() signal might not work
+   *       as expected.
+   */
+  setsid ();
+#endif
+}
+
+static void
+ide_subprocess_launcher_kill_process_group (GCancellable *cancellable,
+                                            GSubprocess  *subprocess)
+{
+#ifdef G_OS_UNIX
+  const gchar *ident;
+  pid_t pid;
+
+  g_assert (G_IS_CANCELLABLE (cancellable));
+  g_assert (G_IS_SUBPROCESS (subprocess));
+
+  /*
+   * This will send SIGKILL to all processes in the process group that
+   * was created for our subprocess using setsid().
+   */
+
+  if (NULL != (ident = g_subprocess_get_identifier (subprocess)))
+    {
+      g_debug ("Killing process group %s due to cancellation", ident);
+      pid = atoi (ident);
+      kill (-pid, SIGKILL);
+    }
+
+  g_signal_handlers_disconnect_by_func (cancellable,
+                                        G_CALLBACK (ide_subprocess_launcher_kill_process_group),
+                                        subprocess);
+#else
+# error "Your platform is not yet supported"
+#endif
+}
+
 IdeSubprocessLauncher *
 ide_subprocess_launcher_new (GSubprocessFlags flags)
 {
@@ -77,6 +124,7 @@ ide_subprocess_launcher_spawn_worker (GTask        *task,
 #endif
 
   launcher = g_subprocess_launcher_new (priv->flags);
+  g_subprocess_launcher_set_child_setup (launcher, child_setup_func, NULL, NULL);
   g_subprocess_launcher_set_cwd (launcher, priv->cwd);
   if (priv->environ->len > 1)
     g_subprocess_launcher_set_environ (launcher, (gchar **)priv->environ->pdata);
@@ -90,6 +138,16 @@ ide_subprocess_launcher_spawn_worker (GTask        *task,
       return;
     }
 
+  if (cancellable != NULL)
+    {
+      g_signal_connect_data (cancellable,
+                             "cancelled",
+                             G_CALLBACK (ide_subprocess_launcher_kill_process_group),
+                             g_object_ref (ret),
+                             (GClosureNotify)g_object_unref,
+                             0);
+    }
+
   g_task_return_pointer (task, ret, g_object_unref);
 }
 


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