0aee7597e045d34582a767af618216baaefe2d1e
[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               (11)
25
26 static GMutex      *tmutex = NULL;
27 static GCond       *tcond = NULL;
28 static volatile int tmain_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_exchange_and_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_exchange_and_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_exchange_and_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_exchange_and_add (&tmain_call_count, 1);
106   return NULL;
107 }
108
109 int
110 main (int   argc,
111       char *argv[])
112 {
113   GThread *threads[11];
114   int i;
115   /* test simple initializer */
116   initializer1();
117   initializer1();
118   /* test pointer initializer */
119   void *p = initializer2();
120   g_assert (p == &dummy_value);
121   p = initializer2();
122   g_assert (p == &dummy_value);
123   /* setup threads */
124   g_thread_init (NULL);
125   tmutex = g_mutex_new ();
126   tcond = g_cond_new ();
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 (&tmain_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   return 0;
144 }