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 | */ |
34 | static void |
35 | test_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 | |
52 | static gint private2_destroy_count; |
53 | |
54 | static void |
55 | private2_destroy (gpointer data) |
56 | { |
57 | g_atomic_int_inc (&private2_destroy_count); |
58 | } |
59 | |
60 | static GPrivate private2 = G_PRIVATE_INIT (private2_destroy); |
61 | |
62 | static gpointer |
63 | private2_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 | */ |
91 | static void |
92 | test_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 | |
109 | static gboolean private3_freed; |
110 | |
111 | static void |
112 | private3_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 | |
122 | static guint __stdcall |
123 | #else |
124 | #include <pthread.h> |
125 | |
126 | static gpointer |
127 | #endif |
128 | private3_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 | |
137 | static void |
138 | test_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 | */ |
166 | static GStaticPrivate sp1 = G_STATIC_PRIVATE_INIT; |
167 | |
168 | static void |
169 | test_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 | |
190 | static gint sp2_destroy_count; |
191 | |
192 | static void |
193 | sp2_destroy (gpointer data) |
194 | { |
195 | sp2_destroy_count++; |
196 | } |
197 | |
198 | static void |
199 | sp2_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 | */ |
209 | static void |
210 | test_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 | */ |
244 | static void |
245 | test_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 | |
272 | static GStaticPrivate sp4 = G_STATIC_PRIVATE_INIT; |
273 | |
274 | static gpointer |
275 | sp4_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 | */ |
298 | static void |
299 | test_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 | |
313 | static GStaticPrivate sp5 = G_STATIC_PRIVATE_INIT; |
314 | static GMutex m5; |
315 | static GCond c5a; |
316 | static GCond c5b; |
317 | static gint count5; |
318 | |
319 | static gpointer |
320 | sp5_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 | |
348 | static void |
349 | test_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 | |
375 | int |
376 | main (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 | |