cleanup
[platform/upstream/glib.git] / tests / onceinit.c
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 }