Add GPrivate destroy notify testcase
[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 #include <glib.h>
24
25 /* test basics:
26  * - initial value is NULL
27  * - set/get work repeatedly
28  */
29 static void
30 test_private1 (void)
31 {
32   GPrivate *private1;
33   gpointer value;
34
35   private1 = g_private_new (NULL);
36
37   value = g_private_get (private1);
38   g_assert (value == NULL);
39
40   g_private_set (private1, GINT_TO_POINTER(1));
41   value = g_private_get (private1);
42   g_assert_cmpint (GPOINTER_TO_INT (value), ==, 1);
43
44   g_private_set (private1, GINT_TO_POINTER(2));
45   value = g_private_get (private1);
46   g_assert_cmpint (GPOINTER_TO_INT (value), ==, 2);
47 }
48
49 static GPrivate *private2;
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 gpointer
59 private2_func (gpointer data)
60 {
61   gint value = GPOINTER_TO_INT (data);
62   gint i;
63   gint v, v2;
64
65   for (i = 0; i < 1000; i++)
66     {
67       v = value + (i % 5);
68       g_private_set (private2, GINT_TO_POINTER(v));
69       g_usleep (1000);
70       v2 = GPOINTER_TO_INT(g_private_get (private2));
71       g_assert_cmpint (v, ==, v2);
72     }
73
74   if (value % 2 == 0)
75     g_thread_exit (NULL);
76
77   return NULL;
78 }
79
80 /* test that
81  * - threads do not interfere with each other
82  * - destroy notifies are called for each thread exit
83  * - destroy notifies are called for g_thread_exit() too
84  * - destroy notifies are not called on g_private_set()
85  */
86 static void
87 test_private2 (void)
88 {
89   GThread *thread[10];
90   gint i;
91
92   private2 = g_private_new (private2_destroy);
93
94   for (i = 0; i < 10; i++)
95     thread[i] = g_thread_create (private2_func, GINT_TO_POINTER (i), TRUE, NULL);
96
97   for (i = 0; i < 10; i++)
98     g_thread_join (thread[i]);
99
100   g_assert_cmpint (private2_destroy_count, ==, 10);
101 }
102
103 static gboolean private3_freed;
104
105 static void
106 private3_free (gpointer data)
107 {
108   g_assert (data == (void*) 0x1234);
109   private3_freed = TRUE;
110 }
111
112 #ifdef G_OS_WIN32
113 #include <windows.h>
114
115 static guint __stdcall
116 #else
117 #include <pthread.h>
118
119 static gpointer
120 #endif
121 private3_func (gpointer data)
122 {
123   static GPrivate key = G_PRIVATE_INIT (private3_free);
124
125   g_private_set (&key, (void *) 0x1234);
126
127   return 0;
128 }
129
130 static void
131 test_private3 (void)
132 {
133   g_assert (!private3_freed);
134
135 #ifdef G_OS_WIN32
136   {
137     HANDLE thread;
138     guint ignore;
139     thread = _beginthreadex (NULL, 0, private3_func, NULL, 0, &ignore);
140     WaitForSingleObject (thread, INFINITE);
141     CloseHandle (thread);
142   }
143 #else
144   {
145     pthread_t thread;
146
147     pthread_create (&thread, NULL, private3_func, NULL);
148     pthread_join (thread, NULL);
149   }
150 #endif
151   g_assert (private3_freed);
152 }
153
154 /* test basics:
155  * - static initialization works
156  * - initial value is NULL
157  * - get/set works repeatedly
158  */
159 static GStaticPrivate sp1 = G_STATIC_PRIVATE_INIT;
160
161 static void
162 test_static_private1 (void)
163 {
164   gpointer value;
165
166   value = g_static_private_get (&sp1);
167   g_assert (value == NULL);
168
169   g_static_private_set (&sp1, GINT_TO_POINTER(1), NULL);
170   value = g_static_private_get (&sp1);
171   g_assert_cmpint (GPOINTER_TO_INT(value), ==, 1);
172
173   g_static_private_set (&sp1, GINT_TO_POINTER(2), NULL);
174   value = g_static_private_get (&sp1);
175   g_assert_cmpint (GPOINTER_TO_INT(value), ==, 2);
176
177   g_static_private_free (&sp1);
178
179   value = g_static_private_get (&sp1);
180   g_assert (value == NULL);
181 }
182
183 static gint sp2_destroy_count;
184
185 static void
186 sp2_destroy (gpointer data)
187 {
188   sp2_destroy_count++;
189 }
190
191 static void
192 sp2_destroy2 (gpointer data)
193 {
194   gint value = GPOINTER_TO_INT (data);
195
196   g_assert_cmpint (value, ==, 2);
197 }
198
199 /* test that destroy notifies are called as expected
200  * and on the right values
201  */
202 static void
203 test_static_private2 (void)
204 {
205   GStaticPrivate sp2;
206   gpointer value;
207
208   g_static_private_init (&sp2);
209
210   value = g_static_private_get (&sp2);
211   g_assert (value == NULL);
212
213   g_static_private_set (&sp2, GINT_TO_POINTER(1), sp2_destroy);
214   g_assert_cmpint (sp2_destroy_count, ==, 0);
215   value = g_static_private_get (&sp2);
216   g_assert_cmpint (GPOINTER_TO_INT(value), ==, 1);
217
218   g_static_private_set (&sp2, GINT_TO_POINTER(2), sp2_destroy2);
219   g_assert_cmpint (sp2_destroy_count, ==, 1);
220   value = g_static_private_get (&sp2);
221   g_assert_cmpint (GPOINTER_TO_INT(value), ==, 2);
222
223   g_static_private_set (&sp2, GINT_TO_POINTER(3), sp2_destroy);
224   g_assert_cmpint (sp2_destroy_count, ==, 1);
225   value = g_static_private_get (&sp2);
226   g_assert_cmpint (GPOINTER_TO_INT(value), ==, 3);
227
228   g_static_private_free (&sp2);
229
230   value = g_static_private_get (&sp2);
231   g_assert (value == NULL);
232 }
233
234 /* test that freeing and reinitializing a static private
235  * drops previous value
236  */
237 static void
238 test_static_private3 (void)
239 {
240   GStaticPrivate sp3;
241   gpointer value;
242
243   g_static_private_init (&sp3);
244
245   value = g_static_private_get (&sp3);
246   g_assert (value == NULL);
247
248   g_static_private_set (&sp3, GINT_TO_POINTER(1), NULL);
249   value = g_static_private_get (&sp3);
250   g_assert_cmpint (GPOINTER_TO_INT(value), ==, 1);
251
252   g_static_private_free (&sp3);
253   g_static_private_init (&sp3);
254
255   value = g_static_private_get (&sp3);
256   g_assert (value == NULL);
257
258   g_static_private_set (&sp3, GINT_TO_POINTER(2), NULL);
259   value = g_static_private_get (&sp3);
260   g_assert_cmpint (GPOINTER_TO_INT(value), ==, 2);
261
262   g_static_private_free (&sp3);
263 }
264
265 static GStaticPrivate sp4 = G_STATIC_PRIVATE_INIT;
266
267 static gpointer
268 sp4_func (gpointer data)
269 {
270   gint value = GPOINTER_TO_INT (data);
271   gint i;
272   gint v, v2;
273
274   for (i = 0; i < 1000; i++)
275     {
276       v = value + (i % 5);
277       g_static_private_set (&sp4, GINT_TO_POINTER(v), NULL);
278       g_usleep (1000);
279       v2 = GPOINTER_TO_INT(g_static_private_get (&sp4));
280       g_assert_cmpint (v, ==, v2);
281     }
282
283   if (value % 2 == 0)
284     g_thread_exit (NULL);
285
286   return NULL;
287 }
288
289 /* test that threads do not interfere with each other
290  */
291 static void
292 test_static_private4 (void)
293 {
294   GThread *thread[10];
295   gint i;
296
297   for (i = 0; i < 10; i++)
298     thread[i] = g_thread_create (sp4_func, GINT_TO_POINTER (i), TRUE, NULL);
299
300   for (i = 0; i < 10; i++)
301     g_thread_join (thread[i]);
302
303   g_static_private_free (&sp4);
304 }
305
306 static GStaticPrivate sp5 = G_STATIC_PRIVATE_INIT;
307 static GMutex m5;
308 static GCond c5a;
309 static GCond c5b;
310 static gint count5;
311
312 static gpointer
313 sp5_func (gpointer data)
314 {
315   gint v = GPOINTER_TO_INT (data);
316   gpointer value;
317
318   value = g_static_private_get (&sp5);
319   g_assert (value == NULL);
320
321   g_static_private_set (&sp5, GINT_TO_POINTER (v), NULL);
322   value = g_static_private_get (&sp5);
323   g_assert_cmpint (GPOINTER_TO_INT (value), ==, v);
324
325   if (g_test_verbose ())
326     g_print ("thread %d set sp5\n", v);
327   g_mutex_lock (&m5);
328   g_atomic_int_inc (&count5);
329   g_cond_signal (&c5a);
330   g_cond_wait (&c5b, &m5);
331   g_mutex_unlock (&m5);
332
333   if (g_test_verbose ())
334     g_print ("thread %d get sp5\n", v);
335   value = g_static_private_get (&sp5);
336   g_assert (value == NULL);
337
338   return NULL;
339 }
340
341 static void
342 test_static_private5 (void)
343 {
344   GThread *thread[10];
345   gint i;
346
347   g_atomic_int_set (&count5, 0);
348
349   for (i = 0; i < 10; i++)
350     thread[i] = g_thread_create (sp5_func, GINT_TO_POINTER (i), TRUE, NULL);
351
352   g_mutex_lock (&m5);
353   while (g_atomic_int_get (&count5) < 10)
354     g_cond_wait (&c5a, &m5);
355
356   if (g_test_verbose ())
357     g_print ("sp5 gets nuked\n");
358
359   g_static_private_free (&sp5);
360
361   g_cond_broadcast (&c5b);
362   g_mutex_unlock (&m5);
363
364   for (i = 0; i < 10; i++)
365     g_thread_join (thread[i]);
366
367   g_mutex_clear (&m5);
368   g_cond_clear (&c5a);
369   g_cond_clear (&c5b);
370 }
371
372 int
373 main (int argc, char *argv[])
374 {
375   g_test_init (&argc, &argv, NULL);
376
377   g_assert (g_thread_get_initialized ());
378
379   g_test_add_func ("/thread/private1", test_private1);
380   g_test_add_func ("/thread/private2", test_private2);
381   g_test_add_func ("/thread/private3", test_private3);
382   g_test_add_func ("/thread/staticprivate1", test_static_private1);
383   g_test_add_func ("/thread/staticprivate2", test_static_private2);
384   g_test_add_func ("/thread/staticprivate3", test_static_private3);
385   g_test_add_func ("/thread/staticprivate4", test_static_private4);
386   g_test_add_func ("/thread/staticprivate5", test_static_private5);
387
388   return g_test_run ();
389 }