From d00714f7ce62f019d66957966566b4d147723b25 Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Tue, 10 Jan 2012 02:52:42 +0200 Subject: [PATCH] test_terminal: wait on children to avoid zombies Unfortunately, there is no clean way I see to hook this up from the vte object. We can (and will) have more than one vte object opened at a time, but the semantics of signalfd make it impossible to deliver each SIGCHLD to its rightful owner without complicating things. [ From what I tested: - If you have two signalfd's listening to the same signal, they will be dispatched in some round-robin manner. - Also, if more than one child exits before we read signalfd (possibly beloging to different terminals), they will be compressed to one event. ] We therefore need to do the reaping from a central location, and need to remember to copy this snippet over to main.c in the future. Signed-off-by: Ran Benita --- tests/test_terminal.c | 68 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 6 deletions(-) diff --git a/tests/test_terminal.c b/tests/test_terminal.c index 19c20f0..49b9467 100644 --- a/tests/test_terminal.c +++ b/tests/test_terminal.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "eloop.h" #include "input.h" @@ -48,6 +49,7 @@ struct app { struct kmscon_eloop *eloop; struct kmscon_signal *sig_term; struct kmscon_signal *sig_int; + struct kmscon_signal *sig_chld; struct kmscon_symbol_table *st; struct kmscon_font_factory *ff; struct kmscon_compositor *comp; @@ -63,13 +65,61 @@ static void sig_term(struct kmscon_signal *sig, int signum, void *data) terminate = 1; } +static void sig_chld(struct kmscon_signal *sig, int signum, void *data) +{ + pid_t pid; + int status; + + /* + * If multiple children exit at the same time, signalfd would put them + * all in one event. So we reap in a loop. + */ + while (1) { + pid = waitpid(-1, &status, WNOHANG); + if (pid == -1) { + if (errno != ECHILD) + log_warning("vte: cannot wait on child: %m\n"); + break; + } else if (pid == 0) { + break; + } else if (WIFEXITED(status)) { + if (WEXITSTATUS(status) != 0) + log_info("vte: child %d exited with status " + "%hd\n", pid, WEXITSTATUS(status)); + else + log_debug("vte: child %d exited " + "successfully\n", pid); + } else if (WIFSIGNALED(status)) { + log_debug("vte: child %d exited by signal %d\n", pid, + WTERMSIG(status)); + } + } +} + static void terminal_closed(struct kmscon_terminal *term, void *data) { - /* - * Alternativly, we could spwan a new login/shell here, like what - * happens when the user exits the shell in a linux console. - */ - terminate = 1; +#if 0 + /* + * Alternativly, we could spwan a new login/shell here, like what + * happens when the user exits the shell in a linux console: + */ + + int ret; + struct app *app = data; + + if (!app) + goto err_out; + + ret = kmscon_terminal_open(app->term, app->eloop, + terminal_closed, app); + if (ret) + goto err_out; + + return; + +err_out: +#endif + terminate = 1; } static void read_input(struct kmscon_input *input, @@ -134,6 +184,7 @@ static void destroy_app(struct app *app) kmscon_compositor_unref(app->comp); kmscon_font_factory_unref(app->ff); kmscon_symbol_table_unref(app->st); + kmscon_eloop_rm_signal(app->sig_chld); kmscon_eloop_rm_signal(app->sig_int); kmscon_eloop_rm_signal(app->sig_term); kmscon_eloop_unref(app->eloop); @@ -157,6 +208,11 @@ static int setup_app(struct app *app) if (ret) goto err_loop; + ret = kmscon_eloop_new_signal(app->eloop, &app->sig_chld, SIGCHLD, + sig_chld, NULL); + if (ret) + goto err_loop; + ret = kmscon_symbol_table_new(&app->st); if (ret) goto err_loop; @@ -190,7 +246,7 @@ static int setup_app(struct app *app) goto err_loop; ret = kmscon_terminal_open(app->term, app->eloop, - terminal_closed, NULL); + terminal_closed, app); if (ret) goto err_loop;