gkdbus: Fix underflow and unreachable code bug
[platform/upstream/glib.git] / glib / tests / atomic.c
1 /*
2  * Copyright 2011 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.h>
15
16 /* We want the g_atomic_pointer_get() macros to work when compiling third party
17  * projects with -Wbad-function-cast.
18  * See https://gitlab.gnome.org/GNOME/glib/issues/1041. */
19 #pragma GCC diagnostic error "-Wbad-function-cast"
20
21 static void
22 test_types (void)
23 {
24   const gint *csp;
25   const gint * const *cspp;
26   guint u, u2;
27   gint s, s2;
28   gpointer vp, vp2, cp;
29   const char *vp_str, *vp_str2;
30   const char *volatile vp_str_vol;
31   const char *str = "Hello";
32   const char *old_str;
33   int *ip, *ip2;
34   gsize gs, gs2;
35   gboolean res;
36
37   csp = &s;
38   cspp = &csp;
39
40   g_atomic_int_set (&u, 5);
41   u2 = (guint) g_atomic_int_get (&u);
42   g_assert_cmpint (u2, ==, 5);
43   res = g_atomic_int_compare_and_exchange (&u, 6, 7);
44   g_assert_false (res);
45   g_assert_cmpint (u, ==, 5);
46   res = g_atomic_int_compare_and_exchange_full (&u, 6, 7, &u2);
47   g_assert_false (res);
48   g_assert_cmpint (u, ==, 5);
49   g_assert_cmpint (u2, ==, 5);
50   g_atomic_int_add (&u, 1);
51   g_assert_cmpint (u, ==, 6);
52   g_atomic_int_inc (&u);
53   g_assert_cmpint (u, ==, 7);
54   res = g_atomic_int_dec_and_test (&u);
55   g_assert_false (res);
56   g_assert_cmpint (u, ==, 6);
57   u2 = g_atomic_int_and (&u, 5);
58   g_assert_cmpint (u2, ==, 6);
59   g_assert_cmpint (u, ==, 4);
60   u2 = g_atomic_int_or (&u, 8);
61   g_assert_cmpint (u2, ==, 4);
62   g_assert_cmpint (u, ==, 12);
63   u2 = g_atomic_int_xor (&u, 4);
64   g_assert_cmpint (u2, ==, 12);
65   g_assert_cmpint (u, ==, 8);
66   u2 = g_atomic_int_exchange (&u, 55);
67   g_assert_cmpint (u2, ==, 8);
68   g_assert_cmpint (u, ==, 55);
69
70   g_atomic_int_set (&s, 5);
71   s2 = g_atomic_int_get (&s);
72   g_assert_cmpint (s2, ==, 5);
73   res = g_atomic_int_compare_and_exchange (&s, 6, 7);
74   g_assert_false (res);
75   g_assert_cmpint (s, ==, 5);
76   s2 = 0;
77   res = g_atomic_int_compare_and_exchange_full (&s, 6, 7, &s2);
78   g_assert_false (res);
79   g_assert_cmpint (s, ==, 5);
80   g_assert_cmpint (s2, ==, 5);
81   g_atomic_int_add (&s, 1);
82   g_assert_cmpint (s, ==, 6);
83   g_atomic_int_inc (&s);
84   g_assert_cmpint (s, ==, 7);
85   res = g_atomic_int_dec_and_test (&s);
86   g_assert_false (res);
87   g_assert_cmpint (s, ==, 6);
88   s2 = (gint) g_atomic_int_and (&s, 5);
89   g_assert_cmpint (s2, ==, 6);
90   g_assert_cmpint (s, ==, 4);
91   s2 = (gint) g_atomic_int_or (&s, 8);
92   g_assert_cmpint (s2, ==, 4);
93   g_assert_cmpint (s, ==, 12);
94   s2 = (gint) g_atomic_int_xor (&s, 4);
95   g_assert_cmpint (s2, ==, 12);
96   g_assert_cmpint (s, ==, 8);
97   s2 = g_atomic_int_exchange (&s, 55);
98   g_assert_cmpint (s2, ==, 8);
99   g_assert_cmpint (s, ==, 55);
100
101   g_atomic_pointer_set (&vp, 0);
102   vp2 = g_atomic_pointer_get (&vp);
103   g_assert_true (vp2 == 0);
104   res = g_atomic_pointer_compare_and_exchange (&vp, &s, &s);
105   g_assert_false (res);
106   cp = &s;
107   res = g_atomic_pointer_compare_and_exchange_full (&vp, &s, &s, &cp);
108   g_assert_false (res);
109   g_assert_null (cp);
110   g_assert_true (vp == 0);
111   res = g_atomic_pointer_compare_and_exchange (&vp, NULL, NULL);
112   g_assert_true (res);
113   g_assert_true (vp == 0);
114   g_assert_null (g_atomic_pointer_exchange (&vp, &s));
115   g_assert_true (vp == &s);
116   res = g_atomic_pointer_compare_and_exchange_full (&vp, &s, NULL, &cp);
117   g_assert_true (res);
118   g_assert_true (cp == &s);
119
120   g_atomic_pointer_set (&vp_str, NULL);
121   res = g_atomic_pointer_compare_and_exchange (&vp_str, NULL, str);
122   g_assert_true (res);
123   g_assert_cmpstr (g_atomic_pointer_exchange (&vp_str, NULL), ==, str);
124   g_assert_null (vp_str);
125   res = g_atomic_pointer_compare_and_exchange_full (&vp_str, NULL, str, &vp_str2);
126   g_assert_true (res);
127   g_assert_cmpstr (vp_str, ==, str);
128   g_assert_null (vp_str2);
129   res = g_atomic_pointer_compare_and_exchange_full (&vp_str, (char *) str, NULL, &vp_str2);
130   g_assert_true (res);
131   g_assert_null (vp_str);
132   g_assert_true (vp_str2 == str);
133
134   /* Note that atomic variables should almost certainly not be marked as
135    * `volatile` — see http://isvolatileusefulwiththreads.in/c/. This test exists
136    * to make sure that we don’t warn when built against older third party code. */
137 #pragma GCC diagnostic push
138 #pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
139   g_atomic_pointer_set (&vp_str_vol, NULL);
140   g_atomic_pointer_set (&vp_str, str);
141   res = g_atomic_pointer_compare_and_exchange (&vp_str_vol, NULL, str);
142   g_assert_true (res);
143   g_assert_cmpstr (g_atomic_pointer_exchange (&vp_str, NULL), ==, str);
144   g_assert_null (vp_str);
145
146   res = g_atomic_pointer_compare_and_exchange_full (&vp_str_vol, str, NULL, &old_str);
147   g_assert_true (res);
148   g_assert_true (old_str == str);
149 #pragma GCC diagnostic pop
150
151   g_atomic_pointer_set (&ip, 0);
152   ip2 = g_atomic_pointer_get (&ip);
153   g_assert_true (ip2 == 0);
154   res = g_atomic_pointer_compare_and_exchange (&ip, NULL, NULL);
155   g_assert_true (res);
156   g_assert_true (ip == 0);
157
158   res = g_atomic_pointer_compare_and_exchange_full (&ip, NULL, &s, &ip2);
159   g_assert_true (res);
160   g_assert_true (ip == &s);
161   g_assert_cmpuint ((gsize) ip2, ==, 0);
162
163   res = g_atomic_pointer_compare_and_exchange_full (&ip, NULL, NULL, &ip2);
164   g_assert_false (res);
165   g_assert_true (ip == &s);
166   g_assert_true (ip2 == &s);
167
168   g_atomic_pointer_set (&gs, 0);
169   vp2 = (gpointer) g_atomic_pointer_get (&gs);
170   gs2 = (gsize) vp2;
171   g_assert_cmpuint (gs2, ==, 0);
172   res = g_atomic_pointer_compare_and_exchange (&gs, NULL, (gsize) NULL);
173   g_assert_true (res);
174   g_assert_cmpuint (gs, ==, 0);
175   res = g_atomic_pointer_compare_and_exchange_full (&gs, (gsize) NULL, (gsize) NULL, &gs2);
176   g_assert_true (res);
177   g_assert_cmpuint (gs, ==, 0);
178   g_assert_cmpuint (gs2, ==, 0);
179   gs2 = (gsize) g_atomic_pointer_add (&gs, 5);
180   g_assert_cmpuint (gs2, ==, 0);
181   g_assert_cmpuint (gs, ==, 5);
182   gs2 = g_atomic_pointer_and (&gs, 6);
183   g_assert_cmpuint (gs2, ==, 5);
184   g_assert_cmpuint (gs, ==, 4);
185   gs2 = g_atomic_pointer_or (&gs, 8);
186   g_assert_cmpuint (gs2, ==, 4);
187   g_assert_cmpuint (gs, ==, 12);
188   gs2 = g_atomic_pointer_xor (&gs, 4);
189   g_assert_cmpuint (gs2, ==, 12);
190   g_assert_cmpuint (gs, ==, 8);
191   vp_str2 = g_atomic_pointer_exchange (&vp_str, str);
192   g_assert_cmpstr (vp_str, ==, str);
193   g_assert_null (vp_str2);
194
195   g_assert_cmpint (g_atomic_int_get (csp), ==, s);
196   g_assert_true (g_atomic_pointer_get ((const gint **) cspp) == csp);
197
198   /* repeat, without the macros */
199 #undef g_atomic_int_set
200 #undef g_atomic_int_get
201 #undef g_atomic_int_compare_and_exchange
202 #undef g_atomic_int_compare_and_exchange_full
203 #undef g_atomic_int_exchange
204 #undef g_atomic_int_add
205 #undef g_atomic_int_inc
206 #undef g_atomic_int_and
207 #undef g_atomic_int_or
208 #undef g_atomic_int_xor
209 #undef g_atomic_int_dec_and_test
210 #undef g_atomic_pointer_set
211 #undef g_atomic_pointer_get
212 #undef g_atomic_pointer_compare_and_exchange
213 #undef g_atomic_pointer_compare_and_exchange_full
214 #undef g_atomic_pointer_exchange
215 #undef g_atomic_pointer_add
216 #undef g_atomic_pointer_and
217 #undef g_atomic_pointer_or
218 #undef g_atomic_pointer_xor
219
220   g_atomic_int_set ((gint*)&u, 5);
221   u2 = (guint) g_atomic_int_get ((gint*)&u);
222   g_assert_cmpint (u2, ==, 5);
223   res = g_atomic_int_compare_and_exchange ((gint*)&u, 6, 7);
224   g_assert_false (res);
225   g_assert_cmpint (u, ==, 5);
226   u2 = 0;
227   res = g_atomic_int_compare_and_exchange_full ((gint*)&u, 6, 7, (gint*) &u2);
228   g_assert_false (res);
229   g_assert_cmpuint (u, ==, 5);
230   g_assert_cmpuint (u2, ==, 5);
231   g_atomic_int_add ((gint*)&u, 1);
232   g_assert_cmpint (u, ==, 6);
233   g_atomic_int_inc ((gint*)&u);
234   g_assert_cmpint (u, ==, 7);
235   res = g_atomic_int_dec_and_test ((gint*)&u);
236   g_assert_false (res);
237   g_assert_cmpint (u, ==, 6);
238   u2 = g_atomic_int_and (&u, 5);
239   g_assert_cmpint (u2, ==, 6);
240   g_assert_cmpint (u, ==, 4);
241   u2 = g_atomic_int_or (&u, 8);
242   g_assert_cmpint (u2, ==, 4);
243   g_assert_cmpint (u, ==, 12);
244   u2 = g_atomic_int_xor (&u, 4);
245   g_assert_cmpint (u2, ==, 12);
246   u2 = g_atomic_int_exchange ((gint*) &u, 55);
247   g_assert_cmpint (u2, ==, 8);
248   g_assert_cmpint (u, ==, 55);
249
250   g_atomic_int_set (&s, 5);
251   s2 = g_atomic_int_get (&s);
252   g_assert_cmpint (s2, ==, 5);
253   res = g_atomic_int_compare_and_exchange (&s, 6, 7);
254   g_assert_false (res);
255   g_assert_cmpint (s, ==, 5);
256   s2 = 0;
257   res = g_atomic_int_compare_and_exchange_full (&s, 6, 7, &s2);
258   g_assert_false (res);
259   g_assert_cmpint (s, ==, 5);
260   g_assert_cmpint (s2, ==, 5);
261   g_atomic_int_add (&s, 1);
262   g_assert_cmpint (s, ==, 6);
263   g_atomic_int_inc (&s);
264   g_assert_cmpint (s, ==, 7);
265   res = g_atomic_int_dec_and_test (&s);
266   g_assert_false (res);
267   g_assert_cmpint (s, ==, 6);
268   s2 = (gint) g_atomic_int_and ((guint*)&s, 5);
269   g_assert_cmpint (s2, ==, 6);
270   g_assert_cmpint (s, ==, 4);
271   s2 = (gint) g_atomic_int_or ((guint*)&s, 8);
272   g_assert_cmpint (s2, ==, 4);
273   g_assert_cmpint (s, ==, 12);
274   s2 = (gint) g_atomic_int_xor ((guint*)&s, 4);
275   g_assert_cmpint (s2, ==, 12);
276   g_assert_cmpint (s, ==, 8);
277 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
278   s2 = g_atomic_int_exchange_and_add ((gint*)&s, 1);
279 G_GNUC_END_IGNORE_DEPRECATIONS
280   g_assert_cmpint (s2, ==, 8);
281   g_assert_cmpint (s, ==, 9);
282   s2 = g_atomic_int_exchange (&s, 55);
283   g_assert_cmpint (s2, ==, 9);
284   g_assert_cmpint (s, ==, 55);
285
286   g_atomic_pointer_set (&vp, 0);
287   vp2 = g_atomic_pointer_get (&vp);
288   g_assert_true (vp2 == 0);
289   res = g_atomic_pointer_compare_and_exchange (&vp, &s, &s);
290   g_assert_false (res);
291   g_assert_true (vp == 0);
292   res = g_atomic_pointer_compare_and_exchange_full (&vp, &s, &s, &cp);
293   g_assert_false (res);
294   g_assert_null (vp);
295   g_assert_null (cp);
296   res = g_atomic_pointer_compare_and_exchange (&vp, NULL, NULL);
297   g_assert_true (res);
298   g_assert_true (vp == 0);
299   res = g_atomic_pointer_compare_and_exchange_full (&vp, NULL, NULL, &cp);
300   g_assert_true (res);
301   g_assert_null (vp);
302   g_assert_null (cp);
303   g_assert_null (g_atomic_pointer_exchange (&vp, &s));
304   g_assert_true (vp == &s);
305
306   g_atomic_pointer_set (&vp_str, NULL);
307   res = g_atomic_pointer_compare_and_exchange (&vp_str, NULL, (char *) str);
308   g_assert_true (res);
309   g_assert_cmpstr (g_atomic_pointer_exchange (&vp_str, NULL), ==, str);
310   g_assert_null (vp_str);
311   res = g_atomic_pointer_compare_and_exchange_full (&vp_str, NULL, (char *) str, &cp);
312   g_assert_true (res);
313   g_assert_cmpstr (vp_str, ==, str);
314   g_assert_null (cp);
315   res = g_atomic_pointer_compare_and_exchange_full (&vp_str, (char *) str, NULL, &cp);
316   g_assert_true (res);
317   g_assert_null (vp_str);
318   g_assert_true (cp == str);
319
320   /* Note that atomic variables should almost certainly not be marked as
321    * `volatile` — see http://isvolatileusefulwiththreads.in/c/. This test exists
322    * to make sure that we don’t warn when built against older third party code. */
323   g_atomic_pointer_set (&vp_str_vol, NULL);
324   g_atomic_pointer_set (&vp_str, (char *) str);
325   res = g_atomic_pointer_compare_and_exchange (&vp_str_vol, NULL, (char *) str);
326   g_assert_true (res);
327   g_assert_cmpstr (g_atomic_pointer_exchange (&vp_str, NULL), ==, str);
328   g_assert_null (vp_str);
329
330   res = g_atomic_pointer_compare_and_exchange_full ((char **) &vp_str_vol, (char *) str, NULL, &old_str);
331   g_assert_true (res);
332   g_assert_true (old_str == str);
333
334   g_atomic_pointer_set (&ip, 0);
335   ip2 = g_atomic_pointer_get (&ip);
336   g_assert_true (ip2 == 0);
337   res = g_atomic_pointer_compare_and_exchange (&ip, NULL, NULL);
338   g_assert_true (res);
339   g_assert_true (ip == 0);
340
341   res = g_atomic_pointer_compare_and_exchange_full (&ip, NULL, (gpointer) 1, &cp);
342   g_assert_true (res);
343   g_assert_cmpint ((gsize) ip, ==, 1);
344   g_assert_cmpuint ((gsize) cp, ==, 0);
345
346   res = g_atomic_pointer_compare_and_exchange_full (&ip, NULL, NULL, &cp);
347   g_assert_false (res);
348   g_assert_cmpuint ((gsize) ip, ==, 1);
349   g_assert_cmpuint ((gsize) cp, ==, 1);
350
351   g_atomic_pointer_set (&gs, 0);
352   vp = g_atomic_pointer_get (&gs);
353   gs2 = (gsize) vp;
354   g_assert_cmpuint (gs2, ==, 0);
355   res = g_atomic_pointer_compare_and_exchange (&gs, NULL, NULL);
356   g_assert_true (res);
357   g_assert_cmpuint (gs, ==, 0);
358   res = g_atomic_pointer_compare_and_exchange_full (&gs, NULL, NULL, &cp);
359   g_assert_true (res);
360   g_assert_cmpuint (gs, ==, 0);
361   g_assert_cmpuint ((gsize) cp, ==, 0);
362   gs2 = (gsize) g_atomic_pointer_add (&gs, 5);
363   g_assert_cmpuint (gs2, ==, 0);
364   g_assert_cmpuint (gs, ==, 5);
365   gs2 = g_atomic_pointer_and (&gs, 6);
366   g_assert_cmpuint (gs2, ==, 5);
367   g_assert_cmpuint (gs, ==, 4);
368   gs2 = g_atomic_pointer_or (&gs, 8);
369   g_assert_cmpuint (gs2, ==, 4);
370   g_assert_cmpuint (gs, ==, 12);
371   gs2 = g_atomic_pointer_xor (&gs, 4);
372   g_assert_cmpuint (gs2, ==, 12);
373   g_assert_cmpuint (gs, ==, 8);
374   vp2 = g_atomic_pointer_exchange (&gs, NULL);
375   gs2 = (gsize) vp2;
376   g_assert_cmpuint (gs2, ==, 8);
377   g_assert_null ((gpointer) gs);
378
379   g_assert_cmpint (g_atomic_int_get (csp), ==, s);
380   g_assert_true (g_atomic_pointer_get (cspp) == csp);
381 }
382
383 #define THREADS 10
384 #define ROUNDS 10000
385
386 gint bucket[THREADS];  /* never contested by threads, not accessed atomically */
387 gint atomic;  /* (atomic) */
388
389 static gpointer
390 thread_func (gpointer data)
391 {
392   gint idx = GPOINTER_TO_INT (data);
393   gint i;
394   gint d;
395
396   for (i = 0; i < ROUNDS; i++)
397     {
398       d = g_random_int_range (-10, 100);
399       bucket[idx] += d;
400       g_atomic_int_add (&atomic, d);
401       g_thread_yield ();
402     }
403
404   return NULL;
405 }
406
407 static void
408 test_threaded (void)
409 {
410   gint sum;
411   gint i;
412   GThread *threads[THREADS];
413
414   atomic = 0;
415   for (i = 0; i < THREADS; i++)
416     bucket[i] = 0;
417
418   for (i = 0; i < THREADS; i++)
419     threads[i] = g_thread_new ("atomic", thread_func, GINT_TO_POINTER (i));
420
421   for (i = 0; i < THREADS; i++)
422     g_thread_join (threads[i]);
423
424   sum = 0;
425   for (i = 0; i < THREADS; i++)
426     sum += bucket[i];
427
428   g_assert_cmpint (sum, ==, atomic);
429 }
430
431 int
432 main (int argc, char **argv)
433 {
434   g_test_init (&argc, &argv, NULL);
435
436   g_test_add_func ("/atomic/types", test_types);
437   g_test_add_func ("/atomic/threaded", test_threaded);
438
439   return g_test_run ();
440 }