GLib: implement GMutex natively on Linux
[platform/upstream/glib.git] / glib / tests / private.c
1 /* Unit tests for GPrivate and friends
2  * Copyright (C) 2011 Red Hat, Inc
3  * Author: Matthias Clasen
4  *
5  * This work is provided "as is"; redistribution and modification
6  * in whole or in part, in any medium, physical or electronic is
7  * permitted without restriction.
8  *
9  * This work is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  * In no event shall the authors or contributors be liable for any
14  * direct, indirect, incidental, special, exemplary, or consequential
15  * damages (including, but not limited to, procurement of substitute
16  * goods or services; loss of use, data, or profits; or business
17  * interruption) however caused and on any theory of liability, whether
18  * in contract, strict liability, or tort (including negligence or
19  * otherwise) arising in any way out of the use of this software, even
20  * if advised of the possibility of such damage.
21  */
22
23 /* We are testing some deprecated APIs here */
24 #define GLIB_DISABLE_DEPRECATION_WARNINGS
25
26 #include <glib.h>
27
28 /* test basics:
29  * - initial value is NULL
30  * - set/get work repeatedly
31  */
32 static void
33 test_private1 (void)
34 {
35   static GPrivate private = G_PRIVATE_INIT (NULL);
36   gpointer value;
37
38   value = g_private_get (&private);
39   g_assert (value == NULL);
40
41   g_private_set (&private, GINT_TO_POINTER(1));
42   value = g_private_get (&private);
43   g_assert_cmpint (GPOINTER_TO_INT (value), ==, 1);
44
45   g_private_set (&private, GINT_TO_POINTER(2));
46   value = g_private_get (&private);
47   g_assert_cmpint (GPOINTER_TO_INT (value), ==, 2);
48 }
49
50 static gint private2_destroy_count;
51
52 static void
53 private2_destroy (gpointer data)
54 {
55   g_atomic_int_inc (&private2_destroy_count);
56 }
57
58 static GPrivate private2 = G_PRIVATE_INIT (private2_destroy);
59
60 static gpointer
61 private2_func (gpointer data)
62 {
63   gint value = GPOINTER_TO_INT (data);
64   gint i;
65   gint v, v2;
66
67   for (i = 0; i < 1000; i++)
68     {
69       v = value + (i % 5);
70       g_private_set (&private2, GINT_TO_POINTER (v));
71       g_usleep (1000);
72       v2 = GPOINTER_TO_INT (g_private_get (&private2));
73       g_assert_cmpint (v, ==, v2);
74     }
75
76   if (value % 2 == 0)
77     g_thread_exit (NULL);
78
79   return NULL;
80 }
81
82 /* test that
83  * - threads do not interfere with each other
84  * - destroy notifies are called for each thread exit
85  * - destroy notifies are called for g_thread_exit() too
86  * - destroy notifies are not called on g_private_set()
87  * - destroy notifies are called on g_private_replace()
88  */
89 static void
90 test_private2 (void)
91 {
92   GThread *thread[10];
93   gint i;
94
95   g_private_set (&private2, GINT_TO_POINTER (234));
96   g_private_replace (&private2, GINT_TO_POINTER (123));
97
98   for (i = 0; i < 10; i++)
99     thread[i] = g_thread_create (private2_func, GINT_TO_POINTER (i), TRUE, NULL);
100
101   for (i = 0; i < 10; i++)
102     g_thread_join (thread[i]);
103
104   g_assert_cmpint (private2_destroy_count, ==, 11);
105 }
106
107 static gboolean private3_freed;
108
109 static void
110 private3_free (gpointer data)
111 {
112   g_assert (data == (void*) 0x1234);
113   private3_freed = TRUE;
114 }
115
116 #ifdef G_OS_WIN32
117 #include <windows.h>
118 #include <process.h>
119
120 static guint __stdcall
121 #else
122 #include <pthread.h>
123
124 static gpointer
125 #endif
126 private3_func (gpointer data)
127 {
128   static GPrivate key = G_PRIVATE_INIT (private3_free);
129
130   g_private_set (&key, (void *) 0x1234);
131
132   return 0;
133 }
134
135 static void
136 test_private3 (void)
137 {
138   g_assert (!private3_freed);
139
140 #ifdef G_OS_WIN32
141   {
142     HANDLE thread;
143     guint ignore;
144     thread = (HANDLE) _beginthreadex (NULL, 0, private3_func, NULL, 0, &ignore);
145     WaitForSingleObject (thread, INFINITE);
146     CloseHandle (thread);
147   }
148 #else
149   {
150     pthread_t thread;
151
152     pthread_create (&thread, NULL, private3_func, NULL);
153     pthread_join (thread, NULL);
154   }
155 #endif
156   g_assert (private3_freed);
157 }
158
159 /* test basics:
160  * - static initialization works
161  * - initial value is NULL
162  * - get/set works repeatedly
163  */
164 static GStaticPrivate sp1 = G_STATIC_PRIVATE_INIT;
165
166 static void
167 test_static_private1 (void)
168 {
169   gpointer value;
170
171   value = g_static_private_get (&sp1);
172   g_assert (value == NULL);
173
174   g_static_private_set (&sp1, GINT_TO_POINTER(1), NULL);
175   value = g_static_private_get (&sp1);
176   g_assert_cmpint (GPOINTER_TO_INT(value), ==, 1);
177
178   g_static_private_set (&sp1, GINT_TO_POINTER(2), NULL);
179   value = g_static_private_get (&sp1);
180   g_assert_cmpint (GPOINTER_TO_INT(value), ==, 2);
181
182   g_static_private_free (&sp1);
183
184   value = g_static_private_get (&sp1);
185   g_assert (value == NULL);
186 }
187
188 static gint sp2_destroy_count;
189
190 static void
191 sp2_destroy (gpointer data)
192 {
193   sp2_destroy_count++;
194 }
195
196 static void
197 sp2_destroy2 (gpointer data)
198 {
199   gint value = GPOINTER_TO_INT (data);
200
201   g_assert_cmpint (value, ==, 2);
202 }
203
204 /* test that destroy notifies are called as expected
205  * and on the right values
206  */
207 static void
208 test_static_private2 (void)
209 {
210   GStaticPrivate sp2;
211   gpointer value;
212
213   g_static_private_init (&sp2);
214
215   value = g_static_private_get (&sp2);
216   g_assert (value == NULL);
217
218   g_static_private_set (&sp2, GINT_TO_POINTER(1), sp2_destroy);
219   g_assert_cmpint (sp2_destroy_count, ==, 0);
220   value = g_static_private_get (&sp2);
221   g_assert_cmpint (GPOINTER_TO_INT(value), ==, 1);
222
223   g_static_private_set (&sp2, GINT_TO_POINTER(2), sp2_destroy2);
224   g_assert_cmpint (sp2_destroy_count, ==, 1);
225   value = g_static_private_get (&sp2);
226   g_assert_cmpint (GPOINTER_TO_INT(value), ==, 2);
227
228   g_static_private_set (&sp2, GINT_TO_POINTER(3), sp2_destroy);
229   g_assert_cmpint (sp2_destroy_count, ==, 1);
230   value = g_static_private_get (&sp2);
231   g_assert_cmpint (GPOINTER_TO_INT(value), ==, 3);
232
233   g_static_private_free (&sp2);
234
235   value = g_static_private_get (&sp2);
236   g_assert (value == NULL);
237 }
238
239 /* test that freeing and reinitializing a static private
240  * drops previous value
241  */
242 static void
243 test_static_private3 (void)
244 {
245   GStaticPrivate sp3;
246   gpointer value;
247
248   g_static_private_init (&sp3);
249
250   value = g_static_private_get (&sp3);
251   g_assert (value == NULL);
252
253   g_static_private_set (&sp3, GINT_TO_POINTER(1), NULL);
254   value = g_static_private_get (&sp3);
255   g_assert_cmpint (GPOINTER_TO_INT(value), ==, 1);
256
257   g_static_private_free (&sp3);
258   g_static_private_init (&sp3);
259
260   value = g_static_private_get (&sp3);
261   g_assert (value == NULL);
262
263   g_static_private_set (&sp3, GINT_TO_POINTER(2), NULL);
264   value = g_static_private_get (&sp3);
265   g_assert_cmpint (GPOINTER_TO_INT(value), ==, 2);
266
267   g_static_private_free (&sp3);
268 }
269
270 static GStaticPrivate sp4 = G_STATIC_PRIVATE_INIT;
271
272 static gpointer
273 sp4_func (gpointer data)
274 {
275   gint value = GPOINTER_TO_INT (data);
276   gint i;
277   gint v, v2;
278
279   for (i = 0; i < 1000; i++)
280     {
281       v = value + (i % 5);
282       g_static_private_set (&sp4, GINT_TO_POINTER(v), NULL);
283       g_usleep (1000);
284       v2 = GPOINTER_TO_INT(g_static_private_get (&sp4));
285       g_assert_cmpint (v, ==, v2);
286     }
287
288   if (value % 2 == 0)
289     g_thread_exit (NULL);
290
291   return NULL;
292 }
293
294 /* test that threads do not interfere with each other
295  */
296 static void
297 test_static_private4 (void)
298 {
299   GThread *thread[10];
300   gint i;
301
302   for (i = 0; i < 10; i++)
303     thread[i] = g_thread_create (sp4_func, GINT_TO_POINTER (i), TRUE, NULL);
304
305   for (i = 0; i < 10; i++)
306     g_thread_join (thread[i]);
307
308   g_static_private_free (&sp4);
309 }
310
311 static GStaticPrivate sp5 = G_STATIC_PRIVATE_INIT;
312 static GMutex m5;
313 static GCond c5a;
314 static GCond c5b;
315 static gint count5;
316
317 static gpointer
318 sp5_func (gpointer data)
319 {
320   gint v = GPOINTER_TO_INT (data);
321   gpointer value;
322
323   value = g_static_private_get (&sp5);
324   g_assert (value == NULL);
325
326   g_static_private_set (&sp5, GINT_TO_POINTER (v), NULL);
327   value = g_static_private_get (&sp5);
328   g_assert_cmpint (GPOINTER_TO_INT (value), ==, v);
329
330   if (g_test_verbose ())
331     g_print ("thread %d set sp5\n", v);
332   g_mutex_lock (&m5);
333   g_atomic_int_inc (&count5);
334   g_cond_signal (&c5a);
335   g_cond_wait (&c5b, &m5);
336   g_mutex_unlock (&m5);
337
338   if (g_test_verbose ())
339     g_print ("thread %d get sp5\n", v);
340   value = g_static_private_get (&sp5);
341   g_assert (value == NULL);
342
343   return NULL;
344 }
345
346 static void
347 test_static_private5 (void)
348 {
349   GThread *thread[10];
350   gint i;
351
352   g_atomic_int_set (&count5, 0);
353
354   for (i = 0; i < 10; i++)
355     thread[i] = g_thread_create (sp5_func, GINT_TO_POINTER (i), TRUE, NULL);
356
357   g_mutex_lock (&m5);
358   while (g_atomic_int_get (&count5) < 10)
359     g_cond_wait (&c5a, &m5);
360
361   if (g_test_verbose ())
362     g_print ("sp5 gets nuked\n");
363
364   g_static_private_free (&sp5);
365
366   g_cond_broadcast (&c5b);
367   g_mutex_unlock (&m5);
368
369   for (i = 0; i < 10; i++)
370     g_thread_join (thread[i]);
371 }
372
373 int
374 main (int argc, char *argv[])
375 {
376   g_test_init (&argc, &argv, NULL);
377
378   g_test_add_func ("/thread/private1", test_private1);
379   g_test_add_func ("/thread/private2", test_private2);
380   g_test_add_func ("/thread/private3", test_private3);
381   g_test_add_func ("/thread/staticprivate1", test_static_private1);
382   g_test_add_func ("/thread/staticprivate2", test_static_private2);
383   g_test_add_func ("/thread/staticprivate3", test_static_private3);
384   g_test_add_func ("/thread/staticprivate4", test_static_private4);
385   g_test_add_func ("/thread/staticprivate5", test_static_private5);
386
387   return g_test_run ();
388 }