| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587 |
- /*
- * Copyright © 2011 Ryan Lortie
- *
- * SPDX-License-Identifier: LGPL-2.1-or-later
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- * Author: Ryan Lortie <desrt@desrt.ca>
- */
- #ifndef __G_ATOMIC_H__
- #define __G_ATOMIC_H__
- #if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
- #error "Only <glib.h> can be included directly."
- #endif
- #include <glib/gtypes.h>
- #include <glib/glib-typeof.h>
- G_BEGIN_DECLS
- GLIB_AVAILABLE_IN_ALL
- gint g_atomic_int_get (const volatile gint *atomic);
- GLIB_AVAILABLE_IN_ALL
- void g_atomic_int_set (volatile gint *atomic,
- gint newval);
- GLIB_AVAILABLE_IN_ALL
- void g_atomic_int_inc (volatile gint *atomic);
- GLIB_AVAILABLE_IN_ALL
- gboolean g_atomic_int_dec_and_test (volatile gint *atomic);
- GLIB_AVAILABLE_IN_ALL
- gboolean g_atomic_int_compare_and_exchange (volatile gint *atomic,
- gint oldval,
- gint newval);
- GLIB_AVAILABLE_IN_2_74
- gboolean g_atomic_int_compare_and_exchange_full (gint *atomic,
- gint oldval,
- gint newval,
- gint *preval);
- GLIB_AVAILABLE_IN_2_74
- gint g_atomic_int_exchange (gint *atomic,
- gint newval);
- GLIB_AVAILABLE_IN_ALL
- gint g_atomic_int_add (volatile gint *atomic,
- gint val);
- GLIB_AVAILABLE_IN_2_30
- guint g_atomic_int_and (volatile guint *atomic,
- guint val);
- GLIB_AVAILABLE_IN_2_30
- guint g_atomic_int_or (volatile guint *atomic,
- guint val);
- GLIB_AVAILABLE_IN_ALL
- guint g_atomic_int_xor (volatile guint *atomic,
- guint val);
- GLIB_AVAILABLE_IN_ALL
- gpointer g_atomic_pointer_get (const volatile void *atomic);
- GLIB_AVAILABLE_IN_ALL
- void g_atomic_pointer_set (volatile void *atomic,
- gpointer newval);
- GLIB_AVAILABLE_IN_ALL
- gboolean g_atomic_pointer_compare_and_exchange (volatile void *atomic,
- gpointer oldval,
- gpointer newval);
- GLIB_AVAILABLE_IN_2_74
- gboolean g_atomic_pointer_compare_and_exchange_full (void *atomic,
- gpointer oldval,
- gpointer newval,
- void *preval);
- GLIB_AVAILABLE_IN_2_74
- gpointer g_atomic_pointer_exchange (void *atomic,
- gpointer newval);
- GLIB_AVAILABLE_IN_ALL
- gintptr g_atomic_pointer_add (volatile void *atomic,
- gssize val);
- GLIB_AVAILABLE_IN_2_30
- guintptr g_atomic_pointer_and (volatile void *atomic,
- gsize val);
- GLIB_AVAILABLE_IN_2_30
- guintptr g_atomic_pointer_or (volatile void *atomic,
- gsize val);
- GLIB_AVAILABLE_IN_ALL
- guintptr g_atomic_pointer_xor (volatile void *atomic,
- gsize val);
- GLIB_DEPRECATED_IN_2_30_FOR(g_atomic_int_add)
- gint g_atomic_int_exchange_and_add (volatile gint *atomic,
- gint val);
- G_END_DECLS
- #if defined(G_ATOMIC_LOCK_FREE) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
- /* We prefer the new C11-style atomic extension of GCC if available */
- #if defined(__ATOMIC_SEQ_CST)
- #define g_atomic_int_get(atomic) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
- gint gaig_temp; \
- (void) (0 ? *(atomic) ^ *(atomic) : 1); \
- __atomic_load ((gint *)(atomic), &gaig_temp, __ATOMIC_SEQ_CST); \
- (gint) gaig_temp; \
- }))
- #define g_atomic_int_set(atomic, newval) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
- gint gais_temp = (gint) (newval); \
- (void) (0 ? *(atomic) ^ (newval) : 1); \
- __atomic_store ((gint *)(atomic), &gais_temp, __ATOMIC_SEQ_CST); \
- }))
- #if defined(glib_typeof)
- #define g_atomic_pointer_get(atomic) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
- glib_typeof (*(atomic)) gapg_temp_newval; \
- glib_typeof ((atomic)) gapg_temp_atomic = (atomic); \
- __atomic_load (gapg_temp_atomic, &gapg_temp_newval, __ATOMIC_SEQ_CST); \
- gapg_temp_newval; \
- }))
- #define g_atomic_pointer_set(atomic, newval) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
- glib_typeof ((atomic)) gaps_temp_atomic = (atomic); \
- glib_typeof (*(atomic)) gaps_temp_newval = (newval); \
- (void) (0 ? (gpointer) * (atomic) : NULL); \
- __atomic_store (gaps_temp_atomic, &gaps_temp_newval, __ATOMIC_SEQ_CST); \
- }))
- #else /* if !(defined(glib_typeof) */
- #define g_atomic_pointer_get(atomic) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
- gpointer gapg_temp_newval; \
- gpointer *gapg_temp_atomic = (gpointer *)(atomic); \
- __atomic_load (gapg_temp_atomic, &gapg_temp_newval, __ATOMIC_SEQ_CST); \
- gapg_temp_newval; \
- }))
- #define g_atomic_pointer_set(atomic, newval) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
- gpointer *gaps_temp_atomic = (gpointer *)(atomic); \
- gpointer gaps_temp_newval = (gpointer)(newval); \
- (void) (0 ? (gpointer) *(atomic) : NULL); \
- __atomic_store (gaps_temp_atomic, &gaps_temp_newval, __ATOMIC_SEQ_CST); \
- }))
- #endif /* if defined(glib_typeof) */
- #define g_atomic_int_inc(atomic) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
- (void) (0 ? *(atomic) ^ *(atomic) : 1); \
- (void) __atomic_fetch_add ((atomic), 1, __ATOMIC_SEQ_CST); \
- }))
- #define g_atomic_int_dec_and_test(atomic) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
- (void) (0 ? *(atomic) ^ *(atomic) : 1); \
- __atomic_fetch_sub ((atomic), 1, __ATOMIC_SEQ_CST) == 1; \
- }))
- #if defined(glib_typeof) && defined(G_CXX_STD_VERSION)
- /* See comments below about equivalent g_atomic_pointer_compare_and_exchange()
- * shenanigans for type-safety when compiling in C++ mode. */
- #define g_atomic_int_compare_and_exchange(atomic, oldval, newval) \
- (G_GNUC_EXTENSION ({ \
- glib_typeof (*(atomic)) gaicae_oldval = (oldval); \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
- (void) (0 ? *(atomic) ^ (newval) ^ (oldval) : 1); \
- __atomic_compare_exchange_n ((atomic), &gaicae_oldval, (newval), FALSE, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ? TRUE : FALSE; \
- }))
- #else /* if !(defined(glib_typeof) && defined(G_CXX_STD_VERSION)) */
- #define g_atomic_int_compare_and_exchange(atomic, oldval, newval) \
- (G_GNUC_EXTENSION ({ \
- gint gaicae_oldval = (oldval); \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
- (void) (0 ? *(atomic) ^ (newval) ^ (oldval) : 1); \
- __atomic_compare_exchange_n ((atomic), (void *) (&(gaicae_oldval)), (newval), FALSE, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ? TRUE : FALSE; \
- }))
- #endif /* defined(glib_typeof) */
- #define g_atomic_int_compare_and_exchange_full(atomic, oldval, newval, preval) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
- G_STATIC_ASSERT (sizeof *(preval) == sizeof (gint)); \
- (void) (0 ? *(atomic) ^ (newval) ^ (oldval) ^ *(preval) : 1); \
- *(preval) = (oldval); \
- __atomic_compare_exchange_n ((atomic), (preval), (newval), FALSE, \
- __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) \
- ? TRUE : FALSE; \
- }))
- #define g_atomic_int_exchange(atomic, newval) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
- (void) (0 ? *(atomic) ^ (newval) : 1); \
- (gint) __atomic_exchange_n ((atomic), (newval), __ATOMIC_SEQ_CST); \
- }))
- #define g_atomic_int_add(atomic, val) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
- (void) (0 ? *(atomic) ^ (val) : 1); \
- (gint) __atomic_fetch_add ((atomic), (val), __ATOMIC_SEQ_CST); \
- }))
- #define g_atomic_int_and(atomic, val) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
- (void) (0 ? *(atomic) ^ (val) : 1); \
- (guint) __atomic_fetch_and ((atomic), (val), __ATOMIC_SEQ_CST); \
- }))
- #define g_atomic_int_or(atomic, val) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
- (void) (0 ? *(atomic) ^ (val) : 1); \
- (guint) __atomic_fetch_or ((atomic), (val), __ATOMIC_SEQ_CST); \
- }))
- #define g_atomic_int_xor(atomic, val) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
- (void) (0 ? *(atomic) ^ (val) : 1); \
- (guint) __atomic_fetch_xor ((atomic), (val), __ATOMIC_SEQ_CST); \
- }))
- #if defined(glib_typeof) && defined(G_CXX_STD_VERSION)
- /* This is typesafe because we check we can assign oldval to the type of
- * (*atomic). Unfortunately it can only be done in C++ because gcc/clang warn
- * when atomic is volatile and not oldval, or when atomic is gsize* and oldval
- * is NULL. Note that clang++ force us to be typesafe because it is an error if the 2nd
- * argument of __atomic_compare_exchange_n() has a different type than the
- * first.
- * https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1919
- * https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1715#note_1024120. */
- #define g_atomic_pointer_compare_and_exchange(atomic, oldval, newval) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof (static_cast<glib_typeof (*(atomic))>((oldval))) \
- == sizeof (gpointer)); \
- glib_typeof (*(atomic)) gapcae_oldval = (oldval); \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
- (void) (0 ? (gpointer) *(atomic) : NULL); \
- __atomic_compare_exchange_n ((atomic), &gapcae_oldval, (newval), FALSE, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ? TRUE : FALSE; \
- }))
- #else /* if !(defined(glib_typeof) && defined(G_CXX_STD_VERSION) */
- #define g_atomic_pointer_compare_and_exchange(atomic, oldval, newval) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof (oldval) == sizeof (gpointer)); \
- gpointer gapcae_oldval = (gpointer)(oldval); \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
- (void) (0 ? (gpointer) *(atomic) : NULL); \
- __atomic_compare_exchange_n ((atomic), (void *) (&(gapcae_oldval)), (newval), FALSE, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ? TRUE : FALSE; \
- }))
- #endif /* defined(glib_typeof) */
- #define g_atomic_pointer_compare_and_exchange_full(atomic, oldval, newval, preval) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
- G_STATIC_ASSERT (sizeof *(preval) == sizeof (gpointer)); \
- (void) (0 ? (gpointer) *(atomic) : NULL); \
- (void) (0 ? (gpointer) *(preval) : NULL); \
- *(preval) = (oldval); \
- __atomic_compare_exchange_n ((atomic), (preval), (newval), FALSE, \
- __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ? \
- TRUE : FALSE; \
- }))
- #define g_atomic_pointer_exchange(atomic, newval) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
- (void) (0 ? (gpointer) *(atomic) : NULL); \
- (gpointer) __atomic_exchange_n ((atomic), (newval), __ATOMIC_SEQ_CST); \
- }))
- #define g_atomic_pointer_add(atomic, val) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
- (void) (0 ? (gpointer) *(atomic) : NULL); \
- (void) (0 ? (val) ^ (val) : 1); \
- (gintptr) __atomic_fetch_add ((atomic), (val), __ATOMIC_SEQ_CST); \
- }))
- #define g_atomic_pointer_and(atomic, val) \
- (G_GNUC_EXTENSION ({ \
- guintptr *gapa_atomic = (guintptr *) (atomic); \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (guintptr)); \
- (void) (0 ? (gpointer) *(atomic) : NULL); \
- (void) (0 ? (val) ^ (val) : 1); \
- (guintptr) __atomic_fetch_and (gapa_atomic, (val), __ATOMIC_SEQ_CST); \
- }))
- #define g_atomic_pointer_or(atomic, val) \
- (G_GNUC_EXTENSION ({ \
- guintptr *gapo_atomic = (guintptr *) (atomic); \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (guintptr)); \
- (void) (0 ? (gpointer) *(atomic) : NULL); \
- (void) (0 ? (val) ^ (val) : 1); \
- (guintptr) __atomic_fetch_or (gapo_atomic, (val), __ATOMIC_SEQ_CST); \
- }))
- #define g_atomic_pointer_xor(atomic, val) \
- (G_GNUC_EXTENSION ({ \
- guintptr *gapx_atomic = (guintptr *) (atomic); \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (guintptr)); \
- (void) (0 ? (gpointer) *(atomic) : NULL); \
- (void) (0 ? (val) ^ (val) : 1); \
- (guintptr) __atomic_fetch_xor (gapx_atomic, (val), __ATOMIC_SEQ_CST); \
- }))
- #else /* defined(__ATOMIC_SEQ_CST) */
- /* We want to achieve __ATOMIC_SEQ_CST semantics here. See
- * https://en.cppreference.com/w/c/atomic/memory_order#Constants. For load
- * operations, that means performing an *acquire*:
- * > A load operation with this memory order performs the acquire operation on
- * > the affected memory location: no reads or writes in the current thread can
- * > be reordered before this load. All writes in other threads that release
- * > the same atomic variable are visible in the current thread.
- *
- * “no reads or writes in the current thread can be reordered before this load”
- * is implemented using a compiler barrier (a no-op `__asm__` section) to
- * prevent instruction reordering. Writes in other threads are synchronised
- * using `__sync_synchronize()`. It’s unclear from the GCC documentation whether
- * `__sync_synchronize()` acts as a compiler barrier, hence our explicit use of
- * one.
- *
- * For store operations, `__ATOMIC_SEQ_CST` means performing a *release*:
- * > A store operation with this memory order performs the release operation:
- * > no reads or writes in the current thread can be reordered after this store.
- * > All writes in the current thread are visible in other threads that acquire
- * > the same atomic variable (see Release-Acquire ordering below) and writes
- * > that carry a dependency into the atomic variable become visible in other
- * > threads that consume the same atomic (see Release-Consume ordering below).
- *
- * “no reads or writes in the current thread can be reordered after this store”
- * is implemented using a compiler barrier to prevent instruction reordering.
- * “All writes in the current thread are visible in other threads” is implemented
- * using `__sync_synchronize()`; similarly for “writes that carry a dependency”.
- */
- #define g_atomic_int_get(atomic) \
- (G_GNUC_EXTENSION ({ \
- gint gaig_result; \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
- (void) (0 ? *(atomic) ^ *(atomic) : 1); \
- gaig_result = (gint) *(atomic); \
- __sync_synchronize (); \
- __asm__ __volatile__ ("" : : : "memory"); \
- gaig_result; \
- }))
- #define g_atomic_int_set(atomic, newval) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
- (void) (0 ? *(atomic) ^ (newval) : 1); \
- __sync_synchronize (); \
- __asm__ __volatile__ ("" : : : "memory"); \
- *(atomic) = (newval); \
- }))
- #define g_atomic_pointer_get(atomic) \
- (G_GNUC_EXTENSION ({ \
- gpointer gapg_result; \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
- gapg_result = (gpointer) *(atomic); \
- __sync_synchronize (); \
- __asm__ __volatile__ ("" : : : "memory"); \
- gapg_result; \
- }))
- #if defined(glib_typeof)
- #define g_atomic_pointer_set(atomic, newval) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
- (void) (0 ? (gpointer) *(atomic) : NULL); \
- __sync_synchronize (); \
- __asm__ __volatile__ ("" : : : "memory"); \
- *(atomic) = (glib_typeof (*(atomic))) (guintptr) (newval); \
- }))
- #else /* if !(defined(glib_typeof) */
- #define g_atomic_pointer_set(atomic, newval) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
- (void) (0 ? (gpointer) *(atomic) : NULL); \
- __sync_synchronize (); \
- __asm__ __volatile__ ("" : : : "memory"); \
- *(atomic) = (gpointer) (guintptr) (newval); \
- }))
- #endif /* if defined(glib_typeof) */
- #define g_atomic_int_inc(atomic) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
- (void) (0 ? *(atomic) ^ *(atomic) : 1); \
- (void) __sync_fetch_and_add ((atomic), 1); \
- }))
- #define g_atomic_int_dec_and_test(atomic) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
- (void) (0 ? *(atomic) ^ *(atomic) : 1); \
- __sync_fetch_and_sub ((atomic), 1) == 1; \
- }))
- #define g_atomic_int_compare_and_exchange(atomic, oldval, newval) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
- (void) (0 ? *(atomic) ^ (newval) ^ (oldval) : 1); \
- __sync_bool_compare_and_swap ((atomic), (oldval), (newval)) ? TRUE : FALSE; \
- }))
- #define g_atomic_int_compare_and_exchange_full(atomic, oldval, newval, preval) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
- G_STATIC_ASSERT (sizeof *(preval) == sizeof (gint)); \
- (void) (0 ? *(atomic) ^ (newval) ^ (oldval) ^ *(preval) : 1); \
- *(preval) = __sync_val_compare_and_swap ((atomic), (oldval), (newval)); \
- (*(preval) == (oldval)) ? TRUE : FALSE; \
- }))
- #if defined(_GLIB_GCC_HAVE_SYNC_SWAP)
- #define g_atomic_int_exchange(atomic, newval) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
- (void) (0 ? *(atomic) ^ (newval) : 1); \
- (gint) __sync_swap ((atomic), (newval)); \
- }))
- #else /* defined(_GLIB_GCC_HAVE_SYNC_SWAP) */
- #define g_atomic_int_exchange(atomic, newval) \
- (G_GNUC_EXTENSION ({ \
- gint oldval; \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
- (void) (0 ? *(atomic) ^ (newval) : 1); \
- do \
- { \
- oldval = *atomic; \
- } while (!__sync_bool_compare_and_swap (atomic, oldval, newval)); \
- oldval; \
- }))
- #endif /* defined(_GLIB_GCC_HAVE_SYNC_SWAP) */
- #define g_atomic_int_add(atomic, val) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
- (void) (0 ? *(atomic) ^ (val) : 1); \
- (gint) __sync_fetch_and_add ((atomic), (val)); \
- }))
- #define g_atomic_int_and(atomic, val) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
- (void) (0 ? *(atomic) ^ (val) : 1); \
- (guint) __sync_fetch_and_and ((atomic), (val)); \
- }))
- #define g_atomic_int_or(atomic, val) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
- (void) (0 ? *(atomic) ^ (val) : 1); \
- (guint) __sync_fetch_and_or ((atomic), (val)); \
- }))
- #define g_atomic_int_xor(atomic, val) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \
- (void) (0 ? *(atomic) ^ (val) : 1); \
- (guint) __sync_fetch_and_xor ((atomic), (val)); \
- }))
- #define g_atomic_pointer_compare_and_exchange(atomic, oldval, newval) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
- (void) (0 ? (gpointer) *(atomic) : NULL); \
- __sync_bool_compare_and_swap ((atomic), (oldval), (newval)) ? TRUE : FALSE; \
- }))
- #define g_atomic_pointer_compare_and_exchange_full(atomic, oldval, newval, preval) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
- G_STATIC_ASSERT (sizeof *(preval) == sizeof (gpointer)); \
- (void) (0 ? (gpointer) *(atomic) : NULL); \
- (void) (0 ? (gpointer) *(preval) : NULL); \
- *(preval) = __sync_val_compare_and_swap ((atomic), (oldval), (newval)); \
- (*(preval) == (oldval)) ? TRUE : FALSE; \
- }))
- #if defined(_GLIB_GCC_HAVE_SYNC_SWAP)
- #define g_atomic_pointer_exchange(atomic, newval) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
- (void) (0 ? (gpointer) *(atomic) : NULL); \
- (gpointer) __sync_swap ((atomic), (newval)); \
- }))
- #else
- #define g_atomic_pointer_exchange(atomic, newval) \
- (G_GNUC_EXTENSION ({ \
- gpointer oldval; \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
- (void) (0 ? (gpointer) *(atomic) : NULL); \
- do \
- { \
- oldval = (gpointer) *atomic; \
- } while (!__sync_bool_compare_and_swap (atomic, oldval, newval)); \
- oldval; \
- }))
- #endif /* defined(_GLIB_GCC_HAVE_SYNC_SWAP) */
- #define g_atomic_pointer_add(atomic, val) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
- (void) (0 ? (gpointer) *(atomic) : NULL); \
- (void) (0 ? (val) ^ (val) : 1); \
- (gintptr) __sync_fetch_and_add ((atomic), (val)); \
- }))
- #define g_atomic_pointer_and(atomic, val) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
- (void) (0 ? (gpointer) *(atomic) : NULL); \
- (void) (0 ? (val) ^ (val) : 1); \
- (guintptr) __sync_fetch_and_and ((atomic), (val)); \
- }))
- #define g_atomic_pointer_or(atomic, val) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
- (void) (0 ? (gpointer) *(atomic) : NULL); \
- (void) (0 ? (val) ^ (val) : 1); \
- (guintptr) __sync_fetch_and_or ((atomic), (val)); \
- }))
- #define g_atomic_pointer_xor(atomic, val) \
- (G_GNUC_EXTENSION ({ \
- G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \
- (void) (0 ? (gpointer) *(atomic) : NULL); \
- (void) (0 ? (val) ^ (val) : 1); \
- (guintptr) __sync_fetch_and_xor ((atomic), (val)); \
- }))
- #endif /* !defined(__ATOMIC_SEQ_CST) */
- #else /* defined(G_ATOMIC_LOCK_FREE) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) */
- #define g_atomic_int_get(atomic) \
- (g_atomic_int_get ((gint *) (atomic)))
- #define g_atomic_int_set(atomic, newval) \
- (g_atomic_int_set ((gint *) (atomic), (gint) (newval)))
- #define g_atomic_int_compare_and_exchange(atomic, oldval, newval) \
- (g_atomic_int_compare_and_exchange ((gint *) (atomic), (oldval), (newval)))
- #define g_atomic_int_compare_and_exchange_full(atomic, oldval, newval, preval) \
- (g_atomic_int_compare_and_exchange_full ((gint *) (atomic), (oldval), (newval), (gint *) (preval)))
- #define g_atomic_int_exchange(atomic, newval) \
- (g_atomic_int_exchange ((gint *) (atomic), (newval)))
- #define g_atomic_int_add(atomic, val) \
- (g_atomic_int_add ((gint *) (atomic), (val)))
- #define g_atomic_int_and(atomic, val) \
- (g_atomic_int_and ((guint *) (atomic), (val)))
- #define g_atomic_int_or(atomic, val) \
- (g_atomic_int_or ((guint *) (atomic), (val)))
- #define g_atomic_int_xor(atomic, val) \
- (g_atomic_int_xor ((guint *) (atomic), (val)))
- #define g_atomic_int_inc(atomic) \
- (g_atomic_int_inc ((gint *) (atomic)))
- #define g_atomic_int_dec_and_test(atomic) \
- (g_atomic_int_dec_and_test ((gint *) (atomic)))
- #if defined(glib_typeof)
- /* The (void *) cast in the middle *looks* redundant, because
- * g_atomic_pointer_get returns void * already, but it's to silence
- * -Werror=bad-function-cast when we're doing something like:
- * guintptr a, b; ...; a = g_atomic_pointer_get (&b);
- * which would otherwise be assigning the void * result of
- * g_atomic_pointer_get directly to the pointer-sized but
- * non-pointer-typed result. */
- #define g_atomic_pointer_get(atomic) \
- (glib_typeof (*(atomic))) (void *) ((g_atomic_pointer_get) ((void *) atomic))
- #else /* !(defined(glib_typeof) */
- #define g_atomic_pointer_get(atomic) \
- (g_atomic_pointer_get (atomic))
- #endif
- #define g_atomic_pointer_set(atomic, newval) \
- (g_atomic_pointer_set ((atomic), (gpointer) (newval)))
- #define g_atomic_pointer_compare_and_exchange(atomic, oldval, newval) \
- (g_atomic_pointer_compare_and_exchange ((atomic), (gpointer) (oldval), (gpointer) (newval)))
- #define g_atomic_pointer_compare_and_exchange_full(atomic, oldval, newval, prevval) \
- (g_atomic_pointer_compare_and_exchange_full ((atomic), (gpointer) (oldval), (gpointer) (newval), (prevval)))
- #define g_atomic_pointer_exchange(atomic, newval) \
- (g_atomic_pointer_exchange ((atomic), (gpointer) (newval)))
- #define g_atomic_pointer_add(atomic, val) \
- (g_atomic_pointer_add ((atomic), (gssize) (val)))
- #define g_atomic_pointer_and(atomic, val) \
- (g_atomic_pointer_and ((atomic), (gsize) (val)))
- #define g_atomic_pointer_or(atomic, val) \
- (g_atomic_pointer_or ((atomic), (gsize) (val)))
- #define g_atomic_pointer_xor(atomic, val) \
- (g_atomic_pointer_xor ((atomic), (gsize) (val)))
- #endif /* defined(G_ATOMIC_LOCK_FREE) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) */
- #endif /* __G_ATOMIC_H__ */
|