1 /*- 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 6 * 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 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. 17 * 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 28 * SUCH DAMAGE. 29 */ 30 31 #ifndef _USER_ATOMIC_H_ 32 #define _USER_ATOMIC_H_ 33 34 /* __Userspace__ version of sys/i386/include/atomic.h goes here */ 35 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...) 40 */ 41 42 #include <stdio.h> 43 #include <sys/types.h> 44 45 #if defined(__Userspace_os_Darwin) || defined (__Userspace_os_Windows) 46 #if defined (__Userspace_os_Windows) 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) 52 #else 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) 59 #endif 60 61 #if defined(INVARIANTS) 62 #define SCTP_SAVE_ATOMIC_DECREMENT(addr, val) \ 63 { \ 64 int32_t newval; \ 65 newval = atomic_fetchadd_int(addr, -val); \ 66 if (newval < 0) { \ 67 panic("Counter goes negative"); \ 68 } \ 69 } 70 #else 71 #define SCTP_SAVE_ATOMIC_DECREMENT(addr, val) \ 72 { \ 73 int32_t newval; \ 74 newval = atomic_fetchadd_int(addr, -val); \ 75 if (newval < 0) { \ 76 *addr = 0; \ 77 } \ 78 } 79 #if defined(__Userspace_os_Windows) 80 static void atomic_init() {} /* empty when we are not using atomic_mtx */ 81 #else 82 static inline void atomic_init() {} /* empty when we are not using atomic_mtx */ 83 #endif 84 #endif 85 86 #else 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 91 */ 92 93 /*Atomically add V to *P.*/ 94 #define atomic_add_int(P, V) (void) __sync_fetch_and_add(P, V) 95 96 /*Atomically subtrace V from *P.*/ 97 #define atomic_subtract_int(P, V) (void) __sync_fetch_and_sub(P, V) 98 99 /* 100 * Atomically add the value of v to the integer pointed to by p and return 101 * the previous value of *p. 102 */ 103 #define atomic_fetchadd_int(p, v) __sync_fetch_and_add(p, v) 104 105 /* Following explanation from src/sys/i386/include/atomic.h, 106 * for atomic compare and set 107 * 108 * if (*dst == exp) *dst = src (all 32 bit words) 109 * 110 * Returns 0 on failure, non-zero on success 111 */ 112 113 #define atomic_cmpset_int(dst, exp, src) __sync_bool_compare_and_swap(dst, exp, src) 114 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) \ 118 { \ 119 int32_t oldval; \ 120 oldval = atomic_fetchadd_int(addr, -val); \ 121 if (oldval < val) { \ 122 panic("Counter goes negative"); \ 123 } \ 124 } 125 #else 126 #define SCTP_SAVE_ATOMIC_DECREMENT(addr, val) \ 127 { \ 128 int32_t oldval; \ 129 oldval = atomic_fetchadd_int(addr, -val); \ 130 if (oldval < val) { \ 131 *addr = 0; \ 132 } \ 133 } 134 #endif 135 static inline void atomic_init() {} /* empty when we are not using atomic_mtx */ 136 #endif 137 138 #if 0 /* using libatomic_ops */ 139 #include "user_include/atomic_ops.h" 140 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) 143 144 #define atomic_subtract_int(P, V) AO_fetch_and_add((AO_t*)P, -(V)) 145 146 /* 147 * Atomically add the value of v to the integer pointed to by p and return 148 * the previous value of *p. 149 */ 150 #define atomic_fetchadd_int(p, v) AO_fetch_and_add((AO_t*)p, v) 151 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. 155 */ 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 159 * 160 * if (*dst == exp) *dst = src (all 32 bit words) 161 * 162 * Returns 0 on failure, non-zero on success 163 */ 164 165 #define atomic_cmpset_int(dst, exp, src) AO_compare_and_swap((AO_t*)dst, exp, src) 166 167 static inline void atomic_init() {} /* empty when we are not using atomic_mtx */ 168 #endif /* closing #if for libatomic */ 169 170 #if 0 /* using atomic_mtx */ 171 172 #include <pthread.h> 173 174 extern userland_mutex_t atomic_mtx; 175 176 #if defined (__Userspace_os_Windows) 177 static inline void atomic_init() { 178 InitializeCriticalSection(&atomic_mtx); 179 } 180 static inline void atomic_destroy() { 181 DeleteCriticalSection(&atomic_mtx); 182 } 183 static inline void atomic_lock() { 184 EnterCriticalSection(&atomic_mtx); 185 } 186 static inline void atomic_unlock() { 187 LeaveCriticalSection(&atomic_mtx); 188 } 189 #else 190 static inline void atomic_init() { 191 (void)pthread_mutex_init(&atomic_mtx, NULL); 192 } 193 static inline void atomic_destroy() { 194 (void)pthread_mutex_destroy(&atomic_mtx); 195 } 196 static inline void atomic_lock() { 197 (void)pthread_mutex_lock(&atomic_mtx); 198 } 199 static inline void atomic_unlock() { 200 (void)pthread_mutex_unlock(&atomic_mtx); 201 } 202 #endif 203 /* 204 * For userland, always use lock prefixes so that the binaries will run 205 * on both SMP and !SMP systems. 206 */ 207 208 #define MPLOCKED "lock ; " 209 210 /* 211 * Atomically add the value of v to the integer pointed to by p and return 212 * the previous value of *p. 213 */ 214 static __inline u_int 215 atomic_fetchadd_int(volatile void *n, u_int v) 216 { 217 int *p = (int *) n; 218 atomic_lock(); 219 __asm __volatile( 220 " " MPLOCKED " " 221 " xaddl %0, %1 ; " 222 "# atomic_fetchadd_int" 223 : "+r" (v), /* 0 (result) */ 224 "=m" (*p) /* 1 */ 225 : "m" (*p)); /* 2 */ 226 atomic_unlock(); 227 228 return (v); 229 } 230 231 232 #ifdef CPU_DISABLE_CMPXCHG 233 234 static __inline int 235 atomic_cmpset_int(volatile u_int *dst, u_int exp, u_int src) 236 { 237 u_char res; 238 239 atomic_lock(); 240 __asm __volatile( 241 " pushfl ; " 242 " cli ; " 243 " cmpl %3,%4 ; " 244 " jne 1f ; " 245 " movl %2,%1 ; " 246 "1: " 247 " sete %0 ; " 248 " popfl ; " 249 "# atomic_cmpset_int" 250 : "=q" (res), /* 0 */ 251 "=m" (*dst) /* 1 */ 252 : "r" (src), /* 2 */ 253 "r" (exp), /* 3 */ 254 "m" (*dst) /* 4 */ 255 : "memory"); 256 atomic_unlock(); 257 258 return (res); 259 } 260 261 #else /* !CPU_DISABLE_CMPXCHG */ 262 263 static __inline int 264 atomic_cmpset_int(volatile u_int *dst, u_int exp, u_int src) 265 { 266 atomic_lock(); 267 u_char res; 268 269 __asm __volatile( 270 " " MPLOCKED " " 271 " cmpxchgl %2,%1 ; " 272 " sete %0 ; " 273 "1: " 274 "# atomic_cmpset_int" 275 : "=a" (res), /* 0 */ 276 "=m" (*dst) /* 1 */ 277 : "r" (src), /* 2 */ 278 "a" (exp), /* 3 */ 279 "m" (*dst) /* 4 */ 280 : "memory"); 281 atomic_unlock(); 282 283 return (res); 284 } 285 286 #endif /* CPU_DISABLE_CMPXCHG */ 287 288 #define atomic_add_int(P, V) do { \ 289 atomic_lock(); \ 290 (*(u_int *)(P) += (V)); \ 291 atomic_unlock(); \ 292 } while(0) 293 #define atomic_subtract_int(P, V) do { \ 294 atomic_lock(); \ 295 (*(u_int *)(P) -= (V)); \ 296 atomic_unlock(); \ 297 } while(0) 298 299 #endif 300 #endif 301