[1/6] eal: provide rte stdatomics optional atomics API
Checks
Commit Message
Provide API for atomic operations in the rte namespace that may
optionally be configured to use C11 atomics with meson
option enable_stdatomics=true
Signed-off-by: Tyler Retzlaff <roretzla@linux.microsoft.com>
---
config/meson.build | 1 +
config/rte_config.h | 1 +
lib/eal/include/meson.build | 1 +
lib/eal/include/rte_stdatomic.h | 162 ++++++++++++++++++++++++++++++++++++++++
meson_options.txt | 1 +
5 files changed, 166 insertions(+)
create mode 100644 lib/eal/include/rte_stdatomic.h
Comments
On Thu, Aug 10, 2023 at 06:31:56PM -0700, Tyler Retzlaff wrote:
> Provide API for atomic operations in the rte namespace that may
> optionally be configured to use C11 atomics with meson
> option enable_stdatomics=true
>
> Signed-off-by: Tyler Retzlaff <roretzla@linux.microsoft.com>
> ---
> config/meson.build | 1 +
> config/rte_config.h | 1 +
> lib/eal/include/meson.build | 1 +
> lib/eal/include/rte_stdatomic.h | 162 ++++++++++++++++++++++++++++++++++++++++
> meson_options.txt | 1 +
> 5 files changed, 166 insertions(+)
> create mode 100644 lib/eal/include/rte_stdatomic.h
>
<snip>
> diff --git a/meson_options.txt b/meson_options.txt
> index 621e1ca..7d6784d 100644
> --- a/meson_options.txt
> +++ b/meson_options.txt
> @@ -46,6 +46,7 @@ option('mbuf_refcnt_atomic', type: 'boolean', value: true, description:
> 'Atomically access the mbuf refcnt.')
> option('platform', type: 'string', value: 'native', description:
> 'Platform to build, either "native", "generic" or a SoC. Please refer to the Linux build guide for more information.')
> +option('enable_stdatomic', type: 'boolean', value: false, description: 'enable use of C11 stdatomic')
Minor nit - all other options in this file put the description on it's own
line. For consistency I think we should do the same here.
> option('enable_trace_fp', type: 'boolean', value: false, description:
> 'enable fast path trace points.')
> option('tests', type: 'boolean', value: true, description:
> --
> 1.8.3.1
>
> From: Tyler Retzlaff [mailto:roretzla@linux.microsoft.com]
> Sent: Friday, 11 August 2023 03.32
>
> Provide API for atomic operations in the rte namespace that may
> optionally be configured to use C11 atomics with meson
> option enable_stdatomics=true
>
> Signed-off-by: Tyler Retzlaff <roretzla@linux.microsoft.com>
> ---
> config/meson.build | 1 +
> config/rte_config.h | 1 +
> lib/eal/include/meson.build | 1 +
> lib/eal/include/rte_stdatomic.h | 162
> ++++++++++++++++++++++++++++++++++++++++
> meson_options.txt | 1 +
> 5 files changed, 166 insertions(+)
> create mode 100644 lib/eal/include/rte_stdatomic.h
>
> diff --git a/config/meson.build b/config/meson.build
> index d822371..ec49964 100644
> --- a/config/meson.build
> +++ b/config/meson.build
> @@ -303,6 +303,7 @@ endforeach
> # set other values pulled from the build options
> dpdk_conf.set('RTE_MAX_ETHPORTS', get_option('max_ethports'))
> dpdk_conf.set('RTE_LIBEAL_USE_HPET', get_option('use_hpet'))
> +dpdk_conf.set('RTE_ENABLE_STDATOMIC', get_option('enable_stdatomic'))
> dpdk_conf.set('RTE_ENABLE_TRACE_FP', get_option('enable_trace_fp'))
> # values which have defaults which may be overridden
> dpdk_conf.set('RTE_MAX_VFIO_GROUPS', 64)
> diff --git a/config/rte_config.h b/config/rte_config.h
> index 400e44e..f17b6ae 100644
> --- a/config/rte_config.h
> +++ b/config/rte_config.h
> @@ -13,6 +13,7 @@
> #define _RTE_CONFIG_H_
>
> #include <rte_build_config.h>
> +#include <rte_stdatomic.h>
>
> /* legacy defines */
> #ifdef RTE_EXEC_ENV_LINUX
> diff --git a/lib/eal/include/meson.build b/lib/eal/include/meson.build
> index b0db9b3..f8a47b3 100644
> --- a/lib/eal/include/meson.build
> +++ b/lib/eal/include/meson.build
> @@ -43,6 +43,7 @@ headers += files(
> 'rte_seqlock.h',
> 'rte_service.h',
> 'rte_service_component.h',
> + 'rte_stdatomic.h',
> 'rte_string_fns.h',
> 'rte_tailq.h',
> 'rte_thread.h',
> diff --git a/lib/eal/include/rte_stdatomic.h
> b/lib/eal/include/rte_stdatomic.h
> new file mode 100644
> index 0000000..832fd07
> --- /dev/null
> +++ b/lib/eal/include/rte_stdatomic.h
> @@ -0,0 +1,162 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2023 Microsoft Corporation
> + */
> +
> +#ifndef _RTE_STDATOMIC_H_
> +#define _RTE_STDATOMIC_H_
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +typedef int rte_memory_order;
In C11 memory_order is an enumerated type, and in GCC built-ins it is an int. If possible, rte_memory_order should be too; i.e. remove the typedef here, and make two variants of it instead.
> +
> +#ifdef RTE_ENABLE_STDATOMIC
> +#ifdef __STDC_NO_ATOMICS__
> +#error enable_stdatomics=true but atomics not supported by toolchain
> +#endif
> +
> +#include <stdatomic.h>
> +
> +#define __rte_atomic _Atomic
Move the (changed) C11 memory order type definition here:
/* The memory order is an enumerated type in C11. */
#define memory_order rte_memory_order
> +
> +#define rte_memory_order_relaxed memory_order_relaxed
> +#ifdef __ATOMIC_RELAXED
> +_Static_assert(rte_memory_order_relaxed == __ATOMIC_RELAXED,
> + "rte_memory_order_relaxed == __ATOMIC_RELAXED");
> +#endif
> +
> +#define rte_memory_order_consume memory_order_consume
> +#ifdef __ATOMIC_CONSUME
> +_Static_assert(rte_memory_order_consume == __ATOMIC_CONSUME,
> + "rte_memory_order_consume == __ATOMIC_CONSUME");
> +#endif
> +
> +#define rte_memory_order_acquire memory_order_acquire
> +#ifdef __ATOMIC_ACQUIRE
> +_Static_assert(rte_memory_order_acquire == __ATOMIC_ACQUIRE,
> + "rte_memory_order_acquire == __ATOMIC_ACQUIRE");
> +#endif
> +
> +#define rte_memory_order_release memory_order_release
> +#ifdef __ATOMIC_RELEASE
> +_Static_assert(rte_memory_order_release == __ATOMIC_RELEASE,
> + "rte_memory_order_release == __ATOMIC_RELEASE");
> +#endif
> +
> +#define rte_memory_order_acq_rel memory_order_acq_rel
> +#ifdef __ATOMIC_ACQ_REL
> +_Static_assert(rte_memory_order_acq_rel == __ATOMIC_ACQ_REL,
> + "rte_memory_order_acq_rel == __ATOMIC_ACQ_REL");
> +#endif
> +
> +#define rte_memory_order_seq_cst memory_order_seq_cst
> +#ifdef __ATOMIC_SEQ_CST
> +_Static_assert(rte_memory_order_seq_cst == __ATOMIC_SEQ_CST,
> + "rte_memory_order_seq_cst == __ATOMIC_SEQ_CST");
> +#endif
Excellent idea adding these _Static_asserts!
Have you tested (with the toolchain you are targeting with this _Static_assert) that e.g. __ATOMIC_RELAXED is actually #defined, so the preprocessor can see it? (I guess that being a built-it, it might not be a #define, it might be a magic value known by the compiler only.)
> +
> +#define rte_atomic_load_explicit(ptr, memorder) \
> + atomic_load_explicit(ptr, memorder)
> +
> +#define rte_atomic_store_explicit(ptr, val, memorder) \
> + atomic_store_explicit(ptr, val, memorder)
> +
> +#define rte_atomic_exchange_explicit(ptr, val, memorder) \
> + atomic_exchange_explicit(ptr, val, memorder)
> +
> +#define rte_atomic_compare_exchange_strong_explicit( \
> + ptr, expected, desired, succ_memorder, fail_memorder) \
> + atomic_compare_exchange_strong_explicit( \
> + ptr, expected, desired, succ_memorder, fail_memorder)
> +
> +#define rte_atomic_compare_exchange_weak_explicit( \
> + ptr, expected, desired, succ_memorder, fail_memorder) \
> + atomic_compare_exchange_strong_explicit( \
> + ptr, expected, desired, succ_memorder, fail_memorder)
> +
> +#define rte_atomic_fetch_add_explicit(ptr, val, memorder) \
> + atomic_fetch_add_explicit(ptr, val, memorder)
> +
> +#define rte_atomic_fetch_sub_explicit(ptr, val, memorder) \
> + atomic_fetch_sub_explicit(ptr, val, memorder)
> +
> +#define rte_atomic_fetch_and_explicit(ptr, val, memorder) \
> + atomic_fetch_and_explicit(ptr, val, memorder)
> +
> +#define rte_atomic_fetch_xor_explicit(ptr, val, memorder) \
> + atomic_fetch_xor_explicit(ptr, val, memorder)
> +
> +#define rte_atomic_fetch_or_explicit(ptr, val, memorder) \
> + atomic_fetch_or_explicit(ptr, val, memorder)
> +
> +#define rte_atomic_fetch_nand_explicit(ptr, val, memorder) \
> + atomic_fetch_nand_explicit(ptr, val, memorder)
> +
> +#define rte_atomic_flag_test_and_set_explict(ptr, memorder) \
> + atomic_flag_test_and_set_explicit(ptr, memorder)
> +
> +#define rte_atomic_flag_clear_explicit(ptr, memorder) \
> + atomic_flag_clear(ptr, memorder)
> +
> +#else
> +
> +#define __rte_atomic
Move the built-ins memory order type definition here:
/* The memory order is an integer type in GCC built-ins,
* not an enumerated type like in C11.
*/
typedef int rte_memory_order;
> +
> +#define rte_memory_order_relaxed __ATOMIC_RELAXED
> +#define rte_memory_order_consume __ATOMIC_CONSUME
> +#define rte_memory_order_acquire __ATOMIC_ACQUIRE
> +#define rte_memory_order_release __ATOMIC_RELEASE
> +#define rte_memory_order_acq_rel __ATOMIC_ACQ_REL
> +#define rte_memory_order_seq_cst __ATOMIC_SEQ_CST
Agree; the memorder type is int, so no enum here.
> +
> +#define rte_atomic_load_explicit(ptr, memorder) \
> + __atomic_load_n(ptr, memorder)
> +
> +#define rte_atomic_store_explicit(ptr, val, memorder) \
> + __atomic_store_n(ptr, val, memorder)
> +
> +#define rte_atomic_exchange_explicit(ptr, val, memorder) \
> + __atomic_exchange_n(ptr, val, memorder)
> +
> +#define rte_atomic_compare_exchange_strong_explicit( \
> + ptr, expected, desired, succ_memorder, fail_memorder) \
> + __atomic_compare_exchange_n( \
> + ptr, expected, desired, 0, succ_memorder, fail_memorder)
> +
> +#define rte_atomic_compare_exchange_weak_explicit( \
> + ptr, expected, desired, succ_memorder, fail_memorder) \
> + __atomic_compare_exchange_n( \
> + ptr, expected, desired, 1, succ_memorder, fail_memorder)
> +
> +#define rte_atomic_fetch_add_explicit(ptr, val, memorder) \
> + __atomic_fetch_add(ptr, val, memorder)
> +
> +#define rte_atomic_fetch_sub_explicit(ptr, val, memorder) \
> + __atomic_fetch_sub(ptr, val, memorder)
> +
> +#define rte_atomic_fetch_and_explicit(ptr, val, memorder) \
> + __atomic_fetch_and(ptr, val, memorder)
> +
> +#define rte_atomic_fetch_xor_explicit(ptr, val, memorder) \
> + __atomic_fetch_xor(ptr, val, memorder)
> +
> +#define rte_atomic_fetch_or_explicit(ptr, val, memorder) \
> + __atomic_fetch_or(ptr, val, memorder)
> +
> +#define rte_atomic_fetch_nand_explicit(ptr, val, memorder) \
> + __atomic_fetch_nand(ptr, val, memorder)
> +
> +#define rte_atomic_flag_test_and_set_explicit(ptr, memorder) \
> + __atomic_test_and_set(ptr, memorder)
> +
> +#define rte_atomic_flag_clear_explicit(ptr, memorder) \
> + __atomic_clear(ptr, memorder)
> +
> +#endif
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif /* _RTE_STDATOMIC_H_ */
> diff --git a/meson_options.txt b/meson_options.txt
> index 621e1ca..7d6784d 100644
> --- a/meson_options.txt
> +++ b/meson_options.txt
> @@ -46,6 +46,7 @@ option('mbuf_refcnt_atomic', type: 'boolean', value:
> true, description:
> 'Atomically access the mbuf refcnt.')
> option('platform', type: 'string', value: 'native', description:
> 'Platform to build, either "native", "generic" or a SoC. Please
> refer to the Linux build guide for more information.')
> +option('enable_stdatomic', type: 'boolean', value: false, description:
> 'enable use of C11 stdatomic')
> option('enable_trace_fp', type: 'boolean', value: false, description:
> 'enable fast path trace points.')
> option('tests', type: 'boolean', value: true, description:
> --
> 1.8.3.1
On Fri, Aug 11, 2023 at 11:42:12AM +0200, Morten Brørup wrote:
> > From: Tyler Retzlaff [mailto:roretzla@linux.microsoft.com]
> > Sent: Friday, 11 August 2023 03.32
> >
> > Provide API for atomic operations in the rte namespace that may
> > optionally be configured to use C11 atomics with meson
> > option enable_stdatomics=true
> >
> > Signed-off-by: Tyler Retzlaff <roretzla@linux.microsoft.com>
> > ---
> > config/meson.build | 1 +
> > config/rte_config.h | 1 +
> > lib/eal/include/meson.build | 1 +
> > lib/eal/include/rte_stdatomic.h | 162
> > ++++++++++++++++++++++++++++++++++++++++
> > meson_options.txt | 1 +
> > 5 files changed, 166 insertions(+)
> > create mode 100644 lib/eal/include/rte_stdatomic.h
> >
> > diff --git a/config/meson.build b/config/meson.build
> > index d822371..ec49964 100644
> > --- a/config/meson.build
> > +++ b/config/meson.build
> > @@ -303,6 +303,7 @@ endforeach
> > # set other values pulled from the build options
> > dpdk_conf.set('RTE_MAX_ETHPORTS', get_option('max_ethports'))
> > dpdk_conf.set('RTE_LIBEAL_USE_HPET', get_option('use_hpet'))
> > +dpdk_conf.set('RTE_ENABLE_STDATOMIC', get_option('enable_stdatomic'))
> > dpdk_conf.set('RTE_ENABLE_TRACE_FP', get_option('enable_trace_fp'))
> > # values which have defaults which may be overridden
> > dpdk_conf.set('RTE_MAX_VFIO_GROUPS', 64)
> > diff --git a/config/rte_config.h b/config/rte_config.h
> > index 400e44e..f17b6ae 100644
> > --- a/config/rte_config.h
> > +++ b/config/rte_config.h
> > @@ -13,6 +13,7 @@
> > #define _RTE_CONFIG_H_
> >
> > #include <rte_build_config.h>
> > +#include <rte_stdatomic.h>
> >
> > /* legacy defines */
> > #ifdef RTE_EXEC_ENV_LINUX
> > diff --git a/lib/eal/include/meson.build b/lib/eal/include/meson.build
> > index b0db9b3..f8a47b3 100644
> > --- a/lib/eal/include/meson.build
> > +++ b/lib/eal/include/meson.build
> > @@ -43,6 +43,7 @@ headers += files(
> > 'rte_seqlock.h',
> > 'rte_service.h',
> > 'rte_service_component.h',
> > + 'rte_stdatomic.h',
> > 'rte_string_fns.h',
> > 'rte_tailq.h',
> > 'rte_thread.h',
> > diff --git a/lib/eal/include/rte_stdatomic.h
> > b/lib/eal/include/rte_stdatomic.h
> > new file mode 100644
> > index 0000000..832fd07
> > --- /dev/null
> > +++ b/lib/eal/include/rte_stdatomic.h
> > @@ -0,0 +1,162 @@
> > +/* SPDX-License-Identifier: BSD-3-Clause
> > + * Copyright(c) 2023 Microsoft Corporation
> > + */
> > +
> > +#ifndef _RTE_STDATOMIC_H_
> > +#define _RTE_STDATOMIC_H_
> > +
> > +#ifdef __cplusplus
> > +extern "C" {
> > +#endif
> > +
> > +typedef int rte_memory_order;
>
> In C11 memory_order is an enumerated type, and in GCC built-ins it is an int. If possible, rte_memory_order should be too; i.e. remove the typedef here, and make two variants of it instead.
will be in v2
>
> > +
> > +#ifdef RTE_ENABLE_STDATOMIC
> > +#ifdef __STDC_NO_ATOMICS__
> > +#error enable_stdatomics=true but atomics not supported by toolchain
> > +#endif
> > +
> > +#include <stdatomic.h>
> > +
> > +#define __rte_atomic _Atomic
>
> Move the (changed) C11 memory order type definition here:
>
> /* The memory order is an enumerated type in C11. */
> #define memory_order rte_memory_order
>
> > +
> > +#define rte_memory_order_relaxed memory_order_relaxed
> > +#ifdef __ATOMIC_RELAXED
> > +_Static_assert(rte_memory_order_relaxed == __ATOMIC_RELAXED,
> > + "rte_memory_order_relaxed == __ATOMIC_RELAXED");
> > +#endif
> > +
> > +#define rte_memory_order_consume memory_order_consume
> > +#ifdef __ATOMIC_CONSUME
> > +_Static_assert(rte_memory_order_consume == __ATOMIC_CONSUME,
> > + "rte_memory_order_consume == __ATOMIC_CONSUME");
> > +#endif
> > +
> > +#define rte_memory_order_acquire memory_order_acquire
> > +#ifdef __ATOMIC_ACQUIRE
> > +_Static_assert(rte_memory_order_acquire == __ATOMIC_ACQUIRE,
> > + "rte_memory_order_acquire == __ATOMIC_ACQUIRE");
> > +#endif
> > +
> > +#define rte_memory_order_release memory_order_release
> > +#ifdef __ATOMIC_RELEASE
> > +_Static_assert(rte_memory_order_release == __ATOMIC_RELEASE,
> > + "rte_memory_order_release == __ATOMIC_RELEASE");
> > +#endif
> > +
> > +#define rte_memory_order_acq_rel memory_order_acq_rel
> > +#ifdef __ATOMIC_ACQ_REL
> > +_Static_assert(rte_memory_order_acq_rel == __ATOMIC_ACQ_REL,
> > + "rte_memory_order_acq_rel == __ATOMIC_ACQ_REL");
> > +#endif
> > +
> > +#define rte_memory_order_seq_cst memory_order_seq_cst
> > +#ifdef __ATOMIC_SEQ_CST
> > +_Static_assert(rte_memory_order_seq_cst == __ATOMIC_SEQ_CST,
> > + "rte_memory_order_seq_cst == __ATOMIC_SEQ_CST");
> > +#endif
>
> Excellent idea adding these _Static_asserts!
>
> Have you tested (with the toolchain you are targeting with this _Static_assert) that e.g. __ATOMIC_RELAXED is actually #defined, so the preprocessor can see it? (I guess that being a built-it, it might not be a #define, it might be a magic value known by the compiler only.)
* llvm and gcc both expose it as a built-in #define for test builds i
have run. worst case the assert is lost if it isn't.
* since i have to handle non-{clang,gcc} too i still guard with ifdef
* i do need to switch to using assert.h static_assert macro to
inter-operate with c++ in v2
>
> > +
> > +#define rte_atomic_load_explicit(ptr, memorder) \
> > + atomic_load_explicit(ptr, memorder)
> > +
> > +#define rte_atomic_store_explicit(ptr, val, memorder) \
> > + atomic_store_explicit(ptr, val, memorder)
> > +
> > +#define rte_atomic_exchange_explicit(ptr, val, memorder) \
> > + atomic_exchange_explicit(ptr, val, memorder)
> > +
> > +#define rte_atomic_compare_exchange_strong_explicit( \
> > + ptr, expected, desired, succ_memorder, fail_memorder) \
> > + atomic_compare_exchange_strong_explicit( \
> > + ptr, expected, desired, succ_memorder, fail_memorder)
> > +
> > +#define rte_atomic_compare_exchange_weak_explicit( \
> > + ptr, expected, desired, succ_memorder, fail_memorder) \
> > + atomic_compare_exchange_strong_explicit( \
> > + ptr, expected, desired, succ_memorder, fail_memorder)
> > +
> > +#define rte_atomic_fetch_add_explicit(ptr, val, memorder) \
> > + atomic_fetch_add_explicit(ptr, val, memorder)
> > +
> > +#define rte_atomic_fetch_sub_explicit(ptr, val, memorder) \
> > + atomic_fetch_sub_explicit(ptr, val, memorder)
> > +
> > +#define rte_atomic_fetch_and_explicit(ptr, val, memorder) \
> > + atomic_fetch_and_explicit(ptr, val, memorder)
> > +
> > +#define rte_atomic_fetch_xor_explicit(ptr, val, memorder) \
> > + atomic_fetch_xor_explicit(ptr, val, memorder)
> > +
> > +#define rte_atomic_fetch_or_explicit(ptr, val, memorder) \
> > + atomic_fetch_or_explicit(ptr, val, memorder)
> > +
> > +#define rte_atomic_fetch_nand_explicit(ptr, val, memorder) \
> > + atomic_fetch_nand_explicit(ptr, val, memorder)
> > +
> > +#define rte_atomic_flag_test_and_set_explict(ptr, memorder) \
> > + atomic_flag_test_and_set_explicit(ptr, memorder)
> > +
> > +#define rte_atomic_flag_clear_explicit(ptr, memorder) \
> > + atomic_flag_clear(ptr, memorder)
> > +
> > +#else
> > +
> > +#define __rte_atomic
>
> Move the built-ins memory order type definition here:
>
> /* The memory order is an integer type in GCC built-ins,
> * not an enumerated type like in C11.
> */
> typedef int rte_memory_order;
>
> > +
> > +#define rte_memory_order_relaxed __ATOMIC_RELAXED
> > +#define rte_memory_order_consume __ATOMIC_CONSUME
> > +#define rte_memory_order_acquire __ATOMIC_ACQUIRE
> > +#define rte_memory_order_release __ATOMIC_RELEASE
> > +#define rte_memory_order_acq_rel __ATOMIC_ACQ_REL
> > +#define rte_memory_order_seq_cst __ATOMIC_SEQ_CST
>
> Agree; the memorder type is int, so no enum here.
>
> > +
> > +#define rte_atomic_load_explicit(ptr, memorder) \
> > + __atomic_load_n(ptr, memorder)
> > +
> > +#define rte_atomic_store_explicit(ptr, val, memorder) \
> > + __atomic_store_n(ptr, val, memorder)
> > +
> > +#define rte_atomic_exchange_explicit(ptr, val, memorder) \
> > + __atomic_exchange_n(ptr, val, memorder)
> > +
> > +#define rte_atomic_compare_exchange_strong_explicit( \
> > + ptr, expected, desired, succ_memorder, fail_memorder) \
> > + __atomic_compare_exchange_n( \
> > + ptr, expected, desired, 0, succ_memorder, fail_memorder)
> > +
> > +#define rte_atomic_compare_exchange_weak_explicit( \
> > + ptr, expected, desired, succ_memorder, fail_memorder) \
> > + __atomic_compare_exchange_n( \
> > + ptr, expected, desired, 1, succ_memorder, fail_memorder)
> > +
> > +#define rte_atomic_fetch_add_explicit(ptr, val, memorder) \
> > + __atomic_fetch_add(ptr, val, memorder)
> > +
> > +#define rte_atomic_fetch_sub_explicit(ptr, val, memorder) \
> > + __atomic_fetch_sub(ptr, val, memorder)
> > +
> > +#define rte_atomic_fetch_and_explicit(ptr, val, memorder) \
> > + __atomic_fetch_and(ptr, val, memorder)
> > +
> > +#define rte_atomic_fetch_xor_explicit(ptr, val, memorder) \
> > + __atomic_fetch_xor(ptr, val, memorder)
> > +
> > +#define rte_atomic_fetch_or_explicit(ptr, val, memorder) \
> > + __atomic_fetch_or(ptr, val, memorder)
> > +
> > +#define rte_atomic_fetch_nand_explicit(ptr, val, memorder) \
> > + __atomic_fetch_nand(ptr, val, memorder)
> > +
> > +#define rte_atomic_flag_test_and_set_explicit(ptr, memorder) \
> > + __atomic_test_and_set(ptr, memorder)
> > +
> > +#define rte_atomic_flag_clear_explicit(ptr, memorder) \
> > + __atomic_clear(ptr, memorder)
> > +
> > +#endif
> > +
> > +#ifdef __cplusplus
> > +}
> > +#endif
> > +
> > +#endif /* _RTE_STDATOMIC_H_ */
> > diff --git a/meson_options.txt b/meson_options.txt
> > index 621e1ca..7d6784d 100644
> > --- a/meson_options.txt
> > +++ b/meson_options.txt
> > @@ -46,6 +46,7 @@ option('mbuf_refcnt_atomic', type: 'boolean', value:
> > true, description:
> > 'Atomically access the mbuf refcnt.')
> > option('platform', type: 'string', value: 'native', description:
> > 'Platform to build, either "native", "generic" or a SoC. Please
> > refer to the Linux build guide for more information.')
> > +option('enable_stdatomic', type: 'boolean', value: false, description:
> > 'enable use of C11 stdatomic')
> > option('enable_trace_fp', type: 'boolean', value: false, description:
> > 'enable fast path trace points.')
> > option('tests', type: 'boolean', value: true, description:
> > --
> > 1.8.3.1
>
> From: Tyler Retzlaff [mailto:roretzla@linux.microsoft.com]
> Sent: Friday, 11 August 2023 17.55
>
> On Fri, Aug 11, 2023 at 11:42:12AM +0200, Morten Brørup wrote:
> > > From: Tyler Retzlaff [mailto:roretzla@linux.microsoft.com]
> > > Sent: Friday, 11 August 2023 03.32
> > >
> > > Provide API for atomic operations in the rte namespace that may
> > > optionally be configured to use C11 atomics with meson
> > > option enable_stdatomics=true
> > >
> > > Signed-off-by: Tyler Retzlaff <roretzla@linux.microsoft.com>
> > > ---
[...]
> >
> > Move the (changed) C11 memory order type definition here:
> >
> > /* The memory order is an enumerated type in C11. */
> > #define memory_order rte_memory_order
No objections to your typedef in v2.
[...]
> > > +#ifdef __ATOMIC_SEQ_CST
> > > +_Static_assert(rte_memory_order_seq_cst == __ATOMIC_SEQ_CST,
> > > + "rte_memory_order_seq_cst == __ATOMIC_SEQ_CST");
> > > +#endif
> >
> > Excellent idea adding these _Static_asserts!
> >
> > Have you tested (with the toolchain you are targeting with this
> _Static_assert) that e.g. __ATOMIC_RELAXED is actually #defined, so the
> preprocessor can see it? (I guess that being a built-it, it might not be a
> #define, it might be a magic value known by the compiler only.)
>
> * llvm and gcc both expose it as a built-in #define for test builds i
> have run. worst case the assert is lost if it isn't.
I only wanted to check that we didn't always hit the "worst case" where the static_assert is lost, so thank you for the confirmation regarding GCC/clang.
> * since i have to handle non-{clang,gcc} too i still guard with ifdef
Agree.
> * i do need to switch to using assert.h static_assert macro to
> inter-operate with c++ in v2
OK. I reviewed that in v2 too.
-Morten
@@ -303,6 +303,7 @@ endforeach
# set other values pulled from the build options
dpdk_conf.set('RTE_MAX_ETHPORTS', get_option('max_ethports'))
dpdk_conf.set('RTE_LIBEAL_USE_HPET', get_option('use_hpet'))
+dpdk_conf.set('RTE_ENABLE_STDATOMIC', get_option('enable_stdatomic'))
dpdk_conf.set('RTE_ENABLE_TRACE_FP', get_option('enable_trace_fp'))
# values which have defaults which may be overridden
dpdk_conf.set('RTE_MAX_VFIO_GROUPS', 64)
@@ -13,6 +13,7 @@
#define _RTE_CONFIG_H_
#include <rte_build_config.h>
+#include <rte_stdatomic.h>
/* legacy defines */
#ifdef RTE_EXEC_ENV_LINUX
@@ -43,6 +43,7 @@ headers += files(
'rte_seqlock.h',
'rte_service.h',
'rte_service_component.h',
+ 'rte_stdatomic.h',
'rte_string_fns.h',
'rte_tailq.h',
'rte_thread.h',
new file mode 100644
@@ -0,0 +1,162 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Microsoft Corporation
+ */
+
+#ifndef _RTE_STDATOMIC_H_
+#define _RTE_STDATOMIC_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int rte_memory_order;
+
+#ifdef RTE_ENABLE_STDATOMIC
+#ifdef __STDC_NO_ATOMICS__
+#error enable_stdatomics=true but atomics not supported by toolchain
+#endif
+
+#include <stdatomic.h>
+
+#define __rte_atomic _Atomic
+
+#define rte_memory_order_relaxed memory_order_relaxed
+#ifdef __ATOMIC_RELAXED
+_Static_assert(rte_memory_order_relaxed == __ATOMIC_RELAXED,
+ "rte_memory_order_relaxed == __ATOMIC_RELAXED");
+#endif
+
+#define rte_memory_order_consume memory_order_consume
+#ifdef __ATOMIC_CONSUME
+_Static_assert(rte_memory_order_consume == __ATOMIC_CONSUME,
+ "rte_memory_order_consume == __ATOMIC_CONSUME");
+#endif
+
+#define rte_memory_order_acquire memory_order_acquire
+#ifdef __ATOMIC_ACQUIRE
+_Static_assert(rte_memory_order_acquire == __ATOMIC_ACQUIRE,
+ "rte_memory_order_acquire == __ATOMIC_ACQUIRE");
+#endif
+
+#define rte_memory_order_release memory_order_release
+#ifdef __ATOMIC_RELEASE
+_Static_assert(rte_memory_order_release == __ATOMIC_RELEASE,
+ "rte_memory_order_release == __ATOMIC_RELEASE");
+#endif
+
+#define rte_memory_order_acq_rel memory_order_acq_rel
+#ifdef __ATOMIC_ACQ_REL
+_Static_assert(rte_memory_order_acq_rel == __ATOMIC_ACQ_REL,
+ "rte_memory_order_acq_rel == __ATOMIC_ACQ_REL");
+#endif
+
+#define rte_memory_order_seq_cst memory_order_seq_cst
+#ifdef __ATOMIC_SEQ_CST
+_Static_assert(rte_memory_order_seq_cst == __ATOMIC_SEQ_CST,
+ "rte_memory_order_seq_cst == __ATOMIC_SEQ_CST");
+#endif
+
+#define rte_atomic_load_explicit(ptr, memorder) \
+ atomic_load_explicit(ptr, memorder)
+
+#define rte_atomic_store_explicit(ptr, val, memorder) \
+ atomic_store_explicit(ptr, val, memorder)
+
+#define rte_atomic_exchange_explicit(ptr, val, memorder) \
+ atomic_exchange_explicit(ptr, val, memorder)
+
+#define rte_atomic_compare_exchange_strong_explicit( \
+ ptr, expected, desired, succ_memorder, fail_memorder) \
+ atomic_compare_exchange_strong_explicit( \
+ ptr, expected, desired, succ_memorder, fail_memorder)
+
+#define rte_atomic_compare_exchange_weak_explicit( \
+ ptr, expected, desired, succ_memorder, fail_memorder) \
+ atomic_compare_exchange_strong_explicit( \
+ ptr, expected, desired, succ_memorder, fail_memorder)
+
+#define rte_atomic_fetch_add_explicit(ptr, val, memorder) \
+ atomic_fetch_add_explicit(ptr, val, memorder)
+
+#define rte_atomic_fetch_sub_explicit(ptr, val, memorder) \
+ atomic_fetch_sub_explicit(ptr, val, memorder)
+
+#define rte_atomic_fetch_and_explicit(ptr, val, memorder) \
+ atomic_fetch_and_explicit(ptr, val, memorder)
+
+#define rte_atomic_fetch_xor_explicit(ptr, val, memorder) \
+ atomic_fetch_xor_explicit(ptr, val, memorder)
+
+#define rte_atomic_fetch_or_explicit(ptr, val, memorder) \
+ atomic_fetch_or_explicit(ptr, val, memorder)
+
+#define rte_atomic_fetch_nand_explicit(ptr, val, memorder) \
+ atomic_fetch_nand_explicit(ptr, val, memorder)
+
+#define rte_atomic_flag_test_and_set_explict(ptr, memorder) \
+ atomic_flag_test_and_set_explicit(ptr, memorder)
+
+#define rte_atomic_flag_clear_explicit(ptr, memorder) \
+ atomic_flag_clear(ptr, memorder)
+
+#else
+
+#define __rte_atomic
+
+#define rte_memory_order_relaxed __ATOMIC_RELAXED
+#define rte_memory_order_consume __ATOMIC_CONSUME
+#define rte_memory_order_acquire __ATOMIC_ACQUIRE
+#define rte_memory_order_release __ATOMIC_RELEASE
+#define rte_memory_order_acq_rel __ATOMIC_ACQ_REL
+#define rte_memory_order_seq_cst __ATOMIC_SEQ_CST
+
+#define rte_atomic_load_explicit(ptr, memorder) \
+ __atomic_load_n(ptr, memorder)
+
+#define rte_atomic_store_explicit(ptr, val, memorder) \
+ __atomic_store_n(ptr, val, memorder)
+
+#define rte_atomic_exchange_explicit(ptr, val, memorder) \
+ __atomic_exchange_n(ptr, val, memorder)
+
+#define rte_atomic_compare_exchange_strong_explicit( \
+ ptr, expected, desired, succ_memorder, fail_memorder) \
+ __atomic_compare_exchange_n( \
+ ptr, expected, desired, 0, succ_memorder, fail_memorder)
+
+#define rte_atomic_compare_exchange_weak_explicit( \
+ ptr, expected, desired, succ_memorder, fail_memorder) \
+ __atomic_compare_exchange_n( \
+ ptr, expected, desired, 1, succ_memorder, fail_memorder)
+
+#define rte_atomic_fetch_add_explicit(ptr, val, memorder) \
+ __atomic_fetch_add(ptr, val, memorder)
+
+#define rte_atomic_fetch_sub_explicit(ptr, val, memorder) \
+ __atomic_fetch_sub(ptr, val, memorder)
+
+#define rte_atomic_fetch_and_explicit(ptr, val, memorder) \
+ __atomic_fetch_and(ptr, val, memorder)
+
+#define rte_atomic_fetch_xor_explicit(ptr, val, memorder) \
+ __atomic_fetch_xor(ptr, val, memorder)
+
+#define rte_atomic_fetch_or_explicit(ptr, val, memorder) \
+ __atomic_fetch_or(ptr, val, memorder)
+
+#define rte_atomic_fetch_nand_explicit(ptr, val, memorder) \
+ __atomic_fetch_nand(ptr, val, memorder)
+
+#define rte_atomic_flag_test_and_set_explicit(ptr, memorder) \
+ __atomic_test_and_set(ptr, memorder)
+
+#define rte_atomic_flag_clear_explicit(ptr, memorder) \
+ __atomic_clear(ptr, memorder)
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_STDATOMIC_H_ */
@@ -46,6 +46,7 @@ option('mbuf_refcnt_atomic', type: 'boolean', value: true, description:
'Atomically access the mbuf refcnt.')
option('platform', type: 'string', value: 'native', description:
'Platform to build, either "native", "generic" or a SoC. Please refer to the Linux build guide for more information.')
+option('enable_stdatomic', type: 'boolean', value: false, description: 'enable use of C11 stdatomic')
option('enable_trace_fp', type: 'boolean', value: false, description:
'enable fast path trace points.')
option('tests', type: 'boolean', value: true, description: