Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-22 10:14:03

0001 /*
0002  * Copyright © 2011 Ryan Lortie
0003  *
0004  * SPDX-License-Identifier: LGPL-2.1-or-later
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Lesser General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2.1 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful, but
0012  * WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Lesser General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Lesser General Public
0017  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
0018  *
0019  * Author: Ryan Lortie <desrt@desrt.ca>
0020  */
0021 
0022 #ifndef __G_ATOMIC_H__
0023 #define __G_ATOMIC_H__
0024 
0025 #if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
0026 #error "Only <glib.h> can be included directly."
0027 #endif
0028 
0029 #include <glib/gtypes.h>
0030 #include <glib/glib-typeof.h>
0031 
0032 G_BEGIN_DECLS
0033 
0034 GLIB_AVAILABLE_IN_ALL
0035 gint                    g_atomic_int_get                      (const volatile gint *atomic);
0036 GLIB_AVAILABLE_IN_ALL
0037 void                    g_atomic_int_set                      (volatile gint  *atomic,
0038                                                                gint            newval);
0039 GLIB_AVAILABLE_IN_ALL
0040 void                    g_atomic_int_inc                      (volatile gint  *atomic);
0041 GLIB_AVAILABLE_IN_ALL
0042 gboolean                g_atomic_int_dec_and_test             (volatile gint  *atomic);
0043 GLIB_AVAILABLE_IN_ALL
0044 gboolean                g_atomic_int_compare_and_exchange     (volatile gint  *atomic,
0045                                                                gint            oldval,
0046                                                                gint            newval);
0047 GLIB_AVAILABLE_IN_2_74
0048 gboolean                g_atomic_int_compare_and_exchange_full (gint         *atomic,
0049                                                                 gint          oldval,
0050                                                                 gint          newval,
0051                                                                 gint         *preval);
0052 GLIB_AVAILABLE_IN_2_74
0053 gint                    g_atomic_int_exchange                 (gint           *atomic,
0054                                                                gint            newval);
0055 GLIB_AVAILABLE_IN_ALL
0056 gint                    g_atomic_int_add                      (volatile gint  *atomic,
0057                                                                gint            val);
0058 GLIB_AVAILABLE_IN_2_30
0059 guint                   g_atomic_int_and                      (volatile guint *atomic,
0060                                                                guint           val);
0061 GLIB_AVAILABLE_IN_2_30
0062 guint                   g_atomic_int_or                       (volatile guint *atomic,
0063                                                                guint           val);
0064 GLIB_AVAILABLE_IN_ALL
0065 guint                   g_atomic_int_xor                      (volatile guint *atomic,
0066                                                                guint           val);
0067 
0068 GLIB_AVAILABLE_IN_ALL
0069 gpointer                g_atomic_pointer_get                  (const volatile void *atomic);
0070 GLIB_AVAILABLE_IN_ALL
0071 void                    g_atomic_pointer_set                  (volatile void  *atomic,
0072                                                                gpointer        newval);
0073 GLIB_AVAILABLE_IN_ALL
0074 gboolean                g_atomic_pointer_compare_and_exchange (volatile void  *atomic,
0075                                                                gpointer        oldval,
0076                                                                gpointer        newval);
0077 GLIB_AVAILABLE_IN_2_74
0078 gboolean                g_atomic_pointer_compare_and_exchange_full (void     *atomic,
0079                                                                     gpointer  oldval,
0080                                                                     gpointer  newval,
0081                                                                     void     *preval);
0082 GLIB_AVAILABLE_IN_2_74
0083 gpointer                g_atomic_pointer_exchange             (void           *atomic,
0084                                                                gpointer        newval);
0085 GLIB_AVAILABLE_IN_ALL
0086 gintptr                 g_atomic_pointer_add                  (volatile void  *atomic,
0087                                                                gssize          val);
0088 GLIB_AVAILABLE_IN_2_30
0089 guintptr                g_atomic_pointer_and                  (volatile void  *atomic,
0090                                                                gsize           val);
0091 GLIB_AVAILABLE_IN_2_30
0092 guintptr                g_atomic_pointer_or                   (volatile void  *atomic,
0093                                                                gsize           val);
0094 GLIB_AVAILABLE_IN_ALL
0095 guintptr                g_atomic_pointer_xor                  (volatile void  *atomic,
0096                                                                gsize           val);
0097 
0098 GLIB_DEPRECATED_IN_2_30_FOR(g_atomic_int_add)
0099 gint                    g_atomic_int_exchange_and_add         (volatile gint  *atomic,
0100                                                                gint            val);
0101 
0102 G_END_DECLS
0103 
0104 #if defined(G_ATOMIC_LOCK_FREE) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
0105 
0106 /* We prefer the new C11-style atomic extension of GCC if available */
0107 #if defined(__ATOMIC_SEQ_CST)
0108 
0109 #define g_atomic_int_get(atomic) \
0110   (G_GNUC_EXTENSION ({                                                       \
0111     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
0112     gint gaig_temp;                                                          \
0113     (void) (0 ? *(atomic) ^ *(atomic) : 1);                                  \
0114     __atomic_load ((gint *)(atomic), &gaig_temp, __ATOMIC_SEQ_CST);          \
0115     (gint) gaig_temp;                                                        \
0116   }))
0117 #define g_atomic_int_set(atomic, newval) \
0118   (G_GNUC_EXTENSION ({                                                       \
0119     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
0120     gint gais_temp = (gint) (newval);                                        \
0121     (void) (0 ? *(atomic) ^ (newval) : 1);                                   \
0122     __atomic_store ((gint *)(atomic), &gais_temp, __ATOMIC_SEQ_CST);         \
0123   }))
0124 
0125 #if defined(glib_typeof)
0126 #define g_atomic_pointer_get(atomic)                                       \
0127   (G_GNUC_EXTENSION ({                                                     \
0128     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));               \
0129     glib_typeof (*(atomic)) gapg_temp_newval;                              \
0130     glib_typeof ((atomic)) gapg_temp_atomic = (atomic);                    \
0131     __atomic_load (gapg_temp_atomic, &gapg_temp_newval, __ATOMIC_SEQ_CST); \
0132     gapg_temp_newval;                                                      \
0133   }))
0134 #define g_atomic_pointer_set(atomic, newval)                                \
0135   (G_GNUC_EXTENSION ({                                                      \
0136     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                \
0137     glib_typeof ((atomic)) gaps_temp_atomic = (atomic);                     \
0138     glib_typeof (*(atomic)) gaps_temp_newval = (newval);                    \
0139     (void) (0 ? (gpointer) * (atomic) : NULL);                              \
0140     __atomic_store (gaps_temp_atomic, &gaps_temp_newval, __ATOMIC_SEQ_CST); \
0141   }))
0142 #else /* if !(defined(glib_typeof) */
0143 #define g_atomic_pointer_get(atomic) \
0144   (G_GNUC_EXTENSION ({                                                       \
0145     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
0146     gpointer gapg_temp_newval;                                               \
0147     gpointer *gapg_temp_atomic = (gpointer *)(atomic);                       \
0148     __atomic_load (gapg_temp_atomic, &gapg_temp_newval, __ATOMIC_SEQ_CST);   \
0149     gapg_temp_newval;                                                        \
0150   }))
0151 #define g_atomic_pointer_set(atomic, newval) \
0152   (G_GNUC_EXTENSION ({                                                       \
0153     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
0154     gpointer *gaps_temp_atomic = (gpointer *)(atomic);                       \
0155     gpointer gaps_temp_newval = (gpointer)(newval);                          \
0156     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
0157     __atomic_store (gaps_temp_atomic, &gaps_temp_newval, __ATOMIC_SEQ_CST);  \
0158   }))
0159 #endif /* if defined(glib_typeof) */
0160 
0161 #define g_atomic_int_inc(atomic) \
0162   (G_GNUC_EXTENSION ({                                                       \
0163     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
0164     (void) (0 ? *(atomic) ^ *(atomic) : 1);                                  \
0165     (void) __atomic_fetch_add ((atomic), 1, __ATOMIC_SEQ_CST);               \
0166   }))
0167 #define g_atomic_int_dec_and_test(atomic) \
0168   (G_GNUC_EXTENSION ({                                                       \
0169     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
0170     (void) (0 ? *(atomic) ^ *(atomic) : 1);                                  \
0171     __atomic_fetch_sub ((atomic), 1, __ATOMIC_SEQ_CST) == 1;                 \
0172   }))
0173 #if defined(glib_typeof) && defined(G_CXX_STD_VERSION)
0174 /* See comments below about equivalent g_atomic_pointer_compare_and_exchange()
0175  * shenanigans for type-safety when compiling in C++ mode. */
0176 #define g_atomic_int_compare_and_exchange(atomic, oldval, newval) \
0177   (G_GNUC_EXTENSION ({                                                       \
0178     glib_typeof (*(atomic)) gaicae_oldval = (oldval);                        \
0179     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
0180     (void) (0 ? *(atomic) ^ (newval) ^ (oldval) : 1);                        \
0181     __atomic_compare_exchange_n ((atomic), &gaicae_oldval, (newval), FALSE, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ? TRUE : FALSE; \
0182   }))
0183 #else /* if !(defined(glib_typeof) && defined(G_CXX_STD_VERSION)) */
0184 #define g_atomic_int_compare_and_exchange(atomic, oldval, newval) \
0185   (G_GNUC_EXTENSION ({                                                       \
0186     gint gaicae_oldval = (oldval);                                           \
0187     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
0188     (void) (0 ? *(atomic) ^ (newval) ^ (oldval) : 1);                        \
0189     __atomic_compare_exchange_n ((atomic), (void *) (&(gaicae_oldval)), (newval), FALSE, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ? TRUE : FALSE; \
0190   }))
0191 #endif /* defined(glib_typeof) */
0192 #define g_atomic_int_compare_and_exchange_full(atomic, oldval, newval, preval) \
0193   (G_GNUC_EXTENSION ({                                                         \
0194     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                       \
0195     G_STATIC_ASSERT (sizeof *(preval) == sizeof (gint));                       \
0196     (void) (0 ? *(atomic) ^ (newval) ^ (oldval) ^ *(preval) : 1);              \
0197     *(preval) = (oldval);                                                      \
0198     __atomic_compare_exchange_n ((atomic), (preval), (newval), FALSE,          \
0199                                  __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)           \
0200                                  ? TRUE : FALSE;                               \
0201   }))
0202 #define g_atomic_int_exchange(atomic, newval) \
0203   (G_GNUC_EXTENSION ({                                                       \
0204     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
0205     (void) (0 ? *(atomic) ^ (newval) : 1);                                   \
0206     (gint) __atomic_exchange_n ((atomic), (newval), __ATOMIC_SEQ_CST);       \
0207   }))
0208 #define g_atomic_int_add(atomic, val) \
0209   (G_GNUC_EXTENSION ({                                                       \
0210     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
0211     (void) (0 ? *(atomic) ^ (val) : 1);                                      \
0212     (gint) __atomic_fetch_add ((atomic), (val), __ATOMIC_SEQ_CST);           \
0213   }))
0214 #define g_atomic_int_and(atomic, val) \
0215   (G_GNUC_EXTENSION ({                                                       \
0216     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
0217     (void) (0 ? *(atomic) ^ (val) : 1);                                      \
0218     (guint) __atomic_fetch_and ((atomic), (val), __ATOMIC_SEQ_CST);          \
0219   }))
0220 #define g_atomic_int_or(atomic, val) \
0221   (G_GNUC_EXTENSION ({                                                       \
0222     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
0223     (void) (0 ? *(atomic) ^ (val) : 1);                                      \
0224     (guint) __atomic_fetch_or ((atomic), (val), __ATOMIC_SEQ_CST);           \
0225   }))
0226 #define g_atomic_int_xor(atomic, val) \
0227   (G_GNUC_EXTENSION ({                                                       \
0228     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
0229     (void) (0 ? *(atomic) ^ (val) : 1);                                      \
0230     (guint) __atomic_fetch_xor ((atomic), (val), __ATOMIC_SEQ_CST);          \
0231   }))
0232 
0233 #if defined(glib_typeof) && defined(G_CXX_STD_VERSION)
0234 /* This is typesafe because we check we can assign oldval to the type of
0235  * (*atomic). Unfortunately it can only be done in C++ because gcc/clang warn
0236  * when atomic is volatile and not oldval, or when atomic is gsize* and oldval
0237  * is NULL. Note that clang++ force us to be typesafe because it is an error if the 2nd
0238  * argument of __atomic_compare_exchange_n() has a different type than the
0239  * first.
0240  * https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1919
0241  * https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1715#note_1024120. */
0242 #define g_atomic_pointer_compare_and_exchange(atomic, oldval, newval) \
0243   (G_GNUC_EXTENSION ({                                                       \
0244     G_STATIC_ASSERT (sizeof (static_cast<glib_typeof (*(atomic))>((oldval))) \
0245                      == sizeof (gpointer));                                  \
0246     glib_typeof (*(atomic)) gapcae_oldval = (oldval);                        \
0247     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
0248     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
0249     __atomic_compare_exchange_n ((atomic), &gapcae_oldval, (newval), FALSE, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ? TRUE : FALSE; \
0250   }))
0251 #else /* if !(defined(glib_typeof) && defined(G_CXX_STD_VERSION) */
0252 #define g_atomic_pointer_compare_and_exchange(atomic, oldval, newval) \
0253   (G_GNUC_EXTENSION ({                                                       \
0254     G_STATIC_ASSERT (sizeof (oldval) == sizeof (gpointer));                  \
0255     gpointer gapcae_oldval = (gpointer)(oldval);                             \
0256     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
0257     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
0258     __atomic_compare_exchange_n ((atomic), (void *) (&(gapcae_oldval)), (newval), FALSE, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ? TRUE : FALSE; \
0259   }))
0260 #endif /* defined(glib_typeof) */
0261 #define g_atomic_pointer_compare_and_exchange_full(atomic, oldval, newval, preval) \
0262   (G_GNUC_EXTENSION ({                                                             \
0263     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                       \
0264     G_STATIC_ASSERT (sizeof *(preval) == sizeof (gpointer));                       \
0265     (void) (0 ? (gpointer) *(atomic) : NULL);                                      \
0266     (void) (0 ? (gpointer) *(preval) : NULL);                                      \
0267     *(preval) = (oldval);                                                          \
0268     __atomic_compare_exchange_n ((atomic), (preval), (newval), FALSE,              \
0269                                  __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ?             \
0270                                  TRUE : FALSE;                                     \
0271   }))
0272 #define g_atomic_pointer_exchange(atomic, newval) \
0273   (G_GNUC_EXTENSION ({                                                       \
0274     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
0275     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
0276     (gpointer) __atomic_exchange_n ((atomic), (newval), __ATOMIC_SEQ_CST);   \
0277   }))
0278 #define g_atomic_pointer_add(atomic, val) \
0279   (G_GNUC_EXTENSION ({                                                       \
0280     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
0281     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
0282     (void) (0 ? (val) ^ (val) : 1);                                          \
0283     (gintptr) __atomic_fetch_add ((atomic), (val), __ATOMIC_SEQ_CST);        \
0284   }))
0285 #define g_atomic_pointer_and(atomic, val) \
0286   (G_GNUC_EXTENSION ({                                                       \
0287     guintptr *gapa_atomic = (guintptr *) (atomic);                           \
0288     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
0289     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (guintptr));                 \
0290     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
0291     (void) (0 ? (val) ^ (val) : 1);                                          \
0292     (guintptr) __atomic_fetch_and (gapa_atomic, (val), __ATOMIC_SEQ_CST);    \
0293   }))
0294 #define g_atomic_pointer_or(atomic, val) \
0295   (G_GNUC_EXTENSION ({                                                       \
0296     guintptr *gapo_atomic = (guintptr *) (atomic);                           \
0297     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
0298     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (guintptr));                 \
0299     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
0300     (void) (0 ? (val) ^ (val) : 1);                                          \
0301     (guintptr) __atomic_fetch_or (gapo_atomic, (val), __ATOMIC_SEQ_CST);     \
0302   }))
0303 #define g_atomic_pointer_xor(atomic, val) \
0304   (G_GNUC_EXTENSION ({                                                       \
0305     guintptr *gapx_atomic = (guintptr *) (atomic);                           \
0306     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
0307     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (guintptr));                 \
0308     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
0309     (void) (0 ? (val) ^ (val) : 1);                                          \
0310     (guintptr) __atomic_fetch_xor (gapx_atomic, (val), __ATOMIC_SEQ_CST);    \
0311   }))
0312 
0313 #else /* defined(__ATOMIC_SEQ_CST) */
0314 
0315 /* We want to achieve __ATOMIC_SEQ_CST semantics here. See
0316  * https://en.cppreference.com/w/c/atomic/memory_order#Constants. For load
0317  * operations, that means performing an *acquire*:
0318  * > A load operation with this memory order performs the acquire operation on
0319  * > the affected memory location: no reads or writes in the current thread can
0320  * > be reordered before this load. All writes in other threads that release
0321  * > the same atomic variable are visible in the current thread.
0322  *
0323  * “no reads or writes in the current thread can be reordered before this load”
0324  * is implemented using a compiler barrier (a no-op `__asm__` section) to
0325  * prevent instruction reordering. Writes in other threads are synchronised
0326  * using `__sync_synchronize()`. It’s unclear from the GCC documentation whether
0327  * `__sync_synchronize()` acts as a compiler barrier, hence our explicit use of
0328  * one.
0329  *
0330  * For store operations, `__ATOMIC_SEQ_CST` means performing a *release*:
0331  * > A store operation with this memory order performs the release operation:
0332  * > no reads or writes in the current thread can be reordered after this store.
0333  * > All writes in the current thread are visible in other threads that acquire
0334  * > the same atomic variable (see Release-Acquire ordering below) and writes
0335  * > that carry a dependency into the atomic variable become visible in other
0336  * > threads that consume the same atomic (see Release-Consume ordering below).
0337  *
0338  * “no reads or writes in the current thread can be reordered after this store”
0339  * is implemented using a compiler barrier to prevent instruction reordering.
0340  * “All writes in the current thread are visible in other threads” is implemented
0341  * using `__sync_synchronize()`; similarly for “writes that carry a dependency”.
0342  */
0343 #define g_atomic_int_get(atomic) \
0344   (G_GNUC_EXTENSION ({                                                       \
0345     gint gaig_result;                                                        \
0346     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
0347     (void) (0 ? *(atomic) ^ *(atomic) : 1);                                  \
0348     gaig_result = (gint) *(atomic);                                          \
0349     __sync_synchronize ();                                                   \
0350     __asm__ __volatile__ ("" : : : "memory");                                \
0351     gaig_result;                                                             \
0352   }))
0353 #define g_atomic_int_set(atomic, newval) \
0354   (G_GNUC_EXTENSION ({                                                       \
0355     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
0356     (void) (0 ? *(atomic) ^ (newval) : 1);                                   \
0357     __sync_synchronize ();                                                   \
0358     __asm__ __volatile__ ("" : : : "memory");                                \
0359     *(atomic) = (newval);                                                    \
0360   }))
0361 #define g_atomic_pointer_get(atomic) \
0362   (G_GNUC_EXTENSION ({                                                       \
0363     gpointer gapg_result;                                                    \
0364     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
0365     gapg_result = (gpointer) *(atomic);                                      \
0366     __sync_synchronize ();                                                   \
0367     __asm__ __volatile__ ("" : : : "memory");                                \
0368     gapg_result;                                                             \
0369   }))
0370 #if defined(glib_typeof)
0371 #define g_atomic_pointer_set(atomic, newval) \
0372   (G_GNUC_EXTENSION ({                                                       \
0373     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
0374     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
0375     __sync_synchronize ();                                                   \
0376     __asm__ __volatile__ ("" : : : "memory");                                \
0377     *(atomic) = (glib_typeof (*(atomic))) (guintptr) (newval);               \
0378   }))
0379 #else /* if !(defined(glib_typeof) */
0380 #define g_atomic_pointer_set(atomic, newval) \
0381   (G_GNUC_EXTENSION ({                                                       \
0382     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
0383     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
0384     __sync_synchronize ();                                                   \
0385     __asm__ __volatile__ ("" : : : "memory");                                \
0386     *(atomic) = (gpointer) (guintptr) (newval);                              \
0387   }))
0388 #endif /* if defined(glib_typeof) */
0389 
0390 #define g_atomic_int_inc(atomic) \
0391   (G_GNUC_EXTENSION ({                                                       \
0392     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
0393     (void) (0 ? *(atomic) ^ *(atomic) : 1);                                  \
0394     (void) __sync_fetch_and_add ((atomic), 1);                               \
0395   }))
0396 #define g_atomic_int_dec_and_test(atomic) \
0397   (G_GNUC_EXTENSION ({                                                       \
0398     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
0399     (void) (0 ? *(atomic) ^ *(atomic) : 1);                                  \
0400     __sync_fetch_and_sub ((atomic), 1) == 1;                                 \
0401   }))
0402 #define g_atomic_int_compare_and_exchange(atomic, oldval, newval) \
0403   (G_GNUC_EXTENSION ({                                                       \
0404     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
0405     (void) (0 ? *(atomic) ^ (newval) ^ (oldval) : 1);                        \
0406     __sync_bool_compare_and_swap ((atomic), (oldval), (newval)) ? TRUE : FALSE; \
0407   }))
0408 #define g_atomic_int_compare_and_exchange_full(atomic, oldval, newval, preval) \
0409   (G_GNUC_EXTENSION ({                                                         \
0410     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                       \
0411     G_STATIC_ASSERT (sizeof *(preval) == sizeof (gint));                       \
0412     (void) (0 ? *(atomic) ^ (newval) ^ (oldval) ^ *(preval) : 1);              \
0413     *(preval) = __sync_val_compare_and_swap ((atomic), (oldval), (newval));    \
0414     (*(preval) == (oldval)) ? TRUE : FALSE;                                    \
0415   }))
0416 #if defined(_GLIB_GCC_HAVE_SYNC_SWAP)
0417 #define g_atomic_int_exchange(atomic, newval) \
0418   (G_GNUC_EXTENSION ({                                                       \
0419     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
0420     (void) (0 ? *(atomic) ^ (newval) : 1);                                   \
0421     (gint) __sync_swap ((atomic), (newval));                                 \
0422   }))
0423 #else /* defined(_GLIB_GCC_HAVE_SYNC_SWAP) */
0424   #define g_atomic_int_exchange(atomic, newval) \
0425   (G_GNUC_EXTENSION ({                                                       \
0426     gint oldval;                                                             \
0427     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
0428     (void) (0 ? *(atomic) ^ (newval) : 1);                                   \
0429     do                                                                       \
0430       {                                                                      \
0431         oldval = *atomic;                                                    \
0432       } while (!__sync_bool_compare_and_swap (atomic, oldval, newval));      \
0433     oldval;                                                                  \
0434   }))
0435 #endif /* defined(_GLIB_GCC_HAVE_SYNC_SWAP) */
0436 #define g_atomic_int_add(atomic, val) \
0437   (G_GNUC_EXTENSION ({                                                       \
0438     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
0439     (void) (0 ? *(atomic) ^ (val) : 1);                                      \
0440     (gint) __sync_fetch_and_add ((atomic), (val));                           \
0441   }))
0442 #define g_atomic_int_and(atomic, val) \
0443   (G_GNUC_EXTENSION ({                                                       \
0444     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
0445     (void) (0 ? *(atomic) ^ (val) : 1);                                      \
0446     (guint) __sync_fetch_and_and ((atomic), (val));                          \
0447   }))
0448 #define g_atomic_int_or(atomic, val) \
0449   (G_GNUC_EXTENSION ({                                                       \
0450     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
0451     (void) (0 ? *(atomic) ^ (val) : 1);                                      \
0452     (guint) __sync_fetch_and_or ((atomic), (val));                           \
0453   }))
0454 #define g_atomic_int_xor(atomic, val) \
0455   (G_GNUC_EXTENSION ({                                                       \
0456     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint));                     \
0457     (void) (0 ? *(atomic) ^ (val) : 1);                                      \
0458     (guint) __sync_fetch_and_xor ((atomic), (val));                          \
0459   }))
0460 
0461 #define g_atomic_pointer_compare_and_exchange(atomic, oldval, newval) \
0462   (G_GNUC_EXTENSION ({                                                       \
0463     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
0464     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
0465     __sync_bool_compare_and_swap ((atomic), (oldval), (newval)) ? TRUE : FALSE; \
0466   }))
0467 #define g_atomic_pointer_compare_and_exchange_full(atomic, oldval, newval, preval) \
0468   (G_GNUC_EXTENSION ({                                                             \
0469     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                       \
0470     G_STATIC_ASSERT (sizeof *(preval) == sizeof (gpointer));                       \
0471     (void) (0 ? (gpointer) *(atomic) : NULL);                                      \
0472     (void) (0 ? (gpointer) *(preval) : NULL);                                      \
0473     *(preval) = __sync_val_compare_and_swap ((atomic), (oldval), (newval));        \
0474     (*(preval) == (oldval)) ? TRUE : FALSE;                                        \
0475   }))
0476 #if defined(_GLIB_GCC_HAVE_SYNC_SWAP)
0477 #define g_atomic_pointer_exchange(atomic, newval) \
0478   (G_GNUC_EXTENSION ({                                                       \
0479     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
0480     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
0481     (gpointer) __sync_swap ((atomic), (newval));                             \
0482   }))
0483 #else
0484 #define g_atomic_pointer_exchange(atomic, newval) \
0485   (G_GNUC_EXTENSION ({                                                       \
0486     gpointer oldval;                                                         \
0487     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
0488     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
0489     do                                                                       \
0490       {                                                                      \
0491         oldval = (gpointer) *atomic;                                         \
0492       } while (!__sync_bool_compare_and_swap (atomic, oldval, newval));      \
0493     oldval;                                                                  \
0494   }))
0495 #endif /* defined(_GLIB_GCC_HAVE_SYNC_SWAP) */
0496 #define g_atomic_pointer_add(atomic, val) \
0497   (G_GNUC_EXTENSION ({                                                       \
0498     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
0499     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
0500     (void) (0 ? (val) ^ (val) : 1);                                          \
0501     (gintptr) __sync_fetch_and_add ((atomic), (val));                        \
0502   }))
0503 #define g_atomic_pointer_and(atomic, val) \
0504   (G_GNUC_EXTENSION ({                                                       \
0505     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
0506     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
0507     (void) (0 ? (val) ^ (val) : 1);                                          \
0508     (guintptr) __sync_fetch_and_and ((atomic), (val));                       \
0509   }))
0510 #define g_atomic_pointer_or(atomic, val) \
0511   (G_GNUC_EXTENSION ({                                                       \
0512     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
0513     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
0514     (void) (0 ? (val) ^ (val) : 1);                                          \
0515     (guintptr) __sync_fetch_and_or ((atomic), (val));                        \
0516   }))
0517 #define g_atomic_pointer_xor(atomic, val) \
0518   (G_GNUC_EXTENSION ({                                                       \
0519     G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer));                 \
0520     (void) (0 ? (gpointer) *(atomic) : NULL);                                \
0521     (void) (0 ? (val) ^ (val) : 1);                                          \
0522     (guintptr) __sync_fetch_and_xor ((atomic), (val));                       \
0523   }))
0524 
0525 #endif /* !defined(__ATOMIC_SEQ_CST) */
0526 
0527 #else /* defined(G_ATOMIC_LOCK_FREE) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) */
0528 
0529 #define g_atomic_int_get(atomic) \
0530   (g_atomic_int_get ((gint *) (atomic)))
0531 #define g_atomic_int_set(atomic, newval) \
0532   (g_atomic_int_set ((gint *) (atomic), (gint) (newval)))
0533 #define g_atomic_int_compare_and_exchange(atomic, oldval, newval) \
0534   (g_atomic_int_compare_and_exchange ((gint *) (atomic), (oldval), (newval)))
0535 #define g_atomic_int_compare_and_exchange_full(atomic, oldval, newval, preval) \
0536   (g_atomic_int_compare_and_exchange_full ((gint *) (atomic), (oldval), (newval), (gint *) (preval)))
0537 #define g_atomic_int_exchange(atomic, newval) \
0538   (g_atomic_int_exchange ((gint *) (atomic), (newval)))
0539 #define g_atomic_int_add(atomic, val) \
0540   (g_atomic_int_add ((gint *) (atomic), (val)))
0541 #define g_atomic_int_and(atomic, val) \
0542   (g_atomic_int_and ((guint *) (atomic), (val)))
0543 #define g_atomic_int_or(atomic, val) \
0544   (g_atomic_int_or ((guint *) (atomic), (val)))
0545 #define g_atomic_int_xor(atomic, val) \
0546   (g_atomic_int_xor ((guint *) (atomic), (val)))
0547 #define g_atomic_int_inc(atomic) \
0548   (g_atomic_int_inc ((gint *) (atomic)))
0549 #define g_atomic_int_dec_and_test(atomic) \
0550   (g_atomic_int_dec_and_test ((gint *) (atomic)))
0551 
0552 #if defined(glib_typeof)
0553   /* The (void *) cast in the middle *looks* redundant, because
0554    * g_atomic_pointer_get returns void * already, but it's to silence
0555    * -Werror=bad-function-cast when we're doing something like:
0556    * guintptr a, b; ...; a = g_atomic_pointer_get (&b);
0557    * which would otherwise be assigning the void * result of
0558    * g_atomic_pointer_get directly to the pointer-sized but
0559    * non-pointer-typed result. */
0560 #define g_atomic_pointer_get(atomic)                                       \
0561   (glib_typeof (*(atomic))) (void *) ((g_atomic_pointer_get) ((void *) atomic))
0562 #else /* !(defined(glib_typeof) */
0563 #define g_atomic_pointer_get(atomic) \
0564   (g_atomic_pointer_get (atomic))
0565 #endif
0566 
0567 #define g_atomic_pointer_set(atomic, newval) \
0568   (g_atomic_pointer_set ((atomic), (gpointer) (newval)))
0569 
0570 #define g_atomic_pointer_compare_and_exchange(atomic, oldval, newval) \
0571   (g_atomic_pointer_compare_and_exchange ((atomic), (gpointer) (oldval), (gpointer) (newval)))
0572 #define g_atomic_pointer_compare_and_exchange_full(atomic, oldval, newval, prevval) \
0573   (g_atomic_pointer_compare_and_exchange_full ((atomic), (gpointer) (oldval), (gpointer) (newval), (prevval)))
0574 #define g_atomic_pointer_exchange(atomic, newval) \
0575   (g_atomic_pointer_exchange ((atomic), (gpointer) (newval)))
0576 #define g_atomic_pointer_add(atomic, val) \
0577   (g_atomic_pointer_add ((atomic), (gssize) (val)))
0578 #define g_atomic_pointer_and(atomic, val) \
0579   (g_atomic_pointer_and ((atomic), (gsize) (val)))
0580 #define g_atomic_pointer_or(atomic, val) \
0581   (g_atomic_pointer_or ((atomic), (gsize) (val)))
0582 #define g_atomic_pointer_xor(atomic, val) \
0583   (g_atomic_pointer_xor ((atomic), (gsize) (val)))
0584 
0585 #endif /* defined(G_ATOMIC_LOCK_FREE) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) */
0586 
0587 #endif /* __G_ATOMIC_H__ */