[glib: 1/3] gatomic: Add Compare and Exchange functions that returns the previous value
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib: 1/3] gatomic: Add Compare and Exchange functions that returns the previous value
- Date: Thu, 23 Jun 2022 13:19:09 +0000 (UTC)
commit bfdeb37f6e8d9c11bf889e42e01ae7317718c49e
Author: Marco Trevisan (Treviño) <mail 3v1n0 net>
Date: Wed Jun 22 11:24:44 2022 +0200
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;
}
docs/reference/glib/glib-sections.txt | 2 +
glib/gatomic.c | 132 ++++++++++++++++++++++++++++++++++
glib/gatomic.h | 52 ++++++++++++++
glib/tests/atomic.c | 97 ++++++++++++++++++++++++-
glib/tests/cxx.cpp | 40 +++++++++++
5 files changed, 322 insertions(+), 1 deletion(-)
---
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index c1abf1aee0..8dcc251a46 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -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
diff --git a/glib/gatomic.c b/glib/gatomic.c
index 4771d449de..499fd336f3 100644
--- a/glib/gatomic.c
+++ b/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)
diff --git a/glib/gatomic.h b/glib/gatomic.h
index bbdcbd5960..6a4930cddc 100644
--- a/glib/gatomic.h
+++ b/glib/gatomic.h
@@ -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) \
diff --git a/glib/tests/atomic.c b/glib/tests/atomic.c
index 6a595f2889..3061032b00 100644
--- a/glib/tests/atomic.c
+++ b/glib/tests/atomic.c
@@ -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);
diff --git a/glib/tests/cxx.cpp b/glib/tests/cxx.cpp
index c074e18f3e..363700d14f 100644
--- a/glib/tests/cxx.cpp
+++ b/glib/tests/cxx.cpp
@@ -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);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]