1 | /* |
2 | * Author: Simon McVittie <simon.mcvittie@collabora.co.uk> |
3 | * Copyright © 2011 Nokia Corporation |
4 | * |
5 | * This program is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU Lesser General Public |
7 | * License as published by the Free Software Foundation; either |
8 | * version 2.1 of the License, or (at your option) any later version. |
9 | * |
10 | * See the included COPYING file for more information. |
11 | */ |
12 | |
13 | #ifndef GLIB_DISABLE_DEPRECATION_WARNINGS |
14 | #define GLIB_DISABLE_DEPRECATION_WARNINGS |
15 | #endif |
16 | |
17 | #include <glib.h> |
18 | |
19 | /* On smcv's laptop, 1e4 iterations didn't always exhibit the bug, but 1e5 |
20 | * iterations exhibited it 10/10 times in practice. YMMV. */ |
21 | #define ITERATIONS 100000 |
22 | |
23 | static GStaticPrivate sp; |
24 | static GMutex *mutex; |
25 | static GCond *cond; |
26 | static guint i; |
27 | |
28 | static gint freed = 0; /* (atomic) */ |
29 | |
30 | static void |
31 | notify (gpointer p) |
32 | { |
33 | if (!g_atomic_int_compare_and_exchange (&freed, 0, 1)) |
34 | { |
35 | g_error ("someone already freed it after %u iterations" , i); |
36 | } |
37 | } |
38 | |
39 | static gpointer thread_func (gpointer nil) |
40 | { |
41 | /* wait for main thread to reach its g_cond_wait call */ |
42 | g_mutex_lock (mutex); |
43 | |
44 | g_static_private_set (private_key: &sp, data: &sp, notify); |
45 | g_cond_broadcast (cond); |
46 | g_mutex_unlock (mutex); |
47 | |
48 | return nil; |
49 | } |
50 | |
51 | static void |
52 | testcase (void) |
53 | { |
54 | g_test_bug (bug_uri_snippet: "642026" ); |
55 | |
56 | mutex = g_mutex_new (); |
57 | cond = g_cond_new (); |
58 | |
59 | g_mutex_lock (mutex); |
60 | |
61 | for (i = 0; i < ITERATIONS; i++) |
62 | { |
63 | GThread *t1; |
64 | |
65 | g_static_private_init (private_key: &sp); |
66 | g_atomic_int_set (&freed, 0); |
67 | |
68 | t1 = g_thread_create (func: thread_func, NULL, TRUE, NULL); |
69 | g_assert (t1 != NULL); |
70 | |
71 | /* wait for t1 to set up its thread-private data */ |
72 | g_cond_wait (cond, mutex); |
73 | |
74 | /* exercise the bug, by racing with t1 to free the private data */ |
75 | g_static_private_free (private_key: &sp); |
76 | g_thread_join (thread: t1); |
77 | } |
78 | |
79 | g_cond_free (cond); |
80 | g_mutex_unlock (mutex); |
81 | g_mutex_free (mutex); |
82 | } |
83 | |
84 | int |
85 | main (int argc, |
86 | char **argv) |
87 | { |
88 | g_test_init (argc: &argc, argv: &argv, NULL); |
89 | g_test_bug_base (uri_pattern: "https://bugzilla.gnome.org/show_bug.cgi?id=" ); |
90 | |
91 | g_test_add_func (testpath: "/glib/642026" , test_func: testcase); |
92 | |
93 | return g_test_run (); |
94 | } |
95 | |