gatomic: Add Compare and Exchange functions that returns the previous value

Atomic primitives allow to do conditional compare and exchange but also
to get the value that was previously stored in the atomic variable.

Now, we provided an exchange function that allows to do an exchange if
the atomic value matches an expected value but we had no way to know
at the same time what was the value in the atomic at the moment of the
exchange try, an this can be useful in case that the operation fails,
for example if the current value is still acceptable for us, allowing
to do a kind of "OR" check:

  gint old_value;
  gint valid_value = 222;
  while (!g_atomic_pointer_compare_and_exchange_value (&atomic,
                                                       valid_value, 555,
                                                       &old_value)
    {
      if (old_value == 555 || old_value == 222)
        valid_value = old_value;
    }
This commit is contained in:
Marco Trevisan (Treviño) 2022-06-22 11:24:44 +02:00
parent 9a2bedb22c
commit bfdeb37f6e
5 changed files with 322 additions and 1 deletions

View File

@ -1273,6 +1273,7 @@ g_atomic_int_set
g_atomic_int_inc
g_atomic_int_dec_and_test
g_atomic_int_compare_and_exchange
g_atomic_int_compare_and_exchange_full
g_atomic_int_exchange
g_atomic_int_add
g_atomic_int_and
@ -1283,6 +1284,7 @@ g_atomic_int_xor
g_atomic_pointer_get
g_atomic_pointer_set
g_atomic_pointer_compare_and_exchange
g_atomic_pointer_compare_and_exchange_full
g_atomic_pointer_exchange
g_atomic_pointer_add
g_atomic_pointer_and

View File

@ -218,6 +218,39 @@ gboolean
return g_atomic_int_compare_and_exchange (atomic, oldval, newval);
}
/**
* g_atomic_int_compare_and_exchange_full:
* @atomic: a pointer to a #gint or #guint
* @oldval: the value to compare with
* @newval: the value to conditionally replace with
* @preval: (out): the contents of @atomic before this operation
*
* Compares @atomic to @oldval and, if equal, sets it to @newval.
* If @atomic was not equal to @oldval then no change occurs.
* In any case the value of @atomic before this operation is stored in @preval.
*
* This compare and exchange is done atomically.
*
* Think of this operation as an atomic version of
* `{ *preval = *atomic; if (*atomic == oldval) { *atomic = newval; return TRUE; } else return FALSE; }`.
*
* This call acts as a full compiler and hardware memory barrier.
*
* See also g_atomic_int_compare_and_exchange()
*
* Returns: %TRUE if the exchange took place
*
* Since: 2.74
**/
gboolean
(g_atomic_int_compare_and_exchange_full) (gint *atomic,
gint oldval,
gint newval,
gint *preval)
{
return g_atomic_int_compare_and_exchange_full (atomic, oldval, newval, preval);
}
/**
* g_atomic_int_exchange:
* @atomic: a pointer to a #gint or #guint
@ -430,6 +463,41 @@ gboolean
oldval, newval);
}
/**
* g_atomic_pointer_compare_and_exchange_full:
* @atomic: (not nullable): a pointer to a #gpointer-sized value
* @oldval: the value to compare with
* @newval: the value to conditionally replace with
* @preval: (not nullable) (out): the contents of @atomic before this operation
*
* Compares @atomic to @oldval and, if equal, sets it to @newval.
* If @atomic was not equal to @oldval then no change occurs.
* In any case the value of @atomic before this operation is stored in @preval.
*
* This compare and exchange is done atomically.
*
* Think of this operation as an atomic version of
* `{ *preval = *atomic; if (*atomic == oldval) { *atomic = newval; return TRUE; } else return FALSE; }`.
*
* This call acts as a full compiler and hardware memory barrier.
*
* See also g_atomic_pointer_compare_and_exchange()
*
* Returns: %TRUE if the exchange took place
*
* Since: 2.74
**/
gboolean
(g_atomic_pointer_compare_and_exchange_full) (void *atomic,
gpointer oldval,
gpointer newval,
void *preval)
{
return g_atomic_pointer_compare_and_exchange_full ((gpointer *) atomic,
oldval, newval,
(gpointer *) preval);
}
/**
* g_atomic_pointer_exchange:
* @atomic: a pointer to a #gint or #guint
@ -659,6 +727,16 @@ gboolean
return InterlockedCompareExchange (atomic, newval, oldval) == oldval;
}
gboolean
(g_atomic_int_compare_and_exchange_full) (gint *atomic,
gint oldval,
gint newval,
gint *preval)
{
*preval = InterlockedCompareExchange (atomic, newval, oldval);
return *preval == oldval;
}
gint
(g_atomic_int_exchange) (gint *atomic,
gint newval)
@ -722,6 +800,19 @@ gboolean
return InterlockedCompareExchangePointer (atomic, newval, oldval) == oldval;
}
gboolean
(g_atomic_pointer_compare_and_exchange_full) (void *atomic,
gpointer oldval,
gpointer newval,
void *preval)
{
gpointer *pre = preval;
*pre = InterlockedCompareExchangePointer (atomic, newval, oldval);
return *pre == oldval;
}
gpointer
(g_atomic_pointer_exchange) (void *atomic,
gpointer newval)
@ -851,6 +942,26 @@ gboolean
return success;
}
gboolean
(g_atomic_int_compare_and_exchange_full) (gint *atomic,
gint oldval,
gint newval,
gint *preval)
{
gboolean success;
pthread_mutex_lock (&g_atomic_lock);
*preval = *atomic;
if ((success = (*atomic == oldval)))
*atomic = newval;
pthread_mutex_unlock (&g_atomic_lock);
return success;
}
gint
(g_atomic_int_exchange) (gint *atomic,
gint newval)
@ -965,6 +1076,27 @@ gboolean
return success;
}
gboolean
(g_atomic_pointer_compare_and_exchange_full) (void *atomic,
gpointer oldval,
gpointer newval,
void *preval)
{
gpointer *ptr = atomic;
gpointer *pre = preval;
gboolean success;
pthread_mutex_lock (&g_atomic_lock);
*pre = *ptr;
if ((success = (*ptr == oldval)))
*ptr = newval;
pthread_mutex_unlock (&g_atomic_lock);
return success;
}
gpointer
(g_atomic_pointer_exchange) (void *atomic,
gpointer newval)

View File

@ -45,6 +45,11 @@ gboolean g_atomic_int_compare_and_exchange (volatile gint *a
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
@ -70,6 +75,11 @@ gboolean g_atomic_pointer_compare_and_exchange (volatile void *a
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
@ -179,6 +189,16 @@ G_END_DECLS
__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)); \
@ -237,6 +257,17 @@ G_END_DECLS
__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)); \
@ -373,6 +404,14 @@ G_END_DECLS
(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(__GCC_HAVE_SYNC_SWAP)
#define g_atomic_int_exchange(atomic, newval) \
(G_GNUC_EXTENSION ({ \
@ -424,6 +463,15 @@ G_END_DECLS
(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(__GCC_HAVE_SYNC_SWAP)
#define g_atomic_pointer_exchange(atomic, newval) \
(G_GNUC_EXTENSION ({ \
@ -483,6 +531,8 @@ G_END_DECLS
(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) \
@ -518,6 +568,8 @@ G_END_DECLS
#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) \

View File

@ -23,10 +23,11 @@ test_types (void)
const gint * const *cspp;
guint u, u2;
gint s, s2;
gpointer vp, vp2;
gpointer vp, vp2, cp;
const char *vp_str, *vp_str2;
const char *volatile vp_str_vol;
const char *str = "Hello";
const char *old_str;
int *ip, *ip2;
gsize gs, gs2;
gboolean res;
@ -40,6 +41,10 @@ test_types (void)
res = g_atomic_int_compare_and_exchange (&u, 6, 7);
g_assert_false (res);
g_assert_cmpint (u, ==, 5);
res = g_atomic_int_compare_and_exchange_full (&u, 6, 7, &u2);
g_assert_false (res);
g_assert_cmpint (u, ==, 5);
g_assert_cmpint (u2, ==, 5);
g_atomic_int_add (&u, 1);
g_assert_cmpint (u, ==, 6);
g_atomic_int_inc (&u);
@ -66,6 +71,11 @@ test_types (void)
res = g_atomic_int_compare_and_exchange (&s, 6, 7);
g_assert_false (res);
g_assert_cmpint (s, ==, 5);
s2 = 0;
res = g_atomic_int_compare_and_exchange_full (&s, 6, 7, &s2);
g_assert_false (res);
g_assert_cmpint (s, ==, 5);
g_assert_cmpint (s2, ==, 5);
g_atomic_int_add (&s, 1);
g_assert_cmpint (s, ==, 6);
g_atomic_int_inc (&s);
@ -91,18 +101,33 @@ test_types (void)
g_assert_true (vp2 == 0);
res = g_atomic_pointer_compare_and_exchange (&vp, &s, &s);
g_assert_false (res);
cp = &s;
res = g_atomic_pointer_compare_and_exchange_full (&vp, &s, &s, &cp);
g_assert_false (res);
g_assert_null (cp);
g_assert_true (vp == 0);
res = g_atomic_pointer_compare_and_exchange (&vp, NULL, NULL);
g_assert_true (res);
g_assert_true (vp == 0);
g_assert_null (g_atomic_pointer_exchange (&vp, &s));
g_assert_true (vp == &s);
res = g_atomic_pointer_compare_and_exchange_full (&vp, &s, NULL, &cp);
g_assert_true (res);
g_assert_true (cp == &s);
g_atomic_pointer_set (&vp_str, NULL);
res = g_atomic_pointer_compare_and_exchange (&vp_str, NULL, str);
g_assert_true (res);
g_assert_cmpstr (g_atomic_pointer_exchange (&vp_str, NULL), ==, str);
g_assert_null (vp_str);
res = g_atomic_pointer_compare_and_exchange_full (&vp_str, NULL, str, &cp);
g_assert_true (res);
g_assert_cmpstr (vp_str, ==, str);
g_assert_null (cp);
res = g_atomic_pointer_compare_and_exchange_full (&vp_str, (char *) str, NULL, &cp);
g_assert_true (res);
g_assert_null (vp_str);
g_assert_true (cp == str);
/* Note that atomic variables should almost certainly not be marked as
* `volatile` see http://isvolatileusefulwiththreads.in/c/. This test exists
@ -110,8 +135,15 @@ test_types (void)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
g_atomic_pointer_set (&vp_str_vol, NULL);
g_atomic_pointer_set (&vp_str, str);
res = g_atomic_pointer_compare_and_exchange (&vp_str_vol, NULL, str);
g_assert_true (res);
g_assert_cmpstr (g_atomic_pointer_exchange (&vp_str, NULL), ==, str);
g_assert_null (vp_str);
res = g_atomic_pointer_compare_and_exchange_full (&vp_str_vol, str, NULL, &old_str);
g_assert_true (res);
g_assert_true (old_str == str);
#pragma GCC diagnostic pop
g_atomic_pointer_set (&ip, 0);
@ -121,6 +153,16 @@ test_types (void)
g_assert_true (res);
g_assert_true (ip == 0);
res = g_atomic_pointer_compare_and_exchange_full (&ip, NULL, 1, &cp);
g_assert_true (res);
g_assert_cmpint ((gsize) ip, ==, 1);
g_assert_cmpuint ((gsize) cp, ==, 0);
res = g_atomic_pointer_compare_and_exchange_full (&ip, NULL, NULL, &cp);
g_assert_false (res);
g_assert_cmpuint ((gsize) ip, ==, 1);
g_assert_cmpuint ((gsize) cp, ==, 1);
g_atomic_pointer_set (&gs, 0);
vp2 = (gpointer) g_atomic_pointer_get (&gs);
gs2 = (gsize) vp2;
@ -128,6 +170,10 @@ test_types (void)
res = g_atomic_pointer_compare_and_exchange (&gs, NULL, (gsize) NULL);
g_assert_true (res);
g_assert_cmpuint (gs, ==, 0);
res = g_atomic_pointer_compare_and_exchange_full (&gs, NULL, (gsize) NULL, &cp);
g_assert_true (res);
g_assert_cmpuint (gs, ==, 0);
g_assert_cmpuint ((gsize) cp, ==, 0);
gs2 = (gsize) g_atomic_pointer_add (&gs, 5);
g_assert_cmpuint (gs2, ==, 0);
g_assert_cmpuint (gs, ==, 5);
@ -151,6 +197,7 @@ test_types (void)
#undef g_atomic_int_set
#undef g_atomic_int_get
#undef g_atomic_int_compare_and_exchange
#undef g_atomic_int_compare_and_exchange_full
#undef g_atomic_int_exchange
#undef g_atomic_int_add
#undef g_atomic_int_inc
@ -161,6 +208,7 @@ test_types (void)
#undef g_atomic_pointer_set
#undef g_atomic_pointer_get
#undef g_atomic_pointer_compare_and_exchange
#undef g_atomic_pointer_compare_and_exchange_full
#undef g_atomic_pointer_exchange
#undef g_atomic_pointer_add
#undef g_atomic_pointer_and
@ -173,6 +221,11 @@ test_types (void)
res = g_atomic_int_compare_and_exchange ((gint*)&u, 6, 7);
g_assert_false (res);
g_assert_cmpint (u, ==, 5);
u2 = 0;
res = g_atomic_int_compare_and_exchange_full ((gint*)&u, 6, 7, &u2);
g_assert_false (res);
g_assert_cmpuint (u, ==, 5);
g_assert_cmpuint (u2, ==, 5);
g_atomic_int_add ((gint*)&u, 1);
g_assert_cmpint (u, ==, 6);
g_atomic_int_inc ((gint*)&u);
@ -198,6 +251,11 @@ test_types (void)
res = g_atomic_int_compare_and_exchange (&s, 6, 7);
g_assert_false (res);
g_assert_cmpint (s, ==, 5);
s2 = 0;
res = g_atomic_int_compare_and_exchange_full (&s, 6, 7, &s2);
g_assert_false (res);
g_assert_cmpint (s, ==, 5);
g_assert_cmpint (s2, ==, 5);
g_atomic_int_add (&s, 1);
g_assert_cmpint (s, ==, 6);
g_atomic_int_inc (&s);
@ -229,25 +287,48 @@ G_GNUC_END_IGNORE_DEPRECATIONS
res = g_atomic_pointer_compare_and_exchange (&vp, &s, &s);
g_assert_false (res);
g_assert_true (vp == 0);
res = g_atomic_pointer_compare_and_exchange_full (&vp, &s, &s, &cp);
g_assert_false (res);
g_assert_null (vp);
g_assert_null (cp);
res = g_atomic_pointer_compare_and_exchange (&vp, NULL, NULL);
g_assert_true (res);
g_assert_true (vp == 0);
res = g_atomic_pointer_compare_and_exchange_full (&vp, NULL, NULL, &cp);
g_assert_true (res);
g_assert_null (vp);
g_assert_null (cp);
g_assert_null (g_atomic_pointer_exchange (&vp, &s));
g_assert_true (vp == &s);
g_atomic_pointer_set (&vp_str, NULL);
res = g_atomic_pointer_compare_and_exchange (&vp_str, NULL, (char *) str);
g_assert_true (res);
g_assert_cmpstr (g_atomic_pointer_exchange (&vp_str, NULL), ==, str);
g_assert_null (vp_str);
res = g_atomic_pointer_compare_and_exchange_full (&vp_str, NULL, (char *) str, &cp);
g_assert_true (res);
g_assert_cmpstr (vp_str, ==, str);
g_assert_null (cp);
res = g_atomic_pointer_compare_and_exchange_full (&vp_str, (char *) str, NULL, &cp);
g_assert_true (res);
g_assert_null (vp_str);
g_assert_true (cp == str);
/* Note that atomic variables should almost certainly not be marked as
* `volatile` see http://isvolatileusefulwiththreads.in/c/. This test exists
* to make sure that we dont warn when built against older third party code. */
g_atomic_pointer_set (&vp_str_vol, NULL);
g_atomic_pointer_set (&vp_str, (char *) str);
res = g_atomic_pointer_compare_and_exchange (&vp_str_vol, NULL, (char *) str);
g_assert_true (res);
g_assert_cmpstr (g_atomic_pointer_exchange (&vp_str, NULL), ==, str);
g_assert_null (vp_str);
res = g_atomic_pointer_compare_and_exchange_full ((char **) &vp_str_vol, (char *) str, NULL, &old_str);
g_assert_true (res);
g_assert_true (old_str == str);
g_atomic_pointer_set (&ip, 0);
ip2 = g_atomic_pointer_get (&ip);
g_assert_true (ip2 == 0);
@ -255,6 +336,16 @@ G_GNUC_END_IGNORE_DEPRECATIONS
g_assert_true (res);
g_assert_true (ip == 0);
res = g_atomic_pointer_compare_and_exchange_full (&ip, NULL, (gpointer) 1, &cp);
g_assert_true (res);
g_assert_cmpint ((gsize) ip, ==, 1);
g_assert_cmpuint ((gsize) cp, ==, 0);
res = g_atomic_pointer_compare_and_exchange_full (&ip, NULL, NULL, &cp);
g_assert_false (res);
g_assert_cmpuint ((gsize) ip, ==, 1);
g_assert_cmpuint ((gsize) cp, ==, 1);
g_atomic_pointer_set (&gs, 0);
vp = g_atomic_pointer_get (&gs);
gs2 = (gsize) vp;
@ -262,6 +353,10 @@ G_GNUC_END_IGNORE_DEPRECATIONS
res = g_atomic_pointer_compare_and_exchange (&gs, NULL, NULL);
g_assert_true (res);
g_assert_cmpuint (gs, ==, 0);
res = g_atomic_pointer_compare_and_exchange_full (&gs, NULL, NULL, &cp);
g_assert_true (res);
g_assert_cmpuint (gs, ==, 0);
g_assert_cmpuint ((gsize) cp, ==, 0);
gs2 = (gsize) g_atomic_pointer_add (&gs, 5);
g_assert_cmpuint (gs2, ==, 0);
g_assert_cmpuint (gs, ==, 5);

View File

@ -71,6 +71,26 @@ test_atomic_pointer_compare_and_exchange (void)
#endif
}
static void
test_atomic_pointer_compare_and_exchange_full (void)
{
#if __cplusplus >= 201103L
const gchar *str1 = "str1";
const gchar *str2 = "str2";
const gchar *atomic_string = str1;
const gchar *old;
g_test_message ("Test that g_atomic_pointer_compare_and_exchange_full() with a "
"non-void* pointer doesnt have any compiler warnings in C++ mode");
g_assert_true (g_atomic_pointer_compare_and_exchange_full (&atomic_string, str1, str2, &old));
g_assert_true (atomic_string == str2);
g_assert_true (old == str1);
#else
g_test_skip ("This test requires a C++11 compiler");
#endif
}
static void
test_atomic_int_compare_and_exchange (void)
{
@ -87,6 +107,24 @@ test_atomic_int_compare_and_exchange (void)
#endif
}
static void
test_atomic_int_compare_and_exchange_full (void)
{
#if __cplusplus >= 201103L
gint atomic_int = 5;
gint old_value;
g_test_message ("Test that g_atomic_int_compare_and_exchange_full() doesnt have "
"any compiler warnings in C++ mode");
g_assert_true (g_atomic_int_compare_and_exchange_full (&atomic_int, 5, 50, &old_value));
g_assert_cmpint (atomic_int, ==, 50);
g_assert_cmpint (old_value, ==, 5);
#else
g_test_skip ("This test requires a C++11 compiler");
#endif
}
static void
test_atomic_pointer_exchange (void)
{
@ -131,7 +169,9 @@ main (int argc, char *argv[])
g_test_add_func ("/C++/typeof", test_typeof);
g_test_add_func ("/C++/atomic-pointer-compare-and-exchange", test_atomic_pointer_compare_and_exchange);
g_test_add_func ("/C++/atomic-pointer-compare-and-exchange-full", test_atomic_pointer_compare_and_exchange_full);
g_test_add_func ("/C++/atomic-int-compare-and-exchange", test_atomic_int_compare_and_exchange);
g_test_add_func ("/C++/atomic-int-compare-and-exchange-full", test_atomic_int_compare_and_exchange_full);
g_test_add_func ("/C++/atomic-pointer-exchange", test_atomic_pointer_exchange);
g_test_add_func ("/C++/atomic-int-exchange", test_atomic_int_exchange);