aboutsummaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
authorPetri Savolainen <petri.savolainen@nokia.com>2015-10-23 10:00:19 +0300
committerMaxim Uvarov <maxim.uvarov@linaro.org>2016-02-08 20:45:24 +0300
commit2145a338867f41b37acfb204807891d39002f2aa (patch)
tree985d4d116eae842d3f7d39fff33b86eb240a2fc3 /platform
parent2c4f0006c83a17ab910ff275f3fbe8a468be6e5c (diff)
api: atomic: added cas operations
Added cas operations for 32 and 64 bit atomic variables. These use relaxed memory order (as all other operations). Signed-off-by: Petri Savolainen <petri.savolainen@nokia.com> Reviewed-by: Mike Holmes <mike.holmes@linaro.org> Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
Diffstat (limited to 'platform')
-rw-r--r--platform/linux-generic/include/odp/atomic.h24
-rw-r--r--platform/linux-generic/include/odp/plat/atomic_types.h21
2 files changed, 42 insertions, 3 deletions
diff --git a/platform/linux-generic/include/odp/atomic.h b/platform/linux-generic/include/odp/atomic.h
index 10cf361b4..7d67bf54b 100644
--- a/platform/linux-generic/include/odp/atomic.h
+++ b/platform/linux-generic/include/odp/atomic.h
@@ -84,6 +84,15 @@ static inline void odp_atomic_dec_u32(odp_atomic_u32_t *atom)
(void)__atomic_fetch_sub(&atom->v, 1, __ATOMIC_RELAXED);
}
+static inline int odp_atomic_cas_u32(odp_atomic_u32_t *atom, uint32_t *old_val,
+ uint32_t new_val)
+{
+ return __atomic_compare_exchange_n(&atom->v, old_val, new_val,
+ 0 /* strong */,
+ __ATOMIC_RELAXED,
+ __ATOMIC_RELAXED);
+}
+
static inline void odp_atomic_init_u64(odp_atomic_u64_t *atom, uint64_t val)
{
atom->v = val;
@@ -185,6 +194,21 @@ static inline void odp_atomic_dec_u64(odp_atomic_u64_t *atom)
#endif
}
+static inline int odp_atomic_cas_u64(odp_atomic_u64_t *atom, uint64_t *old_val,
+ uint64_t new_val)
+{
+#if __GCC_ATOMIC_LLONG_LOCK_FREE < 2
+ int ret;
+ *old_val = ATOMIC_OP(atom, ATOMIC_CAS_OP(&ret, *old_val, new_val));
+ return ret;
+#else
+ return __atomic_compare_exchange_n(&atom->v, old_val, new_val,
+ 0 /* strong */,
+ __ATOMIC_RELAXED,
+ __ATOMIC_RELAXED);
+#endif
+}
+
/**
* @}
*/
diff --git a/platform/linux-generic/include/odp/plat/atomic_types.h b/platform/linux-generic/include/odp/plat/atomic_types.h
index 0fe15ed13..bc0bd8bfe 100644
--- a/platform/linux-generic/include/odp/plat/atomic_types.h
+++ b/platform/linux-generic/include/odp/plat/atomic_types.h
@@ -43,6 +43,21 @@ struct odp_atomic_u32_s {
} ODP_ALIGNED(sizeof(uint32_t)); /* Enforce alignement! */;
#if __GCC_ATOMIC_LLONG_LOCK_FREE < 2
+
+/**
+ * @internal
+ * CAS operation expression for the ATOMIC_OP macro
+ */
+#define ATOMIC_CAS_OP(ret_ptr, old_val, new_val) \
+({ \
+ if (atom->v == (old_val)) { \
+ atom->v = (new_val); \
+ *(ret_ptr) = 1; \
+ } else { \
+ *(ret_ptr) = 0; \
+ } \
+})
+
/**
* @internal
* Helper macro for lock-based atomic operations on 64-bit integers
@@ -52,14 +67,14 @@ struct odp_atomic_u32_s {
*/
#define ATOMIC_OP(atom, expr) \
({ \
- uint64_t old_val; \
+ uint64_t _old_val; \
/* Loop while lock is already taken, stop when lock becomes clear */ \
while (__atomic_test_and_set(&(atom)->lock, __ATOMIC_ACQUIRE)) \
(void)0; \
- old_val = (atom)->v; \
+ _old_val = (atom)->v; \
(expr); /* Perform whatever update is desired */ \
__atomic_clear(&(atom)->lock, __ATOMIC_RELEASE); \
- old_val; /* Return old value */ \
+ _old_val; /* Return old value */ \
})
#endif