*/
#define rte_rmb() asm volatile("lfence;" : : : "memory")
+#include <emmintrin.h>
+
/**
* @file
* Atomic Operations on x86_64
static inline int
rte_atomic16_cmpset(volatile uint16_t *dst, uint16_t exp, uint16_t src)
{
+#ifndef RTE_FORCE_INTRINSICS
uint8_t res;
asm volatile(
"m" (*dst)
: "memory"); /* no-clobber list */
return res;
+#else
+ return __sync_bool_compare_and_swap(dst, exp, src);
+#endif
}
/**
static inline void
rte_atomic16_inc(rte_atomic16_t *v)
{
+#ifndef RTE_FORCE_INTRINSICS
asm volatile(
MPLOCKED
"incw %[cnt]"
: [cnt] "=m" (v->cnt) /* output */
: "m" (v->cnt) /* input */
);
+#else
+ rte_atomic16_add(v, 1);
+#endif
}
/**
static inline void
rte_atomic16_dec(rte_atomic16_t *v)
{
+#ifndef RTE_FORCE_INTRINSICS
asm volatile(
MPLOCKED
"decw %[cnt]"
: [cnt] "=m" (v->cnt) /* output */
: "m" (v->cnt) /* input */
);
+#else
+ rte_atomic16_sub(v, 1);
+#endif
}
/**
*/
static inline int rte_atomic16_inc_and_test(rte_atomic16_t *v)
{
+#ifndef RTE_FORCE_INTRINSICS
uint8_t ret;
asm volatile(
[ret] "=qm" (ret)
);
return (ret != 0);
+#else
+ return (__sync_add_and_fetch(&v->cnt, 1) == 0);
+#endif
}
/**
*/
static inline int rte_atomic16_dec_and_test(rte_atomic16_t *v)
{
+#ifndef RTE_FORCE_INTRINSICS
uint8_t ret;
asm volatile(MPLOCKED
[ret] "=qm" (ret)
);
return (ret != 0);
+#else
+ return (__sync_sub_and_fetch(&v->cnt, 1) == 0);
+#endif
}
/**
static inline int
rte_atomic32_cmpset(volatile uint32_t *dst, uint32_t exp, uint32_t src)
{
+#ifndef RTE_FORCE_INTRINSICS
uint8_t res;
asm volatile(
"m" (*dst)
: "memory"); /* no-clobber list */
return res;
+#else
+ return __sync_bool_compare_and_swap(dst, exp, src);
+#endif
}
/**
static inline void
rte_atomic32_inc(rte_atomic32_t *v)
{
+#ifndef RTE_FORCE_INTRINSICS
asm volatile(
MPLOCKED
"incl %[cnt]"
: [cnt] "=m" (v->cnt) /* output */
: "m" (v->cnt) /* input */
);
+#else
+ rte_atomic32_add(v, 1);
+#endif
}
/**
static inline void
rte_atomic32_dec(rte_atomic32_t *v)
{
+#ifndef RTE_FORCE_INTRINSICS
asm volatile(
MPLOCKED
"decl %[cnt]"
: [cnt] "=m" (v->cnt) /* output */
: "m" (v->cnt) /* input */
);
+#else
+ rte_atomic32_sub(v,1);
+#endif
}
/**
*/
static inline int rte_atomic32_inc_and_test(rte_atomic32_t *v)
{
+#ifndef RTE_FORCE_INTRINSICS
uint8_t ret;
asm volatile(
[ret] "=qm" (ret)
);
return (ret != 0);
+#else
+ return (__sync_add_and_fetch(&v->cnt, 1) == 0);
+#endif
}
/**
*/
static inline int rte_atomic32_dec_and_test(rte_atomic32_t *v)
{
+#ifndef RTE_FORCE_INTRINSICS
uint8_t ret;
asm volatile(MPLOCKED
[ret] "=qm" (ret)
);
return (ret != 0);
+#else
+ return (__sync_sub_and_fetch(&v->cnt, 1) == 0);
+#endif
}
/**
v->cnt = 0;
}
+#ifndef RTE_FORCE_INTRINSICS
/* any other functions are in arch specific files */
#include "arch/rte_atomic.h"
#endif /* __DOXYGEN__ */
+#else /*RTE_FORCE_INTRINSICS */
+
+/*------------------------- 64 bit atomic operations -------------------------*/
+
+/**
+ * An atomic compare and set function used by the mutex functions.
+ * (atomic) equivalent to:
+ * if (*dst == exp)
+ * *dst = src (all 64-bit words)
+ *
+ * @param dst
+ * The destination into which the value will be written.
+ * @param exp
+ * The expected value.
+ * @param src
+ * The new value.
+ * @return
+ * Non-zero on success; 0 on failure.
+ */
+static inline int
+rte_atomic64_cmpset(volatile uint64_t *dst, uint64_t exp, uint64_t src)
+{
+ return __sync_bool_compare_and_swap(dst, exp, src);
+}
+
+/**
+ * The atomic counter structure.
+ */
+typedef struct {
+ volatile int64_t cnt; /**< Internal counter value. */
+} rte_atomic64_t;
+
+/**
+ * Static initializer for an atomic counter.
+ */
+#define RTE_ATOMIC64_INIT(val) { (val) }
+
+/**
+ * Initialize the atomic counter.
+ *
+ * @param v
+ * A pointer to the atomic counter.
+ */
+static inline void
+rte_atomic64_init(rte_atomic64_t *v)
+{
+#ifdef __LP64__
+ v->cnt = 0;
+#else
+ int success = 0;
+ uint64_t tmp;
+
+ while (success == 0) {
+ tmp = v->cnt;
+ success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
+ tmp, 0);
+ }
+#endif
+}
+
+/**
+ * Atomically read a 64-bit counter.
+ *
+ * @param v
+ * A pointer to the atomic counter.
+ * @return
+ * The value of the counter.
+ */
+static inline int64_t
+rte_atomic64_read(rte_atomic64_t *v)
+{
+#ifdef __LP64__
+ return v->cnt;
+#else
+ int success = 0;
+ uint64_t tmp;
+
+ while (success == 0) {
+ tmp = v->cnt;
+ /* replace the value by itself */
+ success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
+ tmp, tmp);
+ }
+ return tmp;
+#endif
+}
+
+/**
+ * Atomically set a 64-bit counter.
+ *
+ * @param v
+ * A pointer to the atomic counter.
+ * @param new_value
+ * The new value of the counter.
+ */
+static inline void
+rte_atomic64_set(rte_atomic64_t *v, int64_t new_value)
+{
+#ifdef __LP64__
+ v->cnt = new_value;
+#else
+ int success = 0;
+ uint64_t tmp;
+
+ while (success == 0) {
+ tmp = v->cnt;
+ success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
+ tmp, new_value);
+ }
+#endif
+}
+
+/**
+ * Atomically add a 64-bit value to a counter.
+ *
+ * @param v
+ * A pointer to the atomic counter.
+ * @param inc
+ * The value to be added to the counter.
+ */
+static inline void
+rte_atomic64_add(rte_atomic64_t *v, int64_t inc)
+{
+ __sync_fetch_and_add(&v->cnt, inc);
+}
+
+/**
+ * Atomically subtract a 64-bit value from a counter.
+ *
+ * @param v
+ * A pointer to the atomic counter.
+ * @param dec
+ * The value to be substracted from the counter.
+ */
+static inline void
+rte_atomic64_sub(rte_atomic64_t *v, int64_t dec)
+{
+ __sync_fetch_and_sub(&v->cnt, dec);
+}
+
+/**
+ * Atomically increment a 64-bit counter by one and test.
+ *
+ * @param v
+ * A pointer to the atomic counter.
+ */
+static inline void
+rte_atomic64_inc(rte_atomic64_t *v)
+{
+ rte_atomic64_add(v, 1);
+}
+
+/**
+ * Atomically decrement a 64-bit counter by one and test.
+ *
+ * @param v
+ * A pointer to the atomic counter.
+ */
+static inline void
+rte_atomic64_dec(rte_atomic64_t *v)
+{
+ rte_atomic64_sub(v, 1);
+}
+
+/**
+ * Add a 64-bit value to an atomic counter and return the result.
+ *
+ * Atomically adds the 64-bit value (inc) to the atomic counter (v) and
+ * returns the value of v after the addition.
+ *
+ * @param v
+ * A pointer to the atomic counter.
+ * @param inc
+ * The value to be added to the counter.
+ * @return
+ * The value of v after the addition.
+ */
+static inline int64_t
+rte_atomic64_add_return(rte_atomic64_t *v, int64_t inc)
+{
+ return __sync_add_and_fetch(&v->cnt, inc);
+}
+
+/**
+ * Subtract a 64-bit value from an atomic counter and return the result.
+ *
+ * Atomically subtracts the 64-bit value (dec) from the atomic counter (v)
+ * and returns the value of v after the substraction.
+ *
+ * @param v
+ * A pointer to the atomic counter.
+ * @param dec
+ * The value to be substracted from the counter.
+ * @return
+ * The value of v after the substraction.
+ */
+static inline int64_t
+rte_atomic64_sub_return(rte_atomic64_t *v, int64_t dec)
+{
+ return __sync_sub_and_fetch(&v->cnt, dec);
+}
+
+/**
+ * Atomically increment a 64-bit counter by one and test.
+ *
+ * Atomically increments the atomic counter (v) by one and returns
+ * true if the result is 0, or false in all other cases.
+ *
+ * @param v
+ * A pointer to the atomic counter.
+ * @return
+ * True if the result after the addition is 0; false otherwise.
+ */
+static inline int rte_atomic64_inc_and_test(rte_atomic64_t *v)
+{
+ return rte_atomic64_add_return(v, 1) == 0;
+}
+
+/**
+ * Atomically decrement a 64-bit counter by one and test.
+ *
+ * Atomically decrements the atomic counter (v) by one and returns true if
+ * the result is 0, or false in all other cases.
+ *
+ * @param v
+ * A pointer to the atomic counter.
+ * @return
+ * True if the result after substraction is 0; false otherwise.
+ */
+static inline int rte_atomic64_dec_and_test(rte_atomic64_t *v)
+{
+ return rte_atomic64_sub_return(v, 1) == 0;
+}
+
+/**
+ * Atomically test and set a 64-bit atomic counter.
+ *
+ * If the counter value is already set, return 0 (failed). Otherwise, set
+ * the counter value to 1 and return 1 (success).
+ *
+ * @param v
+ * A pointer to the atomic counter.
+ * @return
+ * 0 if failed; else 1, success.
+ */
+static inline int rte_atomic64_test_and_set(rte_atomic64_t *v)
+{
+ return rte_atomic64_cmpset((volatile uint64_t *)&v->cnt, 0, 1);
+}
+
+/**
+ * Atomically set a 64-bit counter to 0.
+ *
+ * @param v
+ * A pointer to the atomic counter.
+ */
+static inline void rte_atomic64_clear(rte_atomic64_t *v)
+{
+ rte_atomic64_set(v, 0);
+}
+
+#endif /*RTE_FORCE_INTRINSICS */
#ifdef __cplusplus
}