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
23static GStaticPrivate sp;
24static GMutex *mutex;
25static GCond *cond;
26static guint i;
27
28static gint freed = 0; /* (atomic) */
29
30static void
31notify (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
39static 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
51static void
52testcase (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
84int
85main (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

source code of gtk/subprojects/glib/glib/tests/642026.c