1 #ifndef _URCU_ARCH_UATOMIC_X86_H
2 #define _URCU_ARCH_UATOMIC_X86_H
5 * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
6 * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
7 * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
8 * Copyright (c) 2009 Mathieu Desnoyers
10 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
11 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
13 * Permission is hereby granted to use or copy this program
14 * for any purpose, provided the above notices are retained on all copies.
15 * Permission to modify the code and to distribute modified code is granted,
16 * provided the above notices are retained, and a notice that the code was
17 * modified is included with the above copyright notice.
19 * Code inspired from libuatomic_ops-1.2, inherited in part from the
20 * Boehm-Demers-Weiser conservative garbage collector.
23 #include <urcu/arch.h>
24 #include <urcu/config.h>
25 #include <urcu/compiler.h>
26 #include <urcu/system.h>
28 #define UATOMIC_HAS_ATOMIC_BYTE
29 #define UATOMIC_HAS_ATOMIC_SHORT
36 * Derived from AO_compare_and_swap() and AO_test_and_set_full().
40 * The __hp() macro casts the void pointer @x to a pointer to a structure
41 * containing an array of char of the specified size. This allows passing the
42 * @addr arguments of the following inline functions as "m" and "+m" operands
43 * to the assembly. The @size parameter should be a constant to support
44 * compilers such as clang which do not support VLA. Create typedefs because
45 * C++ does not allow types be defined in casts.
48 typedef struct { char v
[1]; } __hp_1
;
49 typedef struct { char v
[2]; } __hp_2
;
50 typedef struct { char v
[4]; } __hp_4
;
51 typedef struct { char v
[8]; } __hp_8
;
53 #define __hp(size, x) ((__hp_##size *)(x))
55 #define _uatomic_set(addr, v) ((void) CMM_STORE_SHARED(*(addr), (v)))
59 static inline __attribute__((always_inline
))
60 unsigned long __uatomic_cmpxchg(void *addr
, unsigned long old
,
61 unsigned long _new
, int len
)
66 unsigned char result
= old
;
69 "lock; cmpxchgb %2, %1"
70 : "+a"(result
), "+m"(*__hp(1, addr
))
71 : "q"((unsigned char)_new
)
77 unsigned short result
= old
;
80 "lock; cmpxchgw %2, %1"
81 : "+a"(result
), "+m"(*__hp(2, addr
))
82 : "r"((unsigned short)_new
)
88 unsigned int result
= old
;
91 "lock; cmpxchgl %2, %1"
92 : "+a"(result
), "+m"(*__hp(4, addr
))
93 : "r"((unsigned int)_new
)
97 #if (CAA_BITS_PER_LONG == 64)
100 unsigned long result
= old
;
102 __asm__
__volatile__(
103 "lock; cmpxchgq %2, %1"
104 : "+a"(result
), "+m"(*__hp(8, addr
))
105 : "r"((unsigned long)_new
)
112 * generate an illegal instruction. Cannot catch this with
113 * linker tricks when optimizations are disabled.
115 __asm__
__volatile__("ud2");
119 #define _uatomic_cmpxchg(addr, old, _new) \
120 ((__typeof__(*(addr))) __uatomic_cmpxchg((addr), \
121 caa_cast_long_keep_sign(old), \
122 caa_cast_long_keep_sign(_new),\
127 static inline __attribute__((always_inline
))
128 unsigned long __uatomic_exchange(void *addr
, unsigned long val
, int len
)
130 /* Note: the "xchg" instruction does not need a "lock" prefix. */
134 unsigned char result
;
135 __asm__
__volatile__(
137 : "=q"(result
), "+m"(*__hp(1, addr
))
138 : "0" ((unsigned char)val
)
144 unsigned short result
;
145 __asm__
__volatile__(
147 : "=r"(result
), "+m"(*__hp(2, addr
))
148 : "0" ((unsigned short)val
)
155 __asm__
__volatile__(
157 : "=r"(result
), "+m"(*__hp(4, addr
))
158 : "0" ((unsigned int)val
)
162 #if (CAA_BITS_PER_LONG == 64)
165 unsigned long result
;
166 __asm__
__volatile__(
168 : "=r"(result
), "+m"(*__hp(8, addr
))
169 : "0" ((unsigned long)val
)
176 * generate an illegal instruction. Cannot catch this with
177 * linker tricks when optimizations are disabled.
179 __asm__
__volatile__("ud2");
183 #define _uatomic_xchg(addr, v) \
184 ((__typeof__(*(addr))) __uatomic_exchange((addr), \
185 caa_cast_long_keep_sign(v), \
188 /* uatomic_add_return */
190 static inline __attribute__((always_inline
))
191 unsigned long __uatomic_add_return(void *addr
, unsigned long val
,
197 unsigned char result
= val
;
199 __asm__
__volatile__(
201 : "+m"(*__hp(1, addr
)), "+q" (result
)
204 return result
+ (unsigned char)val
;
208 unsigned short result
= val
;
210 __asm__
__volatile__(
212 : "+m"(*__hp(2, addr
)), "+r" (result
)
215 return result
+ (unsigned short)val
;
219 unsigned int result
= val
;
221 __asm__
__volatile__(
223 : "+m"(*__hp(4, addr
)), "+r" (result
)
226 return result
+ (unsigned int)val
;
228 #if (CAA_BITS_PER_LONG == 64)
231 unsigned long result
= val
;
233 __asm__
__volatile__(
235 : "+m"(*__hp(8, addr
)), "+r" (result
)
238 return result
+ (unsigned long)val
;
243 * generate an illegal instruction. Cannot catch this with
244 * linker tricks when optimizations are disabled.
246 __asm__
__volatile__("ud2");
250 #define _uatomic_add_return(addr, v) \
251 ((__typeof__(*(addr))) __uatomic_add_return((addr), \
252 caa_cast_long_keep_sign(v), \
257 static inline __attribute__((always_inline
))
258 void __uatomic_and(void *addr
, unsigned long val
, int len
)
263 __asm__
__volatile__(
265 : "=m"(*__hp(1, addr
))
266 : "iq" ((unsigned char)val
)
272 __asm__
__volatile__(
274 : "=m"(*__hp(2, addr
))
275 : "ir" ((unsigned short)val
)
281 __asm__
__volatile__(
283 : "=m"(*__hp(4, addr
))
284 : "ir" ((unsigned int)val
)
288 #if (CAA_BITS_PER_LONG == 64)
291 __asm__
__volatile__(
293 : "=m"(*__hp(8, addr
))
294 : "er" ((unsigned long)val
)
301 * generate an illegal instruction. Cannot catch this with
302 * linker tricks when optimizations are disabled.
304 __asm__
__volatile__("ud2");
308 #define _uatomic_and(addr, v) \
309 (__uatomic_and((addr), caa_cast_long_keep_sign(v), sizeof(*(addr))))
313 static inline __attribute__((always_inline
))
314 void __uatomic_or(void *addr
, unsigned long val
, int len
)
319 __asm__
__volatile__(
321 : "=m"(*__hp(1, addr
))
322 : "iq" ((unsigned char)val
)
328 __asm__
__volatile__(
330 : "=m"(*__hp(2, addr
))
331 : "ir" ((unsigned short)val
)
337 __asm__
__volatile__(
339 : "=m"(*__hp(4, addr
))
340 : "ir" ((unsigned int)val
)
344 #if (CAA_BITS_PER_LONG == 64)
347 __asm__
__volatile__(
349 : "=m"(*__hp(8, addr
))
350 : "er" ((unsigned long)val
)
357 * generate an illegal instruction. Cannot catch this with
358 * linker tricks when optimizations are disabled.
360 __asm__
__volatile__("ud2");
364 #define _uatomic_or(addr, v) \
365 (__uatomic_or((addr), caa_cast_long_keep_sign(v), sizeof(*(addr))))
369 static inline __attribute__((always_inline
))
370 void __uatomic_add(void *addr
, unsigned long val
, int len
)
375 __asm__
__volatile__(
377 : "=m"(*__hp(1, addr
))
378 : "iq" ((unsigned char)val
)
384 __asm__
__volatile__(
386 : "=m"(*__hp(2, addr
))
387 : "ir" ((unsigned short)val
)
393 __asm__
__volatile__(
395 : "=m"(*__hp(4, addr
))
396 : "ir" ((unsigned int)val
)
400 #if (CAA_BITS_PER_LONG == 64)
403 __asm__
__volatile__(
405 : "=m"(*__hp(8, addr
))
406 : "er" ((unsigned long)val
)
413 * generate an illegal instruction. Cannot catch this with
414 * linker tricks when optimizations are disabled.
416 __asm__
__volatile__("ud2");
420 #define _uatomic_add(addr, v) \
421 (__uatomic_add((addr), caa_cast_long_keep_sign(v), sizeof(*(addr))))
426 static inline __attribute__((always_inline
))
427 void __uatomic_inc(void *addr
, int len
)
432 __asm__
__volatile__(
434 : "=m"(*__hp(1, addr
))
441 __asm__
__volatile__(
443 : "=m"(*__hp(2, addr
))
450 __asm__
__volatile__(
452 : "=m"(*__hp(4, addr
))
457 #if (CAA_BITS_PER_LONG == 64)
460 __asm__
__volatile__(
462 : "=m"(*__hp(8, addr
))
469 /* generate an illegal instruction. Cannot catch this with linker tricks
470 * when optimizations are disabled. */
471 __asm__
__volatile__("ud2");
475 #define _uatomic_inc(addr) (__uatomic_inc((addr), sizeof(*(addr))))
479 static inline __attribute__((always_inline
))
480 void __uatomic_dec(void *addr
, int len
)
485 __asm__
__volatile__(
487 : "=m"(*__hp(1, addr
))
494 __asm__
__volatile__(
496 : "=m"(*__hp(2, addr
))
503 __asm__
__volatile__(
505 : "=m"(*__hp(4, addr
))
510 #if (CAA_BITS_PER_LONG == 64)
513 __asm__
__volatile__(
515 : "=m"(*__hp(8, addr
))
523 * generate an illegal instruction. Cannot catch this with
524 * linker tricks when optimizations are disabled.
526 __asm__
__volatile__("ud2");
530 #define _uatomic_dec(addr) (__uatomic_dec((addr), sizeof(*(addr))))
532 #ifdef URCU_ARCH_X86_NO_CAS
534 /* For backwards compat */
535 #define CONFIG_RCU_COMPAT_ARCH 1
537 extern int __rcu_cas_avail
;
538 extern int __rcu_cas_init(void);
540 #define UATOMIC_COMPAT(insn) \
541 ((caa_likely(__rcu_cas_avail > 0)) \
542 ? (_uatomic_##insn) \
543 : ((caa_unlikely(__rcu_cas_avail < 0) \
544 ? ((__rcu_cas_init() > 0) \
545 ? (_uatomic_##insn) \
546 : (compat_uatomic_##insn)) \
547 : (compat_uatomic_##insn))))
550 * We leave the return value so we don't break the ABI, but remove the
551 * return value from the API.
553 extern unsigned long _compat_uatomic_set(void *addr
,
554 unsigned long _new
, int len
);
555 #define compat_uatomic_set(addr, _new) \
556 ((void) _compat_uatomic_set((addr), \
557 caa_cast_long_keep_sign(_new), \
561 extern unsigned long _compat_uatomic_xchg(void *addr
,
562 unsigned long _new
, int len
);
563 #define compat_uatomic_xchg(addr, _new) \
564 ((__typeof__(*(addr))) _compat_uatomic_xchg((addr), \
565 caa_cast_long_keep_sign(_new), \
568 extern unsigned long _compat_uatomic_cmpxchg(void *addr
, unsigned long old
,
569 unsigned long _new
, int len
);
570 #define compat_uatomic_cmpxchg(addr, old, _new) \
571 ((__typeof__(*(addr))) _compat_uatomic_cmpxchg((addr), \
572 caa_cast_long_keep_sign(old), \
573 caa_cast_long_keep_sign(_new), \
576 extern void _compat_uatomic_and(void *addr
, unsigned long _new
, int len
);
577 #define compat_uatomic_and(addr, v) \
578 (_compat_uatomic_and((addr), \
579 caa_cast_long_keep_sign(v), \
582 extern void _compat_uatomic_or(void *addr
, unsigned long _new
, int len
);
583 #define compat_uatomic_or(addr, v) \
584 (_compat_uatomic_or((addr), \
585 caa_cast_long_keep_sign(v), \
588 extern unsigned long _compat_uatomic_add_return(void *addr
,
589 unsigned long _new
, int len
);
590 #define compat_uatomic_add_return(addr, v) \
591 ((__typeof__(*(addr))) _compat_uatomic_add_return((addr), \
592 caa_cast_long_keep_sign(v), \
595 #define compat_uatomic_add(addr, v) \
596 ((void)compat_uatomic_add_return((addr), (v)))
597 #define compat_uatomic_inc(addr) \
598 (compat_uatomic_add((addr), 1))
599 #define compat_uatomic_dec(addr) \
600 (compat_uatomic_add((addr), -1))
603 #define UATOMIC_COMPAT(insn) (_uatomic_##insn)
606 /* Read is atomic even in compat mode */
607 #define uatomic_set(addr, v) \
608 UATOMIC_COMPAT(set(addr, v))
610 #define uatomic_cmpxchg(addr, old, _new) \
611 UATOMIC_COMPAT(cmpxchg(addr, old, _new))
612 #define uatomic_xchg(addr, v) \
613 UATOMIC_COMPAT(xchg(addr, v))
615 #define uatomic_and(addr, v) \
616 UATOMIC_COMPAT(and(addr, v))
617 #define cmm_smp_mb__before_uatomic_and() cmm_barrier()
618 #define cmm_smp_mb__after_uatomic_and() cmm_barrier()
620 #define uatomic_or(addr, v) \
621 UATOMIC_COMPAT(or(addr, v))
622 #define cmm_smp_mb__before_uatomic_or() cmm_barrier()
623 #define cmm_smp_mb__after_uatomic_or() cmm_barrier()
625 #define uatomic_add_return(addr, v) \
626 UATOMIC_COMPAT(add_return(addr, v))
628 #define uatomic_add(addr, v) UATOMIC_COMPAT(add(addr, v))
629 #define cmm_smp_mb__before_uatomic_add() cmm_barrier()
630 #define cmm_smp_mb__after_uatomic_add() cmm_barrier()
632 #define uatomic_inc(addr) UATOMIC_COMPAT(inc(addr))
633 #define cmm_smp_mb__before_uatomic_inc() cmm_barrier()
634 #define cmm_smp_mb__after_uatomic_inc() cmm_barrier()
636 #define uatomic_dec(addr) UATOMIC_COMPAT(dec(addr))
637 #define cmm_smp_mb__before_uatomic_dec() cmm_barrier()
638 #define cmm_smp_mb__after_uatomic_dec() cmm_barrier()
644 #include <urcu/uatomic/generic.h>
646 #endif /* _URCU_ARCH_UATOMIC_X86_H */
This page took 0.043627 seconds and 4 git commands to generate.