1 1.1 christos // SPDX-FileCopyrightText: 1991-1994 by Xerox Corporation. All rights reserved. 2 1.1 christos // SPDX-FileCopyrightText: 1996-1999 by Silicon Graphics. All rights reserved. 3 1.1 christos // SPDX-FileCopyrightText: 1999-2004 Hewlett-Packard Development Company, L.P. 4 1.1 christos // SPDX-FileCopyrightText: 2009 Mathieu Desnoyers <mathieu.desnoyers (at) efficios.com> 5 1.1 christos // SPDX-FileCopyrightText: 2010 Paolo Bonzini 6 1.1 christos // 7 1.1 christos // SPDX-License-Identifier: LicenseRef-Boehm-GC 8 1.1 christos 9 1.1 christos #ifndef _URCU_UATOMIC_GENERIC_H 10 1.1 christos #define _URCU_UATOMIC_GENERIC_H 11 1.1 christos 12 1.1 christos /* 13 1.1 christos * Code inspired from libuatomic_ops-1.2, inherited in part from the 14 1.1 christos * Boehm-Demers-Weiser conservative garbage collector. 15 1.1 christos */ 16 1.1 christos 17 1.1 christos #include <stdint.h> 18 1.1 christos #include <urcu/compiler.h> 19 1.1 christos #include <urcu/system.h> 20 1.1 christos 21 1.1 christos #ifdef __cplusplus 22 1.1 christos extern "C" { 23 1.1 christos #endif 24 1.1 christos 25 1.1 christos /* 26 1.1 christos * Can be defined for the architecture. 27 1.1 christos * 28 1.1 christos * What needs to be emitted _before_ the `operation' with memory ordering `mo'. 29 1.1 christos */ 30 1.1 christos #ifndef _cmm_compat_c11_smp_mb__before_mo 31 1.1 christos # define _cmm_compat_c11_smp_mb__before_mo(operation, mo) \ 32 1.1 christos do { \ 33 1.1 christos switch (mo) { \ 34 1.1 christos case CMM_SEQ_CST_FENCE: \ 35 1.1 christos case CMM_SEQ_CST: \ 36 1.1 christos case CMM_ACQ_REL: \ 37 1.1 christos case CMM_RELEASE: \ 38 1.1 christos cmm_smp_mb(); \ 39 1.1 christos break; \ 40 1.1 christos case CMM_ACQUIRE: \ 41 1.1 christos case CMM_CONSUME: \ 42 1.1 christos case CMM_RELAXED: \ 43 1.1 christos break; \ 44 1.1 christos default: \ 45 1.1 christos abort(); \ 46 1.1 christos break; \ 47 1.1 christos \ 48 1.1 christos } \ 49 1.1 christos } while(0) 50 1.1 christos 51 1.1 christos #endif /* _cmm_compat_c11_smp_mb__before_mo */ 52 1.1 christos 53 1.1 christos /* 54 1.1 christos * Can be defined for the architecture. 55 1.1 christos * 56 1.1 christos * What needs to be emitted _after_ the `operation' with memory ordering `mo'. 57 1.1 christos */ 58 1.1 christos #ifndef _cmm_compat_c11_smp_mb__after_mo 59 1.1 christos # define _cmm_compat_c11_smp_mb__after_mo(operation, mo) \ 60 1.1 christos do { \ 61 1.1 christos switch (mo) { \ 62 1.1 christos case CMM_SEQ_CST_FENCE: \ 63 1.1 christos case CMM_SEQ_CST: \ 64 1.1 christos case CMM_ACQUIRE: \ 65 1.1 christos case CMM_CONSUME: \ 66 1.1 christos case CMM_ACQ_REL: \ 67 1.1 christos cmm_smp_mb(); \ 68 1.1 christos break; \ 69 1.1 christos case CMM_RELEASE: \ 70 1.1 christos case CMM_RELAXED: \ 71 1.1 christos break; \ 72 1.1 christos default: \ 73 1.1 christos abort(); \ 74 1.1 christos break; \ 75 1.1 christos \ 76 1.1 christos } \ 77 1.1 christos } while(0) 78 1.1 christos #endif /* _cmm_compat_c11_smp_mb__after_mo */ 79 1.1 christos 80 1.1 christos /* 81 1.1 christos * If the toolchain supports the C11 memory model, then it is safe to implement 82 1.1 christos * `uatomic_store_mo()' in term of __atomic builtins. This has the effect of 83 1.1 christos * reducing the number of emitted memory barriers except for the 84 1.1 christos * CMM_SEQ_CST_FENCE memory order. 85 1.1 christos */ 86 1.1 christos #ifndef uatomic_store_mo 87 1.1 christos # ifdef _CMM_TOOLCHAIN_SUPPORT_C11_MM 88 1.1 christos # define uatomic_store_mo(addr, v, mo) \ 89 1.1 christos do { \ 90 1.1 christos __atomic_store_n(cmm_cast_volatile(addr), v, \ 91 1.1 christos cmm_to_c11(mo)); \ 92 1.1 christos cmm_seq_cst_fence_after_atomic(mo); \ 93 1.1 christos } while (0) 94 1.1 christos # else 95 1.1 christos # define uatomic_store_mo(addr, v, mo) \ 96 1.1 christos do { \ 97 1.1 christos _cmm_compat_c11_smp_mb__before_mo(uatomic_store, mo); \ 98 1.1 christos (void) CMM_STORE_SHARED(*(addr), v); \ 99 1.1 christos _cmm_compat_c11_smp_mb__after_mo(uatomic_store, mo); \ 100 1.1 christos } while (0) 101 1.1 christos # endif /* _CMM_TOOLCHAIN_SUPPORT_C11_MM */ 102 1.1 christos #endif /* !uatomic_store */ 103 1.1 christos 104 1.1 christos /* 105 1.1 christos * If the toolchain supports the C11 memory model, then it is safe to implement 106 1.1 christos * `uatomic_load_mo()' in term of __atomic builtins. This has the effect of 107 1.1 christos * reducing the number of emitted memory barriers except for the 108 1.1 christos * CMM_SEQ_CST_FENCE memory order. 109 1.1 christos */ 110 1.1 christos #ifndef uatomic_load_mo 111 1.1 christos # ifdef _CMM_TOOLCHAIN_SUPPORT_C11_MM 112 1.1 christos # define uatomic_load_mo(addr, mo) \ 113 1.1 christos __extension__ \ 114 1.1 christos ({ \ 115 1.1 christos __typeof__(*(addr)) _value = \ 116 1.1 christos __atomic_load_n(cmm_cast_volatile(addr), \ 117 1.1 christos cmm_to_c11(mo)); \ 118 1.1 christos cmm_seq_cst_fence_after_atomic(mo); \ 119 1.1 christos \ 120 1.1 christos _value; \ 121 1.1 christos }) 122 1.1 christos # else 123 1.1 christos # define uatomic_load_mo(addr, mo) \ 124 1.1 christos __extension__ \ 125 1.1 christos ({ \ 126 1.1 christos _cmm_compat_c11_smp_mb__before_mo(uatomic_load, mo); \ 127 1.1 christos __typeof__(*(addr)) _rcu_value = CMM_LOAD_SHARED(*(addr)); \ 128 1.1 christos _cmm_compat_c11_smp_mb__after_mo(uatomic_load, mo); \ 129 1.1 christos \ 130 1.1 christos _rcu_value; \ 131 1.1 christos }) 132 1.1 christos # endif /* _CMM_TOOLCHAIN_SUPPORT_C11_MM */ 133 1.1 christos #endif /* !uatomic_load */ 134 1.1 christos 135 1.1 christos #if !defined __OPTIMIZE__ || defined UATOMIC_NO_LINK_ERROR 136 1.1 christos #ifdef ILLEGAL_INSTR 137 1.1 christos static inline __attribute__((always_inline)) 138 1.1 christos void _uatomic_link_error(void) 139 1.1 christos { 140 1.1 christos /* 141 1.1 christos * generate an illegal instruction. Cannot catch this with 142 1.1 christos * linker tricks when optimizations are disabled. 143 1.1 christos */ 144 1.1 christos __asm__ __volatile__(ILLEGAL_INSTR); 145 1.1 christos } 146 1.1 christos #else 147 1.1 christos static inline __attribute__((always_inline, __noreturn__)) 148 1.1 christos void _uatomic_link_error(void) 149 1.1 christos { 150 1.1 christos __builtin_trap(); 151 1.1 christos } 152 1.1 christos #endif 153 1.1 christos 154 1.1 christos 155 1.1 christos /* 156 1.1 christos * NOTE: All RMW operations are implemented using the `__sync' builtins. All 157 1.1 christos * builtins used are documented to be considered a "full barrier". Therefore, 158 1.1 christos * for RMW operations, nothing is emitted for any memory order. 159 1.1 christos */ 160 1.1 christos 161 1.1 christos #else /* #if !defined __OPTIMIZE__ || defined UATOMIC_NO_LINK_ERROR */ 162 1.1 christos extern void _uatomic_link_error(void); 163 1.1 christos #endif /* #else #if !defined __OPTIMIZE__ || defined UATOMIC_NO_LINK_ERROR */ 164 1.1 christos 165 1.1 christos /* uatomic_cmpxchg_mo */ 166 1.1 christos 167 1.1 christos #ifndef uatomic_cmpxchg_mo 168 1.1 christos static inline __attribute__((always_inline)) 169 1.1 christos unsigned long _uatomic_cmpxchg(void *addr, unsigned long old, 170 1.1 christos unsigned long _new, int len) 171 1.1 christos { 172 1.1 christos switch (len) { 173 1.1 christos #ifdef UATOMIC_HAS_ATOMIC_BYTE 174 1.1 christos case 1: 175 1.1 christos return __sync_val_compare_and_swap_1((uint8_t *) addr, old, 176 1.1 christos _new); 177 1.1 christos #endif 178 1.1 christos #ifdef UATOMIC_HAS_ATOMIC_SHORT 179 1.1 christos case 2: 180 1.1 christos return __sync_val_compare_and_swap_2((uint16_t *) addr, old, 181 1.1 christos _new); 182 1.1 christos #endif 183 1.1 christos case 4: 184 1.1 christos return __sync_val_compare_and_swap_4((uint32_t *) addr, old, 185 1.1 christos _new); 186 1.1 christos #if (CAA_BITS_PER_LONG == 64) 187 1.1 christos case 8: 188 1.1 christos return __sync_val_compare_and_swap_8((uint64_t *) addr, old, 189 1.1 christos _new); 190 1.1 christos #endif 191 1.1 christos } 192 1.1 christos _uatomic_link_error(); 193 1.1 christos return 0; 194 1.1 christos } 195 1.1 christos 196 1.1 christos #define uatomic_cmpxchg_mo(addr, old, _new, mos, mof) \ 197 1.1 christos ((__typeof__(*(addr))) _uatomic_cmpxchg((addr), \ 198 1.1 christos caa_cast_long_keep_sign(old), \ 199 1.1 christos caa_cast_long_keep_sign(_new), \ 200 1.1 christos sizeof(*(addr)))) 201 1.1 christos /* uatomic_and_mo */ 202 1.1 christos 203 1.1 christos #ifndef uatomic_and_mo 204 1.1 christos static inline __attribute__((always_inline)) 205 1.1 christos void _uatomic_and(void *addr, unsigned long val, 206 1.1 christos int len) 207 1.1 christos { 208 1.1 christos switch (len) { 209 1.1 christos #ifdef UATOMIC_HAS_ATOMIC_BYTE 210 1.1 christos case 1: 211 1.1 christos __sync_and_and_fetch_1((uint8_t *) addr, val); 212 1.1 christos return; 213 1.1 christos #endif 214 1.1 christos #ifdef UATOMIC_HAS_ATOMIC_SHORT 215 1.1 christos case 2: 216 1.1 christos __sync_and_and_fetch_2((uint16_t *) addr, val); 217 1.1 christos return; 218 1.1 christos #endif 219 1.1 christos case 4: 220 1.1 christos __sync_and_and_fetch_4((uint32_t *) addr, val); 221 1.1 christos return; 222 1.1 christos #if (CAA_BITS_PER_LONG == 64) 223 1.1 christos case 8: 224 1.1 christos __sync_and_and_fetch_8((uint64_t *) addr, val); 225 1.1 christos return; 226 1.1 christos #endif 227 1.1 christos } 228 1.1 christos _uatomic_link_error(); 229 1.1 christos } 230 1.1 christos 231 1.1 christos #define uatomic_and_mo(addr, v, mo) \ 232 1.1 christos (_uatomic_and((addr), \ 233 1.1 christos caa_cast_long_keep_sign(v), \ 234 1.1 christos sizeof(*(addr)))) 235 1.1 christos #define cmm_smp_mb__before_uatomic_and() cmm_barrier() 236 1.1 christos #define cmm_smp_mb__after_uatomic_and() cmm_barrier() 237 1.1 christos 238 1.1 christos #endif 239 1.1 christos 240 1.1 christos /* uatomic_or_mo */ 241 1.1 christos 242 1.1 christos #ifndef uatomic_or_mo 243 1.1 christos static inline __attribute__((always_inline)) 244 1.1 christos void _uatomic_or(void *addr, unsigned long val, 245 1.1 christos int len) 246 1.1 christos { 247 1.1 christos switch (len) { 248 1.1 christos #ifdef UATOMIC_HAS_ATOMIC_BYTE 249 1.1 christos case 1: 250 1.1 christos __sync_or_and_fetch_1((uint8_t *) addr, val); 251 1.1 christos return; 252 1.1 christos #endif 253 1.1 christos #ifdef UATOMIC_HAS_ATOMIC_SHORT 254 1.1 christos case 2: 255 1.1 christos __sync_or_and_fetch_2((uint16_t *) addr, val); 256 1.1 christos return; 257 1.1 christos #endif 258 1.1 christos case 4: 259 1.1 christos __sync_or_and_fetch_4((uint32_t *) addr, val); 260 1.1 christos return; 261 1.1 christos #if (CAA_BITS_PER_LONG == 64) 262 1.1 christos case 8: 263 1.1 christos __sync_or_and_fetch_8((uint64_t *) addr, val); 264 1.1 christos return; 265 1.1 christos #endif 266 1.1 christos } 267 1.1 christos _uatomic_link_error(); 268 1.1 christos return; 269 1.1 christos } 270 1.1 christos 271 1.1 christos #define uatomic_or_mo(addr, v, mo) \ 272 1.1 christos (_uatomic_or((addr), \ 273 1.1 christos caa_cast_long_keep_sign(v), \ 274 1.1 christos sizeof(*(addr)))) 275 1.1 christos #define cmm_smp_mb__before_uatomic_or() cmm_barrier() 276 1.1 christos #define cmm_smp_mb__after_uatomic_or() cmm_barrier() 277 1.1 christos 278 1.1 christos #endif 279 1.1 christos 280 1.1 christos 281 1.1 christos /* uatomic_add_return_mo */ 282 1.1 christos 283 1.1 christos #ifndef uatomic_add_return_mo 284 1.1 christos static inline __attribute__((always_inline)) 285 1.1 christos unsigned long _uatomic_add_return(void *addr, unsigned long val, 286 1.1 christos int len) 287 1.1 christos { 288 1.1 christos switch (len) { 289 1.1 christos #ifdef UATOMIC_HAS_ATOMIC_BYTE 290 1.1 christos case 1: 291 1.1 christos return __sync_add_and_fetch_1((uint8_t *) addr, val); 292 1.1 christos #endif 293 1.1 christos #ifdef UATOMIC_HAS_ATOMIC_SHORT 294 1.1 christos case 2: 295 1.1 christos return __sync_add_and_fetch_2((uint16_t *) addr, val); 296 1.1 christos #endif 297 1.1 christos case 4: 298 1.1 christos return __sync_add_and_fetch_4((uint32_t *) addr, val); 299 1.1 christos #if (CAA_BITS_PER_LONG == 64) 300 1.1 christos case 8: 301 1.1 christos return __sync_add_and_fetch_8((uint64_t *) addr, val); 302 1.1 christos #endif 303 1.1 christos } 304 1.1 christos _uatomic_link_error(); 305 1.1 christos return 0; 306 1.1 christos } 307 1.1 christos 308 1.1 christos 309 1.1 christos #define uatomic_add_return_mo(addr, v, mo) \ 310 1.1 christos ((__typeof__(*(addr))) _uatomic_add_return((addr), \ 311 1.1 christos caa_cast_long_keep_sign(v), \ 312 1.1 christos sizeof(*(addr)))) 313 1.1 christos #endif /* #ifndef uatomic_add_return */ 314 1.1 christos 315 1.1 christos #ifndef uatomic_xchg_mo 316 1.1 christos /* xchg */ 317 1.1 christos 318 1.1 christos static inline __attribute__((always_inline)) 319 1.1 christos unsigned long _uatomic_exchange(void *addr, unsigned long val, int len) 320 1.1 christos { 321 1.1 christos switch (len) { 322 1.1 christos #ifdef UATOMIC_HAS_ATOMIC_BYTE 323 1.1 christos case 1: 324 1.1 christos { 325 1.1 christos uint8_t old; 326 1.1 christos 327 1.1 christos do { 328 1.1 christos old = uatomic_read((uint8_t *) addr); 329 1.1 christos } while (!__sync_bool_compare_and_swap_1((uint8_t *) addr, 330 1.1 christos old, val)); 331 1.1 christos 332 1.1 christos return old; 333 1.1 christos } 334 1.1 christos #endif 335 1.1 christos #ifdef UATOMIC_HAS_ATOMIC_SHORT 336 1.1 christos case 2: 337 1.1 christos { 338 1.1 christos uint16_t old; 339 1.1 christos 340 1.1 christos do { 341 1.1 christos old = uatomic_read((uint16_t *) addr); 342 1.1 christos } while (!__sync_bool_compare_and_swap_2((uint16_t *) addr, 343 1.1 christos old, val)); 344 1.1 christos 345 1.1 christos return old; 346 1.1 christos } 347 1.1 christos #endif 348 1.1 christos case 4: 349 1.1 christos { 350 1.1 christos uint32_t old; 351 1.1 christos 352 1.1 christos do { 353 1.1 christos old = uatomic_read((uint32_t *) addr); 354 1.1 christos } while (!__sync_bool_compare_and_swap_4((uint32_t *) addr, 355 1.1 christos old, val)); 356 1.1 christos 357 1.1 christos return old; 358 1.1 christos } 359 1.1 christos #if (CAA_BITS_PER_LONG == 64) 360 1.1 christos case 8: 361 1.1 christos { 362 1.1 christos uint64_t old; 363 1.1 christos 364 1.1 christos do { 365 1.1 christos old = uatomic_read((uint64_t *) addr); 366 1.1 christos } while (!__sync_bool_compare_and_swap_8((uint64_t *) addr, 367 1.1 christos old, val)); 368 1.1 christos 369 1.1 christos return old; 370 1.1 christos } 371 1.1 christos #endif 372 1.1 christos } 373 1.1 christos _uatomic_link_error(); 374 1.1 christos return 0; 375 1.1 christos } 376 1.1 christos 377 1.1 christos #define uatomic_xchg_mo(addr, v, mo) \ 378 1.1 christos ((__typeof__(*(addr))) _uatomic_exchange((addr), \ 379 1.1 christos caa_cast_long_keep_sign(v), \ 380 1.1 christos sizeof(*(addr)))) 381 1.1 christos #endif /* #ifndef uatomic_xchg_mo */ 382 1.1 christos 383 1.1 christos #else /* #ifndef uatomic_cmpxchg_mo */ 384 1.1 christos 385 1.1 christos #ifndef uatomic_and_mo 386 1.1 christos /* uatomic_and_mo */ 387 1.1 christos 388 1.1 christos static inline __attribute__((always_inline)) 389 1.1 christos void _uatomic_and(void *addr, unsigned long val, int len) 390 1.1 christos { 391 1.1 christos switch (len) { 392 1.1 christos #ifdef UATOMIC_HAS_ATOMIC_BYTE 393 1.1 christos case 1: 394 1.1 christos { 395 1.1 christos uint8_t old, oldt; 396 1.1 christos 397 1.1 christos oldt = uatomic_read((uint8_t *) addr); 398 1.1 christos do { 399 1.1 christos old = oldt; 400 1.1 christos oldt = _uatomic_cmpxchg(addr, old, old & val, 1); 401 1.1 christos } while (oldt != old); 402 1.1 christos 403 1.1 christos return; 404 1.1 christos } 405 1.1 christos #endif 406 1.1 christos #ifdef UATOMIC_HAS_ATOMIC_SHORT 407 1.1 christos case 2: 408 1.1 christos { 409 1.1 christos uint16_t old, oldt; 410 1.1 christos 411 1.1 christos oldt = uatomic_read((uint16_t *) addr); 412 1.1 christos do { 413 1.1 christos old = oldt; 414 1.1 christos oldt = _uatomic_cmpxchg(addr, old, old & val, 2); 415 1.1 christos } while (oldt != old); 416 1.1 christos } 417 1.1 christos #endif 418 1.1 christos case 4: 419 1.1 christos { 420 1.1 christos uint32_t old, oldt; 421 1.1 christos 422 1.1 christos oldt = uatomic_read((uint32_t *) addr); 423 1.1 christos do { 424 1.1 christos old = oldt; 425 1.1 christos oldt = _uatomic_cmpxchg(addr, old, old & val, 4); 426 1.1 christos } while (oldt != old); 427 1.1 christos 428 1.1 christos return; 429 1.1 christos } 430 1.1 christos #if (CAA_BITS_PER_LONG == 64) 431 1.1 christos case 8: 432 1.1 christos { 433 1.1 christos uint64_t old, oldt; 434 1.1 christos 435 1.1 christos oldt = uatomic_read((uint64_t *) addr); 436 1.1 christos do { 437 1.1 christos old = oldt; 438 1.1 christos oldt = _uatomic_cmpxchg(addr, old, old & val, 8); 439 1.1 christos } while (oldt != old); 440 1.1 christos 441 1.1 christos return; 442 1.1 christos } 443 1.1 christos #endif 444 1.1 christos } 445 1.1 christos _uatomic_link_error(); 446 1.1 christos } 447 1.1 christos 448 1.1 christos #define uatomic_and_mo(addr, v, mo) \ 449 1.1 christos (_uatomic_and((addr), \ 450 1.1 christos caa_cast_long_keep_sign(v), \ 451 1.1 christos sizeof(*(addr)))) 452 1.1 christos #define cmm_smp_mb__before_uatomic_and() cmm_barrier() 453 1.1 christos #define cmm_smp_mb__after_uatomic_and() cmm_barrier() 454 1.1 christos 455 1.1 christos #endif /* #ifndef uatomic_and_mo */ 456 1.1 christos 457 1.1 christos #ifndef uatomic_or_mo 458 1.1 christos /* uatomic_or_mo */ 459 1.1 christos 460 1.1 christos static inline __attribute__((always_inline)) 461 1.1 christos void _uatomic_or(void *addr, unsigned long val, int len) 462 1.1 christos { 463 1.1 christos switch (len) { 464 1.1 christos #ifdef UATOMIC_HAS_ATOMIC_BYTE 465 1.1 christos case 1: 466 1.1 christos { 467 1.1 christos uint8_t old, oldt; 468 1.1 christos 469 1.1 christos oldt = uatomic_read((uint8_t *) addr); 470 1.1 christos do { 471 1.1 christos old = oldt; 472 1.1 christos oldt = _uatomic_cmpxchg(addr, old, old | val, 1); 473 1.1 christos } while (oldt != old); 474 1.1 christos 475 1.1 christos return; 476 1.1 christos } 477 1.1 christos #endif 478 1.1 christos #ifdef UATOMIC_HAS_ATOMIC_SHORT 479 1.1 christos case 2: 480 1.1 christos { 481 1.1 christos uint16_t old, oldt; 482 1.1 christos 483 1.1 christos oldt = uatomic_read((uint16_t *) addr); 484 1.1 christos do { 485 1.1 christos old = oldt; 486 1.1 christos oldt = _uatomic_cmpxchg(addr, old, old | val, 2); 487 1.1 christos } while (oldt != old); 488 1.1 christos 489 1.1 christos return; 490 1.1 christos } 491 1.1 christos #endif 492 1.1 christos case 4: 493 1.1 christos { 494 1.1 christos uint32_t old, oldt; 495 1.1 christos 496 1.1 christos oldt = uatomic_read((uint32_t *) addr); 497 1.1 christos do { 498 1.1 christos old = oldt; 499 1.1 christos oldt = _uatomic_cmpxchg(addr, old, old | val, 4); 500 1.1 christos } while (oldt != old); 501 1.1 christos 502 1.1 christos return; 503 1.1 christos } 504 1.1 christos #if (CAA_BITS_PER_LONG == 64) 505 1.1 christos case 8: 506 1.1 christos { 507 1.1 christos uint64_t old, oldt; 508 1.1 christos 509 1.1 christos oldt = uatomic_read((uint64_t *) addr); 510 1.1 christos do { 511 1.1 christos old = oldt; 512 1.1 christos oldt = _uatomic_cmpxchg(addr, old, old | val, 8); 513 1.1 christos } while (oldt != old); 514 1.1 christos 515 1.1 christos return; 516 1.1 christos } 517 1.1 christos #endif 518 1.1 christos } 519 1.1 christos _uatomic_link_error(); 520 1.1 christos } 521 1.1 christos 522 1.1 christos #define uatomic_or_mo(addr, v, mo) \ 523 1.1 christos (_uatomic_or((addr), \ 524 1.1 christos caa_cast_long_keep_sign(v), \ 525 1.1 christos sizeof(*(addr)))) 526 1.1 christos #define cmm_smp_mb__before_uatomic_or() cmm_barrier() 527 1.1 christos #define cmm_smp_mb__after_uatomic_or() cmm_barrier() 528 1.1 christos 529 1.1 christos #endif /* #ifndef uatomic_or_mo */ 530 1.1 christos 531 1.1 christos #ifndef uatomic_add_return_mo 532 1.1 christos /* uatomic_add_return_mo */ 533 1.1 christos 534 1.1 christos static inline __attribute__((always_inline)) 535 1.1 christos unsigned long _uatomic_add_return(void *addr, unsigned long val, int len) 536 1.1 christos { 537 1.1 christos switch (len) { 538 1.1 christos #ifdef UATOMIC_HAS_ATOMIC_BYTE 539 1.1 christos case 1: 540 1.1 christos { 541 1.1 christos uint8_t old, oldt; 542 1.1 christos 543 1.1 christos oldt = uatomic_read((uint8_t *) addr); 544 1.1 christos do { 545 1.1 christos old = oldt; 546 1.1 christos oldt = uatomic_cmpxchg((uint8_t *) addr, 547 1.1 christos old, old + val); 548 1.1 christos } while (oldt != old); 549 1.1 christos 550 1.1 christos return old + val; 551 1.1 christos } 552 1.1 christos #endif 553 1.1 christos #ifdef UATOMIC_HAS_ATOMIC_SHORT 554 1.1 christos case 2: 555 1.1 christos { 556 1.1 christos uint16_t old, oldt; 557 1.1 christos 558 1.1 christos oldt = uatomic_read((uint16_t *) addr); 559 1.1 christos do { 560 1.1 christos old = oldt; 561 1.1 christos oldt = uatomic_cmpxchg((uint16_t *) addr, 562 1.1 christos old, old + val); 563 1.1 christos } while (oldt != old); 564 1.1 christos 565 1.1 christos return old + val; 566 1.1 christos } 567 1.1 christos #endif 568 1.1 christos case 4: 569 1.1 christos { 570 1.1 christos uint32_t old, oldt; 571 1.1 christos 572 1.1 christos oldt = uatomic_read((uint32_t *) addr); 573 1.1 christos do { 574 1.1 christos old = oldt; 575 1.1 christos oldt = uatomic_cmpxchg((uint32_t *) addr, 576 1.1 christos old, old + val); 577 1.1 christos } while (oldt != old); 578 1.1 christos 579 1.1 christos return old + val; 580 1.1 christos } 581 1.1 christos #if (CAA_BITS_PER_LONG == 64) 582 1.1 christos case 8: 583 1.1 christos { 584 1.1 christos uint64_t old, oldt; 585 1.1 christos 586 1.1 christos oldt = uatomic_read((uint64_t *) addr); 587 1.1 christos do { 588 1.1 christos old = oldt; 589 1.1 christos oldt = uatomic_cmpxchg((uint64_t *) addr, 590 1.1 christos old, old + val); 591 1.1 christos } while (oldt != old); 592 1.1 christos 593 1.1 christos return old + val; 594 1.1 christos } 595 1.1 christos #endif 596 1.1 christos } 597 1.1 christos _uatomic_link_error(); 598 1.1 christos return 0; 599 1.1 christos } 600 1.1 christos 601 1.1 christos #define uatomic_add_return_mo(addr, v, mo) \ 602 1.1 christos ((__typeof__(*(addr))) _uatomic_add_return((addr), \ 603 1.1 christos caa_cast_long_keep_sign(v), \ 604 1.1 christos sizeof(*(addr)))) 605 1.1 christos #endif /* #ifndef uatomic_add_return_mo */ 606 1.1 christos 607 1.1 christos #ifndef uatomic_xchg_mo 608 1.1 christos /* uatomic_xchg_mo */ 609 1.1 christos 610 1.1 christos static inline __attribute__((always_inline)) 611 1.1 christos unsigned long _uatomic_exchange(void *addr, unsigned long val, int len) 612 1.1 christos { 613 1.1 christos switch (len) { 614 1.1 christos #ifdef UATOMIC_HAS_ATOMIC_BYTE 615 1.1 christos case 1: 616 1.1 christos { 617 1.1 christos uint8_t old, oldt; 618 1.1 christos 619 1.1 christos oldt = uatomic_read((uint8_t *) addr); 620 1.1 christos do { 621 1.1 christos old = oldt; 622 1.1 christos oldt = uatomic_cmpxchg((uint8_t *) addr, 623 1.1 christos old, val); 624 1.1 christos } while (oldt != old); 625 1.1 christos 626 1.1 christos return old; 627 1.1 christos } 628 1.1 christos #endif 629 1.1 christos #ifdef UATOMIC_HAS_ATOMIC_SHORT 630 1.1 christos case 2: 631 1.1 christos { 632 1.1 christos uint16_t old, oldt; 633 1.1 christos 634 1.1 christos oldt = uatomic_read((uint16_t *) addr); 635 1.1 christos do { 636 1.1 christos old = oldt; 637 1.1 christos oldt = uatomic_cmpxchg((uint16_t *) addr, 638 1.1 christos old, val); 639 1.1 christos } while (oldt != old); 640 1.1 christos 641 1.1 christos return old; 642 1.1 christos } 643 1.1 christos #endif 644 1.1 christos case 4: 645 1.1 christos { 646 1.1 christos uint32_t old, oldt; 647 1.1 christos 648 1.1 christos oldt = uatomic_read((uint32_t *) addr); 649 1.1 christos do { 650 1.1 christos old = oldt; 651 1.1 christos oldt = uatomic_cmpxchg((uint32_t *) addr, 652 1.1 christos old, val); 653 1.1 christos } while (oldt != old); 654 1.1 christos 655 1.1 christos return old; 656 1.1 christos } 657 1.1 christos #if (CAA_BITS_PER_LONG == 64) 658 1.1 christos case 8: 659 1.1 christos { 660 1.1 christos uint64_t old, oldt; 661 1.1 christos 662 1.1 christos oldt = uatomic_read((uint64_t *) addr); 663 1.1 christos do { 664 1.1 christos old = oldt; 665 1.1 christos oldt = uatomic_cmpxchg((uint64_t *) addr, 666 1.1 christos old, val); 667 1.1 christos } while (oldt != old); 668 1.1 christos 669 1.1 christos return old; 670 1.1 christos } 671 1.1 christos #endif 672 1.1 christos } 673 1.1 christos _uatomic_link_error(); 674 1.1 christos return 0; 675 1.1 christos } 676 1.1 christos 677 1.1 christos #define uatomic_xchg_mo(addr, v, mo) \ 678 1.1 christos ((__typeof__(*(addr))) _uatomic_exchange((addr), \ 679 1.1 christos caa_cast_long_keep_sign(v), \ 680 1.1 christos sizeof(*(addr)))) 681 1.1 christos #endif /* #ifndef uatomic_xchg_mo */ 682 1.1 christos 683 1.1 christos #endif /* #else #ifndef uatomic_cmpxchg_mo */ 684 1.1 christos 685 1.1 christos /* uatomic_sub_return_mo, uatomic_add_mo, uatomic_sub_mo, uatomic_inc_mo, uatomic_dec_mo */ 686 1.1 christos 687 1.1 christos #ifndef uatomic_add_mo 688 1.1 christos #define uatomic_add_mo(addr, v, mo) (void)uatomic_add_return_mo((addr), (v), mo) 689 1.1 christos #define cmm_smp_mb__before_uatomic_add() cmm_barrier() 690 1.1 christos #define cmm_smp_mb__after_uatomic_add() cmm_barrier() 691 1.1 christos #endif 692 1.1 christos 693 1.1 christos #define uatomic_sub_return_mo(addr, v, mo) \ 694 1.1 christos uatomic_add_return_mo((addr), -(caa_cast_long_keep_sign(v)), mo) 695 1.1 christos #define uatomic_sub_mo(addr, v, mo) \ 696 1.1 christos uatomic_add_mo((addr), -(caa_cast_long_keep_sign(v)), mo) 697 1.1 christos #define cmm_smp_mb__before_uatomic_sub() cmm_smp_mb__before_uatomic_add() 698 1.1 christos #define cmm_smp_mb__after_uatomic_sub() cmm_smp_mb__after_uatomic_add() 699 1.1 christos 700 1.1 christos #ifndef uatomic_inc_mo 701 1.1 christos #define uatomic_inc_mo(addr, mo) uatomic_add_mo((addr), 1, mo) 702 1.1 christos #define cmm_smp_mb__before_uatomic_inc() cmm_smp_mb__before_uatomic_add() 703 1.1 christos #define cmm_smp_mb__after_uatomic_inc() cmm_smp_mb__after_uatomic_add() 704 1.1 christos #endif 705 1.1 christos 706 1.1 christos #ifndef uatomic_dec_mo 707 1.1 christos #define uatomic_dec_mo(addr, mo) uatomic_add((addr), -1, mo) 708 1.1 christos #define cmm_smp_mb__before_uatomic_dec() cmm_smp_mb__before_uatomic_add() 709 1.1 christos #define cmm_smp_mb__after_uatomic_dec() cmm_smp_mb__after_uatomic_add() 710 1.1 christos #endif 711 1.1 christos 712 1.1 christos #ifdef __cplusplus 713 1.1 christos } 714 1.1 christos #endif 715 1.1 christos 716 1.1 christos #endif /* _URCU_UATOMIC_GENERIC_H */ 717