• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   const char *vp_str;
28   const char *volatile vp_str_vol;
29   const char *str = "Hello";
30   int *ip, *ip2;
31   gsize gs, gs2;
32   gboolean res;
33 
34   csp = &s;
35   cspp = &csp;
36 
37   g_atomic_int_set (&u, 5);
38   u2 = (guint) g_atomic_int_get (&u);
39   g_assert_cmpint (u2, ==, 5);
40   res = g_atomic_int_compare_and_exchange (&u, 6, 7);
41   g_assert_false (res);
42   g_assert_cmpint (u, ==, 5);
43   g_atomic_int_add (&u, 1);
44   g_assert_cmpint (u, ==, 6);
45   g_atomic_int_inc (&u);
46   g_assert_cmpint (u, ==, 7);
47   res = g_atomic_int_dec_and_test (&u);
48   g_assert_false (res);
49   g_assert_cmpint (u, ==, 6);
50   u2 = g_atomic_int_and (&u, 5);
51   g_assert_cmpint (u2, ==, 6);
52   g_assert_cmpint (u, ==, 4);
53   u2 = g_atomic_int_or (&u, 8);
54   g_assert_cmpint (u2, ==, 4);
55   g_assert_cmpint (u, ==, 12);
56   u2 = g_atomic_int_xor (&u, 4);
57   g_assert_cmpint (u2, ==, 12);
58   g_assert_cmpint (u, ==, 8);
59 
60   g_atomic_int_set (&s, 5);
61   s2 = g_atomic_int_get (&s);
62   g_assert_cmpint (s2, ==, 5);
63   res = g_atomic_int_compare_and_exchange (&s, 6, 7);
64   g_assert_false (res);
65   g_assert_cmpint (s, ==, 5);
66   g_atomic_int_add (&s, 1);
67   g_assert_cmpint (s, ==, 6);
68   g_atomic_int_inc (&s);
69   g_assert_cmpint (s, ==, 7);
70   res = g_atomic_int_dec_and_test (&s);
71   g_assert_false (res);
72   g_assert_cmpint (s, ==, 6);
73   s2 = (gint) g_atomic_int_and (&s, 5);
74   g_assert_cmpint (s2, ==, 6);
75   g_assert_cmpint (s, ==, 4);
76   s2 = (gint) g_atomic_int_or (&s, 8);
77   g_assert_cmpint (s2, ==, 4);
78   g_assert_cmpint (s, ==, 12);
79   s2 = (gint) g_atomic_int_xor (&s, 4);
80   g_assert_cmpint (s2, ==, 12);
81   g_assert_cmpint (s, ==, 8);
82 
83   g_atomic_pointer_set (&vp, 0);
84   vp2 = g_atomic_pointer_get (&vp);
85   g_assert_true (vp2 == 0);
86   res = g_atomic_pointer_compare_and_exchange (&vp, &s, &s);
87   g_assert_false (res);
88   g_assert_true (vp == 0);
89   res = g_atomic_pointer_compare_and_exchange (&vp, NULL, NULL);
90   g_assert_true (res);
91   g_assert_true (vp == 0);
92 
93   g_atomic_pointer_set (&vp_str, NULL);
94   res = g_atomic_pointer_compare_and_exchange (&vp_str, NULL, str);
95   g_assert_true (res);
96 
97   /* Note that atomic variables should almost certainly not be marked as
98    * `volatile` — see http://isvolatileusefulwiththreads.in/c/. This test exists
99    * to make sure that we don’t warn when built against older third party code. */
100   g_atomic_pointer_set (&vp_str_vol, NULL);
101   res = g_atomic_pointer_compare_and_exchange (&vp_str_vol, NULL, str);
102   g_assert_true (res);
103 
104   g_atomic_pointer_set (&ip, 0);
105   ip2 = g_atomic_pointer_get (&ip);
106   g_assert_true (ip2 == 0);
107   res = g_atomic_pointer_compare_and_exchange (&ip, NULL, NULL);
108   g_assert_true (res);
109   g_assert_true (ip == 0);
110 
111   g_atomic_pointer_set (&gs, 0);
112   vp2 = (gpointer) g_atomic_pointer_get (&gs);
113   gs2 = (gsize) vp2;
114   g_assert_cmpuint (gs2, ==, 0);
115   res = g_atomic_pointer_compare_and_exchange (&gs, NULL, NULL);
116   g_assert_true (res);
117   g_assert_cmpuint (gs, ==, 0);
118   gs2 = (gsize) g_atomic_pointer_add (&gs, 5);
119   g_assert_cmpuint (gs2, ==, 0);
120   g_assert_cmpuint (gs, ==, 5);
121   gs2 = g_atomic_pointer_and (&gs, 6);
122   g_assert_cmpuint (gs2, ==, 5);
123   g_assert_cmpuint (gs, ==, 4);
124   gs2 = g_atomic_pointer_or (&gs, 8);
125   g_assert_cmpuint (gs2, ==, 4);
126   g_assert_cmpuint (gs, ==, 12);
127   gs2 = g_atomic_pointer_xor (&gs, 4);
128   g_assert_cmpuint (gs2, ==, 12);
129   g_assert_cmpuint (gs, ==, 8);
130 
131   g_assert_cmpint (g_atomic_int_get (csp), ==, s);
132   g_assert_true (g_atomic_pointer_get (cspp) == csp);
133 
134   /* repeat, without the macros */
135 #undef g_atomic_int_set
136 #undef g_atomic_int_get
137 #undef g_atomic_int_compare_and_exchange
138 #undef g_atomic_int_add
139 #undef g_atomic_int_inc
140 #undef g_atomic_int_and
141 #undef g_atomic_int_or
142 #undef g_atomic_int_xor
143 #undef g_atomic_int_dec_and_test
144 #undef g_atomic_pointer_set
145 #undef g_atomic_pointer_get
146 #undef g_atomic_pointer_compare_and_exchange
147 #undef g_atomic_pointer_add
148 #undef g_atomic_pointer_and
149 #undef g_atomic_pointer_or
150 #undef g_atomic_pointer_xor
151 
152   g_atomic_int_set ((gint*)&u, 5);
153   u2 = (guint) g_atomic_int_get ((gint*)&u);
154   g_assert_cmpint (u2, ==, 5);
155   res = g_atomic_int_compare_and_exchange ((gint*)&u, 6, 7);
156   g_assert_false (res);
157   g_assert_cmpint (u, ==, 5);
158   g_atomic_int_add ((gint*)&u, 1);
159   g_assert_cmpint (u, ==, 6);
160   g_atomic_int_inc ((gint*)&u);
161   g_assert_cmpint (u, ==, 7);
162   res = g_atomic_int_dec_and_test ((gint*)&u);
163   g_assert_false (res);
164   g_assert_cmpint (u, ==, 6);
165   u2 = g_atomic_int_and (&u, 5);
166   g_assert_cmpint (u2, ==, 6);
167   g_assert_cmpint (u, ==, 4);
168   u2 = g_atomic_int_or (&u, 8);
169   g_assert_cmpint (u2, ==, 4);
170   g_assert_cmpint (u, ==, 12);
171   u2 = g_atomic_int_xor (&u, 4);
172   g_assert_cmpint (u2, ==, 12);
173 
174   g_atomic_int_set (&s, 5);
175   s2 = g_atomic_int_get (&s);
176   g_assert_cmpint (s2, ==, 5);
177   res = g_atomic_int_compare_and_exchange (&s, 6, 7);
178   g_assert_false (res);
179   g_assert_cmpint (s, ==, 5);
180   g_atomic_int_add (&s, 1);
181   g_assert_cmpint (s, ==, 6);
182   g_atomic_int_inc (&s);
183   g_assert_cmpint (s, ==, 7);
184   res = g_atomic_int_dec_and_test (&s);
185   g_assert_false (res);
186   g_assert_cmpint (s, ==, 6);
187   s2 = (gint) g_atomic_int_and ((guint*)&s, 5);
188   g_assert_cmpint (s2, ==, 6);
189   g_assert_cmpint (s, ==, 4);
190   s2 = (gint) g_atomic_int_or ((guint*)&s, 8);
191   g_assert_cmpint (s2, ==, 4);
192   g_assert_cmpint (s, ==, 12);
193   s2 = (gint) g_atomic_int_xor ((guint*)&s, 4);
194   g_assert_cmpint (s2, ==, 12);
195   g_assert_cmpint (s, ==, 8);
196 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
197   s2 = g_atomic_int_exchange_and_add ((gint*)&s, 1);
198 G_GNUC_END_IGNORE_DEPRECATIONS
199   g_assert_cmpint (s2, ==, 8);
200   g_assert_cmpint (s, ==, 9);
201 
202   g_atomic_pointer_set (&vp, 0);
203   vp2 = g_atomic_pointer_get (&vp);
204   g_assert_true (vp2 == 0);
205   res = g_atomic_pointer_compare_and_exchange (&vp, &s, &s);
206   g_assert_false (res);
207   g_assert_true (vp == 0);
208   res = g_atomic_pointer_compare_and_exchange (&vp, NULL, NULL);
209   g_assert_true (res);
210   g_assert_true (vp == 0);
211 
212   g_atomic_pointer_set (&vp_str, NULL);
213   res = g_atomic_pointer_compare_and_exchange (&vp_str, NULL, (char *) str);
214   g_assert_true (res);
215 
216   /* Note that atomic variables should almost certainly not be marked as
217    * `volatile` — see http://isvolatileusefulwiththreads.in/c/. This test exists
218    * to make sure that we don’t warn when built against older third party code. */
219   g_atomic_pointer_set (&vp_str_vol, NULL);
220   res = g_atomic_pointer_compare_and_exchange (&vp_str_vol, NULL, (char *) str);
221   g_assert_true (res);
222 
223   g_atomic_pointer_set (&ip, 0);
224   ip2 = g_atomic_pointer_get (&ip);
225   g_assert_true (ip2 == 0);
226   res = g_atomic_pointer_compare_and_exchange (&ip, NULL, NULL);
227   g_assert_true (res);
228   g_assert_true (ip == 0);
229 
230   g_atomic_pointer_set (&gs, 0);
231   vp = g_atomic_pointer_get (&gs);
232   gs2 = (gsize) vp;
233   g_assert_cmpuint (gs2, ==, 0);
234   res = g_atomic_pointer_compare_and_exchange (&gs, NULL, NULL);
235   g_assert_true (res);
236   g_assert_cmpuint (gs, ==, 0);
237   gs2 = (gsize) g_atomic_pointer_add (&gs, 5);
238   g_assert_cmpuint (gs2, ==, 0);
239   g_assert_cmpuint (gs, ==, 5);
240   gs2 = g_atomic_pointer_and (&gs, 6);
241   g_assert_cmpuint (gs2, ==, 5);
242   g_assert_cmpuint (gs, ==, 4);
243   gs2 = g_atomic_pointer_or (&gs, 8);
244   g_assert_cmpuint (gs2, ==, 4);
245   g_assert_cmpuint (gs, ==, 12);
246   gs2 = g_atomic_pointer_xor (&gs, 4);
247   g_assert_cmpuint (gs2, ==, 12);
248   g_assert_cmpuint (gs, ==, 8);
249 
250   g_assert_cmpint (g_atomic_int_get (csp), ==, s);
251   g_assert_true (g_atomic_pointer_get (cspp) == csp);
252 }
253 
254 #define THREADS 10
255 #define ROUNDS 10000
256 
257 gint bucket[THREADS];  /* never contested by threads, not accessed atomically */
258 gint atomic;  /* (atomic) */
259 
260 static gpointer
thread_func(gpointer data)261 thread_func (gpointer data)
262 {
263   gint idx = GPOINTER_TO_INT (data);
264   gint i;
265   gint d;
266 
267   for (i = 0; i < ROUNDS; i++)
268     {
269       d = g_random_int_range (-10, 100);
270       bucket[idx] += d;
271       g_atomic_int_add (&atomic, d);
272       g_thread_yield ();
273     }
274 
275   return NULL;
276 }
277 
278 static void
test_threaded(void)279 test_threaded (void)
280 {
281   gint sum;
282   gint i;
283   GThread *threads[THREADS];
284 
285   atomic = 0;
286   for (i = 0; i < THREADS; i++)
287     bucket[i] = 0;
288 
289   for (i = 0; i < THREADS; i++)
290     threads[i] = g_thread_new ("atomic", thread_func, GINT_TO_POINTER (i));
291 
292   for (i = 0; i < THREADS; i++)
293     g_thread_join (threads[i]);
294 
295   sum = 0;
296   for (i = 0; i < THREADS; i++)
297     sum += bucket[i];
298 
299   g_assert_cmpint (sum, ==, atomic);
300 }
301 
302 int
main(int argc,char ** argv)303 main (int argc, char **argv)
304 {
305   g_test_init (&argc, &argv, NULL);
306 
307   g_test_add_func ("/atomic/types", test_types);
308   g_test_add_func ("/atomic/threaded", test_threaded);
309 
310   return g_test_run ();
311 }
312