|
1 /* g_once_init_*() test |
|
2 * Copyright (C) 2007 Tim Janik |
|
3 * Portions copyright (c) 2009 Nokia Corporation. All rights reserved. |
|
4 * This work is provided "as is"; redistribution and modification |
|
5 * in whole or in part, in any medium, physical or electronic is |
|
6 * permitted without restriction. |
|
7 |
|
8 * This work is distributed in the hope that it will be useful, |
|
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
11 |
|
12 * In no event shall the authors or contributors be liable for any |
|
13 * direct, indirect, incidental, special, exemplary, or consequential |
|
14 * damages (including, but not limited to, procurement of substitute |
|
15 * goods or services; loss of use, data, or profits; or business |
|
16 * interruption) however caused and on any theory of liability, whether |
|
17 * in contract, strict liability, or tort (including negligence or |
|
18 * otherwise) arising in any way out of the use of this software, even |
|
19 * if advised of the possibility of such damage. |
|
20 */ |
|
21 #include <glib.h> |
|
22 #include <stdlib.h> |
|
23 #ifdef __SYMBIAN32__ |
|
24 #include <glib_global.h> |
|
25 #include "mrt2_glib2_test.h" |
|
26 #endif /*__SYMBIAN32__*/ |
|
27 #define N_THREADS (13) |
|
28 |
|
29 static GMutex *tmutex = NULL; |
|
30 static GCond *tcond = NULL; |
|
31 static volatile int thread_call_count = 0; |
|
32 static char dummy_value = 'x'; |
|
33 |
|
34 static void |
|
35 assert_singleton_execution1 (void) |
|
36 { |
|
37 static volatile int seen_execution = 0; |
|
38 int old_seen_execution = g_atomic_int_exchange_and_add (&seen_execution, 1); |
|
39 if (old_seen_execution != 0) |
|
40 g_error ("%s: function executed more than once", G_STRFUNC); |
|
41 } |
|
42 |
|
43 static void |
|
44 assert_singleton_execution2 (void) |
|
45 { |
|
46 static volatile int seen_execution = 0; |
|
47 int old_seen_execution = g_atomic_int_exchange_and_add (&seen_execution, 1); |
|
48 if (old_seen_execution != 0) |
|
49 g_error ("%s: function executed more than once", G_STRFUNC); |
|
50 } |
|
51 |
|
52 static void |
|
53 assert_singleton_execution3 (void) |
|
54 { |
|
55 static volatile int seen_execution = 0; |
|
56 int old_seen_execution = g_atomic_int_exchange_and_add (&seen_execution, 1); |
|
57 if (old_seen_execution != 0) |
|
58 g_error ("%s: function executed more than once", G_STRFUNC); |
|
59 } |
|
60 |
|
61 static void |
|
62 initializer1 (void) |
|
63 { |
|
64 static volatile gsize initialized = 0; |
|
65 if (g_once_init_enter (&initialized)) |
|
66 { |
|
67 gsize initval = 42; |
|
68 assert_singleton_execution1(); |
|
69 g_once_init_leave (&initialized, initval); |
|
70 } |
|
71 } |
|
72 |
|
73 static gpointer |
|
74 initializer2 (void) |
|
75 { |
|
76 static volatile gsize initialized = 0; |
|
77 if (g_once_init_enter (&initialized)) |
|
78 { |
|
79 void *pointer_value = &dummy_value; |
|
80 assert_singleton_execution2(); |
|
81 g_once_init_leave (&initialized, (gsize) pointer_value); |
|
82 } |
|
83 return (void*) initialized; |
|
84 } |
|
85 |
|
86 static void |
|
87 initializer3 (void) |
|
88 { |
|
89 static volatile gsize initialized = 0; |
|
90 if (g_once_init_enter (&initialized)) |
|
91 { |
|
92 gsize initval = 42; |
|
93 assert_singleton_execution3(); |
|
94 g_usleep (25 * 1000); /* waste time for multiple threads to wait */ |
|
95 g_once_init_leave (&initialized, initval); |
|
96 } |
|
97 } |
|
98 |
|
99 static gpointer |
|
100 tmain_call_initializer3 (gpointer user_data) |
|
101 { |
|
102 g_mutex_lock (tmutex); |
|
103 g_cond_wait (tcond, tmutex); |
|
104 g_mutex_unlock (tmutex); |
|
105 //g_printf ("["); |
|
106 initializer3(); |
|
107 //g_printf ("]\n"); |
|
108 g_atomic_int_exchange_and_add (&thread_call_count, 1); |
|
109 return NULL; |
|
110 } |
|
111 |
|
112 static void* stress_concurrent_initializers (void*); |
|
113 |
|
114 int |
|
115 main (int argc, |
|
116 char *argv[]) |
|
117 { |
|
118 GThread *threads[N_THREADS]; |
|
119 int i; |
|
120 void *p; |
|
121 #ifdef __SYMBIAN32__ |
|
122 g_log_set_handler (NULL, G_LOG_FLAG_FATAL| G_LOG_FLAG_RECURSION | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG, &mrtLogHandler, NULL); |
|
123 g_set_print_handler(mrtPrintHandler); |
|
124 #endif /*__SYMBIAN32__*/ |
|
125 |
|
126 /* test simple initializer */ |
|
127 initializer1(); |
|
128 initializer1(); |
|
129 /* test pointer initializer */ |
|
130 /*void */p = initializer2(); |
|
131 g_assert (p == &dummy_value); |
|
132 p = initializer2(); |
|
133 g_assert (p == &dummy_value); |
|
134 /* setup threads */ |
|
135 g_thread_init (NULL); |
|
136 tmutex = g_mutex_new (); |
|
137 tcond = g_cond_new (); |
|
138 /* start multiple threads for initializer3() */ |
|
139 g_mutex_lock (tmutex); |
|
140 for (i = 0; i < N_THREADS; i++) |
|
141 threads[i] = g_thread_create (tmain_call_initializer3, 0, FALSE, NULL); |
|
142 g_mutex_unlock (tmutex); |
|
143 /* concurrently call initializer3() */ |
|
144 g_cond_broadcast (tcond); |
|
145 /* loop until all threads passed the call to initializer3() */ |
|
146 while (g_atomic_int_get (&thread_call_count) < i) |
|
147 { |
|
148 if (rand() % 2) |
|
149 g_thread_yield(); /* concurrent shuffling for single core */ |
|
150 else |
|
151 g_usleep (1000); /* concurrent shuffling for multi core */ |
|
152 g_cond_broadcast (tcond); |
|
153 } |
|
154 /* call multiple (unoptimized) initializers from multiple threads */ |
|
155 g_mutex_lock (tmutex); |
|
156 g_atomic_int_set (&thread_call_count, 0); |
|
157 for (i = 0; i < N_THREADS; i++) |
|
158 g_thread_create (stress_concurrent_initializers, 0, FALSE, NULL); |
|
159 g_mutex_unlock (tmutex); |
|
160 while (g_atomic_int_get (&thread_call_count) < 256 * 4 * N_THREADS) |
|
161 g_usleep (50 * 1000); /* wait for all 5 threads to complete */ |
|
162 #if __SYMBIAN32__ |
|
163 testResultXml("onceinit"); |
|
164 #endif /* EMULATOR */ |
|
165 return 0; |
|
166 } |
|
167 |
|
168 /* get rid of g_once_init_enter-optimizations in the below definitions |
|
169 * to uncover possible races in the g_once_init_enter_impl()/ |
|
170 * g_once_init_leave() implementations |
|
171 */ |
|
172 #define g_once_init_enter g_once_init_enter_impl |
|
173 |
|
174 /* define 16 * 16 simple initializers */ |
|
175 #define DEFINE_TEST_INITIALIZER(N) \ |
|
176 static void \ |
|
177 test_initializer_##N (void) \ |
|
178 { \ |
|
179 static volatile gsize initialized = 0; \ |
|
180 if (g_once_init_enter (&initialized)) \ |
|
181 { \ |
|
182 g_free (g_strdup_printf ("cpuhog%5d", 1)); \ |
|
183 g_free (g_strdup_printf ("cpuhog%6d", 2)); \ |
|
184 g_free (g_strdup_printf ("cpuhog%7d", 3)); \ |
|
185 g_once_init_leave (&initialized, 1); \ |
|
186 } \ |
|
187 } |
|
188 #define DEFINE_16_TEST_INITIALIZERS(P) \ |
|
189 DEFINE_TEST_INITIALIZER (P##0) \ |
|
190 DEFINE_TEST_INITIALIZER (P##1) \ |
|
191 DEFINE_TEST_INITIALIZER (P##2) \ |
|
192 DEFINE_TEST_INITIALIZER (P##3) \ |
|
193 DEFINE_TEST_INITIALIZER (P##4) \ |
|
194 DEFINE_TEST_INITIALIZER (P##5) \ |
|
195 DEFINE_TEST_INITIALIZER (P##6) \ |
|
196 DEFINE_TEST_INITIALIZER (P##7) \ |
|
197 DEFINE_TEST_INITIALIZER (P##8) \ |
|
198 DEFINE_TEST_INITIALIZER (P##9) \ |
|
199 DEFINE_TEST_INITIALIZER (P##a) \ |
|
200 DEFINE_TEST_INITIALIZER (P##b) \ |
|
201 DEFINE_TEST_INITIALIZER (P##c) \ |
|
202 DEFINE_TEST_INITIALIZER (P##d) \ |
|
203 DEFINE_TEST_INITIALIZER (P##e) \ |
|
204 DEFINE_TEST_INITIALIZER (P##f) |
|
205 #define DEFINE_256_TEST_INITIALIZERS(P) \ |
|
206 DEFINE_16_TEST_INITIALIZERS (P##_0) \ |
|
207 DEFINE_16_TEST_INITIALIZERS (P##_1) \ |
|
208 DEFINE_16_TEST_INITIALIZERS (P##_2) \ |
|
209 DEFINE_16_TEST_INITIALIZERS (P##_3) \ |
|
210 DEFINE_16_TEST_INITIALIZERS (P##_4) \ |
|
211 DEFINE_16_TEST_INITIALIZERS (P##_5) \ |
|
212 DEFINE_16_TEST_INITIALIZERS (P##_6) \ |
|
213 DEFINE_16_TEST_INITIALIZERS (P##_7) \ |
|
214 DEFINE_16_TEST_INITIALIZERS (P##_8) \ |
|
215 DEFINE_16_TEST_INITIALIZERS (P##_9) \ |
|
216 DEFINE_16_TEST_INITIALIZERS (P##_a) \ |
|
217 DEFINE_16_TEST_INITIALIZERS (P##_b) \ |
|
218 DEFINE_16_TEST_INITIALIZERS (P##_c) \ |
|
219 DEFINE_16_TEST_INITIALIZERS (P##_d) \ |
|
220 DEFINE_16_TEST_INITIALIZERS (P##_e) \ |
|
221 DEFINE_16_TEST_INITIALIZERS (P##_f) |
|
222 |
|
223 /* list 16 * 16 simple initializers */ |
|
224 #define LIST_16_TEST_INITIALIZERS(P) \ |
|
225 test_initializer_##P##0, \ |
|
226 test_initializer_##P##1, \ |
|
227 test_initializer_##P##2, \ |
|
228 test_initializer_##P##3, \ |
|
229 test_initializer_##P##4, \ |
|
230 test_initializer_##P##5, \ |
|
231 test_initializer_##P##6, \ |
|
232 test_initializer_##P##7, \ |
|
233 test_initializer_##P##8, \ |
|
234 test_initializer_##P##9, \ |
|
235 test_initializer_##P##a, \ |
|
236 test_initializer_##P##b, \ |
|
237 test_initializer_##P##c, \ |
|
238 test_initializer_##P##d, \ |
|
239 test_initializer_##P##e, \ |
|
240 test_initializer_##P##f |
|
241 #define LIST_256_TEST_INITIALIZERS(P) \ |
|
242 LIST_16_TEST_INITIALIZERS (P##_0), \ |
|
243 LIST_16_TEST_INITIALIZERS (P##_1), \ |
|
244 LIST_16_TEST_INITIALIZERS (P##_2), \ |
|
245 LIST_16_TEST_INITIALIZERS (P##_3), \ |
|
246 LIST_16_TEST_INITIALIZERS (P##_4), \ |
|
247 LIST_16_TEST_INITIALIZERS (P##_5), \ |
|
248 LIST_16_TEST_INITIALIZERS (P##_6), \ |
|
249 LIST_16_TEST_INITIALIZERS (P##_7), \ |
|
250 LIST_16_TEST_INITIALIZERS (P##_8), \ |
|
251 LIST_16_TEST_INITIALIZERS (P##_9), \ |
|
252 LIST_16_TEST_INITIALIZERS (P##_a), \ |
|
253 LIST_16_TEST_INITIALIZERS (P##_b), \ |
|
254 LIST_16_TEST_INITIALIZERS (P##_c), \ |
|
255 LIST_16_TEST_INITIALIZERS (P##_d), \ |
|
256 LIST_16_TEST_INITIALIZERS (P##_e), \ |
|
257 LIST_16_TEST_INITIALIZERS (P##_f) |
|
258 |
|
259 /* define 4 * 256 initializers */ |
|
260 DEFINE_256_TEST_INITIALIZERS (stress1); |
|
261 DEFINE_256_TEST_INITIALIZERS (stress2); |
|
262 DEFINE_256_TEST_INITIALIZERS (stress3); |
|
263 DEFINE_256_TEST_INITIALIZERS (stress4); |
|
264 |
|
265 /* call the above 1024 initializers */ |
|
266 static void* |
|
267 stress_concurrent_initializers (void *user_data) |
|
268 { |
|
269 static void (*initializers[]) (void) = { |
|
270 LIST_256_TEST_INITIALIZERS (stress1), |
|
271 LIST_256_TEST_INITIALIZERS (stress2), |
|
272 LIST_256_TEST_INITIALIZERS (stress3), |
|
273 LIST_256_TEST_INITIALIZERS (stress4), |
|
274 }; |
|
275 int i; |
|
276 /* sync to main thread */ |
|
277 g_mutex_lock (tmutex); |
|
278 g_mutex_unlock (tmutex); |
|
279 /* initialize concurrently */ |
|
280 for (i = 0; i < G_N_ELEMENTS (initializers); i++) |
|
281 { |
|
282 initializers[i](); |
|
283 g_atomic_int_exchange_and_add (&thread_call_count, 1); |
|
284 } |
|
285 return NULL; |
|
286 } |