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