tizen: kdbus: make i explicitly positive in make_single_header_vector
[platform/upstream/glib.git] / glib / gatomic.h
1 /*
2  * Copyright © 2011 Ryan Lortie
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  * This library 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  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  *
19  * Author: Ryan Lortie <desrt@desrt.ca>
20  */
21
22 #ifndef __G_ATOMIC_H__
23 #define __G_ATOMIC_H__
24
25 #if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
26 #error "Only <glib.h> can be included directly."
27 #endif
28
29 #include <glib/gtypes.h>
30 #include <glib/glib-typeof.h>
31
32 G_BEGIN_DECLS
33
34 GLIB_AVAILABLE_IN_ALL
35 gint                    g_atomic_int_get                      (const volatile gint *atomic);
36 GLIB_AVAILABLE_IN_ALL
37 void                    g_atomic_int_set                      (volatile gint  *atomic,
38                                                                gint            newval);
39 GLIB_AVAILABLE_IN_ALL
40 void                    g_atomic_int_inc                      (volatile gint  *atomic);
41 GLIB_AVAILABLE_IN_ALL
42 gboolean                g_atomic_int_dec_and_test             (volatile gint  *atomic);
43 GLIB_AVAILABLE_IN_ALL
44 gboolean                g_atomic_int_compare_and_exchange     (volatile gint  *atomic,
45                                                                gint            oldval,
46                                                                gint            newval);
47 GLIB_AVAILABLE_IN_2_74
48 gboolean                g_atomic_int_compare_and_exchange_full (gint         *atomic,
49                                                                 gint          oldval,
50                                                                 gint          newval,
51                                                                 gint         *preval);
52 GLIB_AVAILABLE_IN_2_74
53 gint                    g_atomic_int_exchange                 (gint           *atomic,
54                                                                gint            newval);
55 GLIB_AVAILABLE_IN_ALL
56 gint                    g_atomic_int_add                      (volatile gint  *atomic,
57                                                                gint            val);
58 GLIB_AVAILABLE_IN_2_30
59 guint                   g_atomic_int_and                      (volatile guint *atomic,
60                                                                guint           val);
61 GLIB_AVAILABLE_IN_2_30
62 guint                   g_atomic_int_or                       (volatile guint *atomic,
63                                                                guint           val);
64 GLIB_AVAILABLE_IN_ALL
65 guint                   g_atomic_int_xor                      (volatile guint *atomic,
66                                                                guint           val);
67
68 GLIB_AVAILABLE_IN_ALL
69 gpointer                g_atomic_pointer_get                  (const volatile void *atomic);
70 GLIB_AVAILABLE_IN_ALL
71 void                    g_atomic_pointer_set                  (volatile void  *atomic,
72                                                                gpointer        newval);
73 GLIB_AVAILABLE_IN_ALL
74 gboolean                g_atomic_pointer_compare_and_exchange (volatile void  *atomic,
75                                                                gpointer        oldval,
76                                                                gpointer        newval);
77 GLIB_AVAILABLE_IN_2_74
78 gboolean                g_atomic_pointer_compare_and_exchange_full (void     *atomic,
79                                                                     gpointer  oldval,
80                                                                     gpointer  newval,
81                                                                     void     *preval);
82 GLIB_AVAILABLE_IN_2_74
83 gpointer                g_atomic_pointer_exchange             (void           *atomic,
84                                                                gpointer        newval);
85 GLIB_AVAILABLE_IN_ALL
86 gintptr                 g_atomic_pointer_add                  (volatile void  *atomic,
87                                                                gssize          val);
88 GLIB_AVAILABLE_IN_2_30
89 guintptr                g_atomic_pointer_and                  (volatile void  *atomic,
90                                                                gsize           val);
91 GLIB_AVAILABLE_IN_2_30
92 guintptr                g_atomic_pointer_or                   (volatile void  *atomic,
93                                                                gsize           val);
94 GLIB_AVAILABLE_IN_ALL
95 guintptr                g_atomic_pointer_xor                  (volatile void  *atomic,
96                                                                gsize           val);
97
98 GLIB_DEPRECATED_IN_2_30_FOR(g_atomic_int_add)
99 gint                    g_atomic_int_exchange_and_add         (volatile gint  *atomic,
100                                                                gint            val);
101
102 G_END_DECLS
103
104 #if defined(G_ATOMIC_LOCK_FREE) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
105
106 /* We prefer the new C11-style atomic extension of GCC if available */
107 #if defined(__ATOMIC_SEQ_CST)
108
109 #define g_atomic_int_get(atomic) \
110   (G_GNUC_EXTENSION ({                                                       \
111     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
112     gint gaig_temp;                                                          \
113     (void) (0 ? *(atomic) ^ *(atomic) : 1);                                  \
114     __atomic_load ((gint *)(atomic), &gaig_temp, __ATOMIC_SEQ_CST);          \
115     (gint) gaig_temp;                                                        \
116   }))
117 #define g_atomic_int_set(atomic, newval) \
118   (G_GNUC_EXTENSION ({                                                       \
119     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
120     gint gais_temp = (gint) (newval);                                        \
121     (void) (0 ? *(atomic) ^ (newval) : 1);                                   \
122     __atomic_store ((gint *)(atomic), &gais_temp, __ATOMIC_SEQ_CST);         \
123   }))
124
125 #if defined(glib_typeof)
126 #define g_atomic_pointer_get(atomic)                                       \
127   (G_GNUC_EXTENSION ({                                                     \
128     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));               \
129     glib_typeof (*(atomic)) gapg_temp_newval;                              \
130     glib_typeof ((atomic)) gapg_temp_atomic = (atomic);                    \
131     __atomic_load (gapg_temp_atomic, &gapg_temp_newval, __ATOMIC_SEQ_CST); \
132     gapg_temp_newval;                                                      \
133   }))
134 #define g_atomic_pointer_set(atomic, newval)                                \
135   (G_GNUC_EXTENSION ({                                                      \
136     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                \
137     glib_typeof ((atomic)) gaps_temp_atomic = (atomic);                     \
138     glib_typeof (*(atomic)) gaps_temp_newval = (newval);                    \
139     (void) (0 ? (gpointer) * (atomic) : NULL);                              \
140     __atomic_store (gaps_temp_atomic, &gaps_temp_newval, __ATOMIC_SEQ_CST); \
141   }))
142 #else /* if !(defined(glib_typeof) */
143 #define g_atomic_pointer_get(atomic) \
144   (G_GNUC_EXTENSION ({                                                       \
145     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
146     gpointer gapg_temp_newval;                                               \
147     gpointer *gapg_temp_atomic = (gpointer *)(atomic);                       \
148     __atomic_load (gapg_temp_atomic, &gapg_temp_newval, __ATOMIC_SEQ_CST);   \
149     gapg_temp_newval;                                                        \
150   }))
151 #define g_atomic_pointer_set(atomic, newval) \
152   (G_GNUC_EXTENSION ({                                                       \
153     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
154     gpointer *gaps_temp_atomic = (gpointer *)(atomic);                       \
155     gpointer gaps_temp_newval = (gpointer)(newval);                          \
156     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
157     __atomic_store (gaps_temp_atomic, &gaps_temp_newval, __ATOMIC_SEQ_CST);  \
158   }))
159 #endif /* if defined(glib_typeof) */
160
161 #define g_atomic_int_inc(atomic) \
162   (G_GNUC_EXTENSION ({                                                       \
163     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
164     (void) (0 ? *(atomic) ^ *(atomic) : 1);                                  \
165     (void) __atomic_fetch_add ((atomic), 1, __ATOMIC_SEQ_CST);               \
166   }))
167 #define g_atomic_int_dec_and_test(atomic) \
168   (G_GNUC_EXTENSION ({                                                       \
169     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
170     (void) (0 ? *(atomic) ^ *(atomic) : 1);                                  \
171     __atomic_fetch_sub ((atomic), 1, __ATOMIC_SEQ_CST) == 1;                 \
172   }))
173 #if defined(glib_typeof) && defined(G_CXX_STD_VERSION)
174 /* See comments below about equivalent g_atomic_pointer_compare_and_exchange()
175  * shenanigans for type-safety when compiling in C++ mode. */
176 #define g_atomic_int_compare_and_exchange(atomic, oldval, newval) \
177   (G_GNUC_EXTENSION ({                                                       \
178     glib_typeof (*(atomic)) gaicae_oldval = (oldval);                        \
179     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
180     (void) (0 ? *(atomic) ^ (newval) ^ (oldval) : 1);                        \
181     __atomic_compare_exchange_n ((atomic), &gaicae_oldval, (newval), FALSE, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ? TRUE : FALSE; \
182   }))
183 #else /* if !(defined(glib_typeof) && defined(G_CXX_STD_VERSION)) */
184 #define g_atomic_int_compare_and_exchange(atomic, oldval, newval) \
185   (G_GNUC_EXTENSION ({                                                       \
186     gint gaicae_oldval = (oldval);                                           \
187     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
188     (void) (0 ? *(atomic) ^ (newval) ^ (oldval) : 1);                        \
189     __atomic_compare_exchange_n ((atomic), (void *) (&(gaicae_oldval)), (newval), FALSE, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ? TRUE : FALSE; \
190   }))
191 #endif /* defined(glib_typeof) */
192 #define g_atomic_int_compare_and_exchange_full(atomic, oldval, newval, preval) \
193   (G_GNUC_EXTENSION ({                                                         \
194     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                       \
195     G_STATIC_ASSERT (sizeof *(preval) == sizeof (gint));                       \
196     (void) (0 ? *(atomic) ^ (newval) ^ (oldval) ^ *(preval) : 1);              \
197     *(preval) = (oldval);                                                      \
198     __atomic_compare_exchange_n ((atomic), (preval), (newval), FALSE,          \
199                                  __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)           \
200                                  ? TRUE : FALSE;                               \
201   }))
202 #define g_atomic_int_exchange(atomic, newval) \
203   (G_GNUC_EXTENSION ({                                                       \
204     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
205     (void) (0 ? *(atomic) ^ (newval) : 1);                                   \
206     (gint) __atomic_exchange_n ((atomic), (newval), __ATOMIC_SEQ_CST);       \
207   }))
208 #define g_atomic_int_add(atomic, val) \
209   (G_GNUC_EXTENSION ({                                                       \
210     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
211     (void) (0 ? *(atomic) ^ (val) : 1);                                      \
212     (gint) __atomic_fetch_add ((atomic), (val), __ATOMIC_SEQ_CST);           \
213   }))
214 #define g_atomic_int_and(atomic, val) \
215   (G_GNUC_EXTENSION ({                                                       \
216     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
217     (void) (0 ? *(atomic) ^ (val) : 1);                                      \
218     (guint) __atomic_fetch_and ((atomic), (val), __ATOMIC_SEQ_CST);          \
219   }))
220 #define g_atomic_int_or(atomic, val) \
221   (G_GNUC_EXTENSION ({                                                       \
222     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
223     (void) (0 ? *(atomic) ^ (val) : 1);                                      \
224     (guint) __atomic_fetch_or ((atomic), (val), __ATOMIC_SEQ_CST);           \
225   }))
226 #define g_atomic_int_xor(atomic, val) \
227   (G_GNUC_EXTENSION ({                                                       \
228     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
229     (void) (0 ? *(atomic) ^ (val) : 1);                                      \
230     (guint) __atomic_fetch_xor ((atomic), (val), __ATOMIC_SEQ_CST);          \
231   }))
232
233 #if defined(glib_typeof) && defined(G_CXX_STD_VERSION)
234 /* This is typesafe because we check we can assign oldval to the type of
235  * (*atomic). Unfortunately it can only be done in C++ because gcc/clang warn
236  * when atomic is volatile and not oldval, or when atomic is gsize* and oldval
237  * is NULL. Note that clang++ force us to be typesafe because it is an error if the 2nd
238  * argument of __atomic_compare_exchange_n() has a different type than the
239  * first.
240  * https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1919
241  * https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1715#note_1024120. */
242 #define g_atomic_pointer_compare_and_exchange(atomic, oldval, newval) \
243   (G_GNUC_EXTENSION ({                                                       \
244     G_STATIC_ASSERT (sizeof (static_cast<glib_typeof (*(atomic))>((oldval))) \
245                      == sizeof (gpointer));                                  \
246     glib_typeof (*(atomic)) gapcae_oldval = (oldval);                        \
247     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
248     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
249     __atomic_compare_exchange_n ((atomic), &gapcae_oldval, (newval), FALSE, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ? TRUE : FALSE; \
250   }))
251 #else /* if !(defined(glib_typeof) && defined(G_CXX_STD_VERSION) */
252 #define g_atomic_pointer_compare_and_exchange(atomic, oldval, newval) \
253   (G_GNUC_EXTENSION ({                                                       \
254     G_STATIC_ASSERT (sizeof (oldval) == sizeof (gpointer));                  \
255     gpointer gapcae_oldval = (gpointer)(oldval);                             \
256     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
257     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
258     __atomic_compare_exchange_n ((atomic), (void *) (&(gapcae_oldval)), (newval), FALSE, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ? TRUE : FALSE; \
259   }))
260 #endif /* defined(glib_typeof) */
261 #define g_atomic_pointer_compare_and_exchange_full(atomic, oldval, newval, preval) \
262   (G_GNUC_EXTENSION ({                                                             \
263     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                       \
264     G_STATIC_ASSERT (sizeof *(preval) == sizeof (gpointer));                       \
265     (void) (0 ? (gpointer) *(atomic) : NULL);                                      \
266     (void) (0 ? (gpointer) *(preval) : NULL);                                      \
267     *(preval) = (oldval);                                                          \
268     __atomic_compare_exchange_n ((atomic), (preval), (newval), FALSE,              \
269                                  __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ?             \
270                                  TRUE : FALSE;                                     \
271   }))
272 #define g_atomic_pointer_exchange(atomic, newval) \
273   (G_GNUC_EXTENSION ({                                                       \
274     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
275     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
276     (gpointer) __atomic_exchange_n ((atomic), (newval), __ATOMIC_SEQ_CST);   \
277   }))
278 #define g_atomic_pointer_add(atomic, val) \
279   (G_GNUC_EXTENSION ({                                                       \
280     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
281     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
282     (void) (0 ? (val) ^ (val) : 1);                                          \
283     (gintptr) __atomic_fetch_add ((atomic), (val), __ATOMIC_SEQ_CST);        \
284   }))
285 #define g_atomic_pointer_and(atomic, val) \
286   (G_GNUC_EXTENSION ({                                                       \
287     guintptr *gapa_atomic = (guintptr *) (atomic);                           \
288     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
289     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (guintptr));                 \
290     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
291     (void) (0 ? (val) ^ (val) : 1);                                          \
292     (guintptr) __atomic_fetch_and (gapa_atomic, (val), __ATOMIC_SEQ_CST);    \
293   }))
294 #define g_atomic_pointer_or(atomic, val) \
295   (G_GNUC_EXTENSION ({                                                       \
296     guintptr *gapo_atomic = (guintptr *) (atomic);                           \
297     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
298     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (guintptr));                 \
299     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
300     (void) (0 ? (val) ^ (val) : 1);                                          \
301     (guintptr) __atomic_fetch_or (gapo_atomic, (val), __ATOMIC_SEQ_CST);     \
302   }))
303 #define g_atomic_pointer_xor(atomic, val) \
304   (G_GNUC_EXTENSION ({                                                       \
305     guintptr *gapx_atomic = (guintptr *) (atomic);                           \
306     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
307     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (guintptr));                 \
308     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
309     (void) (0 ? (val) ^ (val) : 1);                                          \
310     (guintptr) __atomic_fetch_xor (gapx_atomic, (val), __ATOMIC_SEQ_CST);    \
311   }))
312
313 #else /* defined(__ATOMIC_SEQ_CST) */
314
315 /* We want to achieve __ATOMIC_SEQ_CST semantics here. See
316  * https://en.cppreference.com/w/c/atomic/memory_order#Constants. For load
317  * operations, that means performing an *acquire*:
318  * > A load operation with this memory order performs the acquire operation on
319  * > the affected memory location: no reads or writes in the current thread can
320  * > be reordered before this load. All writes in other threads that release
321  * > the same atomic variable are visible in the current thread.
322  *
323  * “no reads or writes in the current thread can be reordered before this load”
324  * is implemented using a compiler barrier (a no-op `__asm__` section) to
325  * prevent instruction reordering. Writes in other threads are synchronised
326  * using `__sync_synchronize()`. It’s unclear from the GCC documentation whether
327  * `__sync_synchronize()` acts as a compiler barrier, hence our explicit use of
328  * one.
329  *
330  * For store operations, `__ATOMIC_SEQ_CST` means performing a *release*:
331  * > A store operation with this memory order performs the release operation:
332  * > no reads or writes in the current thread can be reordered after this store.
333  * > All writes in the current thread are visible in other threads that acquire
334  * > the same atomic variable (see Release-Acquire ordering below) and writes
335  * > that carry a dependency into the atomic variable become visible in other
336  * > threads that consume the same atomic (see Release-Consume ordering below).
337  *
338  * “no reads or writes in the current thread can be reordered after this store”
339  * is implemented using a compiler barrier to prevent instruction reordering.
340  * “All writes in the current thread are visible in other threads” is implemented
341  * using `__sync_synchronize()`; similarly for “writes that carry a dependency”.
342  */
343 #define g_atomic_int_get(atomic) \
344   (G_GNUC_EXTENSION ({                                                       \
345     gint gaig_result;                                                        \
346     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
347     (void) (0 ? *(atomic) ^ *(atomic) : 1);                                  \
348     gaig_result = (gint) *(atomic);                                          \
349     __sync_synchronize ();                                                   \
350     __asm__ __volatile__ ("" : : : "memory");                                \
351     gaig_result;                                                             \
352   }))
353 #define g_atomic_int_set(atomic, newval) \
354   (G_GNUC_EXTENSION ({                                                       \
355     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
356     (void) (0 ? *(atomic) ^ (newval) : 1);                                   \
357     __sync_synchronize ();                                                   \
358     __asm__ __volatile__ ("" : : : "memory");                                \
359     *(atomic) = (newval);                                                    \
360   }))
361 #define g_atomic_pointer_get(atomic) \
362   (G_GNUC_EXTENSION ({                                                       \
363     gpointer gapg_result;                                                    \
364     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
365     gapg_result = (gpointer) *(atomic);                                      \
366     __sync_synchronize ();                                                   \
367     __asm__ __volatile__ ("" : : : "memory");                                \
368     gapg_result;                                                             \
369   }))
370 #if defined(glib_typeof)
371 #define g_atomic_pointer_set(atomic, newval) \
372   (G_GNUC_EXTENSION ({                                                       \
373     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
374     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
375     __sync_synchronize ();                                                   \
376     __asm__ __volatile__ ("" : : : "memory");                                \
377     *(atomic) = (glib_typeof (*(atomic))) (guintptr) (newval);               \
378   }))
379 #else /* if !(defined(glib_typeof) */
380 #define g_atomic_pointer_set(atomic, newval) \
381   (G_GNUC_EXTENSION ({                                                       \
382     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
383     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
384     __sync_synchronize ();                                                   \
385     __asm__ __volatile__ ("" : : : "memory");                                \
386     *(atomic) = (gpointer) (guintptr) (newval);                              \
387   }))
388 #endif /* if defined(glib_typeof) */
389
390 #define g_atomic_int_inc(atomic) \
391   (G_GNUC_EXTENSION ({                                                       \
392     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
393     (void) (0 ? *(atomic) ^ *(atomic) : 1);                                  \
394     (void) __sync_fetch_and_add ((atomic), 1);                               \
395   }))
396 #define g_atomic_int_dec_and_test(atomic) \
397   (G_GNUC_EXTENSION ({                                                       \
398     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
399     (void) (0 ? *(atomic) ^ *(atomic) : 1);                                  \
400     __sync_fetch_and_sub ((atomic), 1) == 1;                                 \
401   }))
402 #define g_atomic_int_compare_and_exchange(atomic, oldval, newval) \
403   (G_GNUC_EXTENSION ({                                                       \
404     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
405     (void) (0 ? *(atomic) ^ (newval) ^ (oldval) : 1);                        \
406     __sync_bool_compare_and_swap ((atomic), (oldval), (newval)) ? TRUE : FALSE; \
407   }))
408 #define g_atomic_int_compare_and_exchange_full(atomic, oldval, newval, preval) \
409   (G_GNUC_EXTENSION ({                                                         \
410     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                       \
411     G_STATIC_ASSERT (sizeof *(preval) == sizeof (gint));                       \
412     (void) (0 ? *(atomic) ^ (newval) ^ (oldval) ^ *(preval) : 1);              \
413     *(preval) = __sync_val_compare_and_swap ((atomic), (oldval), (newval));    \
414     (*(preval) == (oldval)) ? TRUE : FALSE;                                    \
415   }))
416 #if defined(_GLIB_GCC_HAVE_SYNC_SWAP)
417 #define g_atomic_int_exchange(atomic, newval) \
418   (G_GNUC_EXTENSION ({                                                       \
419     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
420     (void) (0 ? *(atomic) ^ (newval) : 1);                                   \
421     (gint) __sync_swap ((atomic), (newval));                                 \
422   }))
423 #else /* defined(_GLIB_GCC_HAVE_SYNC_SWAP) */
424   #define g_atomic_int_exchange(atomic, newval) \
425   (G_GNUC_EXTENSION ({                                                       \
426     gint oldval;                                                             \
427     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
428     (void) (0 ? *(atomic) ^ (newval) : 1);                                   \
429     do                                                                       \
430       {                                                                      \
431         oldval = *atomic;                                                    \
432       } while (!__sync_bool_compare_and_swap (atomic, oldval, newval));      \
433     oldval;                                                                  \
434   }))
435 #endif /* defined(_GLIB_GCC_HAVE_SYNC_SWAP) */
436 #define g_atomic_int_add(atomic, val) \
437   (G_GNUC_EXTENSION ({                                                       \
438     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
439     (void) (0 ? *(atomic) ^ (val) : 1);                                      \
440     (gint) __sync_fetch_and_add ((atomic), (val));                           \
441   }))
442 #define g_atomic_int_and(atomic, val) \
443   (G_GNUC_EXTENSION ({                                                       \
444     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
445     (void) (0 ? *(atomic) ^ (val) : 1);                                      \
446     (guint) __sync_fetch_and_and ((atomic), (val));                          \
447   }))
448 #define g_atomic_int_or(atomic, val) \
449   (G_GNUC_EXTENSION ({                                                       \
450     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
451     (void) (0 ? *(atomic) ^ (val) : 1);                                      \
452     (guint) __sync_fetch_and_or ((atomic), (val));                           \
453   }))
454 #define g_atomic_int_xor(atomic, val) \
455   (G_GNUC_EXTENSION ({                                                       \
456     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
457     (void) (0 ? *(atomic) ^ (val) : 1);                                      \
458     (guint) __sync_fetch_and_xor ((atomic), (val));                          \
459   }))
460
461 #define g_atomic_pointer_compare_and_exchange(atomic, oldval, newval) \
462   (G_GNUC_EXTENSION ({                                                       \
463     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
464     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
465     __sync_bool_compare_and_swap ((atomic), (oldval), (newval)) ? TRUE : FALSE; \
466   }))
467 #define g_atomic_pointer_compare_and_exchange_full(atomic, oldval, newval, preval) \
468   (G_GNUC_EXTENSION ({                                                             \
469     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                       \
470     G_STATIC_ASSERT (sizeof *(preval) == sizeof (gpointer));                       \
471     (void) (0 ? (gpointer) *(atomic) : NULL);                                      \
472     (void) (0 ? (gpointer) *(preval) : NULL);                                      \
473     *(preval) = __sync_val_compare_and_swap ((atomic), (oldval), (newval));        \
474     (*(preval) == (oldval)) ? TRUE : FALSE;                                        \
475   }))
476 #if defined(_GLIB_GCC_HAVE_SYNC_SWAP)
477 #define g_atomic_pointer_exchange(atomic, newval) \
478   (G_GNUC_EXTENSION ({                                                       \
479     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
480     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
481     (gpointer) __sync_swap ((atomic), (newval));                             \
482   }))
483 #else
484 #define g_atomic_pointer_exchange(atomic, newval) \
485   (G_GNUC_EXTENSION ({                                                       \
486     gpointer oldval;                                                         \
487     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
488     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
489     do                                                                       \
490       {                                                                      \
491         oldval = (gpointer) *atomic;                                         \
492       } while (!__sync_bool_compare_and_swap (atomic, oldval, newval));      \
493     oldval;                                                                  \
494   }))
495 #endif /* defined(_GLIB_GCC_HAVE_SYNC_SWAP) */
496 #define g_atomic_pointer_add(atomic, val) \
497   (G_GNUC_EXTENSION ({                                                       \
498     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
499     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
500     (void) (0 ? (val) ^ (val) : 1);                                          \
501     (gintptr) __sync_fetch_and_add ((atomic), (val));                        \
502   }))
503 #define g_atomic_pointer_and(atomic, val) \
504   (G_GNUC_EXTENSION ({                                                       \
505     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
506     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
507     (void) (0 ? (val) ^ (val) : 1);                                          \
508     (guintptr) __sync_fetch_and_and ((atomic), (val));                       \
509   }))
510 #define g_atomic_pointer_or(atomic, val) \
511   (G_GNUC_EXTENSION ({                                                       \
512     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
513     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
514     (void) (0 ? (val) ^ (val) : 1);                                          \
515     (guintptr) __sync_fetch_and_or ((atomic), (val));                        \
516   }))
517 #define g_atomic_pointer_xor(atomic, val) \
518   (G_GNUC_EXTENSION ({                                                       \
519     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
520     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
521     (void) (0 ? (val) ^ (val) : 1);                                          \
522     (guintptr) __sync_fetch_and_xor ((atomic), (val));                       \
523   }))
524
525 #endif /* !defined(__ATOMIC_SEQ_CST) */
526
527 #else /* defined(G_ATOMIC_LOCK_FREE) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) */
528
529 #define g_atomic_int_get(atomic) \
530   (g_atomic_int_get ((gint *) (atomic)))
531 #define g_atomic_int_set(atomic, newval) \
532   (g_atomic_int_set ((gint *) (atomic), (gint) (newval)))
533 #define g_atomic_int_compare_and_exchange(atomic, oldval, newval) \
534   (g_atomic_int_compare_and_exchange ((gint *) (atomic), (oldval), (newval)))
535 #define g_atomic_int_compare_and_exchange_full(atomic, oldval, newval, preval) \
536   (g_atomic_int_compare_and_exchange_full ((gint *) (atomic), (oldval), (newval), (gint *) (preval)))
537 #define g_atomic_int_exchange(atomic, newval) \
538   (g_atomic_int_exchange ((gint *) (atomic), (newval)))
539 #define g_atomic_int_add(atomic, val) \
540   (g_atomic_int_add ((gint *) (atomic), (val)))
541 #define g_atomic_int_and(atomic, val) \
542   (g_atomic_int_and ((guint *) (atomic), (val)))
543 #define g_atomic_int_or(atomic, val) \
544   (g_atomic_int_or ((guint *) (atomic), (val)))
545 #define g_atomic_int_xor(atomic, val) \
546   (g_atomic_int_xor ((guint *) (atomic), (val)))
547 #define g_atomic_int_inc(atomic) \
548   (g_atomic_int_inc ((gint *) (atomic)))
549 #define g_atomic_int_dec_and_test(atomic) \
550   (g_atomic_int_dec_and_test ((gint *) (atomic)))
551
552 #if defined(glib_typeof)
553   /* The (void *) cast in the middle *looks* redundant, because
554    * g_atomic_pointer_get returns void * already, but it's to silence
555    * -Werror=bad-function-cast when we're doing something like:
556    * guintptr a, b; ...; a = g_atomic_pointer_get (&b);
557    * which would otherwise be assigning the void * result of
558    * g_atomic_pointer_get directly to the pointer-sized but
559    * non-pointer-typed result. */
560 #define g_atomic_pointer_get(atomic)                                       \
561   (glib_typeof (*(atomic))) (void *) ((g_atomic_pointer_get) ((void *) atomic))
562 #else /* !(defined(glib_typeof) */
563 #define g_atomic_pointer_get(atomic) \
564   (g_atomic_pointer_get (atomic))
565 #endif
566
567 #define g_atomic_pointer_set(atomic, newval) \
568   (g_atomic_pointer_set ((atomic), (gpointer) (newval)))
569
570 #define g_atomic_pointer_compare_and_exchange(atomic, oldval, newval) \
571   (g_atomic_pointer_compare_and_exchange ((atomic), (gpointer) (oldval), (gpointer) (newval)))
572 #define g_atomic_pointer_compare_and_exchange_full(atomic, oldval, newval, prevval) \
573   (g_atomic_pointer_compare_and_exchange_full ((atomic), (gpointer) (oldval), (gpointer) (newval), (prevval)))
574 #define g_atomic_pointer_exchange(atomic, newval) \
575   (g_atomic_pointer_exchange ((atomic), (gpointer) (newval)))
576 #define g_atomic_pointer_add(atomic, val) \
577   (g_atomic_pointer_add ((atomic), (gssize) (val)))
578 #define g_atomic_pointer_and(atomic, val) \
579   (g_atomic_pointer_and ((atomic), (gsize) (val)))
580 #define g_atomic_pointer_or(atomic, val) \
581   (g_atomic_pointer_or ((atomic), (gsize) (val)))
582 #define g_atomic_pointer_xor(atomic, val) \
583   (g_atomic_pointer_xor ((atomic), (gsize) (val)))
584
585 #endif /* defined(G_ATOMIC_LOCK_FREE) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) */
586
587 #endif /* __G_ATOMIC_H__ */