nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* g_once_init_*() test |
2 | * Copyright (C) 2007 Tim Janik |
||
3 | * |
||
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 | |||
24 | #define N_THREADS (13) |
||
25 | |||
26 | static GMutex tmutex; |
||
27 | static GCond tcond; |
||
28 | static volatile int thread_call_count = 0; |
||
29 | static char dummy_value = 'x'; |
||
30 | |||
31 | static void |
||
32 | assert_singleton_execution1 (void) |
||
33 | { |
||
34 | static volatile int seen_execution = 0; |
||
35 | int old_seen_execution = g_atomic_int_add (&seen_execution, 1); |
||
36 | if (old_seen_execution != 0) |
||
37 | g_error ("%s: function executed more than once", G_STRFUNC); |
||
38 | } |
||
39 | |||
40 | static void |
||
41 | assert_singleton_execution2 (void) |
||
42 | { |
||
43 | static volatile int seen_execution = 0; |
||
44 | int old_seen_execution = g_atomic_int_add (&seen_execution, 1); |
||
45 | if (old_seen_execution != 0) |
||
46 | g_error ("%s: function executed more than once", G_STRFUNC); |
||
47 | } |
||
48 | |||
49 | static void |
||
50 | assert_singleton_execution3 (void) |
||
51 | { |
||
52 | static volatile int seen_execution = 0; |
||
53 | int old_seen_execution = g_atomic_int_add (&seen_execution, 1); |
||
54 | if (old_seen_execution != 0) |
||
55 | g_error ("%s: function executed more than once", G_STRFUNC); |
||
56 | } |
||
57 | |||
58 | static void |
||
59 | initializer1 (void) |
||
60 | { |
||
61 | static volatile gsize initialized = 0; |
||
62 | if (g_once_init_enter (&initialized)) |
||
63 | { |
||
64 | gsize initval = 42; |
||
65 | assert_singleton_execution1(); |
||
66 | g_once_init_leave (&initialized, initval); |
||
67 | } |
||
68 | } |
||
69 | |||
70 | static gpointer |
||
71 | initializer2 (void) |
||
72 | { |
||
73 | static volatile gsize initialized = 0; |
||
74 | if (g_once_init_enter (&initialized)) |
||
75 | { |
||
76 | void *pointer_value = &dummy_value; |
||
77 | assert_singleton_execution2(); |
||
78 | g_once_init_leave (&initialized, (gsize) pointer_value); |
||
79 | } |
||
80 | return (void*) initialized; |
||
81 | } |
||
82 | |||
83 | static void |
||
84 | initializer3 (void) |
||
85 | { |
||
86 | static volatile gsize initialized = 0; |
||
87 | if (g_once_init_enter (&initialized)) |
||
88 | { |
||
89 | gsize initval = 42; |
||
90 | assert_singleton_execution3(); |
||
91 | g_usleep (25 * 1000); /* waste time for multiple threads to wait */ |
||
92 | g_once_init_leave (&initialized, initval); |
||
93 | } |
||
94 | } |
||
95 | |||
96 | static gpointer |
||
97 | tmain_call_initializer3 (gpointer user_data) |
||
98 | { |
||
99 | g_mutex_lock (&tmutex); |
||
100 | g_cond_wait (&tcond, &tmutex); |
||
101 | g_mutex_unlock (&tmutex); |
||
102 | //g_printf ("["); |
||
103 | initializer3(); |
||
104 | //g_printf ("]\n"); |
||
105 | g_atomic_int_add (&thread_call_count, 1); |
||
106 | return NULL; |
||
107 | } |
||
108 | |||
109 | static void* stress_concurrent_initializers (void*); |
||
110 | |||
111 | int |
||
112 | main (int argc, |
||
113 | char *argv[]) |
||
114 | { |
||
115 | G_GNUC_UNUSED GThread *threads[N_THREADS]; |
||
116 | int i; |
||
117 | void *p; |
||
118 | |||
119 | /* test simple initializer */ |
||
120 | initializer1(); |
||
121 | initializer1(); |
||
122 | /* test pointer initializer */ |
||
123 | p = initializer2(); |
||
124 | g_assert (p == &dummy_value); |
||
125 | p = initializer2(); |
||
126 | g_assert (p == &dummy_value); |
||
127 | /* start multiple threads for initializer3() */ |
||
128 | g_mutex_lock (&tmutex); |
||
129 | for (i = 0; i < N_THREADS; i++) |
||
130 | threads[i] = g_thread_create (tmain_call_initializer3, 0, FALSE, NULL); |
||
131 | g_mutex_unlock (&tmutex); |
||
132 | /* concurrently call initializer3() */ |
||
133 | g_cond_broadcast (&tcond); |
||
134 | /* loop until all threads passed the call to initializer3() */ |
||
135 | while (g_atomic_int_get (&thread_call_count) < i) |
||
136 | { |
||
137 | if (rand() % 2) |
||
138 | g_thread_yield(); /* concurrent shuffling for single core */ |
||
139 | else |
||
140 | g_usleep (1000); /* concurrent shuffling for multi core */ |
||
141 | g_cond_broadcast (&tcond); |
||
142 | } |
||
143 | /* call multiple (unoptimized) initializers from multiple threads */ |
||
144 | g_mutex_lock (&tmutex); |
||
145 | g_atomic_int_set (&thread_call_count, 0); |
||
146 | for (i = 0; i < N_THREADS; i++) |
||
147 | g_thread_create (stress_concurrent_initializers, 0, FALSE, NULL); |
||
148 | g_mutex_unlock (&tmutex); |
||
149 | while (g_atomic_int_get (&thread_call_count) < 256 * 4 * N_THREADS) |
||
150 | g_usleep (50 * 1000); /* wait for all 5 threads to complete */ |
||
151 | return 0; |
||
152 | } |
||
153 | |||
154 | /* get rid of g_once_init_enter-optimizations in the below definitions |
||
155 | * to uncover possible races in the g_once_init_enter_impl()/ |
||
156 | * g_once_init_leave() implementations |
||
157 | */ |
||
158 | #undef g_once_init_enter |
||
159 | #undef g_once_init_leave |
||
160 | |||
161 | /* define 16 * 16 simple initializers */ |
||
162 | #define DEFINE_TEST_INITIALIZER(N) \ |
||
163 | static void \ |
||
164 | test_initializer_##N (void) \ |
||
165 | { \ |
||
166 | static volatile gsize initialized = 0; \ |
||
167 | if (g_once_init_enter (&initialized)) \ |
||
168 | { \ |
||
169 | g_free (g_strdup_printf ("cpuhog%5d", 1)); \ |
||
170 | g_free (g_strdup_printf ("cpuhog%6d", 2)); \ |
||
171 | g_free (g_strdup_printf ("cpuhog%7d", 3)); \ |
||
172 | g_once_init_leave (&initialized, 1); \ |
||
173 | } \ |
||
174 | } |
||
175 | #define DEFINE_16_TEST_INITIALIZERS(P) \ |
||
176 | DEFINE_TEST_INITIALIZER (P##0) \ |
||
177 | DEFINE_TEST_INITIALIZER (P##1) \ |
||
178 | DEFINE_TEST_INITIALIZER (P##2) \ |
||
179 | DEFINE_TEST_INITIALIZER (P##3) \ |
||
180 | DEFINE_TEST_INITIALIZER (P##4) \ |
||
181 | DEFINE_TEST_INITIALIZER (P##5) \ |
||
182 | DEFINE_TEST_INITIALIZER (P##6) \ |
||
183 | DEFINE_TEST_INITIALIZER (P##7) \ |
||
184 | DEFINE_TEST_INITIALIZER (P##8) \ |
||
185 | DEFINE_TEST_INITIALIZER (P##9) \ |
||
186 | DEFINE_TEST_INITIALIZER (P##a) \ |
||
187 | DEFINE_TEST_INITIALIZER (P##b) \ |
||
188 | DEFINE_TEST_INITIALIZER (P##c) \ |
||
189 | DEFINE_TEST_INITIALIZER (P##d) \ |
||
190 | DEFINE_TEST_INITIALIZER (P##e) \ |
||
191 | DEFINE_TEST_INITIALIZER (P##f) |
||
192 | #define DEFINE_256_TEST_INITIALIZERS(P) \ |
||
193 | DEFINE_16_TEST_INITIALIZERS (P##_0) \ |
||
194 | DEFINE_16_TEST_INITIALIZERS (P##_1) \ |
||
195 | DEFINE_16_TEST_INITIALIZERS (P##_2) \ |
||
196 | DEFINE_16_TEST_INITIALIZERS (P##_3) \ |
||
197 | DEFINE_16_TEST_INITIALIZERS (P##_4) \ |
||
198 | DEFINE_16_TEST_INITIALIZERS (P##_5) \ |
||
199 | DEFINE_16_TEST_INITIALIZERS (P##_6) \ |
||
200 | DEFINE_16_TEST_INITIALIZERS (P##_7) \ |
||
201 | DEFINE_16_TEST_INITIALIZERS (P##_8) \ |
||
202 | DEFINE_16_TEST_INITIALIZERS (P##_9) \ |
||
203 | DEFINE_16_TEST_INITIALIZERS (P##_a) \ |
||
204 | DEFINE_16_TEST_INITIALIZERS (P##_b) \ |
||
205 | DEFINE_16_TEST_INITIALIZERS (P##_c) \ |
||
206 | DEFINE_16_TEST_INITIALIZERS (P##_d) \ |
||
207 | DEFINE_16_TEST_INITIALIZERS (P##_e) \ |
||
208 | DEFINE_16_TEST_INITIALIZERS (P##_f) |
||
209 | |||
210 | /* list 16 * 16 simple initializers */ |
||
211 | #define LIST_16_TEST_INITIALIZERS(P) \ |
||
212 | test_initializer_##P##0, \ |
||
213 | test_initializer_##P##1, \ |
||
214 | test_initializer_##P##2, \ |
||
215 | test_initializer_##P##3, \ |
||
216 | test_initializer_##P##4, \ |
||
217 | test_initializer_##P##5, \ |
||
218 | test_initializer_##P##6, \ |
||
219 | test_initializer_##P##7, \ |
||
220 | test_initializer_##P##8, \ |
||
221 | test_initializer_##P##9, \ |
||
222 | test_initializer_##P##a, \ |
||
223 | test_initializer_##P##b, \ |
||
224 | test_initializer_##P##c, \ |
||
225 | test_initializer_##P##d, \ |
||
226 | test_initializer_##P##e, \ |
||
227 | test_initializer_##P##f |
||
228 | #define LIST_256_TEST_INITIALIZERS(P) \ |
||
229 | LIST_16_TEST_INITIALIZERS (P##_0), \ |
||
230 | LIST_16_TEST_INITIALIZERS (P##_1), \ |
||
231 | LIST_16_TEST_INITIALIZERS (P##_2), \ |
||
232 | LIST_16_TEST_INITIALIZERS (P##_3), \ |
||
233 | LIST_16_TEST_INITIALIZERS (P##_4), \ |
||
234 | LIST_16_TEST_INITIALIZERS (P##_5), \ |
||
235 | LIST_16_TEST_INITIALIZERS (P##_6), \ |
||
236 | LIST_16_TEST_INITIALIZERS (P##_7), \ |
||
237 | LIST_16_TEST_INITIALIZERS (P##_8), \ |
||
238 | LIST_16_TEST_INITIALIZERS (P##_9), \ |
||
239 | LIST_16_TEST_INITIALIZERS (P##_a), \ |
||
240 | LIST_16_TEST_INITIALIZERS (P##_b), \ |
||
241 | LIST_16_TEST_INITIALIZERS (P##_c), \ |
||
242 | LIST_16_TEST_INITIALIZERS (P##_d), \ |
||
243 | LIST_16_TEST_INITIALIZERS (P##_e), \ |
||
244 | LIST_16_TEST_INITIALIZERS (P##_f) |
||
245 | |||
246 | /* define 4 * 256 initializers */ |
||
247 | DEFINE_256_TEST_INITIALIZERS (stress1); |
||
248 | DEFINE_256_TEST_INITIALIZERS (stress2); |
||
249 | DEFINE_256_TEST_INITIALIZERS (stress3); |
||
250 | DEFINE_256_TEST_INITIALIZERS (stress4); |
||
251 | |||
252 | /* call the above 1024 initializers */ |
||
253 | static void* |
||
254 | stress_concurrent_initializers (void *user_data) |
||
255 | { |
||
256 | static void (*initializers[]) (void) = { |
||
257 | LIST_256_TEST_INITIALIZERS (stress1), |
||
258 | LIST_256_TEST_INITIALIZERS (stress2), |
||
259 | LIST_256_TEST_INITIALIZERS (stress3), |
||
260 | LIST_256_TEST_INITIALIZERS (stress4), |
||
261 | }; |
||
262 | int i; |
||
263 | /* sync to main thread */ |
||
264 | g_mutex_lock (&tmutex); |
||
265 | g_mutex_unlock (&tmutex); |
||
266 | /* initialize concurrently */ |
||
267 | for (i = 0; i < G_N_ELEMENTS (initializers); i++) |
||
268 | { |
||
269 | initializers[i](); |
||
270 | g_atomic_int_add (&thread_call_count, 1); |
||
271 | } |
||
272 | return NULL; |
||
273 | } |