(root)/
glib-2.79.0/
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__ */