2 * Copyright (c) 2009-2010 Brad Penoff
3 * Copyright (c) 2009-2010 Humaira Kamal
4 * Copyright (c) 2011-2012 Irene Ruengeler
5 * Copyright (c) 2011-2012 Michael Tuexen
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #ifndef _USER_ATOMIC_H_
32 #define _USER_ATOMIC_H_
34 /* __Userspace__ version of sys/i386/include/atomic.h goes here */
36 /* TODO In the future, might want to not use i386 specific assembly.
37 * The options include:
38 * - implement them generically (but maybe not truly atomic?) in userspace
39 * - have ifdef's for __Userspace_arch_ perhaps (OS isn't enough...)
43 #include <sys/types.h>
45 #if defined(__APPLE__) || defined(_WIN32)
47 #define atomic_add_int(addr, val) InterlockedExchangeAdd((LPLONG)addr, (LONG)val)
48 #define atomic_fetchadd_int(addr, val) InterlockedExchangeAdd((LPLONG)addr, (LONG)val)
49 #define atomic_subtract_int(addr, val) InterlockedExchangeAdd((LPLONG)addr,-((LONG)val))
50 #define atomic_cmpset_int(dst, exp, src) InterlockedCompareExchange((LPLONG)dst, src, exp)
51 #define SCTP_DECREMENT_AND_CHECK_REFCOUNT(addr) (InterlockedExchangeAdd((LPLONG)addr, (-1L)) == 1)
53 #include <libkern/OSAtomic.h>
54 #define atomic_add_int(addr, val) OSAtomicAdd32Barrier(val, (int32_t *)addr)
55 #define atomic_fetchadd_int(addr, val) OSAtomicAdd32Barrier(val, (int32_t *)addr)
56 #define atomic_subtract_int(addr, val) OSAtomicAdd32Barrier(-val, (int32_t *)addr)
57 #define atomic_cmpset_int(dst, exp, src) OSAtomicCompareAndSwapIntBarrier(exp, src, (int *)dst)
58 #define SCTP_DECREMENT_AND_CHECK_REFCOUNT(addr) (atomic_fetchadd_int(addr, -1) == 0)
61 #if defined(INVARIANTS)
62 #define SCTP_SAVE_ATOMIC_DECREMENT(addr, val) \
65 newval = atomic_fetchadd_int(addr, -val); \
67 panic("Counter goes negative"); \
71 #define SCTP_SAVE_ATOMIC_DECREMENT(addr, val) \
74 newval = atomic_fetchadd_int(addr, -val); \
81 static void atomic_init(void) {} /* empty when we are not using atomic_mtx */
83 static inline void atomic_init(void) {} /* empty when we are not using atomic_mtx */
87 /* Using gcc built-in functions for atomic memory operations
88 Reference: http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html
89 Requires gcc version 4.1.0
90 compile with -march=i486
93 /*Atomically add V to *P.*/
94 #define atomic_add_int(P, V) (void) __sync_fetch_and_add(P, V)
96 /*Atomically subtrace V from *P.*/
97 #define atomic_subtract_int(P, V) (void) __sync_fetch_and_sub(P, V)
100 * Atomically add the value of v to the integer pointed to by p and return
101 * the previous value of *p.
103 #define atomic_fetchadd_int(p, v) __sync_fetch_and_add(p, v)
105 /* Following explanation from src/sys/i386/include/atomic.h,
106 * for atomic compare and set
108 * if (*dst == exp) *dst = src (all 32 bit words)
110 * Returns 0 on failure, non-zero on success
113 #define atomic_cmpset_int(dst, exp, src) __sync_bool_compare_and_swap(dst, exp, src)
115 #define SCTP_DECREMENT_AND_CHECK_REFCOUNT(addr) (atomic_fetchadd_int(addr, -1) == 1)
116 #if defined(INVARIANTS)
117 #define SCTP_SAVE_ATOMIC_DECREMENT(addr, val) \
120 oldval = atomic_fetchadd_int(addr, -val); \
121 if (oldval < val) { \
122 panic("Counter goes negative"); \
126 #define SCTP_SAVE_ATOMIC_DECREMENT(addr, val) \
129 oldval = atomic_fetchadd_int(addr, -val); \
130 if (oldval < val) { \
135 static inline void atomic_init(void) {} /* empty when we are not using atomic_mtx */
138 #if 0 /* using libatomic_ops */
139 #include "user_include/atomic_ops.h"
141 /*Atomically add incr to *P, and return the original value of *P.*/
142 #define atomic_add_int(P, V) AO_fetch_and_add((AO_t*)P, V)
144 #define atomic_subtract_int(P, V) AO_fetch_and_add((AO_t*)P, -(V))
147 * Atomically add the value of v to the integer pointed to by p and return
148 * the previous value of *p.
150 #define atomic_fetchadd_int(p, v) AO_fetch_and_add((AO_t*)p, v)
152 /* Atomically compare *addr to old_val, and replace *addr by new_val
153 if the first comparison succeeds. Returns nonzero if the comparison
154 succeeded and *addr was updated.
156 /* Following Explanation from src/sys/i386/include/atomic.h, which
157 matches that of AO_compare_and_swap above.
158 * Atomic compare and set, used by the mutex functions
160 * if (*dst == exp) *dst = src (all 32 bit words)
162 * Returns 0 on failure, non-zero on success
165 #define atomic_cmpset_int(dst, exp, src) AO_compare_and_swap((AO_t*)dst, exp, src)
167 static inline void atomic_init() {} /* empty when we are not using atomic_mtx */
168 #endif /* closing #if for libatomic */
170 #if 0 /* using atomic_mtx */
174 extern userland_mutex_t atomic_mtx;
177 static inline void atomic_init() {
178 InitializeCriticalSection(&atomic_mtx);
180 static inline void atomic_destroy() {
181 DeleteCriticalSection(&atomic_mtx);
183 static inline void atomic_lock() {
184 EnterCriticalSection(&atomic_mtx);
186 static inline void atomic_unlock() {
187 LeaveCriticalSection(&atomic_mtx);
190 static inline void atomic_init() {
191 pthread_mutexattr_t mutex_attr;
193 pthread_mutexattr_init(&mutex_attr);
195 pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
197 pthread_mutex_init(&accept_mtx, &mutex_attr);
198 pthread_mutexattr_destroy(&mutex_attr);
200 static inline void atomic_destroy() {
201 (void)pthread_mutex_destroy(&atomic_mtx);
203 static inline void atomic_lock() {
205 KASSERT(pthread_mutex_lock(&atomic_mtx) == 0, ("atomic_lock: atomic_mtx already locked"))
207 (void)pthread_mutex_lock(&atomic_mtx);
210 static inline void atomic_unlock() {
212 KASSERT(pthread_mutex_unlock(&atomic_mtx) == 0, ("atomic_unlock: atomic_mtx not locked"))
214 (void)pthread_mutex_unlock(&atomic_mtx);
219 * For userland, always use lock prefixes so that the binaries will run
220 * on both SMP and !SMP systems.
223 #define MPLOCKED "lock ; "
226 * Atomically add the value of v to the integer pointed to by p and return
227 * the previous value of *p.
229 static __inline u_int
230 atomic_fetchadd_int(volatile void *n, u_int v)
237 "# atomic_fetchadd_int"
238 : "+r" (v), /* 0 (result) */
247 #ifdef CPU_DISABLE_CMPXCHG
250 atomic_cmpset_int(volatile u_int *dst, u_int exp, u_int src)
264 "# atomic_cmpset_int"
265 : "=q" (res), /* 0 */
276 #else /* !CPU_DISABLE_CMPXCHG */
279 atomic_cmpset_int(volatile u_int *dst, u_int exp, u_int src)
289 "# atomic_cmpset_int"
290 : "=a" (res), /* 0 */
301 #endif /* CPU_DISABLE_CMPXCHG */
303 #define atomic_add_int(P, V) do { \
305 (*(u_int *)(P) += (V)); \
308 #define atomic_subtract_int(P, V) do { \
310 (*(u_int *)(P) -= (V)); \