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"); \
161 /*------------------------- 16 bit atomic operations -------------------------*/
164 * Atomic compare and set.
166 * (atomic) equivalent to:
168 * *dst = src (all 16-bit words)
171 * The destination location into which the value will be written.
173 * The expected value.
177 * Non-zero on success; 0 on failure.
180 rte_atomic16_cmpset(volatile uint16_t *dst, uint16_t exp, uint16_t src);
182 #ifdef RTE_FORCE_INTRINSICS
184 rte_atomic16_cmpset(volatile uint16_t *dst, uint16_t exp, uint16_t src)
186 return __sync_bool_compare_and_swap(dst, exp, src);
193 * (atomic) equivalent to:
199 * The destination location into which the value will be written.
203 * The original value at that location
205 static inline uint16_t
206 rte_atomic16_exchange(volatile uint16_t *dst, uint16_t val);
208 #ifdef RTE_FORCE_INTRINSICS
209 static inline uint16_t
210 rte_atomic16_exchange(volatile uint16_t *dst, uint16_t val)
212 #if defined(__clang__)
213 return __atomic_exchange_n(dst, val, __ATOMIC_SEQ_CST);
215 return __atomic_exchange_2(dst, val, __ATOMIC_SEQ_CST);
221 * The atomic counter structure.
224 volatile int16_t cnt; /**< An internal counter value. */
228 * Static initializer for an atomic counter.
230 #define RTE_ATOMIC16_INIT(val) { (val) }
233 * Initialize an atomic counter.
236 * A pointer to the atomic counter.
239 rte_atomic16_init(rte_atomic16_t *v)
245 * Atomically read a 16-bit value from a counter.
248 * A pointer to the atomic counter.
250 * The value of the counter.
252 static inline int16_t
253 rte_atomic16_read(const rte_atomic16_t *v)
259 * Atomically set a counter to a 16-bit value.
262 * A pointer to the atomic counter.
264 * The new value for the counter.
267 rte_atomic16_set(rte_atomic16_t *v, int16_t new_value)
273 * Atomically add a 16-bit value to an atomic counter.
276 * A pointer to the atomic counter.
278 * The value to be added to the counter.
281 rte_atomic16_add(rte_atomic16_t *v, int16_t inc)
283 __sync_fetch_and_add(&v->cnt, inc);
287 * Atomically subtract a 16-bit value from an atomic counter.
290 * A pointer to the atomic counter.
292 * The value to be subtracted from the counter.
295 rte_atomic16_sub(rte_atomic16_t *v, int16_t dec)
297 __sync_fetch_and_sub(&v->cnt, dec);
301 * Atomically increment a counter by one.
304 * A pointer to the atomic counter.
307 rte_atomic16_inc(rte_atomic16_t *v);
309 #ifdef RTE_FORCE_INTRINSICS
311 rte_atomic16_inc(rte_atomic16_t *v)
313 rte_atomic16_add(v, 1);
318 * Atomically decrement a counter by one.
321 * A pointer to the atomic counter.
324 rte_atomic16_dec(rte_atomic16_t *v);
326 #ifdef RTE_FORCE_INTRINSICS
328 rte_atomic16_dec(rte_atomic16_t *v)
330 rte_atomic16_sub(v, 1);
335 * Atomically add a 16-bit value to a counter and return the result.
337 * Atomically adds the 16-bits value (inc) to the atomic counter (v) and
338 * returns the value of v after addition.
341 * A pointer to the atomic counter.
343 * The value to be added to the counter.
345 * The value of v after the addition.
347 static inline int16_t
348 rte_atomic16_add_return(rte_atomic16_t *v, int16_t inc)
350 return __sync_add_and_fetch(&v->cnt, inc);
354 * Atomically subtract a 16-bit value from a counter and return
357 * Atomically subtracts the 16-bit value (inc) from the atomic counter
358 * (v) and returns the value of v after the subtraction.
361 * A pointer to the atomic counter.
363 * The value to be subtracted from the counter.
365 * The value of v after the subtraction.
367 static inline int16_t
368 rte_atomic16_sub_return(rte_atomic16_t *v, int16_t dec)
370 return __sync_sub_and_fetch(&v->cnt, dec);
374 * Atomically increment a 16-bit counter by one and test.
376 * Atomically increments the atomic counter (v) by one and returns true if
377 * the result is 0, or false in all other cases.
380 * A pointer to the atomic counter.
382 * True if the result after the increment operation is 0; false otherwise.
384 static inline int rte_atomic16_inc_and_test(rte_atomic16_t *v);
386 #ifdef RTE_FORCE_INTRINSICS
387 static inline int rte_atomic16_inc_and_test(rte_atomic16_t *v)
389 return __sync_add_and_fetch(&v->cnt, 1) == 0;
394 * Atomically decrement a 16-bit counter by one and test.
396 * Atomically decrements the atomic counter (v) by one and returns true if
397 * the result is 0, or false in all other cases.
400 * A pointer to the atomic counter.
402 * True if the result after the decrement operation is 0; false otherwise.
404 static inline int rte_atomic16_dec_and_test(rte_atomic16_t *v);
406 #ifdef RTE_FORCE_INTRINSICS
407 static inline int rte_atomic16_dec_and_test(rte_atomic16_t *v)
409 return __sync_sub_and_fetch(&v->cnt, 1) == 0;
414 * Atomically test and set a 16-bit atomic counter.
416 * If the counter value is already set, return 0 (failed). Otherwise, set
417 * the counter value to 1 and return 1 (success).
420 * A pointer to the atomic counter.
422 * 0 if failed; else 1, success.
424 static inline int rte_atomic16_test_and_set(rte_atomic16_t *v);
426 #ifdef RTE_FORCE_INTRINSICS
427 static inline int rte_atomic16_test_and_set(rte_atomic16_t *v)
429 return rte_atomic16_cmpset((volatile uint16_t *)&v->cnt, 0, 1);
434 * Atomically set a 16-bit counter to 0.
437 * A pointer to the atomic counter.
439 static inline void rte_atomic16_clear(rte_atomic16_t *v)
444 /*------------------------- 32 bit atomic operations -------------------------*/
447 * Atomic compare and set.
449 * (atomic) equivalent to:
451 * *dst = src (all 32-bit words)
454 * The destination location into which the value will be written.
456 * The expected value.
460 * Non-zero on success; 0 on failure.
463 rte_atomic32_cmpset(volatile uint32_t *dst, uint32_t exp, uint32_t src);
465 #ifdef RTE_FORCE_INTRINSICS
467 rte_atomic32_cmpset(volatile uint32_t *dst, uint32_t exp, uint32_t src)
469 return __sync_bool_compare_and_swap(dst, exp, src);
476 * (atomic) equivalent to:
482 * The destination location into which the value will be written.
486 * The original value at that location
488 static inline uint32_t
489 rte_atomic32_exchange(volatile uint32_t *dst, uint32_t val);
491 #ifdef RTE_FORCE_INTRINSICS
492 static inline uint32_t
493 rte_atomic32_exchange(volatile uint32_t *dst, uint32_t val)
495 #if defined(__clang__)
496 return __atomic_exchange_n(dst, val, __ATOMIC_SEQ_CST);
498 return __atomic_exchange_4(dst, val, __ATOMIC_SEQ_CST);
504 * The atomic counter structure.
507 volatile int32_t cnt; /**< An internal counter value. */
511 * Static initializer for an atomic counter.
513 #define RTE_ATOMIC32_INIT(val) { (val) }
516 * Initialize an atomic counter.
519 * A pointer to the atomic counter.
522 rte_atomic32_init(rte_atomic32_t *v)
528 * Atomically read a 32-bit value from a counter.
531 * A pointer to the atomic counter.
533 * The value of the counter.
535 static inline int32_t
536 rte_atomic32_read(const rte_atomic32_t *v)
542 * Atomically set a counter to a 32-bit value.
545 * A pointer to the atomic counter.
547 * The new value for the counter.
550 rte_atomic32_set(rte_atomic32_t *v, int32_t new_value)
556 * Atomically add a 32-bit value to an atomic counter.
559 * A pointer to the atomic counter.
561 * The value to be added to the counter.
564 rte_atomic32_add(rte_atomic32_t *v, int32_t inc)
566 __sync_fetch_and_add(&v->cnt, inc);
570 * Atomically subtract a 32-bit value from an atomic counter.
573 * A pointer to the atomic counter.
575 * The value to be subtracted from the counter.
578 rte_atomic32_sub(rte_atomic32_t *v, int32_t dec)
580 __sync_fetch_and_sub(&v->cnt, dec);
584 * Atomically increment a counter by one.
587 * A pointer to the atomic counter.
590 rte_atomic32_inc(rte_atomic32_t *v);
592 #ifdef RTE_FORCE_INTRINSICS
594 rte_atomic32_inc(rte_atomic32_t *v)
596 rte_atomic32_add(v, 1);
601 * Atomically decrement a counter by one.
604 * A pointer to the atomic counter.
607 rte_atomic32_dec(rte_atomic32_t *v);
609 #ifdef RTE_FORCE_INTRINSICS
611 rte_atomic32_dec(rte_atomic32_t *v)
613 rte_atomic32_sub(v,1);
618 * Atomically add a 32-bit value to a counter and return the result.
620 * Atomically adds the 32-bits value (inc) to the atomic counter (v) and
621 * returns the value of v after addition.
624 * A pointer to the atomic counter.
626 * The value to be added to the counter.
628 * The value of v after the addition.
630 static inline int32_t
631 rte_atomic32_add_return(rte_atomic32_t *v, int32_t inc)
633 return __sync_add_and_fetch(&v->cnt, inc);
637 * Atomically subtract a 32-bit value from a counter and return
640 * Atomically subtracts the 32-bit value (inc) from the atomic counter
641 * (v) and returns the value of v after the subtraction.
644 * A pointer to the atomic counter.
646 * The value to be subtracted from the counter.
648 * The value of v after the subtraction.
650 static inline int32_t
651 rte_atomic32_sub_return(rte_atomic32_t *v, int32_t dec)
653 return __sync_sub_and_fetch(&v->cnt, dec);
657 * Atomically increment a 32-bit counter by one and test.
659 * Atomically increments the atomic counter (v) by one and returns true if
660 * the result is 0, or false in all other cases.
663 * A pointer to the atomic counter.
665 * True if the result after the increment operation is 0; false otherwise.
667 static inline int rte_atomic32_inc_and_test(rte_atomic32_t *v);
669 #ifdef RTE_FORCE_INTRINSICS
670 static inline int rte_atomic32_inc_and_test(rte_atomic32_t *v)
672 return __sync_add_and_fetch(&v->cnt, 1) == 0;
677 * Atomically decrement a 32-bit counter by one and test.
679 * Atomically decrements the atomic counter (v) by one and returns true if
680 * the result is 0, or false in all other cases.
683 * A pointer to the atomic counter.
685 * True if the result after the decrement operation is 0; false otherwise.
687 static inline int rte_atomic32_dec_and_test(rte_atomic32_t *v);
689 #ifdef RTE_FORCE_INTRINSICS
690 static inline int rte_atomic32_dec_and_test(rte_atomic32_t *v)
692 return __sync_sub_and_fetch(&v->cnt, 1) == 0;
697 * Atomically test and set a 32-bit atomic counter.
699 * If the counter value is already set, return 0 (failed). Otherwise, set
700 * the counter value to 1 and return 1 (success).
703 * A pointer to the atomic counter.
705 * 0 if failed; else 1, success.
707 static inline int rte_atomic32_test_and_set(rte_atomic32_t *v);
709 #ifdef RTE_FORCE_INTRINSICS
710 static inline int rte_atomic32_test_and_set(rte_atomic32_t *v)
712 return rte_atomic32_cmpset((volatile uint32_t *)&v->cnt, 0, 1);
717 * Atomically set a 32-bit counter to 0.
720 * A pointer to the atomic counter.
722 static inline void rte_atomic32_clear(rte_atomic32_t *v)
727 /*------------------------- 64 bit atomic operations -------------------------*/
730 * An atomic compare and set function used by the mutex functions.
731 * (atomic) equivalent to:
733 * *dst = src (all 64-bit words)
736 * The destination into which the value will be written.
738 * The expected value.
742 * Non-zero on success; 0 on failure.
745 rte_atomic64_cmpset(volatile uint64_t *dst, uint64_t exp, uint64_t src);
747 #ifdef RTE_FORCE_INTRINSICS
749 rte_atomic64_cmpset(volatile uint64_t *dst, uint64_t exp, uint64_t src)
751 return __sync_bool_compare_and_swap(dst, exp, src);
758 * (atomic) equivalent to:
764 * The destination location into which the value will be written.
768 * The original value at that location
770 static inline uint64_t
771 rte_atomic64_exchange(volatile uint64_t *dst, uint64_t val);
773 #ifdef RTE_FORCE_INTRINSICS
774 static inline uint64_t
775 rte_atomic64_exchange(volatile uint64_t *dst, uint64_t val)
777 #if defined(__clang__)
778 return __atomic_exchange_n(dst, val, __ATOMIC_SEQ_CST);
780 return __atomic_exchange_8(dst, val, __ATOMIC_SEQ_CST);
786 * The atomic counter structure.
789 volatile int64_t cnt; /**< Internal counter value. */
793 * Static initializer for an atomic counter.
795 #define RTE_ATOMIC64_INIT(val) { (val) }
798 * Initialize the atomic counter.
801 * A pointer to the atomic counter.
804 rte_atomic64_init(rte_atomic64_t *v);
806 #ifdef RTE_FORCE_INTRINSICS
808 rte_atomic64_init(rte_atomic64_t *v)
816 while (success == 0) {
818 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
826 * Atomically read a 64-bit counter.
829 * A pointer to the atomic counter.
831 * The value of the counter.
833 static inline int64_t
834 rte_atomic64_read(rte_atomic64_t *v);
836 #ifdef RTE_FORCE_INTRINSICS
837 static inline int64_t
838 rte_atomic64_read(rte_atomic64_t *v)
846 while (success == 0) {
848 /* replace the value by itself */
849 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
858 * Atomically set a 64-bit counter.
861 * A pointer to the atomic counter.
863 * The new value of the counter.
866 rte_atomic64_set(rte_atomic64_t *v, int64_t new_value);
868 #ifdef RTE_FORCE_INTRINSICS
870 rte_atomic64_set(rte_atomic64_t *v, int64_t new_value)
878 while (success == 0) {
880 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
888 * Atomically add a 64-bit value to a counter.
891 * A pointer to the atomic counter.
893 * The value to be added to the counter.
896 rte_atomic64_add(rte_atomic64_t *v, int64_t inc);
898 #ifdef RTE_FORCE_INTRINSICS
900 rte_atomic64_add(rte_atomic64_t *v, int64_t inc)
902 __sync_fetch_and_add(&v->cnt, inc);
907 * Atomically subtract a 64-bit value from a counter.
910 * A pointer to the atomic counter.
912 * The value to be subtracted from the counter.
915 rte_atomic64_sub(rte_atomic64_t *v, int64_t dec);
917 #ifdef RTE_FORCE_INTRINSICS
919 rte_atomic64_sub(rte_atomic64_t *v, int64_t dec)
921 __sync_fetch_and_sub(&v->cnt, dec);
926 * Atomically increment a 64-bit counter by one and test.
929 * A pointer to the atomic counter.
932 rte_atomic64_inc(rte_atomic64_t *v);
934 #ifdef RTE_FORCE_INTRINSICS
936 rte_atomic64_inc(rte_atomic64_t *v)
938 rte_atomic64_add(v, 1);
943 * Atomically decrement a 64-bit counter by one and test.
946 * A pointer to the atomic counter.
949 rte_atomic64_dec(rte_atomic64_t *v);
951 #ifdef RTE_FORCE_INTRINSICS
953 rte_atomic64_dec(rte_atomic64_t *v)
955 rte_atomic64_sub(v, 1);
960 * Add a 64-bit value to an atomic counter and return the result.
962 * Atomically adds the 64-bit value (inc) to the atomic counter (v) and
963 * returns the value of v after the addition.
966 * A pointer to the atomic counter.
968 * The value to be added to the counter.
970 * The value of v after the addition.
972 static inline int64_t
973 rte_atomic64_add_return(rte_atomic64_t *v, int64_t inc);
975 #ifdef RTE_FORCE_INTRINSICS
976 static inline int64_t
977 rte_atomic64_add_return(rte_atomic64_t *v, int64_t inc)
979 return __sync_add_and_fetch(&v->cnt, inc);
984 * Subtract a 64-bit value from an atomic counter and return the result.
986 * Atomically subtracts the 64-bit value (dec) from the atomic counter (v)
987 * and returns the value of v after the subtraction.
990 * A pointer to the atomic counter.
992 * The value to be subtracted from the counter.
994 * The value of v after the subtraction.
996 static inline int64_t
997 rte_atomic64_sub_return(rte_atomic64_t *v, int64_t dec);
999 #ifdef RTE_FORCE_INTRINSICS
1000 static inline int64_t
1001 rte_atomic64_sub_return(rte_atomic64_t *v, int64_t dec)
1003 return __sync_sub_and_fetch(&v->cnt, dec);
1008 * Atomically increment a 64-bit counter by one and test.
1010 * Atomically increments the atomic counter (v) by one and returns
1011 * true if the result is 0, or false in all other cases.
1014 * A pointer to the atomic counter.
1016 * True if the result after the addition is 0; false otherwise.
1018 static inline int rte_atomic64_inc_and_test(rte_atomic64_t *v);
1020 #ifdef RTE_FORCE_INTRINSICS
1021 static inline int rte_atomic64_inc_and_test(rte_atomic64_t *v)
1023 return rte_atomic64_add_return(v, 1) == 0;
1028 * Atomically decrement a 64-bit counter by one and test.
1030 * Atomically decrements the atomic counter (v) by one and returns true if
1031 * the result is 0, or false in all other cases.
1034 * A pointer to the atomic counter.
1036 * True if the result after subtraction is 0; false otherwise.
1038 static inline int rte_atomic64_dec_and_test(rte_atomic64_t *v);
1040 #ifdef RTE_FORCE_INTRINSICS
1041 static inline int rte_atomic64_dec_and_test(rte_atomic64_t *v)
1043 return rte_atomic64_sub_return(v, 1) == 0;
1048 * Atomically test and set a 64-bit atomic counter.
1050 * If the counter value is already set, return 0 (failed). Otherwise, set
1051 * the counter value to 1 and return 1 (success).
1054 * A pointer to the atomic counter.
1056 * 0 if failed; else 1, success.
1058 static inline int rte_atomic64_test_and_set(rte_atomic64_t *v);
1060 #ifdef RTE_FORCE_INTRINSICS
1061 static inline int rte_atomic64_test_and_set(rte_atomic64_t *v)
1063 return rte_atomic64_cmpset((volatile uint64_t *)&v->cnt, 0, 1);
1068 * Atomically set a 64-bit counter to 0.
1071 * A pointer to the atomic counter.
1073 static inline void rte_atomic64_clear(rte_atomic64_t *v);
1075 #ifdef RTE_FORCE_INTRINSICS
1076 static inline void rte_atomic64_clear(rte_atomic64_t *v)
1078 rte_atomic64_set(v, 0);
1082 /*------------------------ 128 bit atomic operations -------------------------*/
1087 * An atomic compare and set function used by the mutex functions.
1088 * (Atomically) Equivalent to:
1096 * @note This function is currently only available for the x86-64 platform.
1098 * @note The success and failure arguments must be one of the __ATOMIC_* values
1099 * defined in the C++11 standard. For details on their behavior, refer to the
1103 * The destination into which the value will be written.
1105 * Pointer to the expected value. If the operation fails, this memory is
1106 * updated with the actual value.
1108 * Pointer to the new value.
1110 * A value of true allows the comparison to spuriously fail and allows the
1111 * 'exp' update to occur non-atomically (i.e. a torn read may occur).
1112 * Implementations may ignore this argument and only implement the strong
1115 * If successful, the operation's memory behavior conforms to this (or a
1118 * If unsuccessful, the operation's memory behavior conforms to this (or a
1119 * stronger) model. This argument cannot be __ATOMIC_RELEASE,
1120 * __ATOMIC_ACQ_REL, or a stronger model than success.
1122 * Non-zero on success; 0 on failure.
1126 rte_atomic128_cmp_exchange(rte_int128_t *dst,
1128 const rte_int128_t *src,
1133 #endif /* __DOXYGEN__ */
1135 #endif /* _RTE_ATOMIC_H_ */