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

source code of gtk/subprojects/glib/glib/tests/private.c