diff options
Diffstat (limited to 'include/odp/api/spec/atomic.h')
-rw-r--r-- | include/odp/api/spec/atomic.h | 177 |
1 files changed, 153 insertions, 24 deletions
diff --git a/include/odp/api/spec/atomic.h b/include/odp/api/spec/atomic.h index 408829df2..3a098ead1 100644 --- a/include/odp/api/spec/atomic.h +++ b/include/odp/api/spec/atomic.h @@ -1,7 +1,6 @@ -/* Copyright (c) 2013, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) 2013-2018 Linaro Limited + * Copyright (c) 2021 ARM Limited */ /** @@ -10,8 +9,8 @@ * ODP atomic operations */ -#ifndef ODP_API_ATOMIC_H_ -#define ODP_API_ATOMIC_H_ +#ifndef ODP_API_SPEC_ATOMIC_H_ +#define ODP_API_SPEC_ATOMIC_H_ #include <odp/visibility_begin.h> #ifdef __cplusplus @@ -20,16 +19,18 @@ extern "C" { /** * @defgroup odp_atomic ODP ATOMIC + * Atomic variables. + * * @details * <b> Atomic integers using relaxed memory ordering </b> * - * Atomic integer types (odp_atomic_u32_t and odp_atomic_u64_t) can be used to - * implement e.g. shared counters. If not otherwise documented, operations in - * this API are implemented using <b> RELAXED memory ordering </b> (see memory - * order descriptions in the C11 specification). Relaxed operations do not - * provide synchronization or ordering for other memory accesses (initiated - * before or after the operation), only atomicity of the operation itself is - * guaranteed. + * Atomic integer types (odp_atomic_u32_t, odp_atomic_u64_t and + * odp_atomic_u128_t) can be used to implement e.g. shared counters. If not + * otherwise documented, operations in this API are implemented using + * <b> RELAXED memory ordering </b> (see memory order descriptions in + * the C11 specification). Relaxed operations do not provide synchronization or + * ordering for other memory accesses (initiated before or after the operation), + * only atomicity of the operation itself is guaranteed. * * <b> Operations with non-relaxed memory ordering </b> * @@ -52,6 +53,9 @@ extern "C" { */ /** + * @typedef odp_atomic_u128_t + * Atomic 128-bit unsigned integer + * * @typedef odp_atomic_u64_t * Atomic 64-bit unsigned integer * @@ -187,9 +191,10 @@ void odp_atomic_min_u32(odp_atomic_u32_t *atom, uint32_t new_min); * Compare and swap atomic uint32 variable * * Compares value of atomic variable to the value pointed by 'old_val'. - * If values are equal, the operation writes 'new_val' into the atomic variable - * and returns success. If they are not equal, the operation writes current - * value of atomic variable into 'old_val' and returns failure. + * If the values are equal, the operation writes 'new_val' into the atomic variable + * and returns success. The operation returns failure only when the values are + * not equal (strong CAS operation). The current value of atomic variable is written + * into 'old_val' on failure. * * @param atom Pointer to atomic variable * @param[in,out] old_val Pointer to the old value of the atomic variable. @@ -197,10 +202,8 @@ void odp_atomic_min_u32(odp_atomic_u32_t *atom, uint32_t new_min); * @param new_val New value to be written into the atomic variable * * @return 0 on failure, !0 on success - * */ -int odp_atomic_cas_u32(odp_atomic_u32_t *atom, uint32_t *old_val, - uint32_t new_val); +int odp_atomic_cas_u32(odp_atomic_u32_t *atom, uint32_t *old_val, uint32_t new_val); /** * Exchange value of atomic uint32 variable @@ -343,9 +346,10 @@ void odp_atomic_min_u64(odp_atomic_u64_t *atom, uint64_t new_min); * Compare and swap atomic uint64 variable * * Compares value of atomic variable to the value pointed by 'old_val'. - * If values are equal, the operation writes 'new_val' into the atomic variable - * and returns success. If they are not equal, the operation writes current - * value of atomic variable into 'old_val' and returns failure. + * If the values are equal, the operation writes 'new_val' into the atomic variable + * and returns success. The operation returns failure only when the values are + * not equal (strong CAS operation). The current value of atomic variable is written + * into 'old_val' on failure. * * @param atom Pointer to atomic variable * @param[in,out] old_val Pointer to the old value of the atomic variable. @@ -354,8 +358,7 @@ void odp_atomic_min_u64(odp_atomic_u64_t *atom, uint64_t new_min); * * @return 0 on failure, !0 on success */ -int odp_atomic_cas_u64(odp_atomic_u64_t *atom, uint64_t *old_val, - uint64_t new_val); +int odp_atomic_cas_u64(odp_atomic_u64_t *atom, uint64_t *old_val, uint64_t new_val); /** * Exchange value of atomic uint64 variable @@ -371,6 +374,58 @@ int odp_atomic_cas_u64(odp_atomic_u64_t *atom, uint64_t *old_val, uint64_t odp_atomic_xchg_u64(odp_atomic_u64_t *atom, uint64_t new_val); /* + * 128-bit operations in RELAXED memory ordering + * -------------------------------------------- + */ + +/** + * Initialize atomic odp_u128_t variable + * + * Initializes the atomic variable with 'val'. This operation is not atomic. + * Application must ensure that there's no race condition while initializing + * the variable. + * + * @param atom Pointer to atomic variable + * @param val Value to initialize the variable with + */ +void odp_atomic_init_u128(odp_atomic_u128_t *atom, odp_u128_t val); + +/** + * Load value of atomic odp_u128_t variable + * + * @param atom Pointer to atomic variable + * + * @return Value of the variable + */ +odp_u128_t odp_atomic_load_u128(odp_atomic_u128_t *atom); + +/** + * Store value to atomic odp_u128_t variable + * + * @param atom Pointer to atomic variable + * @param val Value to store in the variable + */ +void odp_atomic_store_u128(odp_atomic_u128_t *atom, odp_u128_t val); + +/** + * Compare and swap atomic odp_u128_t variable + * + * Compares value of atomic variable to the value pointed by 'old_val'. + * If the values are equal, the operation writes 'new_val' into the atomic variable + * and returns success. The operation returns failure only when the values are + * not equal (strong CAS operation). The current value of atomic variable is written + * into 'old_val' on failure. + * + * @param atom Pointer to atomic variable + * @param[in,out] old_val Pointer to the old value of the atomic variable. + * Operation updates this value on failure. + * @param new_val New value to be written into the atomic variable + * + * @return 0 on failure, !0 on success + */ +int odp_atomic_cas_u128(odp_atomic_u128_t *atom, odp_u128_t *old_val, odp_u128_t new_val); + +/* * 32-bit operations in non-RELAXED memory ordering * ------------------------------------------------ */ @@ -620,6 +675,80 @@ typedef union odp_atomic_op_t { */ int odp_atomic_lock_free_u64(odp_atomic_op_t *atomic_op); +/* + * 128-bit operations in non-RELAXED memory ordering + * ------------------------------------------------ + */ + +/** + * Compare and swap atomic odp_u128_t variable using ACQUIRE memory ordering + * + * Otherwise identical to odp_atomic_cas_u128() but ensures ACQUIRE memory + * ordering on success. Memory ordering is RELAXED on failure. + * + * @param atom Pointer to atomic variable + * @param[in,out] old_val Pointer to the old value of the atomic variable. + * Operation updates this value on failure. + * @param new_val New value to be written into the atomic variable + * + * @return 0 on failure, !0 on success + */ +int odp_atomic_cas_acq_u128(odp_atomic_u128_t *atom, odp_u128_t *old_val, + odp_u128_t new_val); + +/** + * Compare and swap atomic odp_u128_t variable using RELEASE memory ordering + * + * Otherwise identical to odp_atomic_cas_u128() but ensures RELEASE memory + * ordering on success. Memory ordering is RELAXED on failure. + * + * @param atom Pointer to atomic variable + * @param[in,out] old_val Pointer to the old value of the atomic variable. + * Operation updates this value on failure. + * @param new_val New value to be written into the atomic variable + * + * @return 0 on failure, !0 on success + */ +int odp_atomic_cas_rel_u128(odp_atomic_u128_t *atom, odp_u128_t *old_val, + odp_u128_t new_val); + +/** + * Compare and swap atomic odp_u128_t variable using ACQUIRE-and-RELEASE memory + * ordering + * + * Otherwise identical to odp_atomic_cas_u128() but ensures ACQUIRE-and-RELEASE + * memory ordering on success. Memory ordering is RELAXED on failure. + * + * @param atom Pointer to atomic variable + * @param[in,out] old_val Pointer to the old value of the atomic variable. + * Operation updates this value on failure. + * @param new_val New value to be written into the atomic variable + * + * @return 0 on failure, !0 on success + */ +int odp_atomic_cas_acq_rel_u128(odp_atomic_u128_t *atom, odp_u128_t *old_val, + odp_u128_t new_val); + +/** + * Query which atomic odp_atomic_u128_t operations are lock-free + * + * Lock-free implementations have higher performance and scale better than + * implementations using locks. + * + * Init operations (e.g. odp_atomic_init_u128()) are not atomic. This function + * clears the op.init bit but will never set it to one. + * + * Note: 128-bit atomic API includes only init, load, store and CAS operations. + * + * @param atomic_op Pointer to atomic operation structure for storing + * operation flags. All bits are initialized to zero during + * the operation. The parameter is ignored when NULL. + * @retval 0 None of the 128-bit atomic operations are lock-free + * @retval 1 Some of the 128-bit atomic operations are lock-free + * @retval 2 All 128-bit atomic operations are lock-free + */ +int odp_atomic_lock_free_u128(odp_atomic_op_t *atomic_op); + /** * @} */ |