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