diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt index c1abf1aee..8dcc251a4 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 1ab4fde91..6c1ea768e 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 #gpointer-sized value @@ -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 bbdcbd596..11d319edc 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,14 +404,22 @@ G_END_DECLS (void) (0 ? *(atomic) ^ (newval) ^ (oldval) : 1); \ __sync_bool_compare_and_swap ((atomic), (oldval), (newval)) ? TRUE : FALSE; \ })) -#if defined(__GCC_HAVE_SYNC_SWAP) +#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(_GLIB_GCC_HAVE_SYNC_SWAP) #define g_atomic_int_exchange(atomic, newval) \ (G_GNUC_EXTENSION ({ \ G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \ (void) (0 ? *(atomic) ^ (newval) : 1); \ (gint) __sync_swap ((atomic), (newval)); \ })) -#else /* defined(__GCC_HAVE_SYNC_SWAP) */ +#else /* defined(_GLIB_GCC_HAVE_SYNC_SWAP) */ #define g_atomic_int_exchange(atomic, newval) \ (G_GNUC_EXTENSION ({ \ gint oldval; \ @@ -392,7 +431,7 @@ G_END_DECLS } while (!__sync_bool_compare_and_swap (atomic, oldval, newval)); \ oldval; \ })) -#endif /* defined(__GCC_HAVE_SYNC_SWAP) */ +#endif /* defined(_GLIB_GCC_HAVE_SYNC_SWAP) */ #define g_atomic_int_add(atomic, val) \ (G_GNUC_EXTENSION ({ \ G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gint)); \ @@ -424,7 +463,16 @@ G_END_DECLS (void) (0 ? (gpointer) *(atomic) : NULL); \ __sync_bool_compare_and_swap ((atomic), (oldval), (newval)) ? TRUE : FALSE; \ })) -#if defined(__GCC_HAVE_SYNC_SWAP) +#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(_GLIB_GCC_HAVE_SYNC_SWAP) #define g_atomic_pointer_exchange(atomic, newval) \ (G_GNUC_EXTENSION ({ \ G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \ @@ -443,7 +491,7 @@ G_END_DECLS } while (!__sync_bool_compare_and_swap (atomic, oldval, newval)); \ oldval; \ })) -#endif /* defined(__GCC_HAVE_SYNC_SWAP) */ +#endif /* defined(_GLIB_GCC_HAVE_SYNC_SWAP) */ #define g_atomic_pointer_add(atomic, val) \ (G_GNUC_EXTENSION ({ \ G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \ @@ -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 6a595f288..3061032b0 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 c074e18f3..363700d14 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); diff --git a/meson.build b/meson.build index 3da0010af..e44bad35b 100644 --- a/meson.build +++ b/meson.build @@ -1874,7 +1874,7 @@ if cc.get_id() == 'msvc' or cc.get_id() == 'clang-cl' or cc.links(atomictest, na } ''' - glib_conf.set('__GCC_HAVE_SYNC_SWAP', cc.links(sync_swap_test, name : 'sync swap')) + glib_conf.set('_GLIB_GCC_HAVE_SYNC_SWAP', cc.links(sync_swap_test, name : 'sync swap')) endif else have_atomic_lock_free = false