aface4ea0221ffa09119b683222049c1c91ef06c
[platform/upstream/glib.git] / glib / tests / 642026.c
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 (&sp, &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 ("https://bugzilla.gnome.org/show_bug.cgi?id=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 (&sp);
66       g_atomic_int_set (&freed, 0);
67
68       t1 = g_thread_create (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 (&sp);
76       g_thread_join (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, &argv, NULL);
89
90   g_test_add_func ("/glib/642026", testcase);
91
92   return g_test_run ();
93 }