4 * Copyright(c) 2010-2013 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
36 * Inspired from FreeBSD src/sys/i386/include/atomic.h
37 * Copyright (c) 1998 Doug Rabson
38 * All rights reserved.
41 #ifndef _RTE_ATOMIC_H_
42 #error "don't include this file directly, please include generic <rte_atomic.h>"
45 #ifndef _RTE_I686_ATOMIC_H_
46 #define _RTE_I686_ATOMIC_H_
51 * Atomic Operations on i686
55 /*------------------------- 64 bit atomic operations -------------------------*/
58 * An atomic compare and set function used by the mutex functions.
59 * (atomic) equivalent to:
61 * *dst = src (all 64-bit words)
64 * The destination into which the value will be written.
70 * Non-zero on success; 0 on failure.
73 rte_atomic64_cmpset(volatile uint64_t *dst, uint64_t exp, uint64_t src)
91 : [res] "=a" (res) /* result in eax */
92 : [dst] "S" (dst), /* esi */
93 "b" (_src.l32), /* ebx */
94 "c" (_src.h32), /* ecx */
95 "a" (_exp.l32), /* eax */
96 "d" (_exp.h32) /* edx */
97 : "memory" ); /* no-clobber list */
103 * The atomic counter structure.
106 volatile int64_t cnt; /**< Internal counter value. */
110 * Static initializer for an atomic counter.
112 #define RTE_ATOMIC64_INIT(val) { (val) }
115 * Initialize the atomic counter.
118 * A pointer to the atomic counter.
121 rte_atomic64_init(rte_atomic64_t *v)
126 while (success == 0) {
128 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
134 * Atomically read a 64-bit counter.
137 * A pointer to the atomic counter.
139 * The value of the counter.
141 static inline int64_t
142 rte_atomic64_read(rte_atomic64_t *v)
147 while (success == 0) {
149 /* replace the value by itself */
150 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
157 * Atomically set a 64-bit counter.
160 * A pointer to the atomic counter.
162 * The new value of the counter.
165 rte_atomic64_set(rte_atomic64_t *v, int64_t new_value)
170 while (success == 0) {
172 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
178 * Atomically add a 64-bit value to a counter.
181 * A pointer to the atomic counter.
183 * The value to be added to the counter.
186 rte_atomic64_add(rte_atomic64_t *v, int64_t inc)
191 while (success == 0) {
193 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
199 * Atomically subtract a 64-bit value from a counter.
202 * A pointer to the atomic counter.
204 * The value to be substracted from the counter.
207 rte_atomic64_sub(rte_atomic64_t *v, int64_t dec)
212 while (success == 0) {
214 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
220 * Atomically increment a 64-bit counter by one and test.
223 * A pointer to the atomic counter.
226 rte_atomic64_inc(rte_atomic64_t *v)
228 rte_atomic64_add(v, 1);
232 * Atomically decrement a 64-bit counter by one and test.
235 * A pointer to the atomic counter.
238 rte_atomic64_dec(rte_atomic64_t *v)
240 rte_atomic64_sub(v, 1);
244 * Add a 64-bit value to an atomic counter and return the result.
246 * Atomically adds the 64-bit value (inc) to the atomic counter (v) and
247 * returns the value of v after the addition.
250 * A pointer to the atomic counter.
252 * The value to be added to the counter.
254 * The value of v after the addition.
256 static inline int64_t
257 rte_atomic64_add_return(rte_atomic64_t *v, int64_t inc)
262 while (success == 0) {
264 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
272 * Subtract a 64-bit value from an atomic counter and return the result.
274 * Atomically subtracts the 64-bit value (dec) from the atomic counter (v)
275 * and returns the value of v after the substraction.
278 * A pointer to the atomic counter.
280 * The value to be substracted from the counter.
282 * The value of v after the substraction.
284 static inline int64_t
285 rte_atomic64_sub_return(rte_atomic64_t *v, int64_t dec)
290 while (success == 0) {
292 success = rte_atomic64_cmpset((volatile uint64_t *)&v->cnt,
300 * Atomically increment a 64-bit counter by one and test.
302 * Atomically increments the atomic counter (v) by one and returns
303 * true if the result is 0, or false in all other cases.
306 * A pointer to the atomic counter.
308 * True if the result after the addition is 0; false otherwise.
310 static inline int rte_atomic64_inc_and_test(rte_atomic64_t *v)
312 return rte_atomic64_add_return(v, 1) == 0;
316 * Atomically decrement a 64-bit counter by one and test.
318 * Atomically decrements the atomic counter (v) by one and returns true if
319 * the result is 0, or false in all other cases.
322 * A pointer to the atomic counter.
324 * True if the result after substraction is 0; false otherwise.
326 static inline int rte_atomic64_dec_and_test(rte_atomic64_t *v)
328 return rte_atomic64_sub_return(v, 1) == 0;
332 * Atomically test and set a 64-bit atomic counter.
334 * If the counter value is already set, return 0 (failed). Otherwise, set
335 * the counter value to 1 and return 1 (success).
338 * A pointer to the atomic counter.
340 * 0 if failed; else 1, success.
342 static inline int rte_atomic64_test_and_set(rte_atomic64_t *v)
344 return rte_atomic64_cmpset((volatile uint64_t *)&v->cnt, 0, 1);
348 * Atomically set a 64-bit counter to 0.
351 * A pointer to the atomic counter.
353 static inline void rte_atomic64_clear(rte_atomic64_t *v)
355 rte_atomic64_set(v, 0);
358 #endif /* _RTE_I686_ATOMIC_H_ */