eal: group memory barriers by type in doxygen
[dpdk.git] / lib / librte_eal / common / include / generic / rte_atomic.h
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation
3  */
4
5 #ifndef _RTE_ATOMIC_H_
6 #define _RTE_ATOMIC_H_
7
8 /**
9  * @file
10  * Atomic Operations
11  *
12  * This file defines a generic API for atomic operations.
13  */
14
15 #include <stdint.h>
16 #include <rte_common.h>
17
18 #ifdef __DOXYGEN__
19
20 /** @name Memory Barrier
21  */
22 ///@{
23 /**
24  * General memory barrier.
25  *
26  * Guarantees that the LOAD and STORE operations generated before the
27  * barrier occur before the LOAD and STORE operations generated after.
28  * This function is architecture dependent.
29  */
30 static inline void rte_mb(void);
31
32 /**
33  * Write memory barrier.
34  *
35  * Guarantees that the STORE operations generated before the barrier
36  * occur before the STORE operations generated after.
37  * This function is architecture dependent.
38  */
39 static inline void rte_wmb(void);
40
41 /**
42  * Read memory barrier.
43  *
44  * Guarantees that the LOAD operations generated before the barrier
45  * occur before the LOAD operations generated after.
46  * This function is architecture dependent.
47  */
48 static inline void rte_rmb(void);
49 ///@}
50
51 /** @name SMP Memory Barrier
52  */
53 ///@{
54 /**
55  * General memory barrier between lcores
56  *
57  * Guarantees that the LOAD and STORE operations that precede the
58  * rte_smp_mb() call are globally visible across the lcores
59  * before the LOAD and STORE operations that follows it.
60  */
61 static inline void rte_smp_mb(void);
62
63 /**
64  * Write memory barrier between lcores
65  *
66  * Guarantees that the STORE operations that precede the
67  * rte_smp_wmb() call are globally visible across the lcores
68  * before the STORE operations that follows it.
69  */
70 static inline void rte_smp_wmb(void);
71
72 /**
73  * Read memory barrier between lcores
74  *
75  * Guarantees that the LOAD operations that precede the
76  * rte_smp_rmb() call are globally visible across the lcores
77  * before the LOAD operations that follows it.
78  */
79 static inline void rte_smp_rmb(void);
80 ///@}
81
82 /** @name I/O Memory Barrier
83  */
84 ///@{
85 /**
86  * General memory barrier for I/O device
87  *
88  * Guarantees that the LOAD and STORE operations that precede the
89  * rte_io_mb() call are visible to I/O device or CPU before the
90  * LOAD and STORE operations that follow it.
91  */
92 static inline void rte_io_mb(void);
93
94 /**
95  * Write memory barrier for I/O device
96  *
97  * Guarantees that the STORE operations that precede the
98  * rte_io_wmb() call are visible to I/O device before the STORE
99  * operations that follow it.
100  */
101 static inline void rte_io_wmb(void);
102
103 /**
104  * Read memory barrier for IO device
105  *
106  * Guarantees that the LOAD operations on I/O device that precede the
107  * rte_io_rmb() call are visible to CPU before the LOAD
108  * operations that follow it.
109  */
110 static inline void rte_io_rmb(void);
111 ///@}
112
113 #endif /* __DOXYGEN__ */
114
115 /**
116  * Compiler barrier.
117  *
118  * Guarantees that operation reordering does not occur at compile time
119  * for operations directly before and after the barrier.
120  */
121 #define rte_compiler_barrier() do {             \
122         asm volatile ("" : : : "memory");       \
123 } while(0)
124
125 /*------------------------- 16 bit atomic operations -------------------------*/
126
127 /**
128  * Atomic compare and set.
129  *
130  * (atomic) equivalent to:
131  *   if (*dst == exp)
132  *     *dst = src (all 16-bit words)
133  *
134  * @param dst
135  *   The destination location into which the value will be written.
136  * @param exp
137  *   The expected value.
138  * @param src
139  *   The new value.
140  * @return
141  *   Non-zero on success; 0 on failure.
142  */
143 static inline int
144 rte_atomic16_cmpset(volatile uint16_t *dst, uint16_t exp, uint16_t src);
145
146 #ifdef RTE_FORCE_INTRINSICS
147 static inline int
148 rte_atomic16_cmpset(volatile uint16_t *dst, uint16_t exp, uint16_t src)
149 {
150         return __sync_bool_compare_and_swap(dst, exp, src);
151 }
152 #endif
153
154 /**
155  * The atomic counter structure.
156  */
157 typedef struct {
158         volatile int16_t cnt; /**< An internal counter value. */
159 } rte_atomic16_t;
160
161 /**
162  * Static initializer for an atomic counter.
163  */
164 #define RTE_ATOMIC16_INIT(val) { (val) }
165
166 /**
167  * Initialize an atomic counter.
168  *
169  * @param v
170  *   A pointer to the atomic counter.
171  */
172 static inline void
173 rte_atomic16_init(rte_atomic16_t *v)
174 {
175         v->cnt = 0;
176 }
177
178 /**
179  * Atomically read a 16-bit value from a counter.
180  *
181  * @param v
182  *   A pointer to the atomic counter.
183  * @return
184  *   The value of the counter.
185  */
186 static inline int16_t
187 rte_atomic16_read(const rte_atomic16_t *v)
188 {
189         return v->cnt;
190 }
191
192 /**
193  * Atomically set a counter to a 16-bit value.
194  *
195  * @param v
196  *   A pointer to the atomic counter.
197  * @param new_value
198  *   The new value for the counter.
199  */
200 static inline void
201 rte_atomic16_set(rte_atomic16_t *v, int16_t new_value)
202 {
203         v->cnt = new_value;
204 }
205
206 /**
207  * Atomically add a 16-bit value to an atomic counter.
208  *
209  * @param v
210  *   A pointer to the atomic counter.
211  * @param inc
212  *   The value to be added to the counter.
213  */
214 static inline void
215 rte_atomic16_add(rte_atomic16_t *v, int16_t inc)
216 {
217         __sync_fetch_and_add(&v->cnt, inc);
218 }
219
220 /**
221  * Atomically subtract a 16-bit value from an atomic counter.
222  *
223  * @param v
224  *   A pointer to the atomic counter.
225  * @param dec
226  *   The value to be subtracted from the counter.
227  */
228 static inline void
229 rte_atomic16_sub(rte_atomic16_t *v, int16_t dec)
230 {
231         __sync_fetch_and_sub(&v->cnt, dec);
232 }
233
234 /**
235  * Atomically increment a counter by one.
236  *
237  * @param v
238  *   A pointer to the atomic counter.
239  */
240 static inline void
241 rte_atomic16_inc(rte_atomic16_t *v);
242
243 #ifdef RTE_FORCE_INTRINSICS
244 static inline void
245 rte_atomic16_inc(rte_atomic16_t *v)
246 {
247         rte_atomic16_add(v, 1);
248 }
249 #endif
250
251 /**
252  * Atomically decrement a counter by one.
253  *
254  * @param v
255  *   A pointer to the atomic counter.
256  */
257 static inline void
258 rte_atomic16_dec(rte_atomic16_t *v);
259
260 #ifdef RTE_FORCE_INTRINSICS
261 static inline void
262 rte_atomic16_dec(rte_atomic16_t *v)
263 {
264         rte_atomic16_sub(v, 1);
265 }
266 #endif
267
268 /**
269  * Atomically add a 16-bit value to a counter and return the result.
270  *
271  * Atomically adds the 16-bits value (inc) to the atomic counter (v) and
272  * returns the value of v after addition.
273  *
274  * @param v
275  *   A pointer to the atomic counter.
276  * @param inc
277  *   The value to be added to the counter.
278  * @return
279  *   The value of v after the addition.
280  */
281 static inline int16_t
282 rte_atomic16_add_return(rte_atomic16_t *v, int16_t inc)
283 {
284         return __sync_add_and_fetch(&v->cnt, inc);
285 }
286
287 /**
288  * Atomically subtract a 16-bit value from a counter and return
289  * the result.
290  *
291  * Atomically subtracts the 16-bit value (inc) from the atomic counter
292  * (v) and returns the value of v after the subtraction.
293  *
294  * @param v
295  *   A pointer to the atomic counter.
296  * @param dec
297  *   The value to be subtracted from the counter.
298  * @return
299  *   The value of v after the subtraction.
300  */
301 static inline int16_t
302 rte_atomic16_sub_return(rte_atomic16_t *v, int16_t dec)
303 {
304         return __sync_sub_and_fetch(&v->cnt, dec);
305 }
306
307 /**
308  * Atomically increment a 16-bit counter by one and test.
309  *
310  * Atomically increments the atomic counter (v) by one and returns true if
311  * the result is 0, or false in all other cases.
312  *
313  * @param v
314  *   A pointer to the atomic counter.
315  * @return
316  *   True if the result after the increment operation is 0; false otherwise.
317  */
318 static inline int rte_atomic16_inc_and_test(rte_atomic16_t *v);
319
320 #ifdef RTE_FORCE_INTRINSICS
321 static inline int rte_atomic16_inc_and_test(rte_atomic16_t *v)
322 {
323         return __sync_add_and_fetch(&v->cnt, 1) == 0;
324 }
325 #endif
326
327 /**
328  * Atomically decrement a 16-bit counter by one and test.
329  *
330  * Atomically decrements the atomic counter (v) by one and returns true if
331  * the result is 0, or false in all other cases.
332  *
333  * @param v
334  *   A pointer to the atomic counter.
335  * @return
336  *   True if the result after the decrement operation is 0; false otherwise.
337  */
338 static inline int rte_atomic16_dec_and_test(rte_atomic16_t *v);
339
340 #ifdef RTE_FORCE_INTRINSICS
341 static inline int rte_atomic16_dec_and_test(rte_atomic16_t *v)
342 {
343         return __sync_sub_and_fetch(&v->cnt, 1) == 0;
344 }
345 #endif
346
347 /**
348  * Atomically test and set a 16-bit atomic counter.
349  *
350  * If the counter value is already set, return 0 (failed). Otherwise, set
351  * the counter value to 1 and return 1 (success).
352  *
353  * @param v
354  *   A pointer to the atomic counter.
355  * @return
356  *   0 if failed; else 1, success.
357  */
358 static inline int rte_atomic16_test_and_set(rte_atomic16_t *v);
359
360 #ifdef RTE_FORCE_INTRINSICS
361 static inline int rte_atomic16_test_and_set(rte_atomic16_t *v)
362 {
363         return rte_atomic16_cmpset((volatile uint16_t *)&v->cnt, 0, 1);
364 }
365 #endif
366
367 /**
368  * Atomically set a 16-bit counter to 0.
369  *
370  * @param v
371  *   A pointer to the atomic counter.
372  */
373 static inline void rte_atomic16_clear(rte_atomic16_t *v)
374 {
375         v->cnt = 0;
376 }
377
378 /*------------------------- 32 bit atomic operations -------------------------*/
379
380 /**
381  * Atomic compare and set.
382  *
383  * (atomic) equivalent to:
384  *   if (*dst == exp)
385  *     *dst = src (all 32-bit words)
386  *
387  * @param dst
388  *   The destination location into which the value will be written.
389  * @param exp
390  *   The expected value.
391  * @param src
392  *   The new value.
393  * @return
394  *   Non-zero on success; 0 on failure.
395  */
396 static inline int
397 rte_atomic32_cmpset(volatile uint32_t *dst, uint32_t exp, uint32_t src);
398
399 #ifdef RTE_FORCE_INTRINSICS
400 static inline int
401 rte_atomic32_cmpset(volatile uint32_t *dst, uint32_t exp, uint32_t src)
402 {
403         return __sync_bool_compare_and_swap(dst, exp, src);
404 }
405 #endif
406
407 /**
408  * The atomic counter structure.
409  */
410 typedef struct {
411         volatile int32_t cnt; /**< An internal counter value. */
412 } rte_atomic32_t;
413
414 /**
415  * Static initializer for an atomic counter.
416  */
417 #define RTE_ATOMIC32_INIT(val) { (val) }
418
419 /**
420  * Initialize an atomic counter.
421  *
422  * @param v
423  *   A pointer to the atomic counter.
424  */
425 static inline void
426 rte_atomic32_init(rte_atomic32_t *v)
427 {
428         v->cnt = 0;
429 }
430
431 /**
432  * Atomically read a 32-bit value from a counter.
433  *
434  * @param v
435  *   A pointer to the atomic counter.
436  * @return
437  *   The value of the counter.
438  */
439 static inline int32_t
440 rte_atomic32_read(const rte_atomic32_t *v)
441 {
442         return v->cnt;
443 }
444
445 /**
446  * Atomically set a counter to a 32-bit value.
447  *
448  * @param v
449  *   A pointer to the atomic counter.
450  * @param new_value
451  *   The new value for the counter.
452  */
453 static inline void
454 rte_atomic32_set(rte_atomic32_t *v, int32_t new_value)
455 {
456         v->cnt = new_value;
457 }
458
459 /**
460  * Atomically add a 32-bit value to an atomic counter.
461  *
462  * @param v
463  *   A pointer to the atomic counter.
464  * @param inc
465  *   The value to be added to the counter.
466  */
467 static inline void
468 rte_atomic32_add(rte_atomic32_t *v, int32_t inc)
469 {
470         __sync_fetch_and_add(&v->cnt, inc);
471 }
472
473 /**
474  * Atomically subtract a 32-bit value from an atomic counter.
475  *
476  * @param v
477  *   A pointer to the atomic counter.
478  * @param dec
479  *   The value to be subtracted from the counter.
480  */
481 static inline void
482 rte_atomic32_sub(rte_atomic32_t *v, int32_t dec)
483 {
484         __sync_fetch_and_sub(&v->cnt, dec);
485 }
486
487 /**
488  * Atomically increment a counter by one.
489  *
490  * @param v
491  *   A pointer to the atomic counter.
492  */
493 static inline void
494 rte_atomic32_inc(rte_atomic32_t *v);
495
496 #ifdef RTE_FORCE_INTRINSICS
497 static inline void
498 rte_atomic32_inc(rte_atomic32_t *v)
499 {
500         rte_atomic32_add(v, 1);
501 }
502 #endif
503
504 /**
505  * Atomically decrement a counter by one.
506  *
507  * @param v
508  *   A pointer to the atomic counter.
509  */
510 static inline void
511 rte_atomic32_dec(rte_atomic32_t *v);
512
513 #ifdef RTE_FORCE_INTRINSICS
514 static inline void
515 rte_atomic32_dec(rte_atomic32_t *v)
516 {
517         rte_atomic32_sub(v,1);
518 }
519 #endif
520
521 /**
522  * Atomically add a 32-bit value to a counter and return the result.
523  *
524  * Atomically adds the 32-bits value (inc) to the atomic counter (v) and
525  * returns the value of v after addition.
526  *
527  * @param v
528  *   A pointer to the atomic counter.
529  * @param inc
530  *   The value to be added to the counter.
531  * @return
532  *   The value of v after the addition.
533  */
534 static inline int32_t
535 rte_atomic32_add_return(rte_atomic32_t *v, int32_t inc)
536 {
537         return __sync_add_and_fetch(&v->cnt, inc);
538 }
539
540 /**
541  * Atomically subtract a 32-bit value from a counter and return
542  * the result.
543  *
544  * Atomically subtracts the 32-bit value (inc) from the atomic counter
545  * (v) and returns the value of v after the subtraction.
546  *
547  * @param v
548  *   A pointer to the atomic counter.
549  * @param dec
550  *   The value to be subtracted from the counter.
551  * @return
552  *   The value of v after the subtraction.
553  */
554 static inline int32_t
555 rte_atomic32_sub_return(rte_atomic32_t *v, int32_t dec)
556 {
557         return __sync_sub_and_fetch(&v->cnt, dec);
558 }
559
560 /**
561  * Atomically increment a 32-bit counter by one and test.
562  *
563  * Atomically increments the atomic counter (v) by one and returns true if
564  * the result is 0, or false in all other cases.
565  *
566  * @param v
567  *   A pointer to the atomic counter.
568  * @return
569  *   True if the result after the increment operation is 0; false otherwise.
570  */
571 static inline int rte_atomic32_inc_and_test(rte_atomic32_t *v);
572
573 #ifdef RTE_FORCE_INTRINSICS
574 static inline int rte_atomic32_inc_and_test(rte_atomic32_t *v)
575 {
576         return __sync_add_and_fetch(&v->cnt, 1) == 0;
577 }
578 #endif
579
580 /**
581  * Atomically decrement a 32-bit counter by one and test.
582  *
583  * Atomically decrements the atomic counter (v) by one and returns true if
584  * the result is 0, or false in all other cases.
585  *
586  * @param v
587  *   A pointer to the atomic counter.
588  * @return
589  *   True if the result after the decrement operation is 0; false otherwise.
590  */
591 static inline int rte_atomic32_dec_and_test(rte_atomic32_t *v);
592
593 #ifdef RTE_FORCE_INTRINSICS
594 static inline int rte_atomic32_dec_and_test(rte_atomic32_t *v)
595 {
596         return __sync_sub_and_fetch(&v->cnt, 1) == 0;
597 }
598 #endif
599
600 /**
601  * Atomically test and set a 32-bit atomic counter.
602  *
603  * If the counter value is already set, return 0 (failed). Otherwise, set
604  * the counter value to 1 and return 1 (success).
605  *
606  * @param v
607  *   A pointer to the atomic counter.
608  * @return
609  *   0 if failed; else 1, success.
610  */
611 static inline int rte_atomic32_test_and_set(rte_atomic32_t *v);
612
613 #ifdef RTE_FORCE_INTRINSICS
614 static inline int rte_atomic32_test_and_set(rte_atomic32_t *v)
615 {
616         return rte_atomic32_cmpset((volatile uint32_t *)&v->cnt, 0, 1);
617 }
618 #endif
619
620 /**
621  * Atomically set a 32-bit counter to 0.
622  *
623  * @param v
624  *   A pointer to the atomic counter.
625  */
626 static inline void rte_atomic32_clear(rte_atomic32_t *v)
627 {
628         v->cnt = 0;
629 }
630
631 /*------------------------- 64 bit atomic operations -------------------------*/
632
633 /**
634  * An atomic compare and set function used by the mutex functions.
635  * (atomic) equivalent to:
636  *   if (*dst == exp)
637  *     *dst = src (all 64-bit words)
638  *
639  * @param dst
640  *   The destination into which the value will be written.
641  * @param exp
642  *   The expected value.
643  * @param src
644  *   The new value.
645  * @return
646  *   Non-zero on success; 0 on failure.
647  */
648 static inline int
649 rte_atomic64_cmpset(volatile uint64_t *dst, uint64_t exp, uint64_t src);
650
651 #ifdef RTE_FORCE_INTRINSICS
652 static inline int
653 rte_atomic64_cmpset(volatile uint64_t *dst, uint64_t exp, uint64_t src)
654 {
655         return __sync_bool_compare_and_swap(dst, exp, src);
656 }
657 #endif
658
659 /**
660  * The atomic counter structure.
661  */
662 typedef struct {
663         volatile int64_t cnt;  /**< Internal counter value. */
664 } rte_atomic64_t;
665
666 /**
667  * Static initializer for an atomic counter.
668  */
669 #define RTE_ATOMIC64_INIT(val) { (val) }
670
671 /**
672  * Initialize the atomic counter.
673  *
674  * @param v
675  *   A pointer to the atomic counter.
676  */
677 static inline void
678 rte_atomic64_init(rte_atomic64_t *v);
679
680 #ifdef RTE_FORCE_INTRINSICS
681 static inline void
682 rte_atomic64_init(rte_atomic64_t *v)
683 {
684 #ifdef __LP64__
685         v->cnt = 0;
686 #else
687         int success = 0;
688         uint64_t tmp;
689
690         while (success == 0) {
691                 tmp = v->cnt;
692                 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
693                                               tmp, 0);
694         }
695 #endif
696 }
697 #endif
698
699 /**
700  * Atomically read a 64-bit counter.
701  *
702  * @param v
703  *   A pointer to the atomic counter.
704  * @return
705  *   The value of the counter.
706  */
707 static inline int64_t
708 rte_atomic64_read(rte_atomic64_t *v);
709
710 #ifdef RTE_FORCE_INTRINSICS
711 static inline int64_t
712 rte_atomic64_read(rte_atomic64_t *v)
713 {
714 #ifdef __LP64__
715         return v->cnt;
716 #else
717         int success = 0;
718         uint64_t tmp;
719
720         while (success == 0) {
721                 tmp = v->cnt;
722                 /* replace the value by itself */
723                 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
724                                               tmp, tmp);
725         }
726         return tmp;
727 #endif
728 }
729 #endif
730
731 /**
732  * Atomically set a 64-bit counter.
733  *
734  * @param v
735  *   A pointer to the atomic counter.
736  * @param new_value
737  *   The new value of the counter.
738  */
739 static inline void
740 rte_atomic64_set(rte_atomic64_t *v, int64_t new_value);
741
742 #ifdef RTE_FORCE_INTRINSICS
743 static inline void
744 rte_atomic64_set(rte_atomic64_t *v, int64_t new_value)
745 {
746 #ifdef __LP64__
747         v->cnt = new_value;
748 #else
749         int success = 0;
750         uint64_t tmp;
751
752         while (success == 0) {
753                 tmp = v->cnt;
754                 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
755                                               tmp, new_value);
756         }
757 #endif
758 }
759 #endif
760
761 /**
762  * Atomically add a 64-bit value to a counter.
763  *
764  * @param v
765  *   A pointer to the atomic counter.
766  * @param inc
767  *   The value to be added to the counter.
768  */
769 static inline void
770 rte_atomic64_add(rte_atomic64_t *v, int64_t inc);
771
772 #ifdef RTE_FORCE_INTRINSICS
773 static inline void
774 rte_atomic64_add(rte_atomic64_t *v, int64_t inc)
775 {
776         __sync_fetch_and_add(&v->cnt, inc);
777 }
778 #endif
779
780 /**
781  * Atomically subtract a 64-bit value from a counter.
782  *
783  * @param v
784  *   A pointer to the atomic counter.
785  * @param dec
786  *   The value to be subtracted from the counter.
787  */
788 static inline void
789 rte_atomic64_sub(rte_atomic64_t *v, int64_t dec);
790
791 #ifdef RTE_FORCE_INTRINSICS
792 static inline void
793 rte_atomic64_sub(rte_atomic64_t *v, int64_t dec)
794 {
795         __sync_fetch_and_sub(&v->cnt, dec);
796 }
797 #endif
798
799 /**
800  * Atomically increment a 64-bit counter by one and test.
801  *
802  * @param v
803  *   A pointer to the atomic counter.
804  */
805 static inline void
806 rte_atomic64_inc(rte_atomic64_t *v);
807
808 #ifdef RTE_FORCE_INTRINSICS
809 static inline void
810 rte_atomic64_inc(rte_atomic64_t *v)
811 {
812         rte_atomic64_add(v, 1);
813 }
814 #endif
815
816 /**
817  * Atomically decrement a 64-bit counter by one and test.
818  *
819  * @param v
820  *   A pointer to the atomic counter.
821  */
822 static inline void
823 rte_atomic64_dec(rte_atomic64_t *v);
824
825 #ifdef RTE_FORCE_INTRINSICS
826 static inline void
827 rte_atomic64_dec(rte_atomic64_t *v)
828 {
829         rte_atomic64_sub(v, 1);
830 }
831 #endif
832
833 /**
834  * Add a 64-bit value to an atomic counter and return the result.
835  *
836  * Atomically adds the 64-bit value (inc) to the atomic counter (v) and
837  * returns the value of v after the addition.
838  *
839  * @param v
840  *   A pointer to the atomic counter.
841  * @param inc
842  *   The value to be added to the counter.
843  * @return
844  *   The value of v after the addition.
845  */
846 static inline int64_t
847 rte_atomic64_add_return(rte_atomic64_t *v, int64_t inc);
848
849 #ifdef RTE_FORCE_INTRINSICS
850 static inline int64_t
851 rte_atomic64_add_return(rte_atomic64_t *v, int64_t inc)
852 {
853         return __sync_add_and_fetch(&v->cnt, inc);
854 }
855 #endif
856
857 /**
858  * Subtract a 64-bit value from an atomic counter and return the result.
859  *
860  * Atomically subtracts the 64-bit value (dec) from the atomic counter (v)
861  * and returns the value of v after the subtraction.
862  *
863  * @param v
864  *   A pointer to the atomic counter.
865  * @param dec
866  *   The value to be subtracted from the counter.
867  * @return
868  *   The value of v after the subtraction.
869  */
870 static inline int64_t
871 rte_atomic64_sub_return(rte_atomic64_t *v, int64_t dec);
872
873 #ifdef RTE_FORCE_INTRINSICS
874 static inline int64_t
875 rte_atomic64_sub_return(rte_atomic64_t *v, int64_t dec)
876 {
877         return __sync_sub_and_fetch(&v->cnt, dec);
878 }
879 #endif
880
881 /**
882  * Atomically increment a 64-bit counter by one and test.
883  *
884  * Atomically increments the atomic counter (v) by one and returns
885  * true if the result is 0, or false in all other cases.
886  *
887  * @param v
888  *   A pointer to the atomic counter.
889  * @return
890  *   True if the result after the addition is 0; false otherwise.
891  */
892 static inline int rte_atomic64_inc_and_test(rte_atomic64_t *v);
893
894 #ifdef RTE_FORCE_INTRINSICS
895 static inline int rte_atomic64_inc_and_test(rte_atomic64_t *v)
896 {
897         return rte_atomic64_add_return(v, 1) == 0;
898 }
899 #endif
900
901 /**
902  * Atomically decrement a 64-bit counter by one and test.
903  *
904  * Atomically decrements the atomic counter (v) by one and returns true if
905  * the result is 0, or false in all other cases.
906  *
907  * @param v
908  *   A pointer to the atomic counter.
909  * @return
910  *   True if the result after subtraction is 0; false otherwise.
911  */
912 static inline int rte_atomic64_dec_and_test(rte_atomic64_t *v);
913
914 #ifdef RTE_FORCE_INTRINSICS
915 static inline int rte_atomic64_dec_and_test(rte_atomic64_t *v)
916 {
917         return rte_atomic64_sub_return(v, 1) == 0;
918 }
919 #endif
920
921 /**
922  * Atomically test and set a 64-bit atomic counter.
923  *
924  * If the counter value is already set, return 0 (failed). Otherwise, set
925  * the counter value to 1 and return 1 (success).
926  *
927  * @param v
928  *   A pointer to the atomic counter.
929  * @return
930  *   0 if failed; else 1, success.
931  */
932 static inline int rte_atomic64_test_and_set(rte_atomic64_t *v);
933
934 #ifdef RTE_FORCE_INTRINSICS
935 static inline int rte_atomic64_test_and_set(rte_atomic64_t *v)
936 {
937         return rte_atomic64_cmpset((volatile uint64_t *)&v->cnt, 0, 1);
938 }
939 #endif
940
941 /**
942  * Atomically set a 64-bit counter to 0.
943  *
944  * @param v
945  *   A pointer to the atomic counter.
946  */
947 static inline void rte_atomic64_clear(rte_atomic64_t *v);
948
949 #ifdef RTE_FORCE_INTRINSICS
950 static inline void rte_atomic64_clear(rte_atomic64_t *v)
951 {
952         rte_atomic64_set(v, 0);
953 }
954 #endif
955
956 #endif /* _RTE_ATOMIC_H_ */