mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-22 12:16:16 +01:00
ef9ce8ea00
g_atomic_pointer_compare_and_exchange() should work with const pointers. Add a test for that. It seems clang 9.0.0-2.fc32 does not like this: ../glib/tests/atomic.c:93:9: warning: incompatible pointer types passing 'typeof ((((void *)0))) *' (aka 'void **') to parameter of type 'const char **' [-Wincompatible-pointer-types] res = g_atomic_pointer_compare_and_exchange (&vp_str, NULL, str); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ../glib/gatomic.h:192:44: note: expanded from macro 'g_atomic_pointer_compare_and_exchange' __atomic_compare_exchange_n ((atomic), &gapcae_oldval, (newval), FALSE, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ? TRUE : FALSE; \ ^~~~~~~~~~~~~~ ../glib/tests/atomic.c:96:9: warning: incompatible pointer types passing 'typeof ((((void *)0))) *' (aka 'void **') to parameter of type 'const char **' [-Wincompatible-pointer-types] res = g_atomic_pointer_compare_and_exchange (&vp_str_vol, NULL, str); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ../glib/gatomic.h:192:44: note: expanded from macro 'g_atomic_pointer_compare_and_exchange' __atomic_compare_exchange_n ((atomic), &gapcae_oldval, (newval), FALSE, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ? TRUE : FALSE; \ ^~~~~~~~~~~~~~ Note that this clang version already issues various compiler warnings for this test. This merely adds another case to check. Eventually g_atomic_pointer_compare_and_exchange() should be fixed to avoid compiler warnings. Actually there is a problem. When you try to use g_atomic_pointer_compare_and_exchange() with const pointers, it is also not working, because the implementation as a function expects "void *" arguments. As the test also shows. As such, it's probably not portable to use g_atomic_pointer_compare_and_exchange() with const pointers at all. However, the macro implementation is (with the right compiler) fine with that, so it's an easy "mistake" to make.
306 lines
8.4 KiB
C
306 lines
8.4 KiB
C
/*
|
|
* Copyright 2011 Red Hat, Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* See the included COPYING file for more information.
|
|
*/
|
|
|
|
#include <glib.h>
|
|
|
|
/* We want the g_atomic_pointer_get() macros to work when compiling third party
|
|
* projects with -Wbad-function-cast.
|
|
* See https://gitlab.gnome.org/GNOME/glib/issues/1041. */
|
|
#pragma GCC diagnostic error "-Wbad-function-cast"
|
|
|
|
static void
|
|
test_types (void)
|
|
{
|
|
const gint *csp;
|
|
const gint * const *cspp;
|
|
guint u, u2;
|
|
gint s, s2;
|
|
gpointer vp, vp2;
|
|
const char *vp_str;
|
|
const char *volatile vp_str_vol;
|
|
const char *str = "Hello";
|
|
int *ip, *ip2;
|
|
gsize gs, gs2;
|
|
gboolean res;
|
|
|
|
csp = &s;
|
|
cspp = &csp;
|
|
|
|
g_atomic_int_set (&u, 5);
|
|
u2 = (guint) g_atomic_int_get (&u);
|
|
g_assert_cmpint (u2, ==, 5);
|
|
res = g_atomic_int_compare_and_exchange (&u, 6, 7);
|
|
g_assert_false (res);
|
|
g_assert_cmpint (u, ==, 5);
|
|
g_atomic_int_add (&u, 1);
|
|
g_assert_cmpint (u, ==, 6);
|
|
g_atomic_int_inc (&u);
|
|
g_assert_cmpint (u, ==, 7);
|
|
res = g_atomic_int_dec_and_test (&u);
|
|
g_assert_false (res);
|
|
g_assert_cmpint (u, ==, 6);
|
|
u2 = g_atomic_int_and (&u, 5);
|
|
g_assert_cmpint (u2, ==, 6);
|
|
g_assert_cmpint (u, ==, 4);
|
|
u2 = g_atomic_int_or (&u, 8);
|
|
g_assert_cmpint (u2, ==, 4);
|
|
g_assert_cmpint (u, ==, 12);
|
|
u2 = g_atomic_int_xor (&u, 4);
|
|
g_assert_cmpint (u2, ==, 12);
|
|
g_assert_cmpint (u, ==, 8);
|
|
|
|
g_atomic_int_set (&s, 5);
|
|
s2 = g_atomic_int_get (&s);
|
|
g_assert_cmpint (s2, ==, 5);
|
|
res = g_atomic_int_compare_and_exchange (&s, 6, 7);
|
|
g_assert_false (res);
|
|
g_assert_cmpint (s, ==, 5);
|
|
g_atomic_int_add (&s, 1);
|
|
g_assert_cmpint (s, ==, 6);
|
|
g_atomic_int_inc (&s);
|
|
g_assert_cmpint (s, ==, 7);
|
|
res = g_atomic_int_dec_and_test (&s);
|
|
g_assert_false (res);
|
|
g_assert_cmpint (s, ==, 6);
|
|
s2 = (gint) g_atomic_int_and (&s, 5);
|
|
g_assert_cmpint (s2, ==, 6);
|
|
g_assert_cmpint (s, ==, 4);
|
|
s2 = (gint) g_atomic_int_or (&s, 8);
|
|
g_assert_cmpint (s2, ==, 4);
|
|
g_assert_cmpint (s, ==, 12);
|
|
s2 = (gint) g_atomic_int_xor (&s, 4);
|
|
g_assert_cmpint (s2, ==, 12);
|
|
g_assert_cmpint (s, ==, 8);
|
|
|
|
g_atomic_pointer_set (&vp, 0);
|
|
vp2 = g_atomic_pointer_get (&vp);
|
|
g_assert_true (vp2 == 0);
|
|
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 (&vp, NULL, NULL);
|
|
g_assert_true (res);
|
|
g_assert_true (vp == 0);
|
|
|
|
g_atomic_pointer_set (&vp_str, NULL);
|
|
res = g_atomic_pointer_compare_and_exchange (&vp_str, NULL, str);
|
|
g_assert_true (res);
|
|
|
|
g_atomic_pointer_set (&vp_str_vol, NULL);
|
|
res = g_atomic_pointer_compare_and_exchange (&vp_str_vol, NULL, str);
|
|
g_assert_true (res);
|
|
|
|
g_atomic_pointer_set (&ip, 0);
|
|
ip2 = g_atomic_pointer_get (&ip);
|
|
g_assert_true (ip2 == 0);
|
|
res = g_atomic_pointer_compare_and_exchange (&ip, NULL, NULL);
|
|
g_assert_true (res);
|
|
g_assert_true (ip == 0);
|
|
|
|
g_atomic_pointer_set (&gs, 0);
|
|
vp2 = (gpointer) g_atomic_pointer_get (&gs);
|
|
gs2 = (gsize) vp2;
|
|
g_assert_cmpuint (gs2, ==, 0);
|
|
res = g_atomic_pointer_compare_and_exchange (&gs, NULL, NULL);
|
|
g_assert_true (res);
|
|
g_assert_cmpuint (gs, ==, 0);
|
|
gs2 = (gsize) g_atomic_pointer_add (&gs, 5);
|
|
g_assert_cmpuint (gs2, ==, 0);
|
|
g_assert_cmpuint (gs, ==, 5);
|
|
gs2 = g_atomic_pointer_and (&gs, 6);
|
|
g_assert_cmpuint (gs2, ==, 5);
|
|
g_assert_cmpuint (gs, ==, 4);
|
|
gs2 = g_atomic_pointer_or (&gs, 8);
|
|
g_assert_cmpuint (gs2, ==, 4);
|
|
g_assert_cmpuint (gs, ==, 12);
|
|
gs2 = g_atomic_pointer_xor (&gs, 4);
|
|
g_assert_cmpuint (gs2, ==, 12);
|
|
g_assert_cmpuint (gs, ==, 8);
|
|
|
|
g_assert_cmpint (g_atomic_int_get (csp), ==, s);
|
|
g_assert_true (g_atomic_pointer_get (cspp) == csp);
|
|
|
|
/* repeat, without the macros */
|
|
#undef g_atomic_int_set
|
|
#undef g_atomic_int_get
|
|
#undef g_atomic_int_compare_and_exchange
|
|
#undef g_atomic_int_add
|
|
#undef g_atomic_int_inc
|
|
#undef g_atomic_int_and
|
|
#undef g_atomic_int_or
|
|
#undef g_atomic_int_xor
|
|
#undef g_atomic_int_dec_and_test
|
|
#undef g_atomic_pointer_set
|
|
#undef g_atomic_pointer_get
|
|
#undef g_atomic_pointer_compare_and_exchange
|
|
#undef g_atomic_pointer_add
|
|
#undef g_atomic_pointer_and
|
|
#undef g_atomic_pointer_or
|
|
#undef g_atomic_pointer_xor
|
|
|
|
g_atomic_int_set ((gint*)&u, 5);
|
|
u2 = (guint) g_atomic_int_get ((gint*)&u);
|
|
g_assert_cmpint (u2, ==, 5);
|
|
res = g_atomic_int_compare_and_exchange ((gint*)&u, 6, 7);
|
|
g_assert_false (res);
|
|
g_assert_cmpint (u, ==, 5);
|
|
g_atomic_int_add ((gint*)&u, 1);
|
|
g_assert_cmpint (u, ==, 6);
|
|
g_atomic_int_inc ((gint*)&u);
|
|
g_assert_cmpint (u, ==, 7);
|
|
res = g_atomic_int_dec_and_test ((gint*)&u);
|
|
g_assert_false (res);
|
|
g_assert_cmpint (u, ==, 6);
|
|
u2 = g_atomic_int_and (&u, 5);
|
|
g_assert_cmpint (u2, ==, 6);
|
|
g_assert_cmpint (u, ==, 4);
|
|
u2 = g_atomic_int_or (&u, 8);
|
|
g_assert_cmpint (u2, ==, 4);
|
|
g_assert_cmpint (u, ==, 12);
|
|
u2 = g_atomic_int_xor (&u, 4);
|
|
g_assert_cmpint (u2, ==, 12);
|
|
|
|
g_atomic_int_set (&s, 5);
|
|
s2 = g_atomic_int_get (&s);
|
|
g_assert_cmpint (s2, ==, 5);
|
|
res = g_atomic_int_compare_and_exchange (&s, 6, 7);
|
|
g_assert_false (res);
|
|
g_assert_cmpint (s, ==, 5);
|
|
g_atomic_int_add (&s, 1);
|
|
g_assert_cmpint (s, ==, 6);
|
|
g_atomic_int_inc (&s);
|
|
g_assert_cmpint (s, ==, 7);
|
|
res = g_atomic_int_dec_and_test (&s);
|
|
g_assert_false (res);
|
|
g_assert_cmpint (s, ==, 6);
|
|
s2 = (gint) g_atomic_int_and ((guint*)&s, 5);
|
|
g_assert_cmpint (s2, ==, 6);
|
|
g_assert_cmpint (s, ==, 4);
|
|
s2 = (gint) g_atomic_int_or ((guint*)&s, 8);
|
|
g_assert_cmpint (s2, ==, 4);
|
|
g_assert_cmpint (s, ==, 12);
|
|
s2 = (gint) g_atomic_int_xor ((guint*)&s, 4);
|
|
g_assert_cmpint (s2, ==, 12);
|
|
g_assert_cmpint (s, ==, 8);
|
|
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
|
s2 = g_atomic_int_exchange_and_add ((gint*)&s, 1);
|
|
G_GNUC_END_IGNORE_DEPRECATIONS
|
|
g_assert_cmpint (s2, ==, 8);
|
|
g_assert_cmpint (s, ==, 9);
|
|
|
|
g_atomic_pointer_set (&vp, 0);
|
|
vp2 = g_atomic_pointer_get (&vp);
|
|
g_assert_true (vp2 == 0);
|
|
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 (&vp, NULL, NULL);
|
|
g_assert_true (res);
|
|
g_assert_true (vp == 0);
|
|
|
|
g_atomic_pointer_set (&vp_str, NULL);
|
|
res = g_atomic_pointer_compare_and_exchange (&vp_str, NULL, (char *) str);
|
|
g_assert_true (res);
|
|
|
|
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_atomic_pointer_set (&ip, 0);
|
|
ip2 = g_atomic_pointer_get (&ip);
|
|
g_assert_true (ip2 == 0);
|
|
res = g_atomic_pointer_compare_and_exchange (&ip, NULL, NULL);
|
|
g_assert_true (res);
|
|
g_assert_true (ip == 0);
|
|
|
|
g_atomic_pointer_set (&gs, 0);
|
|
vp = g_atomic_pointer_get (&gs);
|
|
gs2 = (gsize) vp;
|
|
g_assert_cmpuint (gs2, ==, 0);
|
|
res = g_atomic_pointer_compare_and_exchange (&gs, NULL, NULL);
|
|
g_assert_true (res);
|
|
g_assert_cmpuint (gs, ==, 0);
|
|
gs2 = (gsize) g_atomic_pointer_add (&gs, 5);
|
|
g_assert_cmpuint (gs2, ==, 0);
|
|
g_assert_cmpuint (gs, ==, 5);
|
|
gs2 = g_atomic_pointer_and (&gs, 6);
|
|
g_assert_cmpuint (gs2, ==, 5);
|
|
g_assert_cmpuint (gs, ==, 4);
|
|
gs2 = g_atomic_pointer_or (&gs, 8);
|
|
g_assert_cmpuint (gs2, ==, 4);
|
|
g_assert_cmpuint (gs, ==, 12);
|
|
gs2 = g_atomic_pointer_xor (&gs, 4);
|
|
g_assert_cmpuint (gs2, ==, 12);
|
|
g_assert_cmpuint (gs, ==, 8);
|
|
|
|
g_assert_cmpint (g_atomic_int_get (csp), ==, s);
|
|
g_assert_true (g_atomic_pointer_get (cspp) == csp);
|
|
}
|
|
|
|
#define THREADS 10
|
|
#define ROUNDS 10000
|
|
|
|
volatile gint bucket[THREADS];
|
|
volatile gint atomic;
|
|
|
|
static gpointer
|
|
thread_func (gpointer data)
|
|
{
|
|
gint idx = GPOINTER_TO_INT (data);
|
|
gint i;
|
|
gint d;
|
|
|
|
for (i = 0; i < ROUNDS; i++)
|
|
{
|
|
d = g_random_int_range (-10, 100);
|
|
bucket[idx] += d;
|
|
g_atomic_int_add (&atomic, d);
|
|
g_thread_yield ();
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
test_threaded (void)
|
|
{
|
|
gint sum;
|
|
gint i;
|
|
GThread *threads[THREADS];
|
|
|
|
atomic = 0;
|
|
for (i = 0; i < THREADS; i++)
|
|
bucket[i] = 0;
|
|
|
|
for (i = 0; i < THREADS; i++)
|
|
threads[i] = g_thread_new ("atomic", thread_func, GINT_TO_POINTER (i));
|
|
|
|
for (i = 0; i < THREADS; i++)
|
|
g_thread_join (threads[i]);
|
|
|
|
sum = 0;
|
|
for (i = 0; i < THREADS; i++)
|
|
sum += bucket[i];
|
|
|
|
g_assert_cmpint (sum, ==, atomic);
|
|
}
|
|
|
|
int
|
|
main (int argc, char **argv)
|
|
{
|
|
g_test_init (&argc, &argv, NULL);
|
|
|
|
g_test_add_func ("/atomic/types", test_types);
|
|
g_test_add_func ("/atomic/threaded", test_threaded);
|
|
|
|
return g_test_run ();
|
|
}
|