[PATCHv2] linux-generic: odp_atomic_internal.h: more atomic types

Message ID 1420664191-9848-1-git-send-email-ola.liljedahl@linaro.org
State New
Headers show

Commit Message

Ola Liljedahl Jan. 7, 2015, 8:56 p.m.
Limited support (swap, cas) for 128-bit atomic types and operations,
conditionally enabled if and when the compiler supports it.
Changed some return types from int to odp_bool_t to better match the
semantics of the returned values.

Signed-off-by: Ola Liljedahl <ola.liljedahl@linaro.org>
---
(This document/code contribution attached is provided under the terms of
agreement LES-LTM-21309)
This is actually v2 of patch 1/2 from 2014-12-01. Patch 2/2 became the
separate timer patch set.
The 128-bit atomics support is optionally needed by the new lock-less
timer implementation.

 .../linux-generic/include/odp_atomic_internal.h    | 73 +++++++++++++++++++---
 1 file changed, 65 insertions(+), 8 deletions(-)

Patch

diff --git a/platform/linux-generic/include/odp_atomic_internal.h b/platform/linux-generic/include/odp_atomic_internal.h
index dafa222..91d2c3e 100644
--- a/platform/linux-generic/include/odp_atomic_internal.h
+++ b/platform/linux-generic/include/odp_atomic_internal.h
@@ -146,7 +146,7 @@  static inline uint32_t _odp_atomic_u32_xchg_mm(odp_atomic_u32_t *atom,
  * @retval 1 exchange successul
  * @retval 0 exchange failed and '*exp' updated with current value
  */
-static inline int _odp_atomic_u32_cmp_xchg_strong_mm(
+static inline odp_bool_t _odp_atomic_u32_cmp_xchg_strong_mm(
 		odp_atomic_u32_t *atom,
 		uint32_t *exp,
 		uint32_t val,
@@ -304,7 +304,6 @@  static inline void _odp_atomic_u64_store_mm(odp_atomic_u64_t *atom,
 static inline uint64_t _odp_atomic_u64_xchg_mm(odp_atomic_u64_t *atom,
 		uint64_t val,
 		_odp_memmodel_t mmodel)
-
 {
 #if !defined __GCC_ATOMIC_LLONG_LOCK_FREE ||  __GCC_ATOMIC_LLONG_LOCK_FREE < 2
 	return ATOMIC_OP_MM(atom, atom->v = val, mmodel);
@@ -328,7 +327,8 @@  static inline uint64_t _odp_atomic_u64_xchg_mm(odp_atomic_u64_t *atom,
  * @retval 1 exchange successful
  * @retval 0 exchange failed and '*exp' updated with current value
  */
-static inline int _odp_atomic_u64_cmp_xchg_strong_mm(odp_atomic_u64_t *atom,
+static inline
+odp_bool_t _odp_atomic_u64_cmp_xchg_strong_mm(odp_atomic_u64_t *atom,
 		uint64_t *exp,
 		uint64_t val,
 		_odp_memmodel_t success,
@@ -389,7 +389,6 @@  static inline uint64_t _odp_atomic_u64_fetch_add_mm(odp_atomic_u64_t *atom,
 static inline void _odp_atomic_u64_add_mm(odp_atomic_u64_t *atom,
 		uint64_t val,
 		_odp_memmodel_t mmodel)
-
 {
 #if !defined __GCC_ATOMIC_LLONG_LOCK_FREE ||  __GCC_ATOMIC_LLONG_LOCK_FREE < 2
 	(void)ATOMIC_OP_MM(atom, atom->v += val, mmodel);
@@ -428,7 +427,6 @@  static inline uint64_t _odp_atomic_u64_fetch_sub_mm(odp_atomic_u64_t *atom,
 static inline void _odp_atomic_u64_sub_mm(odp_atomic_u64_t *atom,
 		uint64_t val,
 		_odp_memmodel_t mmodel)
-
 {
 #if !defined __GCC_ATOMIC_LLONG_LOCK_FREE ||  __GCC_ATOMIC_LLONG_LOCK_FREE < 2
 	(void)ATOMIC_OP_MM(atom, atom->v -= val, mmodel);
@@ -519,7 +517,7 @@  static inline void *_odp_atomic_ptr_xchg(_odp_atomic_ptr_t *atom,
  * @retval 1 exchange successful
  * @retval 0 exchange failed and '*exp' updated with current value
  */
-static inline int _odp_atomic_ptr_cmp_xchg_strong(
+static inline odp_bool_t _odp_atomic_ptr_cmp_xchg_strong(
 		_odp_atomic_ptr_t *atom,
 		void **exp,
 		void *val,
@@ -542,7 +540,7 @@  static inline int _odp_atomic_ptr_cmp_xchg_strong(
  *****************************************************************************/
 
 /**
- * Initialize a flag atomic variable
+ * Initialize an atomic flag variable
  *
  * @param[out] flag Pointer to a flag atomic variable
  * @param val The initial value of the variable
@@ -570,7 +568,8 @@  static inline int _odp_atomic_flag_load(_odp_atomic_flag_t *flag)
 /**
  * Test-and-set of atomic flag variable
  * @Note Operation has acquire semantics. It pairs with a later
- * release operation.
+ * release operation in some thread. It does not provide release or
+ * acquire/release semantics.
  *
  * @param[in,out] flag Pointer to a flag atomic variable
  *
@@ -595,6 +594,64 @@  static inline void _odp_atomic_flag_clear(_odp_atomic_flag_t *flag)
 	__atomic_clear(flag, __ATOMIC_RELEASE);
 }
 
+/* Check if target and compiler supports 128-bit scalars and corresponding
+ * exchange and CAS operations */
+/* GCC on x86-64 needs -mcx16 compiler option */
+#if defined __SIZEOF_INT128__ && defined __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16
+
+/** Preprocessor symbol that indicates support for 128-bit atomics */
+#define ODP_ATOMIC_U128
+
+/** An unsigned 128-bit (16-byte) scalar type */
+typedef __int128 _uint128_t;
+
+/** Atomic 128-bit type */
+typedef struct {
+	_uint128_t v; /**< Actual storage for the atomic variable */
+} _odp_atomic_u128_t ODP_ALIGNED(16);
+
+/**
+ * 16-byte atomic exchange operation
+ *
+ * @param ptr   Pointer to a 16-byte atomic variable
+ * @param val   Pointer to new value to write
+ * @param old   Pointer to location for old value
+ * @param       mmodel Memory model associated with the exchange operation
+ */
+static inline void _odp_atomic_u128_xchg_mm(_odp_atomic_u128_t *ptr,
+		_uint128_t *val,
+		_uint128_t *old,
+		_odp_memmodel_t mm)
+{
+	__atomic_exchange(&ptr->v, val, old, mm);
+}
+
+/**
+ * Atomic compare and exchange (swap) of 16-byte atomic variable
+ * "Strong" semantics, will not fail spuriously.
+ *
+ * @param ptr   Pointer to a 16-byte atomic variable
+ * @param exp   Pointer to expected value (updated on failure)
+ * @param val   Pointer to new value to write
+ * @param succ  Memory model associated with a successful compare-and-swap
+ * operation
+ * @param fail  Memory model associated with a failed compare-and-swap
+ * operation
+ *
+ * @retval 1 exchange successul
+ * @retval 0 exchange failed and '*exp' updated with current value
+ */
+static inline odp_bool_t _odp_atomic_u128_cmp_xchg_mm(_odp_atomic_u128_t *ptr,
+		_uint128_t *exp,
+		_uint128_t *val,
+		_odp_memmodel_t succ,
+		_odp_memmodel_t fail)
+{
+	return __atomic_compare_exchange(&ptr->v, exp, val,
+			false/*strong*/, succ, fail);
+}
+#endif
+
 /**
  * @}
  */