/* * Copyright (C) 2002 Red Hat, Inc. * * This is free software; you can redistribute it and/or modify it under * the terms of the GNU Library General Public License as published by * the Free Software Foundation; either version 2 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 Library General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include "debug.h" #include "marshal.h" #include "reaper.h" static VteReaper *singleton_reaper = NULL; G_DEFINE_TYPE(VteReaper, vte_reaper, G_TYPE_OBJECT) static void vte_reaper_child_watch_cb(GPid pid, gint 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. This is * necessary for correct operation when running with glib versions >= 2.4. * * Returns: the new source ID * * Since 0.11.11 */ int vte_reaper_add_child(GPid pid) { return g_child_watch_add_full(G_PRIORITY_LOW, pid, vte_reaper_child_watch_cb, vte_reaper_get(), (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 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 = NULL; } static void vte_reaper_class_init(VteReaperClass *klass) { GObjectClass *gobject_class; klass->child_exited_signal = g_signal_new(g_intern_static_string("child-exited"), G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, _vte_marshal_VOID__INT_INT, 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_get: * * Finds the address of the global #VteReaper object, creating the object if * necessary. * * Returns: the global #VteReaper object, which should not be unreffed. */ VteReaper * vte_reaper_get(void) { return g_object_new(VTE_TYPE_REAPER, NULL); } #ifdef REAPER_MAIN #include 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_get(); g_print("[parent] Forking.\n"); p = fork(); switch (p) { case -1: g_print("[parent] Fork failed.\n"); g_assert_not_reached(); break; case 0: g_print("[child] Going to sleep.\n"); sleep(10); g_print("[child] Quitting.\n"); _exit(30); break; default: g_print("[parent] Starting to wait for %d.\n", p); child = p; g_signal_connect(reaper, "child-exited", G_CALLBACK(child_exited), GINT_TO_POINTER(child)); break; } g_print("[parent] Forking.\n"); q = fork(); switch (q) { case -1: g_print("[parent] Fork failed.\n"); g_assert_not_reached(); break; case 0: g_print("[child] Going to sleep.\n"); sleep(5); _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