1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2014 Intel Corporation
12 * This file defines a generic API for atomic operations.
16 #include <rte_common.h>
20 /** @name Memory Barrier
24 * General memory barrier.
26 * Guarantees that the LOAD and STORE operations generated before the
27 * barrier occur before the LOAD and STORE operations generated after.
29 static inline void rte_mb(void);
32 * Write memory barrier.
34 * Guarantees that the STORE operations generated before the barrier
35 * occur before the STORE operations generated after.
37 static inline void rte_wmb(void);
40 * Read memory barrier.
42 * Guarantees that the LOAD operations generated before the barrier
43 * occur before the LOAD operations generated after.
45 static inline void rte_rmb(void);
48 /** @name SMP Memory Barrier
52 * General memory barrier between lcores
54 * Guarantees that the LOAD and STORE operations that precede the
55 * rte_smp_mb() call are globally visible across the lcores
56 * before the LOAD and STORE operations that follows it.
58 static inline void rte_smp_mb(void);
61 * Write memory barrier between lcores
63 * Guarantees that the STORE operations that precede the
64 * rte_smp_wmb() call are globally visible across the lcores
65 * before the STORE operations that follows it.
67 static inline void rte_smp_wmb(void);
70 * Read memory barrier between lcores
72 * Guarantees that the LOAD operations that precede the
73 * rte_smp_rmb() call are globally visible across the lcores
74 * before the LOAD operations that follows it.
76 static inline void rte_smp_rmb(void);
79 /** @name I/O Memory Barrier
83 * General memory barrier for I/O device
85 * Guarantees that the LOAD and STORE operations that precede the
86 * rte_io_mb() call are visible to I/O device or CPU before the
87 * LOAD and STORE operations that follow it.
89 static inline void rte_io_mb(void);
92 * Write memory barrier for I/O device
94 * Guarantees that the STORE operations that precede the
95 * rte_io_wmb() call are visible to I/O device before the STORE
96 * operations that follow it.
98 static inline void rte_io_wmb(void);
101 * Read memory barrier for IO device
103 * Guarantees that the LOAD operations on I/O device that precede the
104 * rte_io_rmb() call are visible to CPU before the LOAD
105 * operations that follow it.
107 static inline void rte_io_rmb(void);
110 /** @name Coherent I/O Memory Barrier
112 * Coherent I/O memory barrier is a lightweight version of I/O memory
113 * barriers which are system-wide data synchronization barriers. This
114 * is for only coherent memory domain between lcore and I/O device but
115 * it is same as the I/O memory barriers in most of architectures.
116 * However, some architecture provides even lighter barriers which are
117 * somewhere in between I/O memory barriers and SMP memory barriers.
118 * For example, in case of ARMv8, DMB(data memory barrier) instruction
119 * can have different shareability domains - inner-shareable and
120 * outer-shareable. And inner-shareable DMB fits for SMP memory
121 * barriers and outer-shareable DMB for coherent I/O memory barriers,
122 * which acts on coherent memory.
124 * In most cases, I/O memory barriers are safer but if operations are
125 * on coherent memory instead of incoherent MMIO region of a device,
126 * then coherent I/O memory barriers can be used and this could bring
127 * performance gain depending on architectures.
131 * Write memory barrier for coherent memory between lcore and I/O device
133 * Guarantees that the STORE operations on coherent memory that
134 * precede the rte_cio_wmb() call are visible to I/O device before the
135 * STORE operations that follow it.
137 static inline void rte_cio_wmb(void);
140 * Read memory barrier for coherent memory between lcore and I/O device
142 * Guarantees that the LOAD operations on coherent memory updated by
143 * I/O device that precede the rte_cio_rmb() call are visible to CPU
144 * before the LOAD operations that follow it.
146 static inline void rte_cio_rmb(void);
149 #endif /* __DOXYGEN__ */
154 * Guarantees that operation reordering does not occur at compile time
155 * for operations directly before and after the barrier.
157 #define rte_compiler_barrier() do { \
158 asm volatile ("" : : : "memory"); \
162 * Synchronization fence between threads based on the specified memory order.
164 static inline void rte_atomic_thread_fence(int memory_order);
166 /*------------------------- 16 bit atomic operations -------------------------*/
169 * Atomic compare and set.
171 * (atomic) equivalent to:
173 * *dst = src (all 16-bit words)
176 * The destination location into which the value will be written.
178 * The expected value.
182 * Non-zero on success; 0 on failure.
185 rte_atomic16_cmpset(volatile uint16_t *dst, uint16_t exp, uint16_t src);
187 #ifdef RTE_FORCE_INTRINSICS
189 rte_atomic16_cmpset(volatile uint16_t *dst, uint16_t exp, uint16_t src)
191 return __sync_bool_compare_and_swap(dst, exp, src);
198 * (atomic) equivalent to:
204 * The destination location into which the value will be written.
208 * The original value at that location
210 static inline uint16_t
211 rte_atomic16_exchange(volatile uint16_t *dst, uint16_t val);
213 #ifdef RTE_FORCE_INTRINSICS
214 static inline uint16_t
215 rte_atomic16_exchange(volatile uint16_t *dst, uint16_t val)
217 #if defined(__clang__)
218 return __atomic_exchange_n(dst, val, __ATOMIC_SEQ_CST);
220 return __atomic_exchange_2(dst, val, __ATOMIC_SEQ_CST);
226 * The atomic counter structure.
229 volatile int16_t cnt; /**< An internal counter value. */
233 * Static initializer for an atomic counter.
235 #define RTE_ATOMIC16_INIT(val) { (val) }
238 * Initialize an atomic counter.
241 * A pointer to the atomic counter.
244 rte_atomic16_init(rte_atomic16_t *v)
250 * Atomically read a 16-bit value from a counter.
253 * A pointer to the atomic counter.
255 * The value of the counter.
257 static inline int16_t
258 rte_atomic16_read(const rte_atomic16_t *v)
264 * Atomically set a counter to a 16-bit value.
267 * A pointer to the atomic counter.
269 * The new value for the counter.
272 rte_atomic16_set(rte_atomic16_t *v, int16_t new_value)
278 * Atomically add a 16-bit value to an atomic counter.
281 * A pointer to the atomic counter.
283 * The value to be added to the counter.
286 rte_atomic16_add(rte_atomic16_t *v, int16_t inc)
288 __sync_fetch_and_add(&v->cnt, inc);
292 * Atomically subtract a 16-bit value from an atomic counter.
295 * A pointer to the atomic counter.
297 * The value to be subtracted from the counter.
300 rte_atomic16_sub(rte_atomic16_t *v, int16_t dec)
302 __sync_fetch_and_sub(&v->cnt, dec);
306 * Atomically increment a counter by one.
309 * A pointer to the atomic counter.
312 rte_atomic16_inc(rte_atomic16_t *v);
314 #ifdef RTE_FORCE_INTRINSICS
316 rte_atomic16_inc(rte_atomic16_t *v)
318 rte_atomic16_add(v, 1);
323 * Atomically decrement a counter by one.
326 * A pointer to the atomic counter.
329 rte_atomic16_dec(rte_atomic16_t *v);
331 #ifdef RTE_FORCE_INTRINSICS
333 rte_atomic16_dec(rte_atomic16_t *v)
335 rte_atomic16_sub(v, 1);
340 * Atomically add a 16-bit value to a counter and return the result.
342 * Atomically adds the 16-bits value (inc) to the atomic counter (v) and
343 * returns the value of v after addition.
346 * A pointer to the atomic counter.
348 * The value to be added to the counter.
350 * The value of v after the addition.
352 static inline int16_t
353 rte_atomic16_add_return(rte_atomic16_t *v, int16_t inc)
355 return __sync_add_and_fetch(&v->cnt, inc);
359 * Atomically subtract a 16-bit value from a counter and return
362 * Atomically subtracts the 16-bit value (inc) from the atomic counter
363 * (v) and returns the value of v after the subtraction.
366 * A pointer to the atomic counter.
368 * The value to be subtracted from the counter.
370 * The value of v after the subtraction.
372 static inline int16_t
373 rte_atomic16_sub_return(rte_atomic16_t *v, int16_t dec)
375 return __sync_sub_and_fetch(&v->cnt, dec);
379 * Atomically increment a 16-bit counter by one and test.
381 * Atomically increments the atomic counter (v) by one and returns true if
382 * the result is 0, or false in all other cases.
385 * A pointer to the atomic counter.
387 * True if the result after the increment operation is 0; false otherwise.
389 static inline int rte_atomic16_inc_and_test(rte_atomic16_t *v);
391 #ifdef RTE_FORCE_INTRINSICS
392 static inline int rte_atomic16_inc_and_test(rte_atomic16_t *v)
394 return __sync_add_and_fetch(&v->cnt, 1) == 0;
399 * Atomically decrement a 16-bit counter by one and test.
401 * Atomically decrements the atomic counter (v) by one and returns true if
402 * the result is 0, or false in all other cases.
405 * A pointer to the atomic counter.
407 * True if the result after the decrement operation is 0; false otherwise.
409 static inline int rte_atomic16_dec_and_test(rte_atomic16_t *v);
411 #ifdef RTE_FORCE_INTRINSICS
412 static inline int rte_atomic16_dec_and_test(rte_atomic16_t *v)
414 return __sync_sub_and_fetch(&v->cnt, 1) == 0;
419 * Atomically test and set a 16-bit atomic counter.
421 * If the counter value is already set, return 0 (failed). Otherwise, set
422 * the counter value to 1 and return 1 (success).
425 * A pointer to the atomic counter.
427 * 0 if failed; else 1, success.
429 static inline int rte_atomic16_test_and_set(rte_atomic16_t *v);
431 #ifdef RTE_FORCE_INTRINSICS
432 static inline int rte_atomic16_test_and_set(rte_atomic16_t *v)
434 return rte_atomic16_cmpset((volatile uint16_t *)&v->cnt, 0, 1);
439 * Atomically set a 16-bit counter to 0.
442 * A pointer to the atomic counter.
444 static inline void rte_atomic16_clear(rte_atomic16_t *v)
449 /*------------------------- 32 bit atomic operations -------------------------*/
452 * Atomic compare and set.
454 * (atomic) equivalent to:
456 * *dst = src (all 32-bit words)
459 * The destination location into which the value will be written.
461 * The expected value.
465 * Non-zero on success; 0 on failure.
468 rte_atomic32_cmpset(volatile uint32_t *dst, uint32_t exp, uint32_t src);
470 #ifdef RTE_FORCE_INTRINSICS
472 rte_atomic32_cmpset(volatile uint32_t *dst, uint32_t exp, uint32_t src)
474 return __sync_bool_compare_and_swap(dst, exp, src);
481 * (atomic) equivalent to:
487 * The destination location into which the value will be written.
491 * The original value at that location
493 static inline uint32_t
494 rte_atomic32_exchange(volatile uint32_t *dst, uint32_t val);
496 #ifdef RTE_FORCE_INTRINSICS
497 static inline uint32_t
498 rte_atomic32_exchange(volatile uint32_t *dst, uint32_t val)
500 #if defined(__clang__)
501 return __atomic_exchange_n(dst, val, __ATOMIC_SEQ_CST);
503 return __atomic_exchange_4(dst, val, __ATOMIC_SEQ_CST);
509 * The atomic counter structure.
512 volatile int32_t cnt; /**< An internal counter value. */
516 * Static initializer for an atomic counter.
518 #define RTE_ATOMIC32_INIT(val) { (val) }
521 * Initialize an atomic counter.
524 * A pointer to the atomic counter.
527 rte_atomic32_init(rte_atomic32_t *v)
533 * Atomically read a 32-bit value from a counter.
536 * A pointer to the atomic counter.
538 * The value of the counter.
540 static inline int32_t
541 rte_atomic32_read(const rte_atomic32_t *v)
547 * Atomically set a counter to a 32-bit value.
550 * A pointer to the atomic counter.
552 * The new value for the counter.
555 rte_atomic32_set(rte_atomic32_t *v, int32_t new_value)
561 * Atomically add a 32-bit value to an atomic counter.
564 * A pointer to the atomic counter.
566 * The value to be added to the counter.
569 rte_atomic32_add(rte_atomic32_t *v, int32_t inc)
571 __sync_fetch_and_add(&v->cnt, inc);
575 * Atomically subtract a 32-bit value from an atomic counter.
578 * A pointer to the atomic counter.
580 * The value to be subtracted from the counter.
583 rte_atomic32_sub(rte_atomic32_t *v, int32_t dec)
585 __sync_fetch_and_sub(&v->cnt, dec);
589 * Atomically increment a counter by one.
592 * A pointer to the atomic counter.
595 rte_atomic32_inc(rte_atomic32_t *v);
597 #ifdef RTE_FORCE_INTRINSICS
599 rte_atomic32_inc(rte_atomic32_t *v)
601 rte_atomic32_add(v, 1);
606 * Atomically decrement a counter by one.
609 * A pointer to the atomic counter.
612 rte_atomic32_dec(rte_atomic32_t *v);
614 #ifdef RTE_FORCE_INTRINSICS
616 rte_atomic32_dec(rte_atomic32_t *v)
618 rte_atomic32_sub(v,1);
623 * Atomically add a 32-bit value to a counter and return the result.
625 * Atomically adds the 32-bits value (inc) to the atomic counter (v) and
626 * returns the value of v after addition.
629 * A pointer to the atomic counter.
631 * The value to be added to the counter.
633 * The value of v after the addition.
635 static inline int32_t
636 rte_atomic32_add_return(rte_atomic32_t *v, int32_t inc)
638 return __sync_add_and_fetch(&v->cnt, inc);
642 * Atomically subtract a 32-bit value from a counter and return
645 * Atomically subtracts the 32-bit value (inc) from the atomic counter
646 * (v) and returns the value of v after the subtraction.
649 * A pointer to the atomic counter.
651 * The value to be subtracted from the counter.
653 * The value of v after the subtraction.
655 static inline int32_t
656 rte_atomic32_sub_return(rte_atomic32_t *v, int32_t dec)
658 return __sync_sub_and_fetch(&v->cnt, dec);
662 * Atomically increment a 32-bit counter by one and test.
664 * Atomically increments the atomic counter (v) by one and returns true if
665 * the result is 0, or false in all other cases.
668 * A pointer to the atomic counter.
670 * True if the result after the increment operation is 0; false otherwise.
672 static inline int rte_atomic32_inc_and_test(rte_atomic32_t *v);
674 #ifdef RTE_FORCE_INTRINSICS
675 static inline int rte_atomic32_inc_and_test(rte_atomic32_t *v)
677 return __sync_add_and_fetch(&v->cnt, 1) == 0;
682 * Atomically decrement a 32-bit counter by one and test.
684 * Atomically decrements the atomic counter (v) by one and returns true if
685 * the result is 0, or false in all other cases.
688 * A pointer to the atomic counter.
690 * True if the result after the decrement operation is 0; false otherwise.
692 static inline int rte_atomic32_dec_and_test(rte_atomic32_t *v);
694 #ifdef RTE_FORCE_INTRINSICS
695 static inline int rte_atomic32_dec_and_test(rte_atomic32_t *v)
697 return __sync_sub_and_fetch(&v->cnt, 1) == 0;
702 * Atomically test and set a 32-bit atomic counter.
704 * If the counter value is already set, return 0 (failed). Otherwise, set
705 * the counter value to 1 and return 1 (success).
708 * A pointer to the atomic counter.
710 * 0 if failed; else 1, success.
712 static inline int rte_atomic32_test_and_set(rte_atomic32_t *v);
714 #ifdef RTE_FORCE_INTRINSICS
715 static inline int rte_atomic32_test_and_set(rte_atomic32_t *v)
717 return rte_atomic32_cmpset((volatile uint32_t *)&v->cnt, 0, 1);
722 * Atomically set a 32-bit counter to 0.
725 * A pointer to the atomic counter.
727 static inline void rte_atomic32_clear(rte_atomic32_t *v)
732 /*------------------------- 64 bit atomic operations -------------------------*/
735 * An atomic compare and set function used by the mutex functions.
736 * (atomic) equivalent to:
738 * *dst = src (all 64-bit words)
741 * The destination into which the value will be written.
743 * The expected value.
747 * Non-zero on success; 0 on failure.
750 rte_atomic64_cmpset(volatile uint64_t *dst, uint64_t exp, uint64_t src);
752 #ifdef RTE_FORCE_INTRINSICS
754 rte_atomic64_cmpset(volatile uint64_t *dst, uint64_t exp, uint64_t src)
756 return __sync_bool_compare_and_swap(dst, exp, src);
763 * (atomic) equivalent to:
769 * The destination location into which the value will be written.
773 * The original value at that location
775 static inline uint64_t
776 rte_atomic64_exchange(volatile uint64_t *dst, uint64_t val);
778 #ifdef RTE_FORCE_INTRINSICS
779 static inline uint64_t
780 rte_atomic64_exchange(volatile uint64_t *dst, uint64_t val)
782 #if defined(__clang__)
783 return __atomic_exchange_n(dst, val, __ATOMIC_SEQ_CST);
785 return __atomic_exchange_8(dst, val, __ATOMIC_SEQ_CST);
791 * The atomic counter structure.
794 volatile int64_t cnt; /**< Internal counter value. */
798 * Static initializer for an atomic counter.
800 #define RTE_ATOMIC64_INIT(val) { (val) }
803 * Initialize the atomic counter.
806 * A pointer to the atomic counter.
809 rte_atomic64_init(rte_atomic64_t *v);
811 #ifdef RTE_FORCE_INTRINSICS
813 rte_atomic64_init(rte_atomic64_t *v)
821 while (success == 0) {
823 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
831 * Atomically read a 64-bit counter.
834 * A pointer to the atomic counter.
836 * The value of the counter.
838 static inline int64_t
839 rte_atomic64_read(rte_atomic64_t *v);
841 #ifdef RTE_FORCE_INTRINSICS
842 static inline int64_t
843 rte_atomic64_read(rte_atomic64_t *v)
851 while (success == 0) {
853 /* replace the value by itself */
854 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
863 * Atomically set a 64-bit counter.
866 * A pointer to the atomic counter.
868 * The new value of the counter.
871 rte_atomic64_set(rte_atomic64_t *v, int64_t new_value);
873 #ifdef RTE_FORCE_INTRINSICS
875 rte_atomic64_set(rte_atomic64_t *v, int64_t new_value)
883 while (success == 0) {
885 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
893 * Atomically add a 64-bit value to a counter.
896 * A pointer to the atomic counter.
898 * The value to be added to the counter.
901 rte_atomic64_add(rte_atomic64_t *v, int64_t inc);
903 #ifdef RTE_FORCE_INTRINSICS
905 rte_atomic64_add(rte_atomic64_t *v, int64_t inc)
907 __sync_fetch_and_add(&v->cnt, inc);
912 * Atomically subtract a 64-bit value from a counter.
915 * A pointer to the atomic counter.
917 * The value to be subtracted from the counter.
920 rte_atomic64_sub(rte_atomic64_t *v, int64_t dec);
922 #ifdef RTE_FORCE_INTRINSICS
924 rte_atomic64_sub(rte_atomic64_t *v, int64_t dec)
926 __sync_fetch_and_sub(&v->cnt, dec);
931 * Atomically increment a 64-bit counter by one and test.
934 * A pointer to the atomic counter.
937 rte_atomic64_inc(rte_atomic64_t *v);
939 #ifdef RTE_FORCE_INTRINSICS
941 rte_atomic64_inc(rte_atomic64_t *v)
943 rte_atomic64_add(v, 1);
948 * Atomically decrement a 64-bit counter by one and test.
951 * A pointer to the atomic counter.
954 rte_atomic64_dec(rte_atomic64_t *v);
956 #ifdef RTE_FORCE_INTRINSICS
958 rte_atomic64_dec(rte_atomic64_t *v)
960 rte_atomic64_sub(v, 1);
965 * Add a 64-bit value to an atomic counter and return the result.
967 * Atomically adds the 64-bit value (inc) to the atomic counter (v) and
968 * returns the value of v after the addition.
971 * A pointer to the atomic counter.
973 * The value to be added to the counter.
975 * The value of v after the addition.
977 static inline int64_t
978 rte_atomic64_add_return(rte_atomic64_t *v, int64_t inc);
980 #ifdef RTE_FORCE_INTRINSICS
981 static inline int64_t
982 rte_atomic64_add_return(rte_atomic64_t *v, int64_t inc)
984 return __sync_add_and_fetch(&v->cnt, inc);
989 * Subtract a 64-bit value from an atomic counter and return the result.
991 * Atomically subtracts the 64-bit value (dec) from the atomic counter (v)
992 * and returns the value of v after the subtraction.
995 * A pointer to the atomic counter.
997 * The value to be subtracted from the counter.
999 * The value of v after the subtraction.
1001 static inline int64_t
1002 rte_atomic64_sub_return(rte_atomic64_t *v, int64_t dec);
1004 #ifdef RTE_FORCE_INTRINSICS
1005 static inline int64_t
1006 rte_atomic64_sub_return(rte_atomic64_t *v, int64_t dec)
1008 return __sync_sub_and_fetch(&v->cnt, dec);
1013 * Atomically increment a 64-bit counter by one and test.
1015 * Atomically increments the atomic counter (v) by one and returns
1016 * true if the result is 0, or false in all other cases.
1019 * A pointer to the atomic counter.
1021 * True if the result after the addition is 0; false otherwise.
1023 static inline int rte_atomic64_inc_and_test(rte_atomic64_t *v);
1025 #ifdef RTE_FORCE_INTRINSICS
1026 static inline int rte_atomic64_inc_and_test(rte_atomic64_t *v)
1028 return rte_atomic64_add_return(v, 1) == 0;
1033 * Atomically decrement a 64-bit counter by one and test.
1035 * Atomically decrements the atomic counter (v) by one and returns true if
1036 * the result is 0, or false in all other cases.
1039 * A pointer to the atomic counter.
1041 * True if the result after subtraction is 0; false otherwise.
1043 static inline int rte_atomic64_dec_and_test(rte_atomic64_t *v);
1045 #ifdef RTE_FORCE_INTRINSICS
1046 static inline int rte_atomic64_dec_and_test(rte_atomic64_t *v)
1048 return rte_atomic64_sub_return(v, 1) == 0;
1053 * Atomically test and set a 64-bit atomic counter.
1055 * If the counter value is already set, return 0 (failed). Otherwise, set
1056 * the counter value to 1 and return 1 (success).
1059 * A pointer to the atomic counter.
1061 * 0 if failed; else 1, success.
1063 static inline int rte_atomic64_test_and_set(rte_atomic64_t *v);
1065 #ifdef RTE_FORCE_INTRINSICS
1066 static inline int rte_atomic64_test_and_set(rte_atomic64_t *v)
1068 return rte_atomic64_cmpset((volatile uint64_t *)&v->cnt, 0, 1);
1073 * Atomically set a 64-bit counter to 0.
1076 * A pointer to the atomic counter.
1078 static inline void rte_atomic64_clear(rte_atomic64_t *v);
1080 #ifdef RTE_FORCE_INTRINSICS
1081 static inline void rte_atomic64_clear(rte_atomic64_t *v)
1083 rte_atomic64_set(v, 0);
1087 /*------------------------ 128 bit atomic operations -------------------------*/
1090 * 128-bit integer structure.
1098 __extension__ __int128 int128;
1101 } __rte_aligned(16) rte_int128_t;
1106 * An atomic compare and set function used by the mutex functions.
1107 * (Atomically) Equivalent to:
1115 * @note This function is currently available for the x86-64 and aarch64
1118 * @note The success and failure arguments must be one of the __ATOMIC_* values
1119 * defined in the C++11 standard. For details on their behavior, refer to the
1123 * The destination into which the value will be written.
1125 * Pointer to the expected value. If the operation fails, this memory is
1126 * updated with the actual value.
1128 * Pointer to the new value.
1130 * A value of true allows the comparison to spuriously fail and allows the
1131 * 'exp' update to occur non-atomically (i.e. a torn read may occur).
1132 * Implementations may ignore this argument and only implement the strong
1135 * If successful, the operation's memory behavior conforms to this (or a
1138 * If unsuccessful, the operation's memory behavior conforms to this (or a
1139 * stronger) model. This argument cannot be __ATOMIC_RELEASE,
1140 * __ATOMIC_ACQ_REL, or a stronger model than success.
1142 * Non-zero on success; 0 on failure.
1146 rte_atomic128_cmp_exchange(rte_int128_t *dst,
1148 const rte_int128_t *src,
1153 #endif /* __DOXYGEN__ */
1155 #endif /* _RTE_ATOMIC_H_ */