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