| /* |
| * 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; |
| int *ip, *ip2; |
| gsize gs, gs2; |
| gboolean res; |
| |
| csp = &s; |
| cspp = &csp; |
| |
| g_atomic_int_set (&u, 5); |
| u2 = g_atomic_int_get (&u); |
| g_assert_cmpint (u2, ==, 5); |
| res = g_atomic_int_compare_and_exchange (&u, 6, 7); |
| g_assert (!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 (!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 (!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 (!res); |
| g_assert_cmpint (s, ==, 6); |
| s2 = g_atomic_int_and (&s, 5); |
| g_assert_cmpint (s2, ==, 6); |
| g_assert_cmpint (s, ==, 4); |
| s2 = g_atomic_int_or (&s, 8); |
| g_assert_cmpint (s2, ==, 4); |
| g_assert_cmpint (s, ==, 12); |
| s2 = 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 (vp2 == 0); |
| res = g_atomic_pointer_compare_and_exchange (&vp, 0, 0); |
| g_assert (res); |
| g_assert (vp == 0); |
| |
| g_atomic_pointer_set (&ip, 0); |
| ip2 = g_atomic_pointer_get (&ip); |
| g_assert (ip2 == 0); |
| res = g_atomic_pointer_compare_and_exchange (&ip, 0, 0); |
| g_assert (res); |
| g_assert (ip == 0); |
| |
| g_atomic_pointer_set (&gs, 0); |
| gs2 = (gsize) g_atomic_pointer_get (&gs); |
| g_assert (gs2 == 0); |
| res = g_atomic_pointer_compare_and_exchange (&gs, 0, 0); |
| g_assert (res); |
| g_assert (gs == 0); |
| gs2 = g_atomic_pointer_add (&gs, 5); |
| g_assert (gs2 == 0); |
| g_assert (gs == 5); |
| gs2 = g_atomic_pointer_and (&gs, 6); |
| g_assert (gs2 == 5); |
| g_assert (gs == 4); |
| gs2 = g_atomic_pointer_or (&gs, 8); |
| g_assert (gs2 == 4); |
| g_assert (gs == 12); |
| gs2 = g_atomic_pointer_xor (&gs, 4); |
| g_assert (gs2 == 12); |
| g_assert (gs == 8); |
| |
| g_assert (g_atomic_int_get (csp) == s); |
| g_assert (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 = g_atomic_int_get ((gint*)&u); |
| g_assert_cmpint (u2, ==, 5); |
| res = g_atomic_int_compare_and_exchange ((gint*)&u, 6, 7); |
| g_assert (!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 (!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 (!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 (!res); |
| g_assert_cmpint (s, ==, 6); |
| s2 = g_atomic_int_and ((guint*)&s, 5); |
| g_assert_cmpint (s2, ==, 6); |
| g_assert_cmpint (s, ==, 4); |
| s2 = g_atomic_int_or ((guint*)&s, 8); |
| g_assert_cmpint (s2, ==, 4); |
| g_assert_cmpint (s, ==, 12); |
| s2 = 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 (vp2 == 0); |
| res = g_atomic_pointer_compare_and_exchange (&vp, 0, 0); |
| g_assert (res); |
| g_assert (vp == 0); |
| |
| g_atomic_pointer_set (&ip, 0); |
| ip2 = g_atomic_pointer_get (&ip); |
| g_assert (ip2 == 0); |
| res = g_atomic_pointer_compare_and_exchange (&ip, 0, 0); |
| g_assert (res); |
| g_assert (ip == 0); |
| |
| g_atomic_pointer_set (&gs, 0); |
| vp = g_atomic_pointer_get (&gs); |
| gs2 = (gsize) vp; |
| g_assert (gs2 == 0); |
| res = g_atomic_pointer_compare_and_exchange (&gs, 0, 0); |
| g_assert (res); |
| g_assert (gs == 0); |
| gs2 = g_atomic_pointer_add (&gs, 5); |
| g_assert (gs2 == 0); |
| g_assert (gs == 5); |
| gs2 = g_atomic_pointer_and (&gs, 6); |
| g_assert (gs2 == 5); |
| g_assert (gs == 4); |
| gs2 = g_atomic_pointer_or (&gs, 8); |
| g_assert (gs2 == 4); |
| g_assert (gs == 12); |
| gs2 = g_atomic_pointer_xor (&gs, 4); |
| g_assert (gs2 == 12); |
| g_assert (gs == 8); |
| |
| g_assert (g_atomic_int_get (csp) == s); |
| g_assert (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 (); |
| } |