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