summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorRan Benita <ran234@gmail.com>2012-01-10 02:52:42 +0200
committerDavid Herrmann <dh.herrmann@googlemail.com>2012-01-24 15:06:51 +0100
commit5cc190d94700c043a54e36d00af21f1884377d85 (patch)
tree7515f1676bb1fcf5fed3dc978d268777baa80a5d /tests
parent6ebc7c18920384be8e66021b2ea93db1a1c9f5be (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.c68
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;