]>
Commit | Line | Data |
---|---|---|
35485da9 DM |
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 | ||
17 | static 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 | ||
23 | void dejagnu_pass (const char* fmt, ...); | |
24 | void dejagnu_fail (const char* fmt, ...); | |
25 | void 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 | ||
30 | inline void | |
31 | pass (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 | ||
45 | inline void | |
46 | fail (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 | ||
60 | inline void | |
61 | note (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 | ||
94 | struct testcase | |
95 | { | |
96 | const char *m_name; | |
97 | void (*m_hook_to_create_code) (gcc_jit_context *ctxt, | |
98 | void * user_data); | |
99 | void (*m_hook_to_verify_code) (gcc_jit_context *ctxt, | |
100 | gcc_jit_result *result); | |
101 | }; | |
102 | ||
103 | const struct testcase testcases[] = { | |
104 | {"accessing_struct", | |
105 | create_code_accessing_struct, | |
106 | verify_code_accessing_struct}, | |
107 | {"accessing_union", | |
108 | create_code_accessing_union, | |
109 | verify_code_accessing_union}, | |
f63c7f85 DM |
110 | {"arith_overflow", |
111 | create_code_arith_overflow, | |
112 | verify_code_arith_overflow}, | |
35485da9 DM |
113 | {"array_as_pointer", |
114 | create_code_array_as_pointer, | |
115 | verify_code_array_as_pointer}, | |
116 | {"arrays", | |
117 | create_code_arrays, | |
118 | verify_code_arrays}, | |
119 | {"calling_external_function", | |
120 | create_code_calling_external_function, | |
121 | verify_code_calling_external_function}, | |
122 | {"calling_function_ptr", | |
123 | create_code_calling_function_ptr, | |
124 | verify_code_calling_function_ptr}, | |
125 | {"dot_product", | |
126 | create_code_dot_product, | |
127 | verify_code_dot_product}, | |
128 | {"expressions", | |
129 | create_code_expressions, | |
130 | verify_code_expressions}, | |
131 | {"factorial", | |
132 | create_code_factorial, | |
133 | verify_code_factorial}, | |
134 | {"fibonacci", | |
135 | create_code_fibonacci, | |
136 | verify_code_fibonacci}, | |
137 | {"functions", | |
138 | create_code_functions, | |
139 | verify_code_functions}, | |
140 | {"hello_world", | |
141 | create_code_hello_world, | |
142 | verify_code_hello_world}, | |
143 | {"linked_list", | |
144 | create_code_linked_list, | |
145 | verify_code_linked_list}, | |
146 | {"long_names", | |
147 | create_code_long_names, | |
148 | verify_code_long_names}, | |
149 | {"quadratic", | |
150 | create_code_quadratic, | |
151 | verify_code_quadratic}, | |
152 | {"nested_loop", | |
153 | create_code_nested_loop, | |
154 | verify_code_nested_loop}, | |
155 | {"reading_struct ", | |
156 | create_code_reading_struct , | |
157 | verify_code_reading_struct }, | |
158 | {"string_literal", | |
159 | create_code_string_literal, | |
160 | verify_code_string_literal}, | |
161 | {"sum_of_squares", | |
162 | create_code_sum_of_squares, | |
163 | verify_code_sum_of_squares}, | |
164 | {"types", | |
165 | create_code_types, | |
166 | verify_code_types}, | |
167 | {"using_global", | |
168 | create_code_using_global, | |
169 | verify_code_using_global}, | |
170 | {"volatile", | |
171 | create_code_volatile, | |
172 | verify_code_volatile} | |
173 | }; | |
174 | ||
175 | const int num_testcases = (sizeof (testcases) / sizeof (testcases[0])); | |
176 | ||
177 | struct thread_data | |
178 | { | |
179 | pthread_t m_tid; | |
180 | const struct testcase *m_testcase; | |
181 | }; | |
182 | ||
183 | static const char *argv0; | |
184 | ||
185 | void * | |
186 | run_threaded_test (void *data) | |
187 | { | |
188 | struct thread_data *thread = (struct thread_data *)data; | |
189 | int i; | |
190 | ||
191 | for (i = 0; i < 5; i++) | |
192 | { | |
193 | gcc_jit_context *ctxt; | |
194 | gcc_jit_result *result; | |
195 | ||
196 | note ("run_threaded_test: %s iteration: %d", | |
197 | thread->m_testcase->m_name, i); | |
198 | ||
199 | ctxt = gcc_jit_context_acquire (); | |
200 | ||
201 | set_options (ctxt, argv0); | |
202 | ||
203 | thread->m_testcase->m_hook_to_create_code (ctxt, NULL); | |
204 | ||
205 | result = gcc_jit_context_compile (ctxt); | |
206 | ||
207 | thread->m_testcase->m_hook_to_verify_code (ctxt, result); | |
208 | ||
209 | gcc_jit_context_release (ctxt); | |
210 | ||
211 | /* Once we're done with the code, this unloads the built .so file: */ | |
212 | gcc_jit_result_release (result); | |
213 | } | |
214 | ||
215 | return NULL; | |
216 | } | |
217 | ||
218 | int | |
219 | main (int argc, char **argv) | |
220 | { | |
221 | int i; | |
222 | ||
223 | snprintf (test, sizeof (test), | |
224 | "%s", | |
225 | extract_progname (argv[0])); | |
226 | ||
227 | argv0 = argv[0]; | |
228 | ||
229 | /* The individual testcases are not thread-safe (some have their own | |
230 | global variables), so we have one thread per test-case. */ | |
231 | struct thread_data *threads = | |
232 | calloc (num_testcases, sizeof (struct thread_data)); | |
233 | ||
234 | /* Start a thread per test-case. */ | |
235 | for (i = 0; i < num_testcases; i++) | |
236 | { | |
237 | struct thread_data *thread = &threads[i]; | |
238 | thread->m_testcase = &testcases[i]; | |
239 | pthread_create (&thread->m_tid, | |
240 | NULL, | |
241 | run_threaded_test, | |
242 | thread); | |
243 | } | |
244 | ||
245 | /* Wait for all the threads to be done. */ | |
246 | for (i = 0; i < num_testcases; i++) | |
247 | { | |
248 | struct thread_data *thread = &threads[i]; | |
249 | (void)pthread_join (thread->m_tid, NULL); | |
250 | } | |
251 | ||
252 | totals (); | |
253 | ||
254 | return 0; | |
255 | } |