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