1 /*
2 * Copyright 2011 Red Hat, Inc.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * See the included COPYING file for more information.
10 */
11
12 #include <glib.h>
13
14 /* We want the g_atomic_pointer_get() macros to work when compiling third party
15 * projects with -Wbad-function-cast.
16 * See https://gitlab.gnome.org/GNOME/glib/issues/1041. */
17 #pragma GCC diagnostic error "-Wbad-function-cast"
18
19 static void
test_types(void)20 test_types (void)
21 {
22 const gint *csp;
23 const gint * const *cspp;
24 guint u, u2;
25 gint s, s2;
26 gpointer vp, vp2;
27 int *ip, *ip2;
28 gsize gs, gs2;
29 gboolean res;
30
31 csp = &s;
32 cspp = &csp;
33
34 g_atomic_int_set (&u, 5);
35 u2 = g_atomic_int_get (&u);
36 g_assert_cmpint (u2, ==, 5);
37 res = g_atomic_int_compare_and_exchange (&u, 6, 7);
38 g_assert (!res);
39 g_assert_cmpint (u, ==, 5);
40 g_atomic_int_add (&u, 1);
41 g_assert_cmpint (u, ==, 6);
42 g_atomic_int_inc (&u);
43 g_assert_cmpint (u, ==, 7);
44 res = g_atomic_int_dec_and_test (&u);
45 g_assert (!res);
46 g_assert_cmpint (u, ==, 6);
47 u2 = g_atomic_int_and (&u, 5);
48 g_assert_cmpint (u2, ==, 6);
49 g_assert_cmpint (u, ==, 4);
50 u2 = g_atomic_int_or (&u, 8);
51 g_assert_cmpint (u2, ==, 4);
52 g_assert_cmpint (u, ==, 12);
53 u2 = g_atomic_int_xor (&u, 4);
54 g_assert_cmpint (u2, ==, 12);
55 g_assert_cmpint (u, ==, 8);
56
57 g_atomic_int_set (&s, 5);
58 s2 = g_atomic_int_get (&s);
59 g_assert_cmpint (s2, ==, 5);
60 res = g_atomic_int_compare_and_exchange (&s, 6, 7);
61 g_assert (!res);
62 g_assert_cmpint (s, ==, 5);
63 g_atomic_int_add (&s, 1);
64 g_assert_cmpint (s, ==, 6);
65 g_atomic_int_inc (&s);
66 g_assert_cmpint (s, ==, 7);
67 res = g_atomic_int_dec_and_test (&s);
68 g_assert (!res);
69 g_assert_cmpint (s, ==, 6);
70 s2 = g_atomic_int_and (&s, 5);
71 g_assert_cmpint (s2, ==, 6);
72 g_assert_cmpint (s, ==, 4);
73 s2 = g_atomic_int_or (&s, 8);
74 g_assert_cmpint (s2, ==, 4);
75 g_assert_cmpint (s, ==, 12);
76 s2 = g_atomic_int_xor (&s, 4);
77 g_assert_cmpint (s2, ==, 12);
78 g_assert_cmpint (s, ==, 8);
79
80 g_atomic_pointer_set (&vp, 0);
81 vp2 = g_atomic_pointer_get (&vp);
82 g_assert (vp2 == 0);
83 res = g_atomic_pointer_compare_and_exchange (&vp, 0, 0);
84 g_assert (res);
85 g_assert (vp == 0);
86
87 g_atomic_pointer_set (&ip, 0);
88 ip2 = g_atomic_pointer_get (&ip);
89 g_assert (ip2 == 0);
90 res = g_atomic_pointer_compare_and_exchange (&ip, 0, 0);
91 g_assert (res);
92 g_assert (ip == 0);
93
94 g_atomic_pointer_set (&gs, 0);
95 vp2 = g_atomic_pointer_get (&gs);
96 gs2 = (gsize) vp2;
97 g_assert (gs2 == 0);
98 res = g_atomic_pointer_compare_and_exchange (&gs, 0, 0);
99 g_assert (res);
100 g_assert (gs == 0);
101 gs2 = g_atomic_pointer_add (&gs, 5);
102 g_assert (gs2 == 0);
103 g_assert (gs == 5);
104 gs2 = g_atomic_pointer_and (&gs, 6);
105 g_assert (gs2 == 5);
106 g_assert (gs == 4);
107 gs2 = g_atomic_pointer_or (&gs, 8);
108 g_assert (gs2 == 4);
109 g_assert (gs == 12);
110 gs2 = g_atomic_pointer_xor (&gs, 4);
111 g_assert (gs2 == 12);
112 g_assert (gs == 8);
113
114 g_assert (g_atomic_int_get (csp) == s);
115 g_assert (g_atomic_pointer_get (cspp) == csp);
116
117 /* repeat, without the macros */
118 #undef g_atomic_int_set
119 #undef g_atomic_int_get
120 #undef g_atomic_int_compare_and_exchange
121 #undef g_atomic_int_add
122 #undef g_atomic_int_inc
123 #undef g_atomic_int_and
124 #undef g_atomic_int_or
125 #undef g_atomic_int_xor
126 #undef g_atomic_int_dec_and_test
127 #undef g_atomic_pointer_set
128 #undef g_atomic_pointer_get
129 #undef g_atomic_pointer_compare_and_exchange
130 #undef g_atomic_pointer_add
131 #undef g_atomic_pointer_and
132 #undef g_atomic_pointer_or
133 #undef g_atomic_pointer_xor
134
135 g_atomic_int_set ((gint*)&u, 5);
136 u2 = g_atomic_int_get ((gint*)&u);
137 g_assert_cmpint (u2, ==, 5);
138 res = g_atomic_int_compare_and_exchange ((gint*)&u, 6, 7);
139 g_assert (!res);
140 g_assert_cmpint (u, ==, 5);
141 g_atomic_int_add ((gint*)&u, 1);
142 g_assert_cmpint (u, ==, 6);
143 g_atomic_int_inc ((gint*)&u);
144 g_assert_cmpint (u, ==, 7);
145 res = g_atomic_int_dec_and_test ((gint*)&u);
146 g_assert (!res);
147 g_assert_cmpint (u, ==, 6);
148 u2 = g_atomic_int_and (&u, 5);
149 g_assert_cmpint (u2, ==, 6);
150 g_assert_cmpint (u, ==, 4);
151 u2 = g_atomic_int_or (&u, 8);
152 g_assert_cmpint (u2, ==, 4);
153 g_assert_cmpint (u, ==, 12);
154 u2 = g_atomic_int_xor (&u, 4);
155 g_assert_cmpint (u2, ==, 12);
156
157 g_atomic_int_set (&s, 5);
158 s2 = g_atomic_int_get (&s);
159 g_assert_cmpint (s2, ==, 5);
160 res = g_atomic_int_compare_and_exchange (&s, 6, 7);
161 g_assert (!res);
162 g_assert_cmpint (s, ==, 5);
163 g_atomic_int_add (&s, 1);
164 g_assert_cmpint (s, ==, 6);
165 g_atomic_int_inc (&s);
166 g_assert_cmpint (s, ==, 7);
167 res = g_atomic_int_dec_and_test (&s);
168 g_assert (!res);
169 g_assert_cmpint (s, ==, 6);
170 s2 = g_atomic_int_and ((guint*)&s, 5);
171 g_assert_cmpint (s2, ==, 6);
172 g_assert_cmpint (s, ==, 4);
173 s2 = g_atomic_int_or ((guint*)&s, 8);
174 g_assert_cmpint (s2, ==, 4);
175 g_assert_cmpint (s, ==, 12);
176 s2 = g_atomic_int_xor ((guint*)&s, 4);
177 g_assert_cmpint (s2, ==, 12);
178 g_assert_cmpint (s, ==, 8);
179 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
180 s2 = g_atomic_int_exchange_and_add ((gint*)&s, 1);
181 G_GNUC_END_IGNORE_DEPRECATIONS
182 g_assert_cmpint (s2, ==, 8);
183 g_assert_cmpint (s, ==, 9);
184
185 g_atomic_pointer_set (&vp, 0);
186 vp2 = g_atomic_pointer_get (&vp);
187 g_assert (vp2 == 0);
188 res = g_atomic_pointer_compare_and_exchange (&vp, 0, 0);
189 g_assert (res);
190 g_assert (vp == 0);
191
192 g_atomic_pointer_set (&ip, 0);
193 ip2 = g_atomic_pointer_get (&ip);
194 g_assert (ip2 == 0);
195 res = g_atomic_pointer_compare_and_exchange (&ip, 0, 0);
196 g_assert (res);
197 g_assert (ip == 0);
198
199 g_atomic_pointer_set (&gs, 0);
200 vp = g_atomic_pointer_get (&gs);
201 gs2 = (gsize) vp;
202 g_assert (gs2 == 0);
203 res = g_atomic_pointer_compare_and_exchange (&gs, 0, 0);
204 g_assert (res);
205 g_assert (gs == 0);
206 gs2 = g_atomic_pointer_add (&gs, 5);
207 g_assert (gs2 == 0);
208 g_assert (gs == 5);
209 gs2 = g_atomic_pointer_and (&gs, 6);
210 g_assert (gs2 == 5);
211 g_assert (gs == 4);
212 gs2 = g_atomic_pointer_or (&gs, 8);
213 g_assert (gs2 == 4);
214 g_assert (gs == 12);
215 gs2 = g_atomic_pointer_xor (&gs, 4);
216 g_assert (gs2 == 12);
217 g_assert (gs == 8);
218
219 g_assert (g_atomic_int_get (csp) == s);
220 g_assert (g_atomic_pointer_get (cspp) == csp);
221 }
222
223 #define THREADS 10
224 #define ROUNDS 10000
225
226 volatile gint bucket[THREADS];
227 volatile gint atomic;
228
229 static gpointer
thread_func(gpointer data)230 thread_func (gpointer data)
231 {
232 gint idx = GPOINTER_TO_INT (data);
233 gint i;
234 gint d;
235
236 for (i = 0; i < ROUNDS; i++)
237 {
238 d = g_random_int_range (-10, 100);
239 bucket[idx] += d;
240 g_atomic_int_add (&atomic, d);
241 g_thread_yield ();
242 }
243
244 return NULL;
245 }
246
247 static void
test_threaded(void)248 test_threaded (void)
249 {
250 gint sum;
251 gint i;
252 GThread *threads[THREADS];
253
254 atomic = 0;
255 for (i = 0; i < THREADS; i++)
256 bucket[i] = 0;
257
258 for (i = 0; i < THREADS; i++)
259 threads[i] = g_thread_new ("atomic", thread_func, GINT_TO_POINTER (i));
260
261 for (i = 0; i < THREADS; i++)
262 g_thread_join (threads[i]);
263
264 sum = 0;
265 for (i = 0; i < THREADS; i++)
266 sum += bucket[i];
267
268 g_assert_cmpint (sum, ==, atomic);
269 }
270
271 int
main(int argc,char ** argv)272 main (int argc, char **argv)
273 {
274 g_test_init (&argc, &argv, NULL);
275
276 g_test_add_func ("/atomic/types", test_types);
277 g_test_add_func ("/atomic/threaded", test_threaded);
278
279 return g_test_run ();
280 }
281