[vte] lib: Ressurrect the reaper
- From: Christian Persch <chpe src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vte] lib: Ressurrect the reaper
- Date: Sun, 8 Jan 2017 12:39:56 +0000 (UTC)
commit b9b928a84559ea9eab5f415513d374f067b9847a
Author: Christian Persch <chpe gnome org>
Date: Sun Jan 8 13:39:24 2017 +0100
lib: Ressurrect the reaper
Bring back the reaper as an internal-only thing. This makes
for cleaner code when we need to reap a child process without
a VteTerminalPrivate around.
This reverts commit de112fd8039ab6244e2cf53dbacdfc4a49504c48.
src/Makefile.am | 14 +++
src/reaper.cc | 227 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/reaper.hh | 30 +++++++
src/vte.cc | 60 ++++++++------
src/vtegtk.cc | 12 ++-
src/vteinternal.hh | 3 +-
6 files changed, 318 insertions(+), 28 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 8d72475..da6c5d7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -57,6 +57,8 @@ libvte_@VTE_API_MAJOR_VERSION@_@VTE_API_MINOR_VERSION@_la_SOURCES = \
matcher.cc \
matcher.h \
pty.cc \
+ reaper.cc \
+ reaper.hh \
ring.cc \
ring.h \
table.cc \
@@ -332,6 +334,7 @@ EXTRA_DIST += $(noinst_SCRIPTS)
check_PROGRAMS = \
dumpkeys \
+ reaper \
reflect-text-view \
reflect-vte mev \
table \
@@ -347,6 +350,7 @@ dist_check_SCRIPTS = \
$(NULL)
TESTS = \
+ reaper \
table \
test-vtetypes \
vteconv \
@@ -360,6 +364,16 @@ TESTS_ENVIRONMENT = \
VTE_API_VERSION="$(VTE_API_VERSION)" \
$(NULL)
+reaper_CPPFLAGS = -DMAIN -I$(srcdir) -I $(builddir) $(AM_CPPFLAGS)
+reaper_CXXFLAGS = $(VTE_CFLAGS) $(AM_CXXFLAGS)
+reaper_SOURCES = \
+ debug.cc \
+ debug.h \
+ reaper.cc \
+ reaper.hh \
+ $(NULL)
+reaper_LDADD = $(VTE_LIBS)
+
reflect_text_view_CPPFLAGS = -DUSE_TEXT_VIEW -I$(srcdir) -I $(builddir) $(AM_CPPFLAGS)
reflect_text_view_CFLAGS = $(VTE_CFLAGS) $(AM_CFLAGS)
reflect_text_view_SOURCES = reflect.c
diff --git a/src/reaper.cc b/src/reaper.cc
new file mode 100644
index 0000000..e630a05
--- /dev/null
+++ b/src/reaper.cc
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2002 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include "debug.h"
+#include "reaper.hh"
+
+struct _VteReaper {
+ GObject parent_instance;
+};
+
+struct _VteReaperClass {
+ GObjectClass parent_class;
+};
+typedef struct _VteReaperClass VteReaperClass;
+
+#define VTE_TYPE_REAPER (vte_reaper_get_type())
+#define VTE_REAPER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), VTE_TYPE_REAPER, VteReaper))
+#define VTE_REAPER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), VTE_TYPE_REAPER, VteReaperClass))
+#define VTE_IS_REAPER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VTE_TYPE_REAPER))
+#define VTE_IS_REAPER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), VTE_TYPE_REAPER))
+#define VTE_REAPER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), VTE_TYPE_REAPER, VteReaperClass))
+
+static GType vte_reaper_get_type(void);
+
+G_DEFINE_TYPE(VteReaper, vte_reaper, G_TYPE_OBJECT)
+
+static VteReaper *singleton_reaper = nullptr;
+
+static void
+vte_reaper_child_watch_cb(GPid pid,
+ int status,
+ gpointer data)
+{
+ _vte_debug_print(VTE_DEBUG_SIGNALS,
+ "Reaper emitting child-exited signal.\n");
+ g_signal_emit_by_name(data, "child-exited", pid, status);
+ g_spawn_close_pid (pid);
+}
+
+/*
+ * vte_reaper_add_child:
+ * @pid: the ID of a child process which will be monitored
+ *
+ * Ensures that child-exited signals will be emitted when @pid exits.
+ */
+void
+vte_reaper_add_child(GPid pid)
+{
+ g_child_watch_add_full(G_PRIORITY_LOW,
+ pid,
+ vte_reaper_child_watch_cb,
+ vte_reaper_ref(),
+ (GDestroyNotify)g_object_unref);
+}
+
+static void
+vte_reaper_init(VteReaper *reaper)
+{
+}
+
+static GObject*
+vte_reaper_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ if (singleton_reaper) {
+ return (GObject*)g_object_ref (singleton_reaper);
+ } else {
+ GObject *obj;
+ obj = G_OBJECT_CLASS (vte_reaper_parent_class)->constructor (type, n_construct_properties,
construct_properties);
+ singleton_reaper = VTE_REAPER (obj);
+ return obj;
+ }
+}
+
+
+static void
+vte_reaper_finalize(GObject *reaper)
+{
+ G_OBJECT_CLASS(vte_reaper_parent_class)->finalize(reaper);
+ singleton_reaper = nullptr;
+}
+
+static void
+vte_reaper_class_init(VteReaperClass *klass)
+{
+ GObjectClass *gobject_class;
+
+ /*
+ * VteReaper::child-exited:
+ * @vtereaper: the object which received the signal
+ * @arg1: the process ID of the exited child
+ * @arg2: the status of the exited child, as returned by waitpid()
+ *
+ * Emitted when the #VteReaper object detects that a child of the
+ * current process has exited.
+ */
+ g_signal_new(g_intern_static_string("child-exited"),
+ G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ nullptr,
+ nullptr,
+ g_cclosure_marshal_generic,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_INT, G_TYPE_INT);
+
+ gobject_class = G_OBJECT_CLASS(klass);
+ gobject_class->constructor = vte_reaper_constructor;
+ gobject_class->finalize = vte_reaper_finalize;
+}
+
+/*
+ * vte_reaper_ref:
+ *
+ * Finds the address of the global #VteReaper object, creating the object if
+ * necessary.
+ *
+ * Returns: a reference to the global #VteReaper object, which
+ * must be unreffed when done with it
+ */
+VteReaper *
+vte_reaper_ref(void)
+{
+ return (VteReaper*)g_object_new(VTE_TYPE_REAPER, nullptr);
+}
+
+#ifdef MAIN
+
+#include <unistd.h>
+
+GMainContext *context;
+GMainLoop *loop;
+pid_t child;
+
+static void
+child_exited(GObject *object, int pid, int status, gpointer data)
+{
+ g_print("[parent] Child with pid %d exited with code %d, "
+ "was waiting for %d.\n", pid, status, GPOINTER_TO_INT(data));
+ if (child == pid) {
+ g_print("[parent] Quitting.\n");
+ g_main_loop_quit(loop);
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ VteReaper *reaper;
+ pid_t p, q;
+
+ _vte_debug_init();
+
+ g_type_init();
+ context = g_main_context_default();
+ loop = g_main_loop_new(context, FALSE);
+ reaper = vte_reaper_ref();
+
+ g_print("[parent] Forking1.\n");
+ p = fork();
+ switch (p) {
+ case -1:
+ g_print("[parent] Fork1 failed.\n");
+ g_assert_not_reached();
+ break;
+ case 0:
+ g_print("[child1] Going to sleep.\n");
+ sleep(10);
+ g_print("[child1] Quitting.\n");
+ _exit(30);
+ break;
+ default:
+ g_print("[parent] Starting to wait for %d.\n", p);
+ vte_reaper_add_child(p);
+ child = p;
+ g_signal_connect(reaper,
+ "child-exited",
+ G_CALLBACK(child_exited),
+ GINT_TO_POINTER(child));
+ break;
+ }
+
+ g_print("[parent] Forking2.\n");
+ q = fork();
+ switch (q) {
+ case -1:
+ g_print("[parent] Fork2 failed.\n");
+ g_assert_not_reached();
+ break;
+ case 0:
+ g_print("[child2] Going to sleep.\n");
+ sleep(5);
+ g_print("[child2] Quitting.\n");
+ _exit(5);
+ break;
+ default:
+ g_print("[parent] Not waiting for %d.\n", q);
+ break;
+ }
+
+
+ g_main_loop_run(loop);
+
+ g_object_unref(reaper);
+
+ return 0;
+}
+#endif
diff --git a/src/reaper.hh b/src/reaper.hh
new file mode 100644
index 0000000..3426d7c
--- /dev/null
+++ b/src/reaper.hh
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2002 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#pragma once
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <glib-object.h>
+
+typedef struct _VteReaper VteReaper;
+
+VteReaper *vte_reaper_ref(void);
+
+void vte_reaper_add_child(GPid pid);
diff --git a/src/vte.cc b/src/vte.cc
index 70733a6..e241907 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -40,6 +40,7 @@
#include "debug.h"
#include "vteconv.h"
#include "vtedraw.hh"
+#include "reaper.hh"
#include "ring.h"
#include "caps.h"
@@ -3104,15 +3105,12 @@ not_inserted:
}
static void
-child_watch_cb(GPid pid,
- int status,
- VteTerminalPrivate *that)
+reaper_child_exited_cb(VteReaper *reaper,
+ int ipid,
+ int status,
+ VteTerminalPrivate *that)
{
- if (that == NULL) {
- /* The child outlived us. Do nothing, we're happy that Glib
- * read its exit data and hence it's no longer there as zombie. */
- return;
- }
+ GPid pid = GPid(ipid);
auto terminal = that->m_terminal;
/* keep the VteTerminalPrivate in a death grip */
@@ -3146,7 +3144,15 @@ VteTerminalPrivate::child_watch_done(GPid pid,
#endif
}
- m_child_watch_source = 0;
+ /* Disconnect from the reaper */
+ if (m_reaper) {
+ g_signal_handlers_disconnect_by_func(m_reaper,
+ (gpointer)reaper_child_exited_cb,
+ this);
+ g_object_unref(m_reaper);
+ m_reaper = nullptr;
+ }
+
m_pty_pid = -1;
/* Close out the PTY. */
@@ -3304,14 +3310,22 @@ VteTerminalPrivate::watch_child (GPid child_pid)
m_pty_pid = child_pid;
/* Catch a child-exited signal from the child pid. */
- if (m_child_watch_source != 0) {
- g_source_remove (m_child_watch_source);
+ auto reaper = vte_reaper_ref();
+ vte_reaper_add_child(child_pid);
+ if (reaper != m_reaper) {
+ if (m_reaper) {
+ g_signal_handlers_disconnect_by_func(m_reaper,
+ (gpointer)reaper_child_exited_cb,
+ this);
+ g_object_unref(m_reaper);
+ }
+ m_reaper = reaper; /* adopts */
+ g_signal_connect(m_reaper, "child-exited",
+ G_CALLBACK(reaper_child_exited_cb),
+ this);
+ } else {
+ g_object_unref(reaper);
}
- m_child_watch_source =
- g_child_watch_add_full(G_PRIORITY_HIGH,
- child_pid,
- (GChildWatchFunc)child_watch_cb,
- this, nullptr);
/* FIXMEchpe: call set_size() here? */
@@ -8239,14 +8253,12 @@ VteTerminalPrivate::~VteTerminalPrivate()
m_outgoing_conv = VTE_INVALID_CONV;
}
- /* Start listening for child-exited signals and ignore them, so that no zombie child is left behind.
*/
- if (m_child_watch_source != 0) {
- g_source_remove (m_child_watch_source);
- m_child_watch_source = 0;
- g_child_watch_add_full(G_PRIORITY_HIGH,
- m_pty_pid,
- (GChildWatchFunc)child_watch_cb,
- NULL, NULL);
+ /* Stop listening for child-exited signals. */
+ if (m_reaper) {
+ g_signal_handlers_disconnect_by_func(m_reaper,
+ (gpointer)reaper_child_exited_cb,
+ this);
+ g_object_unref(m_reaper);
}
/* Stop processing input. */
diff --git a/src/vtegtk.cc b/src/vtegtk.cc
index 94f07ac..f763b46 100644
--- a/src/vtegtk.cc
+++ b/src/vtegtk.cc
@@ -49,6 +49,7 @@
#include "debug.h"
#include "marshal.h"
+#include "reaper.hh"
#include "vtedefines.hh"
#include "vteinternal.hh"
#include "vteaccess.h"
@@ -2326,18 +2327,20 @@ spawn_async_cb (GObject *source,
VteTerminal* terminal = (VteTerminal*)g_weak_ref_get(&data->wref);
/* Automatically watch the child */
- if (terminal) {
+ if (terminal != nullptr) {
if (pid != -1)
vte_terminal_watch_child(terminal, pid);
else
vte_terminal_set_pty(terminal, nullptr);
+ } else {
+ if (pid != -1) {
+ vte_reaper_add_child(pid);
+ }
}
if (data->callback)
data->callback(terminal, pid, error, data->user_data);
- g_clear_error(&error);
-
if (terminal == nullptr) {
/* If the terminal was destroyed, we need to abort the child process, if any */
if (pid != -1) {
@@ -2352,6 +2355,9 @@ spawn_async_cb (GObject *source,
}
}
+ if (error)
+ g_error_free(error);
+
spawn_async_callback_data_free(data);
}
diff --git a/src/vteinternal.hh b/src/vteinternal.hh
index 947eed4..ff5b93c 100644
--- a/src/vteinternal.hh
+++ b/src/vteinternal.hh
@@ -22,6 +22,7 @@
#include "vtedefines.hh"
#include "vtetypes.hh"
+#include "reaper.hh"
#include "ring.h"
#include "vteconv.h"
#include "buffer.h"
@@ -286,7 +287,7 @@ public:
guint m_pty_output_source;
gboolean m_pty_input_active;
GPid m_pty_pid; /* pid of child process */
- guint m_child_watch_source;
+ VteReaper *m_reaper;
/* Input data queues. */
const char *m_encoding; /* the pty's encoding */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]