diff options
author | Ran Benita <ran234@gmail.com> | 2012-01-10 02:52:42 +0200 |
---|---|---|
committer | David Herrmann <dh.herrmann@googlemail.com> | 2012-01-24 15:06:51 +0100 |
commit | 5cc190d94700c043a54e36d00af21f1884377d85 (patch) | |
tree | 7515f1676bb1fcf5fed3dc978d268777baa80a5d /tests | |
parent | 6ebc7c18920384be8e66021b2ea93db1a1c9f5be (diff) |
test_terminal: wait on children to avoid zombies
Unfortunately, there is no clean way I see to hook this up from the pty
object. We can (and will) have more than one pty 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 <ran234@gmail.com>
Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/test_terminal.c | 68 |
1 files changed, 62 insertions, 6 deletions
diff --git a/tests/test_terminal.c b/tests/test_terminal.c index 186f888..a5c998e 100644 --- a/tests/test_terminal.c +++ b/tests/test_terminal.c @@ -36,6 +36,7 @@ #include <stdbool.h> #include <stdlib.h> #include <string.h> +#include <sys/wait.h> #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("test: cannot wait on child: %m\n"); + break; + } else if (pid == 0) { + break; + } else if (WIFEXITED(status)) { + if (WEXITSTATUS(status) != 0) + log_info("test: child %d exited with status " + "%d\n", pid, WEXITSTATUS(status)); + else + log_debug("test: child %d exited " + "successfully\n", pid); + } else if (WIFSIGNALED(status)) { + log_debug("test: 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, @@ -140,6 +190,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); @@ -163,6 +214,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; @@ -196,7 +252,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; |