mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-13 15:56:23 +01:00
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:
parent
9a2bedb22c
commit
bfdeb37f6e
@ -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
|
||||
|
132
glib/gatomic.c
132
glib/gatomic.c
@ -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)
|
||||
|
@ -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) \
|
||||
|
@ -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 don’t 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);
|
||||
|
@ -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 doesn’t 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() doesn’t 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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user