1 #ifndef GLIB_DISABLE_DEPRECATION_WARNINGS
2 #define GLIB_DISABLE_DEPRECATION_WARNINGS
3 #endif
4
5 #include <glib.h>
6
7 /* GMutex */
8
9 static GMutex test_g_mutex_mutex;
10 static guint test_g_mutex_int = 0;
11 static gboolean test_g_mutex_thread_ready;
12 G_LOCK_DEFINE_STATIC (test_g_mutex);
13
14 static gpointer
15 test_g_mutex_thread (gpointer data)
16 {
17 g_assert_cmpint (GPOINTER_TO_INT (data), ==, 42);
18 g_assert_false (g_mutex_trylock (&test_g_mutex_mutex));
19 g_assert_false (G_TRYLOCK (test_g_mutex));
20 test_g_mutex_thread_ready = TRUE;
21 g_mutex_lock (&test_g_mutex_mutex);
22 g_assert_cmpint (test_g_mutex_int, ==, 42);
23 g_mutex_unlock (&test_g_mutex_mutex);
24
25 return GINT_TO_POINTER (41);
26 }
27
28 static void
29 test_g_mutex (void)
30 {
31 GThread *thread;
32
33 g_assert_true (g_mutex_trylock (&test_g_mutex_mutex));
34 g_assert_true (G_TRYLOCK (test_g_mutex));
35 test_g_mutex_thread_ready = FALSE;
36 thread = g_thread_create (test_g_mutex_thread, GINT_TO_POINTER (42),
37 TRUE, NULL);
38 /* This busy wait is only for testing purposes and not an example of
39 * good code!*/
40 while (!test_g_mutex_thread_ready)
41 g_usleep (G_USEC_PER_SEC / 5);
42 test_g_mutex_int = 42;
43 G_UNLOCK (test_g_mutex);
44 g_mutex_unlock (&test_g_mutex_mutex);
45 g_assert_cmpint (GPOINTER_TO_INT (g_thread_join (thread)), ==, 41);
46 }
47
48 /* GStaticRecMutex */
49
50 static GStaticRecMutex test_g_static_rec_mutex_mutex = G_STATIC_REC_MUTEX_INIT;
51 static guint test_g_static_rec_mutex_int = 0;
52 static gboolean test_g_static_rec_mutex_thread_ready;
53
54 static gpointer
55 test_g_static_rec_mutex_thread (gpointer data)
56 {
57 g_assert_cmpint (GPOINTER_TO_INT (data), ==, 42);
58 g_assert_false (g_static_rec_mutex_trylock (&test_g_static_rec_mutex_mutex));
59
60 test_g_static_rec_mutex_thread_ready = TRUE;
61 g_static_rec_mutex_lock (&test_g_static_rec_mutex_mutex);
62 g_static_rec_mutex_lock (&test_g_static_rec_mutex_mutex);
63 g_assert_cmpint (test_g_static_rec_mutex_int, ==, 42);
64
65 test_g_static_rec_mutex_thread_ready = FALSE;
66 g_static_rec_mutex_unlock (&test_g_static_rec_mutex_mutex);
67 g_static_rec_mutex_unlock (&test_g_static_rec_mutex_mutex);
68
69 g_thread_exit (GINT_TO_POINTER (43));
70
71 g_assert_not_reached ();
72 return NULL;
73 }
74
75 static void
76 test_g_static_rec_mutex (void)
77 {
78 GThread *thread;
79
80 g_assert_true (g_static_rec_mutex_trylock (&test_g_static_rec_mutex_mutex));
81 test_g_static_rec_mutex_thread_ready = FALSE;
82 thread = g_thread_create (test_g_static_rec_mutex_thread,
83 GINT_TO_POINTER (42), TRUE, NULL);
84 /* This busy wait is only for testing purposes and not an example of
85 * good code!*/
86 while (!test_g_static_rec_mutex_thread_ready)
87 g_usleep (G_USEC_PER_SEC / 5);
88
89 g_assert_true (g_static_rec_mutex_trylock (&test_g_static_rec_mutex_mutex));
90 test_g_static_rec_mutex_int = 41;
91 g_static_rec_mutex_unlock (&test_g_static_rec_mutex_mutex);
92 test_g_static_rec_mutex_int = 42;
93 g_static_rec_mutex_unlock (&test_g_static_rec_mutex_mutex);
94
95 /* This busy wait is only for testing purposes and not an example of
96 * good code!*/
97 while (test_g_static_rec_mutex_thread_ready)
98 g_usleep (G_USEC_PER_SEC / 5);
99
100 g_static_rec_mutex_lock (&test_g_static_rec_mutex_mutex);
101 test_g_static_rec_mutex_int = 0;
102 g_static_rec_mutex_unlock (&test_g_static_rec_mutex_mutex);
103
104 g_assert_cmpint (GPOINTER_TO_INT (g_thread_join (thread)), ==, 43);
105 }
106
107 /* GStaticPrivate */
108
109 #define THREADS 10
110
111 static GStaticPrivate test_g_static_private_private1 = G_STATIC_PRIVATE_INIT;
112 static GStaticPrivate test_g_static_private_private2 = G_STATIC_PRIVATE_INIT;
113 static GMutex test_g_static_private_mutex;
114 static guint test_g_static_private_counter = 0;
115 static guint test_g_static_private_ready = 0;
116
117 static gpointer
118 test_g_static_private_constructor (void)
119 {
120 g_mutex_lock (&test_g_static_private_mutex);
121 test_g_static_private_counter++;
122 g_mutex_unlock (&test_g_static_private_mutex);
123 return g_new (guint,1);
124 }
125
126 static void
127 test_g_static_private_destructor (gpointer data)
128 {
129 g_mutex_lock (&test_g_static_private_mutex);
130 test_g_static_private_counter--;
131 g_mutex_unlock (&test_g_static_private_mutex);
132 g_free (data);
133 }
134
135
136 static gpointer
137 test_g_static_private_thread (gpointer data)
138 {
139 guint number = GPOINTER_TO_INT (data);
140 guint i;
141 guint *private1, *private2;
142 for (i = 0; i < 10; i++)
143 {
144 number = number * 11 + 1; /* A very simple and bad RNG ;-) */
145 private1 = g_static_private_get (&test_g_static_private_private1);
146 if (!private1 || number % 7 > 3)
147 {
148 private1 = test_g_static_private_constructor ();
149 g_static_private_set (&test_g_static_private_private1, private1,
150 test_g_static_private_destructor);
151 }
152 *private1 = number;
153 private2 = g_static_private_get (&test_g_static_private_private2);
154 if (!private2 || number % 13 > 5)
155 {
156 private2 = test_g_static_private_constructor ();
157 g_static_private_set (&test_g_static_private_private2, private2,
158 test_g_static_private_destructor);
159 }
160 *private2 = number * 2;
161 g_usleep (G_USEC_PER_SEC / 5);
162 g_assert_cmpint (number, ==, *private1);
163 g_assert_cmpint (number * 2, ==, *private2);
164 }
165 g_mutex_lock (&test_g_static_private_mutex);
166 test_g_static_private_ready++;
167 g_mutex_unlock (&test_g_static_private_mutex);
168
169 /* Busy wait is not nice but that's just a test */
170 while (test_g_static_private_ready != 0)
171 g_usleep (G_USEC_PER_SEC / 5);
172
173 for (i = 0; i < 10; i++)
174 {
175 private2 = g_static_private_get (&test_g_static_private_private2);
176 number = number * 11 + 1; /* A very simple and bad RNG ;-) */
177 if (!private2 || number % 13 > 5)
178 {
179 private2 = test_g_static_private_constructor ();
180 g_static_private_set (&test_g_static_private_private2, private2,
181 test_g_static_private_destructor);
182 }
183 *private2 = number * 2;
184 g_usleep (G_USEC_PER_SEC / 5);
185 g_assert_cmpint (number * 2, ==, *private2);
186 }
187
188 return GINT_TO_POINTER (GPOINTER_TO_INT (data) * 3);
189 }
190
191 static void
192 test_g_static_private (void)
193 {
194 GThread *threads[THREADS];
195 guint i;
196
197 test_g_static_private_ready = 0;
198
199 for (i = 0; i < THREADS; i++)
200 {
201 threads[i] = g_thread_create (test_g_static_private_thread,
202 GINT_TO_POINTER (i), TRUE, NULL);
203 }
204
205 /* Busy wait is not nice but that's just a test */
206 while (test_g_static_private_ready != THREADS)
207 g_usleep (G_USEC_PER_SEC / 5);
208
209 /* Reuse the static private */
210 g_static_private_free (&test_g_static_private_private2);
211 g_static_private_init (&test_g_static_private_private2);
212
213 test_g_static_private_ready = 0;
214
215 for (i = 0; i < THREADS; i++)
216 g_assert_cmpint (GPOINTER_TO_UINT (g_thread_join (threads[i])), ==, i * 3);
217
218 g_assert_cmpint (test_g_static_private_counter, ==, 0);
219 }
220
221 /* GStaticRWLock */
222
223 /* -1 = writing; >0 = # of readers */
224 static gint test_g_static_rw_lock_state = 0;
225 G_LOCK_DEFINE (test_g_static_rw_lock_state);
226
227 static gboolean test_g_static_rw_lock_run = TRUE;
228 static GStaticRWLock test_g_static_rw_lock_lock = G_STATIC_RW_LOCK_INIT;
229
230 static gpointer
231 test_g_static_rw_lock_thread (gpointer data)
232 {
233 while (test_g_static_rw_lock_run)
234 {
235 if (g_random_double() > .2) /* I'm a reader */
236 {
237
238 if (g_random_double() > .2) /* I'll block */
239 g_static_rw_lock_reader_lock (&test_g_static_rw_lock_lock);
240 else /* I'll only try */
241 if (!g_static_rw_lock_reader_trylock (&test_g_static_rw_lock_lock))
242 continue;
243 G_LOCK (test_g_static_rw_lock_state);
244 g_assert_cmpint (test_g_static_rw_lock_state, >=, 0);
245 test_g_static_rw_lock_state++;
246 G_UNLOCK (test_g_static_rw_lock_state);
247
248 g_usleep (g_random_int_range (20,1000));
249
250 G_LOCK (test_g_static_rw_lock_state);
251 test_g_static_rw_lock_state--;
252 G_UNLOCK (test_g_static_rw_lock_state);
253
254 g_static_rw_lock_reader_unlock (&test_g_static_rw_lock_lock);
255 }
256 else /* I'm a writer */
257 {
258 if (g_random_double () > .2) /* I'll block */
259 g_static_rw_lock_writer_lock (&test_g_static_rw_lock_lock);
260 else /* I'll only try */
261 if (!g_static_rw_lock_writer_trylock (&test_g_static_rw_lock_lock))
262 continue;
263 G_LOCK (test_g_static_rw_lock_state);
264 g_assert_cmpint (test_g_static_rw_lock_state, ==, 0);
265 test_g_static_rw_lock_state = -1;
266 G_UNLOCK (test_g_static_rw_lock_state);
267
268 g_usleep (g_random_int_range (20,1000));
269
270 G_LOCK (test_g_static_rw_lock_state);
271 test_g_static_rw_lock_state = 0;
272 G_UNLOCK (test_g_static_rw_lock_state);
273
274 g_static_rw_lock_writer_unlock (&test_g_static_rw_lock_lock);
275 }
276 }
277 return NULL;
278 }
279
280 static void
281 test_g_static_rw_lock (void)
282 {
283 GThread *threads[THREADS];
284 guint i;
285 for (i = 0; i < THREADS; i++)
286 {
287 threads[i] = g_thread_create (test_g_static_rw_lock_thread,
288 NULL, TRUE, NULL);
289 }
290 g_usleep (G_USEC_PER_SEC * 5);
291 test_g_static_rw_lock_run = FALSE;
292 for (i = 0; i < THREADS; i++)
293 {
294 g_thread_join (threads[i]);
295 }
296 g_assert_cmpint (test_g_static_rw_lock_state, ==, 0);
297 }
298
299 #define G_ONCE_SIZE 100
300 #define G_ONCE_THREADS 10
301
302 G_LOCK_DEFINE (test_g_once);
303 static guint test_g_once_guint_array[G_ONCE_SIZE];
304 static GOnce test_g_once_array[G_ONCE_SIZE];
305
306 static gpointer
307 test_g_once_init_func(gpointer arg)
308 {
309 guint *count = arg;
310 g_usleep (g_random_int_range (20,1000));
311 (*count)++;
312 g_usleep (g_random_int_range (20,1000));
313 return arg;
314 }
315
316 static gpointer
317 test_g_once_thread (gpointer ignore)
318 {
319 guint i;
320 G_LOCK (test_g_once);
321 /* Don't start before all threads are created */
322 G_UNLOCK (test_g_once);
323 for (i = 0; i < 1000; i++)
324 {
325 guint pos = g_random_int_range (0, G_ONCE_SIZE);
326 gpointer ret = g_once (test_g_once_array + pos,
327 test_g_once_init_func,
328 test_g_once_guint_array + pos);
329 g_assert_cmpmem (ret, sizeof (int),
330 test_g_once_guint_array + pos, sizeof (int));
331 }
332
333 /* Make sure, that all counters are touched at least once */
334 for (i = 0; i < G_ONCE_SIZE; i++)
335 {
336 gpointer ret = g_once (test_g_once_array + i,
337 test_g_once_init_func,
338 test_g_once_guint_array + i);
339 g_assert_cmpmem (ret, sizeof (int),
340 test_g_once_guint_array + i, sizeof (int));
341 }
342
343 return NULL;
344 }
345
346 static void
347 test_g_thread_once (void)
348 {
349 static GOnce once_init = G_ONCE_INIT;
350 GThread *threads[G_ONCE_THREADS];
351 guint i;
352 for (i = 0; i < G_ONCE_SIZE; i++)
353 {
354 test_g_once_array[i] = once_init;
355 test_g_once_guint_array[i] = i;
356 }
357 G_LOCK (test_g_once);
358 for (i = 0; i < G_ONCE_THREADS; i++)
359 {
360 threads[i] = g_thread_create (test_g_once_thread, GUINT_TO_POINTER (i % 2),
361 TRUE, NULL);
362 }
363 G_UNLOCK (test_g_once);
364 for (i = 0; i < G_ONCE_THREADS; i++)
365 {
366 g_thread_join (threads[i]);
367 }
368
369 for (i = 0; i < G_ONCE_SIZE; i++)
370 {
371 g_assert_cmpint (test_g_once_guint_array[i], ==, i + 1);
372 }
373 }
374
375 /* rerun all the tests */
376 static void
377 test_rerun_all (void)
378 {
379 /* Now we rerun all tests, but this time we fool the system into
380 * thinking, that the available thread system is not native, but
381 * userprovided. */
382 g_thread_use_default_impl = FALSE;
383
384 test_g_mutex ();
385 test_g_static_rec_mutex ();
386 test_g_static_private ();
387 test_g_static_rw_lock ();
388 test_g_thread_once ();
389
390 /* XXX: And this shows how silly the above non-native tests are */
391 g_static_rw_lock_free (&test_g_static_rw_lock_lock);
392 g_static_rec_mutex_free (&test_g_static_rec_mutex_mutex);
393 g_static_private_free (&test_g_static_private_private2);
394 }
395
396 int
397 main (int argc,
398 char *argv[])
399 {
400 g_test_init (&argc, &argv, NULL);
401
402 g_test_add_func ("/thread/mutex", test_g_mutex);
403 g_test_add_func ("/thread/static-rec-mutex", test_g_static_rec_mutex);
404 g_test_add_func ("/thread/static-private", test_g_static_private);
405 g_test_add_func ("/thread/static-rw-lock", test_g_static_rw_lock);
406 g_test_add_func ("/thread/once", test_g_thread_once);
407 g_test_add_func ("/thread/rerun-all", test_rerun_all);
408
409 return g_test_run ();
410 }