1 /** 2 * Many similar implementations exist. See for example libwsbm 3 * or the linux kernel include/atomic.h 4 * 5 * No copyright claimed on this file. 6 * 7 */ 8 9 #ifndef U_ATOMIC_H 10 #define U_ATOMIC_H 11 12 #include "pipe/p_compiler.h" 13 #include "pipe/p_defines.h" 14 15 /* Favor OS-provided implementations. 16 * 17 * Where no OS-provided implementation is available, fall back to 18 * locally coded assembly, compiler intrinsic or ultimately a 19 * mutex-based implementation. 20 */ 21 #if defined(PIPE_OS_SOLARIS) 22 #define PIPE_ATOMIC_OS_SOLARIS 23 #elif defined(PIPE_CC_MSVC) 24 #define PIPE_ATOMIC_MSVC_INTRINSIC 25 #elif (defined(PIPE_CC_MSVC) && defined(PIPE_ARCH_X86)) 26 #define PIPE_ATOMIC_ASM_MSVC_X86 27 #elif (defined(PIPE_CC_GCC) && defined(PIPE_ARCH_X86)) 28 #define PIPE_ATOMIC_ASM_GCC_X86 29 #elif (defined(PIPE_CC_GCC) && defined(PIPE_ARCH_X86_64)) 30 #define PIPE_ATOMIC_ASM_GCC_X86_64 31 #elif defined(PIPE_CC_GCC) && (PIPE_CC_GCC_VERSION >= 401) 32 #define PIPE_ATOMIC_GCC_INTRINSIC 33 #else 34 #error "Unsupported platform" 35 #endif 36 37 38 #if defined(PIPE_ATOMIC_ASM_GCC_X86_64) 39 #define PIPE_ATOMIC "GCC x86_64 assembly" 40 41 #ifdef __cplusplus 42 extern "C" { 43 #endif 44 45 #define p_atomic_set(_v, _i) (*(_v) = (_i)) 46 #define p_atomic_read(_v) (*(_v)) 47 48 static INLINE boolean 49 p_atomic_dec_zero(int32_t *v) 50 { 51 unsigned char c; 52 53 __asm__ __volatile__("lock; decl %0; sete %1":"+m"(*v), "=qm"(c) 54 ::"memory"); 55 56 return c != 0; 57 } 58 59 static INLINE void 60 p_atomic_inc(int32_t *v) 61 { 62 __asm__ __volatile__("lock; incl %0":"+m"(*v)); 63 } 64 65 static INLINE void 66 p_atomic_dec(int32_t *v) 67 { 68 __asm__ __volatile__("lock; decl %0":"+m"(*v)); 69 } 70 71 static INLINE int32_t 72 p_atomic_cmpxchg(int32_t *v, int32_t old, int32_t _new) 73 { 74 return __sync_val_compare_and_swap(v, old, _new); 75 } 76 77 #ifdef __cplusplus 78 } 79 #endif 80 81 #endif /* PIPE_ATOMIC_ASM_GCC_X86_64 */ 82 83 84 #if defined(PIPE_ATOMIC_ASM_GCC_X86) 85 86 #define PIPE_ATOMIC "GCC x86 assembly" 87 88 #ifdef __cplusplus 89 extern "C" { 90 #endif 91 92 #define p_atomic_set(_v, _i) (*(_v) = (_i)) 93 #define p_atomic_read(_v) (*(_v)) 94 95 static INLINE boolean 96 p_atomic_dec_zero(int32_t *v) 97 { 98 unsigned char c; 99 100 __asm__ __volatile__("lock; decl %0; sete %1":"+m"(*v), "=qm"(c) 101 ::"memory"); 102 103 return c != 0; 104 } 105 106 static INLINE void 107 p_atomic_inc(int32_t *v) 108 { 109 __asm__ __volatile__("lock; incl %0":"+m"(*v)); 110 } 111 112 static INLINE void 113 p_atomic_dec(int32_t *v) 114 { 115 __asm__ __volatile__("lock; decl %0":"+m"(*v)); 116 } 117 118 static INLINE int32_t 119 p_atomic_cmpxchg(int32_t *v, int32_t old, int32_t _new) 120 { 121 return __sync_val_compare_and_swap(v, old, _new); 122 } 123 124 #ifdef __cplusplus 125 } 126 #endif 127 128 #endif 129 130 131 132 /* Implementation using GCC-provided synchronization intrinsics 133 */ 134 #if defined(PIPE_ATOMIC_GCC_INTRINSIC) 135 136 #define PIPE_ATOMIC "GCC Sync Intrinsics" 137 138 #ifdef __cplusplus 139 extern "C" { 140 #endif 141 142 #define p_atomic_set(_v, _i) (*(_v) = (_i)) 143 #define p_atomic_read(_v) (*(_v)) 144 145 static INLINE boolean 146 p_atomic_dec_zero(int32_t *v) 147 { 148 return (__sync_sub_and_fetch(v, 1) == 0); 149 } 150 151 static INLINE void 152 p_atomic_inc(int32_t *v) 153 { 154 (void) __sync_add_and_fetch(v, 1); 155 } 156 157 static INLINE void 158 p_atomic_dec(int32_t *v) 159 { 160 (void) __sync_sub_and_fetch(v, 1); 161 } 162 163 static INLINE int32_t 164 p_atomic_cmpxchg(int32_t *v, int32_t old, int32_t _new) 165 { 166 return __sync_val_compare_and_swap(v, old, _new); 167 } 168 169 #ifdef __cplusplus 170 } 171 #endif 172 173 #endif 174 175 176 177 /* Unlocked version for single threaded environments, such as some 178 * windows kernel modules. 179 */ 180 #if defined(PIPE_ATOMIC_OS_UNLOCKED) 181 182 #define PIPE_ATOMIC "Unlocked" 183 184 #define p_atomic_set(_v, _i) (*(_v) = (_i)) 185 #define p_atomic_read(_v) (*(_v)) 186 #define p_atomic_dec_zero(_v) ((boolean) --(*(_v))) 187 #define p_atomic_inc(_v) ((void) (*(_v))++) 188 #define p_atomic_dec(_v) ((void) (*(_v))--) 189 #define p_atomic_cmpxchg(_v, old, _new) (*(_v) == old ? *(_v) = (_new) : *(_v)) 190 191 #endif 192 193 194 /* Locally coded assembly for MSVC on x86: 195 */ 196 #if defined(PIPE_ATOMIC_ASM_MSVC_X86) 197 198 #define PIPE_ATOMIC "MSVC x86 assembly" 199 200 #ifdef __cplusplus 201 extern "C" { 202 #endif 203 204 #define p_atomic_set(_v, _i) (*(_v) = (_i)) 205 #define p_atomic_read(_v) (*(_v)) 206 207 static INLINE boolean 208 p_atomic_dec_zero(int32_t *v) 209 { 210 unsigned char c; 211 212 __asm { 213 mov eax, [v] 214 lock dec dword ptr [eax] 215 sete byte ptr [c] 216 } 217 218 return c != 0; 219 } 220 221 static INLINE void 222 p_atomic_inc(int32_t *v) 223 { 224 __asm { 225 mov eax, [v] 226 lock inc dword ptr [eax] 227 } 228 } 229 230 static INLINE void 231 p_atomic_dec(int32_t *v) 232 { 233 __asm { 234 mov eax, [v] 235 lock dec dword ptr [eax] 236 } 237 } 238 239 static INLINE int32_t 240 p_atomic_cmpxchg(int32_t *v, int32_t old, int32_t _new) 241 { 242 int32_t orig; 243 244 __asm { 245 mov ecx, [v] 246 mov eax, [old] 247 mov edx, [_new] 248 lock cmpxchg [ecx], edx 249 mov [orig], eax 250 } 251 252 return orig; 253 } 254 255 #ifdef __cplusplus 256 } 257 #endif 258 259 #endif 260 261 262 #if defined(PIPE_ATOMIC_MSVC_INTRINSIC) 263 264 #define PIPE_ATOMIC "MSVC Intrinsics" 265 266 #include <intrin.h> 267 268 #pragma intrinsic(_InterlockedIncrement) 269 #pragma intrinsic(_InterlockedDecrement) 270 #pragma intrinsic(_InterlockedCompareExchange) 271 272 #ifdef __cplusplus 273 extern "C" { 274 #endif 275 276 #define p_atomic_set(_v, _i) (*(_v) = (_i)) 277 #define p_atomic_read(_v) (*(_v)) 278 279 static INLINE boolean 280 p_atomic_dec_zero(int32_t *v) 281 { 282 return _InterlockedDecrement((long *)v) == 0; 283 } 284 285 static INLINE void 286 p_atomic_inc(int32_t *v) 287 { 288 _InterlockedIncrement((long *)v); 289 } 290 291 static INLINE void 292 p_atomic_dec(int32_t *v) 293 { 294 _InterlockedDecrement((long *)v); 295 } 296 297 static INLINE int32_t 298 p_atomic_cmpxchg(int32_t *v, int32_t old, int32_t _new) 299 { 300 return _InterlockedCompareExchange((long *)v, _new, old); 301 } 302 303 #ifdef __cplusplus 304 } 305 #endif 306 307 #endif 308 309 #if defined(PIPE_ATOMIC_OS_SOLARIS) 310 311 #define PIPE_ATOMIC "Solaris OS atomic functions" 312 313 #include <atomic.h> 314 315 #ifdef __cplusplus 316 extern "C" { 317 #endif 318 319 #define p_atomic_set(_v, _i) (*(_v) = (_i)) 320 #define p_atomic_read(_v) (*(_v)) 321 322 static INLINE boolean 323 p_atomic_dec_zero(int32_t *v) 324 { 325 uint32_t n = atomic_dec_32_nv((uint32_t *) v); 326 327 return n != 0; 328 } 329 330 #define p_atomic_inc(_v) atomic_inc_32((uint32_t *) _v) 331 #define p_atomic_dec(_v) atomic_dec_32((uint32_t *) _v) 332 333 #define p_atomic_cmpxchg(_v, _old, _new) \ 334 atomic_cas_32( (uint32_t *) _v, (uint32_t) _old, (uint32_t) _new) 335 336 #ifdef __cplusplus 337 } 338 #endif 339 340 #endif 341 342 343 #ifndef PIPE_ATOMIC 344 #error "No pipe_atomic implementation selected" 345 #endif 346 347 348 349 #endif /* U_ATOMIC_H */ 350