| /* test-threads.c |
| |
| As per test-combination.c, construct a test case by combining other test |
| cases, to try to shake out state issues. However each test runs in a |
| separate thread. */ |
| |
| #include <pthread.h> |
| #include <stdarg.h> |
| #include <stdio.h> |
| |
| /* dejagnu.h isn't thread-safe; there's a shared "buffer", and the counts |
| of "passed"/"failed" etc are globals. |
| |
| We get around this by putting a mutex around pass/fail calls. |
| */ |
| |
| static pthread_mutex_t dg_mutex = PTHREAD_MUTEX_INITIALIZER; |
| |
| /* By defining MAKE_DEJAGNU_H_THREADSAFE before we include harness.h, |
| harness.h injects macros before including <dejagnu.h> so that the |
| pass/fail functions become "dejagnu_pass"/"dejagnu_fail" etc. */ |
| |
| /* Forward decls of our implementations of pass/fail/note. */ |
| |
| inline void |
| pass (const char* fmt, ...); |
| |
| inline void |
| fail (const char* fmt, ...); |
| |
| inline void |
| note (const char* fmt, ...); |
| |
| #define MAKE_DEJAGNU_H_THREADSAFE |
| |
| /* We also need to provide our own version of TEST_NAME. */ |
| #define TEST_NAME |
| |
| /* We can now include all of the relevant selftests. */ |
| |
| #include "all-non-failing-tests.h" |
| |
| #define TEST_PROVIDES_MAIN |
| #define TEST_ESCHEWS_TEST_JIT |
| |
| /* Now construct a test case from all the other test cases. |
| |
| We undefine COMBINED_TEST so that we can now include harness.h |
| "for real". */ |
| #undef COMBINED_TEST |
| #include "harness.h" |
| |
| /* We now provide our own implementations of "pass"/"fail"/"note", which |
| call the underlying dejagnu implementations, but with a mutex. */ |
| |
| inline void |
| pass (const char* fmt, ...) |
| { |
| va_list ap; |
| char buffer[512]; |
| |
| va_start (ap, fmt); |
| vsnprintf (buffer, sizeof (buffer), fmt, ap); |
| va_end (ap); |
| |
| pthread_mutex_lock (&dg_mutex); |
| dejagnu_pass (buffer); |
| pthread_mutex_unlock (&dg_mutex); |
| } |
| |
| inline void |
| fail (const char* fmt, ...) |
| { |
| va_list ap; |
| char buffer[512]; |
| |
| va_start (ap, fmt); |
| vsnprintf (buffer, sizeof (buffer), fmt, ap); |
| va_end (ap); |
| |
| pthread_mutex_lock (&dg_mutex); |
| dejagnu_fail (buffer); |
| pthread_mutex_unlock (&dg_mutex); |
| } |
| |
| inline void |
| note (const char* fmt, ...) |
| { |
| va_list ap; |
| char buffer[512]; |
| |
| va_start (ap, fmt); |
| vsnprintf (buffer, sizeof (buffer), fmt, ap); |
| va_end (ap); |
| |
| pthread_mutex_lock (&dg_mutex); |
| dejagnu_note (buffer); |
| pthread_mutex_unlock (&dg_mutex); |
| } |
| |
| struct thread_data |
| { |
| pthread_t m_tid; |
| const struct testcase *m_testcase; |
| }; |
| |
| static const char *argv0; |
| |
| void * |
| run_threaded_test (void *data) |
| { |
| struct thread_data *thread = (struct thread_data *)data; |
| int i; |
| |
| for (i = 0; i < 5; i++) |
| { |
| gcc_jit_context *ctxt; |
| gcc_jit_result *result; |
| |
| note ("run_threaded_test: %s iteration: %d", |
| thread->m_testcase->m_name, i); |
| |
| ctxt = gcc_jit_context_acquire (); |
| |
| set_options (ctxt, argv0); |
| |
| thread->m_testcase->m_hook_to_create_code (ctxt, NULL); |
| |
| result = gcc_jit_context_compile (ctxt); |
| |
| thread->m_testcase->m_hook_to_verify_code (ctxt, result); |
| |
| gcc_jit_context_release (ctxt); |
| |
| /* Once we're done with the code, this unloads the built .so file: */ |
| gcc_jit_result_release (result); |
| } |
| |
| return NULL; |
| } |
| |
| int |
| main (int argc, char **argv) |
| { |
| int i; |
| |
| snprintf (test, sizeof (test), |
| "%s", |
| extract_progname (argv[0])); |
| |
| argv0 = argv[0]; |
| |
| /* The individual testcases are not thread-safe (some have their own |
| global variables), so we have one thread per test-case. */ |
| struct thread_data *threads = |
| calloc (num_testcases, sizeof (struct thread_data)); |
| |
| /* Start a thread per test-case. */ |
| for (i = 0; i < num_testcases; i++) |
| { |
| struct thread_data *thread = &threads[i]; |
| thread->m_testcase = &testcases[i]; |
| pthread_create (&thread->m_tid, |
| NULL, |
| run_threaded_test, |
| thread); |
| } |
| |
| /* Wait for all the threads to be done. */ |
| for (i = 0; i < num_testcases; i++) |
| { |
| struct thread_data *thread = &threads[i]; |
| (void)pthread_join (thread->m_tid, NULL); |
| } |
| |
| totals (); |
| |
| return 0; |
| } |