mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-10-05 13:19:21 +02:00
gatomic: Add APIs to perform atomic int / pointer exchanges
Atomic APIs provide a way to exchange values only if we compare a value that is equal to the old value, but not to just exchange the value returning the old one. However, compilers provide such built-in functions, so we can use them to expose such functionality to GLib. The only drawback is that when using an old version of gcc not providing atomic APIs to swap values, we need to re-implement it with an implementation that may not be fully atomic, but that is safe enough. However this codepath should really not be used currently as gcc introduced __atomic_exchange_n() at version 4.7.4, so 8 years ago.
This commit is contained in:
@@ -56,6 +56,9 @@ test_types (void)
|
||||
u2 = g_atomic_int_xor (&u, 4);
|
||||
g_assert_cmpint (u2, ==, 12);
|
||||
g_assert_cmpint (u, ==, 8);
|
||||
u2 = g_atomic_int_exchange (&u, 55);
|
||||
g_assert_cmpint (u2, ==, 8);
|
||||
g_assert_cmpint (u, ==, 55);
|
||||
|
||||
g_atomic_int_set (&s, 5);
|
||||
s2 = g_atomic_int_get (&s);
|
||||
@@ -79,6 +82,9 @@ test_types (void)
|
||||
s2 = (gint) g_atomic_int_xor (&s, 4);
|
||||
g_assert_cmpint (s2, ==, 12);
|
||||
g_assert_cmpint (s, ==, 8);
|
||||
s2 = g_atomic_int_exchange (&s, 55);
|
||||
g_assert_cmpint (s2, ==, 8);
|
||||
g_assert_cmpint (s, ==, 55);
|
||||
|
||||
g_atomic_pointer_set (&vp, 0);
|
||||
vp2 = g_atomic_pointer_get (&vp);
|
||||
@@ -89,10 +95,14 @@ test_types (void)
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
/* Note that atomic variables should almost certainly not be marked as
|
||||
* `volatile` — see http://isvolatileusefulwiththreads.in/c/. This test exists
|
||||
@@ -130,6 +140,10 @@ test_types (void)
|
||||
gs2 = g_atomic_pointer_xor (&gs, 4);
|
||||
g_assert_cmpuint (gs2, ==, 12);
|
||||
g_assert_cmpuint (gs, ==, 8);
|
||||
vp2 = g_atomic_pointer_exchange ((gpointer*) &gs, NULL);
|
||||
gs2 = (gsize) vp2;
|
||||
g_assert_cmpuint (gs2, ==, 8);
|
||||
g_assert_null ((gpointer) gs);
|
||||
|
||||
g_assert_cmpint (g_atomic_int_get (csp), ==, s);
|
||||
g_assert_true (g_atomic_pointer_get ((const gint **) cspp) == csp);
|
||||
@@ -138,6 +152,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_exchange
|
||||
#undef g_atomic_int_add
|
||||
#undef g_atomic_int_inc
|
||||
#undef g_atomic_int_and
|
||||
@@ -147,6 +162,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_exchange
|
||||
#undef g_atomic_pointer_add
|
||||
#undef g_atomic_pointer_and
|
||||
#undef g_atomic_pointer_or
|
||||
@@ -173,6 +189,9 @@ test_types (void)
|
||||
g_assert_cmpint (u, ==, 12);
|
||||
u2 = g_atomic_int_xor (&u, 4);
|
||||
g_assert_cmpint (u2, ==, 12);
|
||||
u2 = g_atomic_int_exchange (&u, 55);
|
||||
g_assert_cmpint (u2, ==, 8);
|
||||
g_assert_cmpint (u, ==, 55);
|
||||
|
||||
g_atomic_int_set (&s, 5);
|
||||
s2 = g_atomic_int_get (&s);
|
||||
@@ -201,6 +220,9 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
g_assert_cmpint (s2, ==, 8);
|
||||
g_assert_cmpint (s, ==, 9);
|
||||
s2 = g_atomic_int_exchange (&s, 55);
|
||||
g_assert_cmpint (s2, ==, 9);
|
||||
g_assert_cmpint (s, ==, 55);
|
||||
|
||||
g_atomic_pointer_set (&vp, 0);
|
||||
vp2 = g_atomic_pointer_get (&vp);
|
||||
@@ -211,6 +233,8 @@ G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
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);
|
||||
|
||||
g_atomic_pointer_set (&vp_str, NULL);
|
||||
res = g_atomic_pointer_compare_and_exchange (&vp_str, NULL, (char *) str);
|
||||
@@ -222,6 +246,8 @@ G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
g_atomic_pointer_set (&vp_str_vol, NULL);
|
||||
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);
|
||||
|
||||
g_atomic_pointer_set (&ip, 0);
|
||||
ip2 = g_atomic_pointer_get (&ip);
|
||||
@@ -249,6 +275,10 @@ G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
gs2 = g_atomic_pointer_xor (&gs, 4);
|
||||
g_assert_cmpuint (gs2, ==, 12);
|
||||
g_assert_cmpuint (gs, ==, 8);
|
||||
vp2 = g_atomic_pointer_exchange ((gpointer*) &gs, NULL);
|
||||
gs2 = (gsize) vp2;
|
||||
g_assert_cmpuint (gs2, ==, 8);
|
||||
g_assert_null ((gpointer) gs);
|
||||
|
||||
g_assert_cmpint (g_atomic_int_get (csp), ==, s);
|
||||
g_assert_true (g_atomic_pointer_get (cspp) == csp);
|
||||
|
@@ -87,6 +87,39 @@ test_atomic_int_compare_and_exchange (void)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
test_atomic_pointer_exchange (void)
|
||||
{
|
||||
#if __cplusplus >= 201103L
|
||||
const gchar *str1 = "str1";
|
||||
const gchar *str2 = "str2";
|
||||
const gchar *atomic_string = str1;
|
||||
|
||||
g_test_message ("Test that g_atomic_pointer_exchange() with a "
|
||||
"non-void* pointer doesn’t have any compiler warnings in C++ mode");
|
||||
|
||||
g_assert_true (g_atomic_pointer_exchange (&atomic_string, str2) == str1);
|
||||
g_assert_true (atomic_string == str2);
|
||||
#else
|
||||
g_test_skip ("This test requires a C++11 compiler");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
test_atomic_int_exchange (void)
|
||||
{
|
||||
#if __cplusplus >= 201103L
|
||||
gint atomic_int = 5;
|
||||
|
||||
g_test_message ("Test that g_atomic_int_compare_and_exchange() doesn’t have "
|
||||
"any compiler warnings in C++ mode");
|
||||
|
||||
g_assert_cmpint (g_atomic_int_exchange (&atomic_int, 50), ==, 5);
|
||||
#else
|
||||
g_test_skip ("This test requires a C++11 compiler");
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
@@ -99,6 +132,8 @@ 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-int-compare-and-exchange", test_atomic_int_compare_and_exchange);
|
||||
g_test_add_func ("/C++/atomic-pointer-exchange", test_atomic_pointer_exchange);
|
||||
g_test_add_func ("/C++/atomic-int-exchange", test_atomic_int_exchange);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
Reference in New Issue
Block a user