From 23b8f9bf86ae7fa49536bd49aa5ed20e7f7f9150 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 16 Oct 2013 15:49:58 +0200 Subject: [PATCH] unit-tests: Support testing multi-threaded code --- src/libstrongswan/tests/test_runner.c | 9 +++-- src/libstrongswan/tests/test_suite.c | 47 ++++++++++++++++++++++++--- 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/src/libstrongswan/tests/test_runner.c b/src/libstrongswan/tests/test_runner.c index b6087a816..2b63ec72e 100644 --- a/src/libstrongswan/tests/test_runner.c +++ b/src/libstrongswan/tests/test_runner.c @@ -75,6 +75,9 @@ static array_t *load_suites() } otest = 0; library_init(NULL); + + test_setup_handler(); + if (!load_plugins()) { library_deinit(); @@ -276,6 +279,10 @@ static bool post_test(bool check_leaks, array_t *failures, char *name, int i) .i = i, }; + lib->processor->set_threads(lib->processor, 0); + lib->processor->cancel(lib->processor); + lib->plugins->unload(lib->plugins); + if (check_leaks && lib->leak_detective) { lib->leak_detective->set_report_cb(lib->leak_detective, @@ -459,8 +466,6 @@ int main(int argc, char *argv[]) /* redirect all output to stderr (to redirect make's stdout to /dev/null) */ dup2(2, 1); - test_setup_handler(); - suites = load_suites(); if (!suites) { diff --git a/src/libstrongswan/tests/test_suite.c b/src/libstrongswan/tests/test_suite.c index 29221eb68..6a4c7b96b 100644 --- a/src/libstrongswan/tests/test_suite.c +++ b/src/libstrongswan/tests/test_suite.c @@ -18,6 +18,8 @@ #include #include +#include + /** * Failure message buf */ @@ -117,12 +119,25 @@ void test_suite_add_case(test_suite_t *suite, test_case_t *tcase) array_insert(suite->tcases, -1, tcase); } +/** + * Main thread performing tests + */ +static pthread_t main_thread; + /** * Let test case fail */ static inline void test_failure() { - siglongjmp(test_restore_point_env, 1); + if (pthread_self() == main_thread) + { + siglongjmp(test_restore_point_env, 1); + } + else + { + pthread_kill(main_thread, SIGUSR1); + /* how can we stop just the thread? longjmp to a restore point? */ + } } /** @@ -163,6 +178,9 @@ static void test_sighandler(int signal) switch (signal) { + case SIGUSR1: + /* a different thread failed, abort test */ + return test_failure(); case SIGSEGV: signame = "SIGSEGV"; break; @@ -189,6 +207,11 @@ static void test_sighandler(int signal) lib->leak_detective->set_state(lib->leak_detective, old); } test_fail_msg(NULL, 0, "%s(%d)", signame, signal); + /* unable to restore a valid context for that thread, terminate */ + fprintf(stderr, "\n%s(%d) outside of main thread:\n", signame, signal); + failure_backtrace->log(failure_backtrace, stderr, TRUE); + fprintf(stderr, "terminating...\n"); + abort(); } /** @@ -196,15 +219,20 @@ static void test_sighandler(int signal) */ void test_setup_handler() { - struct sigaction action; + struct sigaction action = { + .sa_handler = test_sighandler, + }; - action.sa_handler = test_sighandler; - action.sa_flags = 0; - sigemptyset(&action.sa_mask); + main_thread = pthread_self(); + + /* signal handler inherited by all threads */ sigaction(SIGSEGV, &action, NULL); sigaction(SIGILL, &action, NULL); sigaction(SIGBUS, &action, NULL); + /* ignore ALRM/USR1, these are catched by main thread only */ + action.sa_handler = SIG_IGN; sigaction(SIGALRM, &action, NULL); + sigaction(SIGUSR1, &action, NULL); } /** @@ -212,6 +240,15 @@ void test_setup_handler() */ void test_setup_timeout(int s) { + struct sigaction action = { + .sa_handler = test_sighandler, + }; + + /* This called by main thread only. Setup handler for timeout and + * failure cross-thread signaling. */ + sigaction(SIGALRM, &action, NULL); + sigaction(SIGUSR1, &action, NULL); + alarm(s); }