diff options
-rw-r--r-- | include/atomic.h | 235 | ||||
-rw-r--r-- | test/.gitignore | 2 | ||||
-rw-r--r-- | test/silly/Makefile.in | 3 | ||||
-rw-r--r-- | test/silly/hello.c | 2 | ||||
-rw-r--r-- | test/silly/tst-atomic-long.c | 27 | ||||
-rw-r--r-- | test/silly/tst-atomic.c | 573 |
6 files changed, 837 insertions, 5 deletions
diff --git a/include/atomic.h b/include/atomic.h index 307704cba..3680d8714 100644 --- a/include/atomic.h +++ b/include/atomic.h @@ -1,5 +1,5 @@ /* Internal macros for atomic operations for GNU C Library. - Copyright (C) 2002-2006, 2009 Free Software Foundation, Inc. + Copyright (C) 2002-2015 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. @@ -32,7 +32,7 @@ the multi-thread case. The interfaces have the prefix "catomic_". - - support functions like barriers. They also have the preifx + - support functions like barriers. They also have the prefix "atomic_". Architectures must provide a few lowlevel macros (the compare @@ -198,8 +198,12 @@ /* Add VALUE to *MEM and return the old value of *MEM. */ -#ifndef atomic_exchange_and_add -# define atomic_exchange_and_add(mem, value) \ +#ifndef atomic_exchange_and_add_acq +# ifdef atomic_exchange_and_add +# define atomic_exchange_and_add_acq(mem, value) \ + atomic_exchange_and_add (mem, value) +# else +# define atomic_exchange_and_add_acq(mem, value) \ ({ __typeof (*(mem)) __atg6_oldval; \ __typeof (mem) __atg6_memp = (mem); \ __typeof (*(mem)) __atg6_value = (value); \ @@ -213,8 +217,18 @@ __atg6_oldval), 0)); \ \ __atg6_oldval; }) +# endif #endif +#ifndef atomic_exchange_and_add_rel +# define atomic_exchange_and_add_rel(mem, value) \ + atomic_exchange_and_add_acq(mem, value) +#endif + +#ifndef atomic_exchange_and_add +# define atomic_exchange_and_add(mem, value) \ + atomic_exchange_and_add_acq(mem, value) +#endif #ifndef catomic_exchange_and_add # define catomic_exchange_and_add(mem, value) \ @@ -528,6 +542,219 @@ ({ __typeof (x) __x; __asm__ ("" : "=r" (__x) : "0" (x)); __x; }) #endif +/* This is equal to 1 iff the architecture supports 64b atomic operations. */ +#define __HAVE_64B_ATOMICS 0 /* TODO: not yet used - Add these to arch bits! */ +#ifndef __HAVE_64B_ATOMICS +#error Unable to determine if 64-bit atomics are present. +#endif + +/* The following functions are a subset of the atomic operations provided by + C11. Usually, a function named atomic_OP_MO(args) is equivalent to C11's + atomic_OP_explicit(args, memory_order_MO); exceptions noted below. */ + +/* Each arch can request to use compiler built-ins for C11 atomics. If it + does, all atomics will be based on these. */ +#if 0 /* not yet used USE_ATOMIC_COMPILER_BUILTINS */ + +/* We require 32b atomic operations; some archs also support 64b atomic + operations. */ +void __atomic_link_error (void); +# if __HAVE_64B_ATOMICS == 1 +# define __atomic_check_size(mem) \ + if ((sizeof (*mem) != 4) && (sizeof (*mem) != 8)) \ + __atomic_link_error (); +# else +# define __atomic_check_size(mem) \ + if (sizeof (*mem) != 4) \ + __atomic_link_error (); +# endif + +# define atomic_thread_fence_acquire() \ + __atomic_thread_fence (__ATOMIC_ACQUIRE) +# define atomic_thread_fence_release() \ + __atomic_thread_fence (__ATOMIC_RELEASE) +# define atomic_thread_fence_seq_cst() \ + __atomic_thread_fence (__ATOMIC_SEQ_CST) + +# define atomic_load_relaxed(mem) \ + ({ __atomic_check_size((mem)); __atomic_load_n ((mem), __ATOMIC_RELAXED); }) +# define atomic_load_acquire(mem) \ + ({ __atomic_check_size((mem)); __atomic_load_n ((mem), __ATOMIC_ACQUIRE); }) + +# define atomic_store_relaxed(mem, val) \ + do { \ + __atomic_check_size((mem)); \ + __atomic_store_n ((mem), (val), __ATOMIC_RELAXED); \ + } while (0) +# define atomic_store_release(mem, val) \ + do { \ + __atomic_check_size((mem)); \ + __atomic_store_n ((mem), (val), __ATOMIC_RELEASE); \ + } while (0) + +/* On failure, this CAS has memory_order_relaxed semantics. */ +# define atomic_compare_exchange_weak_relaxed(mem, expected, desired) \ + ({ __atomic_check_size((mem)); \ + __atomic_compare_exchange_n ((mem), (expected), (desired), 1, \ + __ATOMIC_RELAXED, __ATOMIC_RELAXED); }) +# define atomic_compare_exchange_weak_acquire(mem, expected, desired) \ + ({ __atomic_check_size((mem)); \ + __atomic_compare_exchange_n ((mem), (expected), (desired), 1, \ + __ATOMIC_ACQUIRE, __ATOMIC_RELAXED); }) +# define atomic_compare_exchange_weak_release(mem, expected, desired) \ + ({ __atomic_check_size((mem)); \ + __atomic_compare_exchange_n ((mem), (expected), (desired), 1, \ + __ATOMIC_RELEASE, __ATOMIC_RELAXED); }) + +# define atomic_exchange_acquire(mem, desired) \ + ({ __atomic_check_size((mem)); \ + __atomic_exchange_n ((mem), (desired), __ATOMIC_ACQUIRE); }) +# define atomic_exchange_release(mem, desired) \ + ({ __atomic_check_size((mem)); \ + __atomic_exchange_n ((mem), (desired), __ATOMIC_RELEASE); }) + +# define atomic_fetch_add_relaxed(mem, operand) \ + ({ __atomic_check_size((mem)); \ + __atomic_fetch_add ((mem), (operand), __ATOMIC_RELAXED); }) +# define atomic_fetch_add_acquire(mem, operand) \ + ({ __atomic_check_size((mem)); \ + __atomic_fetch_add ((mem), (operand), __ATOMIC_ACQUIRE); }) +# define atomic_fetch_add_release(mem, operand) \ + ({ __atomic_check_size((mem)); \ + __atomic_fetch_add ((mem), (operand), __ATOMIC_RELEASE); }) +# define atomic_fetch_add_acq_rel(mem, operand) \ + ({ __atomic_check_size((mem)); \ + __atomic_fetch_add ((mem), (operand), __ATOMIC_ACQ_REL); }) + +# define atomic_fetch_and_acquire(mem, operand) \ + ({ __atomic_check_size((mem)); \ + __atomic_fetch_and ((mem), (operand), __ATOMIC_ACQUIRE); }) + +# define atomic_fetch_or_relaxed(mem, operand) \ + ({ __atomic_check_size((mem)); \ + __atomic_fetch_or ((mem), (operand), __ATOMIC_RELAXED); }) +# define atomic_fetch_or_acquire(mem, operand) \ + ({ __atomic_check_size((mem)); \ + __atomic_fetch_or ((mem), (operand), __ATOMIC_ACQUIRE); }) + +#else /* !USE_ATOMIC_COMPILER_BUILTINS */ + +/* By default, we assume that read, write, and full barriers are equivalent + to acquire, release, and seq_cst barriers. Archs for which this does not + hold have to provide custom definitions of the fences. */ +# ifndef atomic_thread_fence_acquire +# define atomic_thread_fence_acquire() atomic_read_barrier () +# endif +# ifndef atomic_thread_fence_release +# define atomic_thread_fence_release() atomic_write_barrier () +# endif +# ifndef atomic_thread_fence_seq_cst +# define atomic_thread_fence_seq_cst() atomic_full_barrier () +# endif + +# ifndef atomic_load_relaxed +# define atomic_load_relaxed(mem) \ + ({ __typeof (*(mem)) __atg100_val; \ + __asm__ ("" : "=r" (__atg100_val) : "0" (*(mem))); \ + __atg100_val; }) +# endif +# ifndef atomic_load_acquire +# define atomic_load_acquire(mem) \ + ({ __typeof (*(mem)) __atg101_val = atomic_load_relaxed (mem); \ + atomic_thread_fence_acquire (); \ + __atg101_val; }) +# endif + +# ifndef atomic_store_relaxed +/* XXX Use inline asm here? */ +# define atomic_store_relaxed(mem, val) do { *(mem) = (val); } while (0) +# endif +# ifndef atomic_store_release +# define atomic_store_release(mem, val) \ + do { \ + atomic_thread_fence_release (); \ + atomic_store_relaxed ((mem), (val)); \ + } while (0) +# endif + +/* On failure, this CAS has memory_order_relaxed semantics. */ +/* XXX This potentially has one branch more than necessary, but archs + currently do not define a CAS that returns both the previous value and + the success flag. */ +# ifndef atomic_compare_exchange_weak_acquire +# define atomic_compare_exchange_weak_acquire(mem, expected, desired) \ + ({ __typeof (*(expected)) __atg102_expected = *(expected); \ + *(expected) = \ + atomic_compare_and_exchange_val_acq ((mem), (desired), *(expected)); \ + *(expected) == __atg102_expected; }) +# endif +# ifndef atomic_compare_exchange_weak_relaxed +/* XXX Fall back to CAS with acquire MO because archs do not define a weaker + CAS. */ +# define atomic_compare_exchange_weak_relaxed(mem, expected, desired) \ + atomic_compare_exchange_weak_acquire ((mem), (expected), (desired)) +# endif +# ifndef atomic_compare_exchange_weak_release +# define atomic_compare_exchange_weak_release(mem, expected, desired) \ + ({ __typeof (*(expected)) __atg103_expected = *(expected); \ + *(expected) = \ + atomic_compare_and_exchange_val_rel ((mem), (desired), *(expected)); \ + *(expected) == __atg103_expected; }) +# endif + +# ifndef atomic_exchange_acquire +# define atomic_exchange_acquire(mem, val) \ + atomic_exchange_acq ((mem), (val)) +# endif +# ifndef atomic_exchange_release +# define atomic_exchange_release(mem, val) \ + atomic_exchange_rel ((mem), (val)) +# endif + +# ifndef atomic_fetch_add_acquire +# define atomic_fetch_add_acquire(mem, operand) \ + atomic_exchange_and_add_acq ((mem), (operand)) +# endif +# ifndef atomic_fetch_add_relaxed +/* XXX Fall back to acquire MO because the MO semantics of + atomic_exchange_and_add are not documented; the generic version falls back + to atomic_exchange_and_add_acq if atomic_exchange_and_add is not defined, + and vice versa. */ +# define atomic_fetch_add_relaxed(mem, operand) \ + atomic_fetch_add_acquire ((mem), (operand)) +# endif +# ifndef atomic_fetch_add_release +# define atomic_fetch_add_release(mem, operand) \ + atomic_exchange_and_add_rel ((mem), (operand)) +# endif +# ifndef atomic_fetch_add_acq_rel +# define atomic_fetch_add_acq_rel(mem, operand) \ + ({ atomic_thread_fence_release (); \ + atomic_exchange_and_add_acq ((mem), (operand)); }) +# endif + +/* XXX The default for atomic_and_val has acquire semantics, but this is not + documented. */ +# ifndef atomic_fetch_and_acquire +# define atomic_fetch_and_acquire(mem, operand) \ + atomic_and_val ((mem), (operand)) +# endif + +/* XXX The default for atomic_or_val has acquire semantics, but this is not + documented. */ +# ifndef atomic_fetch_or_acquire +# define atomic_fetch_or_acquire(mem, operand) \ + atomic_or_val ((mem), (operand)) +# endif +/* XXX Fall back to acquire MO because archs do not define a weaker + atomic_or_val. */ +# ifndef atomic_fetch_or_relaxed +# define atomic_fetch_or_relaxed(mem, operand) \ + atomic_fetch_or_acquire ((mem), (operand)) +# endif + +#endif /* !USE_ATOMIC_COMPILER_BUILTINS */ + #ifndef atomic_delay # define atomic_delay() do { /* nothing */ } while (0) diff --git a/test/.gitignore b/test/.gitignore index beb50958d..0d19285e9 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -263,6 +263,8 @@ signal/tst-sigset signal/tst-sigsimple silly/hello silly/tiny +silly/tst-atomic +silly/tst-atomic-long stat/memcmp-stat stat/stat stat/stat64 diff --git a/test/silly/Makefile.in b/test/silly/Makefile.in index bb08e0db9..9bb4032b5 100644 --- a/test/silly/Makefile.in +++ b/test/silly/Makefile.in @@ -3,3 +3,6 @@ RET_hello := 42 RET_tiny := 42 + +# missing internal headers, disable these +GLIBC_TESTS_DISABLED := tst-atomic_glibc tst-atomic-long_glibc diff --git a/test/silly/hello.c b/test/silly/hello.c index 4aba926e6..d330597ab 100644 --- a/test/silly/hello.c +++ b/test/silly/hello.c @@ -1,4 +1,4 @@ -#include<stdio.h> +#include <stdio.h> #include <stdlib.h> int main(void) diff --git a/test/silly/tst-atomic-long.c b/test/silly/tst-atomic-long.c new file mode 100644 index 000000000..d13fb074c --- /dev/null +++ b/test/silly/tst-atomic-long.c @@ -0,0 +1,27 @@ +/* Tests for atomic.h macros. + Copyright (C) 2003-2015 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library 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. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <bits/wordsize.h> + +#define atomic_t long +#if __WORDSIZE == 64 +# define TEST_ATOMIC64 1 +#endif + +#include "tst-atomic.c" diff --git a/test/silly/tst-atomic.c b/test/silly/tst-atomic.c new file mode 100644 index 000000000..fc773b231 --- /dev/null +++ b/test/silly/tst-atomic.c @@ -0,0 +1,573 @@ +/* Tests for atomic.h macros. + Copyright (C) 2003-2015 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + The GNU C Library 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. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <atomic.h> + +#ifndef atomic_t +# define atomic_t int +#endif + +#define CHK2(f,a1,a2,rv,new_mem) \ + retval = f(&mem, a1, a2); \ + if (retval != rv) { \ + printf("%s(mem, %lu, %lu): retval %lu != expected %lu\n", \ + #f, a1, a2, retval, rv); \ + ret = 1; \ + } \ + if (mem != new_mem) { \ + printf("%s(mem, %lu, %lu): mem %lu != expected %lu\n", \ + #f, a1, a2, mem, new_mem); \ + ret = 1; \ + } +#define CHK1(f,a1,rv,new_mem) \ + retval = f(&mem, a1); \ + if (retval != rv) { \ + printf("%s(mem, %lu): retval %lu != expected %lu\n", \ + #f, a1, retval, rv); \ + ret = 1; \ + } \ + if (mem != new_mem) { \ + printf("%s(mem, %lu): mem %lu != expected %lu\n", \ + #f, a1, mem, new_mem); \ + ret = 1; \ + } +#define CHK0(f,rv,new_mem) \ + retval = f(&mem); \ + if (retval != rv) { \ + printf("%s(mem): retval %lu != expected %lu\n", \ + #f, retval, rv); \ + ret = 1; \ + } \ + if (mem != new_mem) { \ + printf("%s(mem): mem %lu != expected %lu\n", \ + #f, mem, new_mem); \ + ret = 1; \ + } + +/* Test various atomic.h macros. */ +static int +do_test (void) +{ + atomic_t mem, expected, retval; + int ret = 0; + +#ifdef atomic_compare_and_exchange_val_acq + mem = 24; + CHK2(atomic_compare_and_exchange_val_acq, 35, 24, 24, 35); + mem = 12; + CHK2(atomic_compare_and_exchange_val_acq, 10, 15, 12, 12); + mem = -15; + CHK2(atomic_compare_and_exchange_val_acq, -56, -15, -15, -56); + mem = -1; + CHK2(atomic_compare_and_exchange_val_acq, 17, 0, -1, -1); +#endif + + mem = 24; + CHK2(atomic_compare_and_exchange_bool_acq, 35, 24, 0, 35); + mem = 12; + CHK2(atomic_compare_and_exchange_bool_acq, 10, 15, 1, 12); + mem = -15; + CHK2(atomic_compare_and_exchange_bool_acq, -56, -15, 0, -56); + mem = -1; + CHK2(atomic_compare_and_exchange_bool_acq, 17, 0, 1, -1); + + mem = 64; + CHK1(atomic_exchange_acq, 31, 64, 31); + mem = 2; + CHK1(atomic_exchange_and_add, 11, 2, 13); + mem = 2; + CHK1(atomic_exchange_and_add_acq, 11, 2, 13); + mem = 2; + CHK1(atomic_exchange_and_add_rel, 11, 2, 13); + + mem = -21; + atomic_add (&mem, 22); + if (mem != 1) + { + printf ("atomic_add(mem, 22): mem %lu != expected 1\n", mem); + ret = 1; + } + + mem = -1; + atomic_increment (&mem); + if (mem != 0) + { + printf ("atomic_increment(mem): mem %lu != expected 0\n", mem); + ret = 1; + } + + mem = 2; + if ((retval = atomic_increment_val (&mem)) != 3) + { + printf ("atomic_increment_val(mem): retval %lu != expected 3\n", retval); + ret = 1; + } + + mem = 0; + CHK0(atomic_increment_and_test, 0, 1); + mem = 35; + CHK0(atomic_increment_and_test, 0, 36); + mem = -1; + CHK0(atomic_increment_and_test, 1, 0); + mem = 17; + atomic_decrement (&mem); + if (mem != 16) + { + printf ("atomic_increment(mem): mem %lu != expected 16\n", mem); + ret = 1; + } + + if ((retval = atomic_decrement_val (&mem)) != 15) + { + printf ("atomic_decrement_val(mem): retval %lu != expected 15\n", retval); + ret = 1; + } + + mem = 0; + CHK0(atomic_decrement_and_test, 0, -1); + + mem = 15; + CHK0(atomic_decrement_and_test, 0, 14); + mem = 1; + CHK0(atomic_decrement_and_test, 1, 0); + mem = 1; + if (atomic_decrement_if_positive (&mem) != 1 + || mem != 0) + { + puts ("atomic_decrement_if_positive test 1 failed"); + ret = 1; + } + + mem = 0; + if (atomic_decrement_if_positive (&mem) != 0 + || mem != 0) + { + puts ("atomic_decrement_if_positive test 2 failed"); + ret = 1; + } + + mem = -1; + if (atomic_decrement_if_positive (&mem) != -1 + || mem != -1) + { + puts ("atomic_decrement_if_positive test 3 failed"); + ret = 1; + } + + mem = -12; + if (! atomic_add_negative (&mem, 10) + || mem != -2) + { + puts ("atomic_add_negative test 1 failed"); + ret = 1; + } + + mem = 0; + if (atomic_add_negative (&mem, 100) + || mem != 100) + { + puts ("atomic_add_negative test 2 failed"); + ret = 1; + } + + mem = 15; + if (atomic_add_negative (&mem, -10) + || mem != 5) + { + puts ("atomic_add_negative test 3 failed"); + ret = 1; + } + + mem = -12; + if (atomic_add_negative (&mem, 14) + || mem != 2) + { + puts ("atomic_add_negative test 4 failed"); + ret = 1; + } + + mem = 0; + if (! atomic_add_negative (&mem, -1) + || mem != -1) + { + puts ("atomic_add_negative test 5 failed"); + ret = 1; + } + + mem = -31; + if (atomic_add_negative (&mem, 31) + || mem != 0) + { + puts ("atomic_add_negative test 6 failed"); + ret = 1; + } + + mem = -34; + if (atomic_add_zero (&mem, 31) + || mem != -3) + { + puts ("atomic_add_zero test 1 failed"); + ret = 1; + } + + mem = -36; + if (! atomic_add_zero (&mem, 36) + || mem != 0) + { + puts ("atomic_add_zero test 2 failed"); + ret = 1; + } + + mem = 113; + if (atomic_add_zero (&mem, -13) + || mem != 100) + { + puts ("atomic_add_zero test 3 failed"); + ret = 1; + } + + mem = -18; + if (atomic_add_zero (&mem, 20) + || mem != 2) + { + puts ("atomic_add_zero test 4 failed"); + ret = 1; + } + + mem = 10; + if (atomic_add_zero (&mem, -20) + || mem != -10) + { + puts ("atomic_add_zero test 5 failed"); + ret = 1; + } + + mem = 10; + if (! atomic_add_zero (&mem, -10) + || mem != 0) + { + puts ("atomic_add_zero test 6 failed"); + ret = 1; + } + + mem = 0; + atomic_bit_set (&mem, 1); + if (mem != 2) + { + puts ("atomic_bit_set test 1 failed"); + ret = 1; + } + + mem = 8; + atomic_bit_set (&mem, 3); + if (mem != 8) + { + puts ("atomic_bit_set test 2 failed"); + ret = 1; + } + +#ifdef TEST_ATOMIC64 + mem = 16; + atomic_bit_set (&mem, 35); + if (mem != 0x800000010LL) + { + puts ("atomic_bit_set test 3 failed"); + ret = 1; + } +#endif + + mem = 0; + if (atomic_bit_test_set (&mem, 1) + || mem != 2) + { + puts ("atomic_bit_test_set test 1 failed"); + ret = 1; + } + + mem = 8; + if (! atomic_bit_test_set (&mem, 3) + || mem != 8) + { + puts ("atomic_bit_test_set test 2 failed"); + ret = 1; + } + +#ifdef TEST_ATOMIC64 + mem = 16; + if (atomic_bit_test_set (&mem, 35) + || mem != 0x800000010LL) + { + puts ("atomic_bit_test_set test 3 failed"); + ret = 1; + } + + mem = 0x100000000LL; + if (! atomic_bit_test_set (&mem, 32) + || mem != 0x100000000LL) + { + puts ("atomic_bit_test_set test 4 failed"); + ret = 1; + } +#endif + +#ifdef catomic_compare_and_exchange_val_acq + mem = 24; + if (catomic_compare_and_exchange_val_acq (&mem, 35, 24) != 24 + || mem != 35) + { + puts ("catomic_compare_and_exchange_val_acq test 1 failed"); + ret = 1; + } + + mem = 12; + if (catomic_compare_and_exchange_val_acq (&mem, 10, 15) != 12 + || mem != 12) + { + puts ("catomic_compare_and_exchange_val_acq test 2 failed"); + ret = 1; + } + + mem = -15; + if (catomic_compare_and_exchange_val_acq (&mem, -56, -15) != -15 + || mem != -56) + { + puts ("catomic_compare_and_exchange_val_acq test 3 failed"); + ret = 1; + } + + mem = -1; + if (catomic_compare_and_exchange_val_acq (&mem, 17, 0) != -1 + || mem != -1) + { + puts ("catomic_compare_and_exchange_val_acq test 4 failed"); + ret = 1; + } +#endif + + mem = 24; + if (catomic_compare_and_exchange_bool_acq (&mem, 35, 24) + || mem != 35) + { + puts ("catomic_compare_and_exchange_bool_acq test 1 failed"); + ret = 1; + } + + mem = 12; + if (! catomic_compare_and_exchange_bool_acq (&mem, 10, 15) + || mem != 12) + { + puts ("catomic_compare_and_exchange_bool_acq test 2 failed"); + ret = 1; + } + + mem = -15; + if (catomic_compare_and_exchange_bool_acq (&mem, -56, -15) + || mem != -56) + { + puts ("catomic_compare_and_exchange_bool_acq test 3 failed"); + ret = 1; + } + + mem = -1; + if (! catomic_compare_and_exchange_bool_acq (&mem, 17, 0) + || mem != -1) + { + puts ("catomic_compare_and_exchange_bool_acq test 4 failed"); + ret = 1; + } + + mem = 2; + if (catomic_exchange_and_add (&mem, 11) != 2 + || mem != 13) + { + puts ("catomic_exchange_and_add test failed"); + ret = 1; + } + + mem = -21; + catomic_add (&mem, 22); + if (mem != 1) + { + puts ("catomic_add test failed"); + ret = 1; + } + + mem = -1; + catomic_increment (&mem); + if (mem != 0) + { + puts ("catomic_increment test failed"); + ret = 1; + } + + mem = 2; + if (catomic_increment_val (&mem) != 3) + { + puts ("catomic_increment_val test failed"); + ret = 1; + } + + mem = 17; + catomic_decrement (&mem); + if (mem != 16) + { + puts ("catomic_decrement test failed"); + ret = 1; + } + + if (catomic_decrement_val (&mem) != 15) + { + puts ("catomic_decrement_val test failed"); + ret = 1; + } + + /* Tests for C11-like atomics. */ + mem = 11; + if (atomic_load_relaxed (&mem) != 11 || atomic_load_acquire (&mem) != 11) + { + puts ("atomic_load_{relaxed,acquire} test failed"); + ret = 1; + } + + atomic_store_relaxed (&mem, 12); + if (mem != 12) + { + puts ("atomic_store_relaxed test failed"); + ret = 1; + } + atomic_store_release (&mem, 13); + if (mem != 13) + { + puts ("atomic_store_release test failed"); + ret = 1; + } + + mem = 14; + expected = 14; + if (!atomic_compare_exchange_weak_relaxed (&mem, &expected, 25) + || mem != 25 || expected != 14) + { + puts ("atomic_compare_exchange_weak_relaxed test 1 failed"); + ret = 1; + } + if (atomic_compare_exchange_weak_relaxed (&mem, &expected, 14) + || mem != 25 || expected != 25) + { + puts ("atomic_compare_exchange_weak_relaxed test 2 failed"); + ret = 1; + } + mem = 14; + expected = 14; + if (!atomic_compare_exchange_weak_acquire (&mem, &expected, 25) + || mem != 25 || expected != 14) + { + puts ("atomic_compare_exchange_weak_acquire test 1 failed"); + ret = 1; + } + if (atomic_compare_exchange_weak_acquire (&mem, &expected, 14) + || mem != 25 || expected != 25) + { + puts ("atomic_compare_exchange_weak_acquire test 2 failed"); + ret = 1; + } + mem = 14; + expected = 14; + if (!atomic_compare_exchange_weak_release (&mem, &expected, 25) + || mem != 25 || expected != 14) + { + puts ("atomic_compare_exchange_weak_release test 1 failed"); + ret = 1; + } + if (atomic_compare_exchange_weak_release (&mem, &expected, 14) + || mem != 25 || expected != 25) + { + puts ("atomic_compare_exchange_weak_release test 2 failed"); + ret = 1; + } + + mem = 23; + if (atomic_exchange_acquire (&mem, 42) != 23 || mem != 42) + { + puts ("atomic_exchange_acquire test failed"); + ret = 1; + } + mem = 23; + if (atomic_exchange_release (&mem, 42) != 23 || mem != 42) + { + puts ("atomic_exchange_release test failed"); + ret = 1; + } + + mem = 23; + if (atomic_fetch_add_relaxed (&mem, 1) != 23 || mem != 24) + { + puts ("atomic_fetch_add_relaxed test failed"); + ret = 1; + } + mem = 23; + if (atomic_fetch_add_acquire (&mem, 1) != 23 || mem != 24) + { + puts ("atomic_fetch_add_acquire test failed"); + ret = 1; + } + mem = 23; + if (atomic_fetch_add_release (&mem, 1) != 23 || mem != 24) + { + puts ("atomic_fetch_add_release test failed"); + ret = 1; + } + mem = 23; + if (atomic_fetch_add_acq_rel (&mem, 1) != 23 || mem != 24) + { + puts ("atomic_fetch_add_acq_rel test failed"); + ret = 1; + } + + mem = 3; + if (atomic_fetch_and_acquire (&mem, 2) != 3 || mem != 2) + { + puts ("atomic_fetch_and_acquire test failed"); + ret = 1; + } + + mem = 4; + if (atomic_fetch_or_relaxed (&mem, 2) != 4 || mem != 6) + { + puts ("atomic_fetch_or_relaxed test failed"); + ret = 1; + } + mem = 4; + if (atomic_fetch_or_acquire (&mem, 2) != 4 || mem != 6) + { + puts ("atomic_fetch_or_acquire test failed"); + ret = 1; + } + + /* This is a single-threaded test, so we can't test the effects of the + fences. */ + atomic_thread_fence_acquire (); + atomic_thread_fence_release (); + atomic_thread_fence_seq_cst (); + + return ret; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" |