1/* test-threads.c
2
3   As per test-combination.c, construct a test case by combining other test
4   cases, to try to shake out state issues.  However each test runs in a
5   separate thread.  */
6
7#include <pthread.h>
8#include <stdarg.h>
9#include <stdio.h>
10
11/* dejagnu.h isn't thread-safe; there's a shared "buffer", and the counts
12   of "passed"/"failed" etc are globals.
13
14   We get around this by putting a mutex around pass/fail calls.
15 */
16
17static pthread_mutex_t dg_mutex = PTHREAD_MUTEX_INITIALIZER;
18
19/* By defining MAKE_DEJAGNU_H_THREADSAFE before we include harness.h,
20   harness.h injects macros before including <dejagnu.h> so that the
21   pass/fail functions become "dejagnu_pass"/"dejagnu_fail" etc.  */
22
23void dejagnu_pass (const char* fmt, ...);
24void dejagnu_fail (const char* fmt, ...);
25void dejagnu_note (const char* fmt, ...);
26
27/* We now provide our own implementations of "pass"/"fail"/"note", which
28   call the underlying dejagnu implementations, but with a mutex.  */
29
30inline void
31pass (const char* fmt, ...)
32{
33  va_list ap;
34  char buffer[512];
35
36  va_start (ap, fmt);
37  vsnprintf (buffer, sizeof (buffer), fmt, ap);
38  va_end (ap);
39
40  pthread_mutex_lock (&dg_mutex);
41  dejagnu_pass (buffer);
42  pthread_mutex_unlock (&dg_mutex);
43}
44
45inline void
46fail (const char* fmt, ...)
47{
48  va_list ap;
49  char buffer[512];
50
51  va_start (ap, fmt);
52  vsnprintf (buffer, sizeof (buffer), fmt, ap);
53  va_end (ap);
54
55  pthread_mutex_lock (&dg_mutex);
56  dejagnu_fail (buffer);
57  pthread_mutex_unlock (&dg_mutex);
58}
59
60inline void
61note (const char* fmt, ...)
62{
63  va_list ap;
64  char buffer[512];
65
66  va_start (ap, fmt);
67  vsnprintf (buffer, sizeof (buffer), fmt, ap);
68  va_end (ap);
69
70  pthread_mutex_lock (&dg_mutex);
71  dejagnu_note (buffer);
72  pthread_mutex_unlock (&dg_mutex);
73}
74
75#define MAKE_DEJAGNU_H_THREADSAFE
76
77/* We also need to provide our own version of TEST_NAME.  */
78#define TEST_NAME
79
80/* We can now include all of the relevant selftests.  */
81
82#include "all-non-failing-tests.h"
83
84#define TEST_PROVIDES_MAIN
85#define TEST_ESCHEWS_TEST_JIT
86
87/* Now construct a test case from all the other test cases.
88
89   We undefine COMBINED_TEST so that we can now include harness.h
90   "for real".  */
91#undef COMBINED_TEST
92#include "harness.h"
93
94struct thread_data
95{
96  pthread_t m_tid;
97  const struct testcase *m_testcase;
98};
99
100static const char *argv0;
101
102void *
103run_threaded_test (void *data)
104{
105  struct thread_data *thread = (struct thread_data *)data;
106  int i;
107
108  for (i = 0; i < 5; i++)
109    {
110      gcc_jit_context *ctxt;
111      gcc_jit_result *result;
112
113      note ("run_threaded_test: %s iteration: %d",
114	    thread->m_testcase->m_name, i);
115
116      ctxt = gcc_jit_context_acquire ();
117
118      set_options (ctxt, argv0);
119
120      thread->m_testcase->m_hook_to_create_code (ctxt, NULL);
121
122      result = gcc_jit_context_compile (ctxt);
123
124      thread->m_testcase->m_hook_to_verify_code (ctxt, result);
125
126      gcc_jit_context_release (ctxt);
127
128      /* Once we're done with the code, this unloads the built .so file: */
129      gcc_jit_result_release (result);
130    }
131
132  return NULL;
133}
134
135int
136main (int argc, char **argv)
137{
138  int i;
139
140  snprintf (test, sizeof (test),
141	    "%s",
142	    extract_progname (argv[0]));
143
144  argv0 = argv[0];
145
146  /* The individual testcases are not thread-safe (some have their own
147     global variables), so we have one thread per test-case.  */
148  struct thread_data *threads =
149    calloc (num_testcases, sizeof (struct thread_data));
150
151  /* Start a thread per test-case.  */
152  for (i = 0; i < num_testcases; i++)
153    {
154      struct thread_data *thread = &threads[i];
155      thread->m_testcase = &testcases[i];
156      pthread_create (&thread->m_tid,
157		      NULL,
158		      run_threaded_test,
159		      thread);
160    }
161
162  /* Wait for all the threads to be done.  */
163  for (i = 0; i < num_testcases; i++)
164    {
165      struct thread_data *thread = &threads[i];
166      (void)pthread_join (thread->m_tid, NULL);
167    }
168
169  totals ();
170
171  return 0;
172}
173