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