Code in tools tries to follow the patterns of the kernel, so the atomic functions names match. However, having include/linux/atomic.h in tools complicates building code in tools as assembly and other functions are necessary - these are often configured in the kernel using CONFIG options. As tools C code is compiled with the -std=gnu11 flag, it is possible to use stdatomic.h and move the build and other complications to the compiler/libc.
Signed-off-by: Ian Rogers irogers@google.com --- tools/arch/x86/include/asm/atomic.h | 84 -------------- tools/include/asm-generic/atomic-gcc.h | 95 ---------------- tools/include/asm/atomic.h | 11 -- tools/include/linux/atomic.h | 107 ++++++++++++++++-- tools/include/linux/types.h | 15 ++- .../selftests/kvm/include/kvm_util_base.h | 3 +- 6 files changed, 110 insertions(+), 205 deletions(-) delete mode 100644 tools/arch/x86/include/asm/atomic.h delete mode 100644 tools/include/asm-generic/atomic-gcc.h delete mode 100644 tools/include/asm/atomic.h
diff --git a/tools/arch/x86/include/asm/atomic.h b/tools/arch/x86/include/asm/atomic.h deleted file mode 100644 index 365cf182df12..000000000000 --- a/tools/arch/x86/include/asm/atomic.h +++ /dev/null @@ -1,84 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _TOOLS_LINUX_ASM_X86_ATOMIC_H -#define _TOOLS_LINUX_ASM_X86_ATOMIC_H - -#include <linux/compiler.h> -#include <linux/types.h> -#include "rmwcc.h" - -#define LOCK_PREFIX "\n\tlock; " - -#include <asm/asm.h> -#include <asm/cmpxchg.h> - -/* - * Atomic operations that C can't guarantee us. Useful for - * resource counting etc.. - */ - -#define ATOMIC_INIT(i) { (i) } - -/** - * atomic_read - read atomic variable - * @v: pointer of type atomic_t - * - * Atomically reads the value of @v. - */ -static inline int atomic_read(const atomic_t *v) -{ - return READ_ONCE((v)->counter); -} - -/** - * atomic_set - set atomic variable - * @v: pointer of type atomic_t - * @i: required value - * - * Atomically sets the value of @v to @i. - */ -static inline void atomic_set(atomic_t *v, int i) -{ - v->counter = i; -} - -/** - * atomic_inc - increment atomic variable - * @v: pointer of type atomic_t - * - * Atomically increments @v by 1. - */ -static inline void atomic_inc(atomic_t *v) -{ - asm volatile(LOCK_PREFIX "incl %0" - : "+m" (v->counter)); -} - -/** - * atomic_dec_and_test - decrement and test - * @v: pointer of type atomic_t - * - * Atomically decrements @v by 1 and - * returns true if the result is 0, or false for all other - * cases. - */ -static inline int atomic_dec_and_test(atomic_t *v) -{ - GEN_UNARY_RMWcc(LOCK_PREFIX "decl", v->counter, "%0", "e"); -} - -static __always_inline int atomic_cmpxchg(atomic_t *v, int old, int new) -{ - return cmpxchg(&v->counter, old, new); -} - -static inline int test_and_set_bit(long nr, unsigned long *addr) -{ - GEN_BINARY_RMWcc(LOCK_PREFIX __ASM_SIZE(bts), *addr, "Ir", nr, "%0", "c"); -} - -static inline int test_and_clear_bit(long nr, unsigned long *addr) -{ - GEN_BINARY_RMWcc(LOCK_PREFIX __ASM_SIZE(btc), *addr, "Ir", nr, "%0", "c"); -} - -#endif /* _TOOLS_LINUX_ASM_X86_ATOMIC_H */ diff --git a/tools/include/asm-generic/atomic-gcc.h b/tools/include/asm-generic/atomic-gcc.h deleted file mode 100644 index 9b3c528bab92..000000000000 --- a/tools/include/asm-generic/atomic-gcc.h +++ /dev/null @@ -1,95 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __TOOLS_ASM_GENERIC_ATOMIC_H -#define __TOOLS_ASM_GENERIC_ATOMIC_H - -#include <linux/compiler.h> -#include <linux/types.h> -#include <linux/bitops.h> - -/* - * Atomic operations that C can't guarantee us. Useful for - * resource counting etc.. - * - * Excerpts obtained from the Linux kernel sources. - */ - -#define ATOMIC_INIT(i) { (i) } - -/** - * atomic_read - read atomic variable - * @v: pointer of type atomic_t - * - * Atomically reads the value of @v. - */ -static inline int atomic_read(const atomic_t *v) -{ - return READ_ONCE((v)->counter); -} - -/** - * atomic_set - set atomic variable - * @v: pointer of type atomic_t - * @i: required value - * - * Atomically sets the value of @v to @i. - */ -static inline void atomic_set(atomic_t *v, int i) -{ - v->counter = i; -} - -/** - * atomic_inc - increment atomic variable - * @v: pointer of type atomic_t - * - * Atomically increments @v by 1. - */ -static inline void atomic_inc(atomic_t *v) -{ - __sync_add_and_fetch(&v->counter, 1); -} - -/** - * atomic_dec_and_test - decrement and test - * @v: pointer of type atomic_t - * - * Atomically decrements @v by 1 and - * returns true if the result is 0, or false for all other - * cases. - */ -static inline int atomic_dec_and_test(atomic_t *v) -{ - return __sync_sub_and_fetch(&v->counter, 1) == 0; -} - -#define cmpxchg(ptr, oldval, newval) \ - __sync_val_compare_and_swap(ptr, oldval, newval) - -static inline int atomic_cmpxchg(atomic_t *v, int oldval, int newval) -{ - return cmpxchg(&(v)->counter, oldval, newval); -} - -static inline int test_and_set_bit(long nr, unsigned long *addr) -{ - unsigned long mask = BIT_MASK(nr); - long old; - - addr += BIT_WORD(nr); - - old = __sync_fetch_and_or(addr, mask); - return !!(old & mask); -} - -static inline int test_and_clear_bit(long nr, unsigned long *addr) -{ - unsigned long mask = BIT_MASK(nr); - long old; - - addr += BIT_WORD(nr); - - old = __sync_fetch_and_and(addr, ~mask); - return !!(old & mask); -} - -#endif /* __TOOLS_ASM_GENERIC_ATOMIC_H */ diff --git a/tools/include/asm/atomic.h b/tools/include/asm/atomic.h deleted file mode 100644 index 8c9bfffd4191..000000000000 --- a/tools/include/asm/atomic.h +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __TOOLS_LINUX_ASM_ATOMIC_H -#define __TOOLS_LINUX_ASM_ATOMIC_H - -#if defined(__i386__) || defined(__x86_64__) -#include "../../arch/x86/include/asm/atomic.h" -#else -#include <asm-generic/atomic-gcc.h> -#endif - -#endif /* __TOOLS_LINUX_ASM_ATOMIC_H */ diff --git a/tools/include/linux/atomic.h b/tools/include/linux/atomic.h index 01907b33537e..2cf4791ddd5d 100644 --- a/tools/include/linux/atomic.h +++ b/tools/include/linux/atomic.h @@ -2,14 +2,107 @@ #ifndef __TOOLS_LINUX_ATOMIC_H #define __TOOLS_LINUX_ATOMIC_H
-#include <asm/atomic.h> +#include <stdatomic.h> +#include <linux/types.h> // For atomic_t
-void atomic_long_set(atomic_long_t *v, long i); +/* + * Reimplementation of the kernel's atomic.h using C11's stdatomic.h to avoid + * build logic around compilers, inline assembler, etc. + */
-/* atomic_cmpxchg_relaxed */ -#ifndef atomic_cmpxchg_relaxed -#define atomic_cmpxchg_relaxed atomic_cmpxchg -#define atomic_cmpxchg_release atomic_cmpxchg -#endif /* atomic_cmpxchg_relaxed */ +#define ATOMIC_OP(op, c_op) \ +static inline void generic_atomic_##op(int i, atomic_t *v) \ +{ \ + atomic_fetch_##op(v, i); \ +} + +#define ATOMIC_OP_RETURN(op, c_op) \ +static inline int generic_atomic_##op##_return(int i, atomic_t *v) \ +{ \ + int c = atomic_fetch_##op(v, i); \ + \ + return c c_op i; \ +} + +#define ATOMIC_FETCH_OP(op, c_op) \ +static inline int generic_atomic_fetch_##op(int i, atomic_t *v) \ +{ \ + return atomic_fetch_##op(v, i); \ +} + +static inline int generic_atomic_read(const atomic_t *v) +{ + return atomic_load(v); +} + +static inline void generic_atomic_set(atomic_t *v, int i) +{ + atomic_store(v, i); +} + +static inline int generic_atomic_cmpxchg_relaxed(atomic_t *v, int old, int new) +{ + int expected = old; + + atomic_compare_exchange_weak_explicit(v, &expected, new, + memory_order_relaxed, memory_order_relaxed); + return expected; +} + +static inline int generic_atomic_cmpxchg_release(atomic_t *v, int old, int new) +{ + int expected = old; + + /* + * Note, the stricter memory_order_seq_cst is used as + * memory_order_release fails with an invalid-memory-model error. + */ + atomic_compare_exchange_weak_explicit(v, &expected, new, + memory_order_seq_cst, memory_order_seq_cst); + return expected; +} + +ATOMIC_OP_RETURN(add, +) +ATOMIC_OP_RETURN(sub, -) + +ATOMIC_FETCH_OP(add, +) +ATOMIC_FETCH_OP(sub, -) +ATOMIC_FETCH_OP(and, &) +ATOMIC_FETCH_OP(or, |) +ATOMIC_FETCH_OP(xor, ^) + +ATOMIC_OP(add, +) +ATOMIC_OP(sub, -) +ATOMIC_OP(and, &) +ATOMIC_OP(or, |) +ATOMIC_OP(xor, ^) + +#undef ATOMIC_FETCH_OP +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP + +#define arch_atomic_add_return generic_atomic_add_return +#define arch_atomic_sub_return generic_atomic_sub_return + +#define arch_atomic_fetch_add generic_atomic_fetch_add +#define arch_atomic_fetch_sub generic_atomic_fetch_sub +#define arch_atomic_fetch_and generic_atomic_fetch_and +#define arch_atomic_fetch_or generic_atomic_fetch_or +#define arch_atomic_fetch_xor generic_atomic_fetch_xor + +#define arch_atomic_add generic_atomic_add +#define arch_atomic_sub generic_atomic_sub +#define arch_atomic_and generic_atomic_and +#define arch_atomic_or generic_atomic_or +#define arch_atomic_xor generic_atomic_xor + +#define arch_atomic_read(v) generic_atomic_read(v) +#define arch_atomic_set(v, i) generic_atomic_set(v, i) +#define atomic_set(v, i) generic_atomic_set(v, i) +#define atomic_read(v) generic_atomic_read(v) +#define atomic_cmpxchg_relaxed(v, o, n) generic_atomic_cmpxchg_relaxed(v, o, n) +#define atomic_cmpxchg_release(v, o, n) generic_atomic_cmpxchg_release(v, o, n) +#define atomic_inc(v) generic_atomic_add(1, v) +#define atomic_dec(v) generic_atomic_sub(1, v)
#endif /* __TOOLS_LINUX_ATOMIC_H */ diff --git a/tools/include/linux/types.h b/tools/include/linux/types.h index 8519386acd23..cb1f44f1ed5e 100644 --- a/tools/include/linux/types.h +++ b/tools/include/linux/types.h @@ -74,13 +74,16 @@ typedef u64 phys_addr_t; typedef u32 phys_addr_t; #endif
-typedef struct { - int counter; -} atomic_t; +#ifndef __cplusplus +/* C++17 doesn't support stdatomic.h but C++23 does. */ +#include <stdatomic.h>
-typedef struct { - long counter; -} atomic_long_t; +typedef atomic_int atomic_t; + +#define ATOMIC_INIT(i) (i) + +typedef atomic_long atomic_long_t; +#endif
#ifndef __aligned_u64 # define __aligned_u64 __u64 __attribute__((aligned(8))) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 9e5afc472c14..7c81da425abc 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -9,6 +9,7 @@
#include "test_util.h"
+#include <linux/atomic.h> #include <linux/compiler.h> #include "linux/hashtable.h" #include "linux/list.h" @@ -17,8 +18,6 @@ #include "linux/rbtree.h" #include <linux/types.h>
-#include <asm/atomic.h> - #include <sys/ioctl.h>
#include "sparsebit.h"