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().
39 struct __uatomic_dummy
{
42 #define __hp(x) ((struct __uatomic_dummy *)(x))
44 #define _uatomic_set(addr, v) ((void) CMM_STORE_SHARED(*(addr), (v)))
48 static inline __attribute__((always_inline
))
49 unsigned long __uatomic_cmpxchg(void *addr
, unsigned long old
,
50 unsigned long _new
, int len
)
55 unsigned char result
= old
;
58 "lock; cmpxchgb %2, %1"
59 : "+a"(result
), "+m"(*__hp(addr
))
60 : "q"((unsigned char)_new
)
66 unsigned short result
= old
;
69 "lock; cmpxchgw %2, %1"
70 : "+a"(result
), "+m"(*__hp(addr
))
71 : "r"((unsigned short)_new
)
77 unsigned int result
= old
;
80 "lock; cmpxchgl %2, %1"
81 : "+a"(result
), "+m"(*__hp(addr
))
82 : "r"((unsigned int)_new
)
86 #if (CAA_BITS_PER_LONG == 64)
89 unsigned long result
= old
;
92 "lock; cmpxchgq %2, %1"
93 : "+a"(result
), "+m"(*__hp(addr
))
94 : "r"((unsigned long)_new
)
101 * generate an illegal instruction. Cannot catch this with
102 * linker tricks when optimizations are disabled.
104 __asm__
__volatile__("ud2");
108 #define _uatomic_cmpxchg(addr, old, _new) \
109 ((__typeof__(*(addr))) __uatomic_cmpxchg((addr), \
110 caa_cast_long_keep_sign(old), \
111 caa_cast_long_keep_sign(_new),\
116 static inline __attribute__((always_inline
))
117 unsigned long __uatomic_exchange(void *addr
, unsigned long val
, int len
)
119 /* Note: the "xchg" instruction does not need a "lock" prefix. */
123 unsigned char result
;
124 __asm__
__volatile__(
126 : "=q"(result
), "+m"(*__hp(addr
))
127 : "0" ((unsigned char)val
)
133 unsigned short result
;
134 __asm__
__volatile__(
136 : "=r"(result
), "+m"(*__hp(addr
))
137 : "0" ((unsigned short)val
)
144 __asm__
__volatile__(
146 : "=r"(result
), "+m"(*__hp(addr
))
147 : "0" ((unsigned int)val
)
151 #if (CAA_BITS_PER_LONG == 64)
154 unsigned long result
;
155 __asm__
__volatile__(
157 : "=r"(result
), "+m"(*__hp(addr
))
158 : "0" ((unsigned long)val
)
165 * generate an illegal instruction. Cannot catch this with
166 * linker tricks when optimizations are disabled.
168 __asm__
__volatile__("ud2");
172 #define _uatomic_xchg(addr, v) \
173 ((__typeof__(*(addr))) __uatomic_exchange((addr), \
174 caa_cast_long_keep_sign(v), \
177 /* uatomic_add_return */
179 static inline __attribute__((always_inline
))
180 unsigned long __uatomic_add_return(void *addr
, unsigned long val
,
186 unsigned char result
= val
;
188 __asm__
__volatile__(
190 : "+m"(*__hp(addr
)), "+q" (result
)
193 return result
+ (unsigned char)val
;
197 unsigned short result
= val
;
199 __asm__
__volatile__(
201 : "+m"(*__hp(addr
)), "+r" (result
)
204 return result
+ (unsigned short)val
;
208 unsigned int result
= val
;
210 __asm__
__volatile__(
212 : "+m"(*__hp(addr
)), "+r" (result
)
215 return result
+ (unsigned int)val
;
217 #if (CAA_BITS_PER_LONG == 64)
220 unsigned long result
= val
;
222 __asm__
__volatile__(
224 : "+m"(*__hp(addr
)), "+r" (result
)
227 return result
+ (unsigned long)val
;
232 * generate an illegal instruction. Cannot catch this with
233 * linker tricks when optimizations are disabled.
235 __asm__
__volatile__("ud2");
239 #define _uatomic_add_return(addr, v) \
240 ((__typeof__(*(addr))) __uatomic_add_return((addr), \
241 caa_cast_long_keep_sign(v), \
246 static inline __attribute__((always_inline
))
247 void __uatomic_and(void *addr
, unsigned long val
, int len
)
252 __asm__
__volatile__(
255 : "iq" ((unsigned char)val
)
261 __asm__
__volatile__(
264 : "ir" ((unsigned short)val
)
270 __asm__
__volatile__(
273 : "ir" ((unsigned int)val
)
277 #if (CAA_BITS_PER_LONG == 64)
280 __asm__
__volatile__(
283 : "er" ((unsigned long)val
)
290 * generate an illegal instruction. Cannot catch this with
291 * linker tricks when optimizations are disabled.
293 __asm__
__volatile__("ud2");
297 #define _uatomic_and(addr, v) \
298 (__uatomic_and((addr), caa_cast_long_keep_sign(v), sizeof(*(addr))))
302 static inline __attribute__((always_inline
))
303 void __uatomic_or(void *addr
, unsigned long val
, int len
)
308 __asm__
__volatile__(
311 : "iq" ((unsigned char)val
)
317 __asm__
__volatile__(
320 : "ir" ((unsigned short)val
)
326 __asm__
__volatile__(
329 : "ir" ((unsigned int)val
)
333 #if (CAA_BITS_PER_LONG == 64)
336 __asm__
__volatile__(
339 : "er" ((unsigned long)val
)
346 * generate an illegal instruction. Cannot catch this with
347 * linker tricks when optimizations are disabled.
349 __asm__
__volatile__("ud2");
353 #define _uatomic_or(addr, v) \
354 (__uatomic_or((addr), caa_cast_long_keep_sign(v), sizeof(*(addr))))
358 static inline __attribute__((always_inline
))
359 void __uatomic_add(void *addr
, unsigned long val
, int len
)
364 __asm__
__volatile__(
367 : "iq" ((unsigned char)val
)
373 __asm__
__volatile__(
376 : "ir" ((unsigned short)val
)
382 __asm__
__volatile__(
385 : "ir" ((unsigned int)val
)
389 #if (CAA_BITS_PER_LONG == 64)
392 __asm__
__volatile__(
395 : "er" ((unsigned long)val
)
402 * generate an illegal instruction. Cannot catch this with
403 * linker tricks when optimizations are disabled.
405 __asm__
__volatile__("ud2");
409 #define _uatomic_add(addr, v) \
410 (__uatomic_add((addr), caa_cast_long_keep_sign(v), sizeof(*(addr))))
415 static inline __attribute__((always_inline
))
416 void __uatomic_inc(void *addr
, int len
)
421 __asm__
__volatile__(
430 __asm__
__volatile__(
439 __asm__
__volatile__(
446 #if (CAA_BITS_PER_LONG == 64)
449 __asm__
__volatile__(
458 /* generate an illegal instruction. Cannot catch this with linker tricks
459 * when optimizations are disabled. */
460 __asm__
__volatile__("ud2");
464 #define _uatomic_inc(addr) (__uatomic_inc((addr), sizeof(*(addr))))
468 static inline __attribute__((always_inline
))
469 void __uatomic_dec(void *addr
, int len
)
474 __asm__
__volatile__(
483 __asm__
__volatile__(
492 __asm__
__volatile__(
499 #if (CAA_BITS_PER_LONG == 64)
502 __asm__
__volatile__(
512 * generate an illegal instruction. Cannot catch this with
513 * linker tricks when optimizations are disabled.
515 __asm__
__volatile__("ud2");
519 #define _uatomic_dec(addr) (__uatomic_dec((addr), sizeof(*(addr))))
521 #if ((CAA_BITS_PER_LONG != 64) && defined(URCU_ARCH_I386))
523 /* For backwards compat */
524 #define CONFIG_RCU_COMPAT_ARCH 1
526 extern int __rcu_cas_avail
;
527 extern int __rcu_cas_init(void);
529 #define UATOMIC_COMPAT(insn) \
530 ((caa_likely(__rcu_cas_avail > 0)) \
531 ? (_uatomic_##insn) \
532 : ((caa_unlikely(__rcu_cas_avail < 0) \
533 ? ((__rcu_cas_init() > 0) \
534 ? (_uatomic_##insn) \
535 : (compat_uatomic_##insn)) \
536 : (compat_uatomic_##insn))))
539 * We leave the return value so we don't break the ABI, but remove the
540 * return value from the API.
542 extern unsigned long _compat_uatomic_set(void *addr
,
543 unsigned long _new
, int len
);
544 #define compat_uatomic_set(addr, _new) \
545 ((void) _compat_uatomic_set((addr), \
546 caa_cast_long_keep_sign(_new), \
550 extern unsigned long _compat_uatomic_xchg(void *addr
,
551 unsigned long _new
, int len
);
552 #define compat_uatomic_xchg(addr, _new) \
553 ((__typeof__(*(addr))) _compat_uatomic_xchg((addr), \
554 caa_cast_long_keep_sign(_new), \
557 extern unsigned long _compat_uatomic_cmpxchg(void *addr
, unsigned long old
,
558 unsigned long _new
, int len
);
559 #define compat_uatomic_cmpxchg(addr, old, _new) \
560 ((__typeof__(*(addr))) _compat_uatomic_cmpxchg((addr), \
561 caa_cast_long_keep_sign(old), \
562 caa_cast_long_keep_sign(_new), \
565 extern void _compat_uatomic_and(void *addr
, unsigned long _new
, int len
);
566 #define compat_uatomic_and(addr, v) \
567 (_compat_uatomic_and((addr), \
568 caa_cast_long_keep_sign(v), \
571 extern void _compat_uatomic_or(void *addr
, unsigned long _new
, int len
);
572 #define compat_uatomic_or(addr, v) \
573 (_compat_uatomic_or((addr), \
574 caa_cast_long_keep_sign(v), \
577 extern unsigned long _compat_uatomic_add_return(void *addr
,
578 unsigned long _new
, int len
);
579 #define compat_uatomic_add_return(addr, v) \
580 ((__typeof__(*(addr))) _compat_uatomic_add_return((addr), \
581 caa_cast_long_keep_sign(v), \
584 #define compat_uatomic_add(addr, v) \
585 ((void)compat_uatomic_add_return((addr), (v)))
586 #define compat_uatomic_inc(addr) \
587 (compat_uatomic_add((addr), 1))
588 #define compat_uatomic_dec(addr) \
589 (compat_uatomic_add((addr), -1))
592 #define UATOMIC_COMPAT(insn) (_uatomic_##insn)
595 /* Read is atomic even in compat mode */
596 #define uatomic_set(addr, v) \
597 UATOMIC_COMPAT(set(addr, v))
599 #define uatomic_cmpxchg(addr, old, _new) \
600 UATOMIC_COMPAT(cmpxchg(addr, old, _new))
601 #define uatomic_xchg(addr, v) \
602 UATOMIC_COMPAT(xchg(addr, v))
604 #define uatomic_and(addr, v) \
605 UATOMIC_COMPAT(and(addr, v))
606 #define cmm_smp_mb__before_uatomic_and() cmm_barrier()
607 #define cmm_smp_mb__after_uatomic_and() cmm_barrier()
609 #define uatomic_or(addr, v) \
610 UATOMIC_COMPAT(or(addr, v))
611 #define cmm_smp_mb__before_uatomic_or() cmm_barrier()
612 #define cmm_smp_mb__after_uatomic_or() cmm_barrier()
614 #define uatomic_add_return(addr, v) \
615 UATOMIC_COMPAT(add_return(addr, v))
617 #define uatomic_add(addr, v) UATOMIC_COMPAT(add(addr, v))
618 #define cmm_smp_mb__before_uatomic_add() cmm_barrier()
619 #define cmm_smp_mb__after_uatomic_add() cmm_barrier()
621 #define uatomic_inc(addr) UATOMIC_COMPAT(inc(addr))
622 #define cmm_smp_mb__before_uatomic_inc() cmm_barrier()
623 #define cmm_smp_mb__after_uatomic_inc() cmm_barrier()
625 #define uatomic_dec(addr) UATOMIC_COMPAT(dec(addr))
626 #define cmm_smp_mb__before_uatomic_dec() cmm_barrier()
627 #define cmm_smp_mb__after_uatomic_dec() cmm_barrier()
633 #include <urcu/uatomic/generic.h>
635 #endif /* _URCU_ARCH_UATOMIC_X86_H */
This page took 0.047084 seconds and 4 git commands to generate.