1 /*
2 * Copyright 2012 Red Hat, Inc.
3 *
4 * SPDX-License-Identifier: LGPL-2.1-or-later
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * See the included COPYING file for more information.
12 */
13
14 #include <glib-object.h>
15
16 gboolean fail;
17
18 #define THREADS 10
19 #define ROUNDS 10000
20
21 GObject *object;
22 gint bucket[THREADS]; /* accessed from multiple threads, but should never be contested due to the sequence of thread operations */
23
24 static gpointer
25 thread_func (gpointer data)
26 {
27 gint idx = GPOINTER_TO_INT (data);
28 gint i;
29 gint d;
30 gint value;
31 gint new_value;
32
33 for (i = 0; i < ROUNDS; i++)
34 {
35 d = g_random_int_range (-10, 100);
36 bucket[idx] += d;
37 retry:
38 value = GPOINTER_TO_INT (g_object_get_data (object, "test"));
39 new_value = value + d;
40 if (fail)
41 g_object_set_data (object, "test", GINT_TO_POINTER (new_value));
42 else
43 {
44 if (!g_object_replace_data (object, "test",
45 GINT_TO_POINTER (value),
46 GINT_TO_POINTER (new_value),
47 NULL, NULL))
48 goto retry;
49 }
50 g_thread_yield ();
51 }
52
53 return NULL;
54 }
55
56 static void
57 test_qdata_threaded (void)
58 {
59 gint sum;
60 gint i;
61 GThread *threads[THREADS];
62 gint result;
63
64 object = g_object_new (G_TYPE_OBJECT, NULL);
65 g_object_set_data (object, "test", GINT_TO_POINTER (0));
66
67 for (i = 0; i < THREADS; i++)
68 bucket[i] = 0;
69
70 for (i = 0; i < THREADS; i++)
71 threads[i] = g_thread_new ("qdata", thread_func, GINT_TO_POINTER (i));
72
73 for (i = 0; i < THREADS; i++)
74 g_thread_join (threads[i]);
75
76 sum = 0;
77 for (i = 0; i < THREADS; i++)
78 sum += bucket[i];
79
80 result = GPOINTER_TO_INT (g_object_get_data (object, "test"));
81
82 g_assert_cmpint (sum, ==, result);
83
84 g_object_unref (object);
85 }
86
87 static void
88 test_qdata_dup (void)
89 {
90 gchar *s, *s2;
91 GQuark quark;
92 gboolean b;
93
94 quark = g_quark_from_static_string ("test");
95 object = g_object_new (G_TYPE_OBJECT, NULL);
96 s = g_strdup ("s");
97 g_object_set_qdata_full (object, quark, s, g_free);
98
99 s2 = g_object_dup_qdata (object, quark, (GDuplicateFunc)g_strdup, NULL);
100
101 g_assert_cmpstr (s, ==, s2);
102 g_assert (s != s2);
103
104 g_free (s2);
105
106 b = g_object_replace_qdata (object, quark, s, "s2", NULL, NULL);
107 g_assert (b);
108
109 g_free (s);
110
111 g_object_unref (object);
112 }
113
114 int
115 main (int argc, char **argv)
116 {
117 g_test_init (&argc, &argv, NULL);
118
119 fail = !!g_getenv ("FAIL");
120
121 g_test_add_func ("/qdata/threaded", test_qdata_threaded);
122 g_test_add_func ("/qdata/dup", test_qdata_dup);
123
124 return g_test_run ();
125 }