From 985b35b18796edab591775098fef83a50a1e55ce Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 9 Jun 2011 09:29:18 -0400 Subject: [PATCH] uatomic: add uatomic_or For now, only the version returning void is used. Also, I am not providing PPC versions because I would be unable to test it right now. Signed-off-by: Paolo Bonzini Signed-off-by: Mathieu Desnoyers --- compat_arch_x86.c | 25 +++++++++++ tests/test_uatomic.c | 6 ++- urcu/uatomic_arch_x86.h | 63 ++++++++++++++++++++++++++ urcu/uatomic_generic.h | 97 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 189 insertions(+), 2 deletions(-) diff --git a/compat_arch_x86.c b/compat_arch_x86.c index 5342c7b..33bf13d 100644 --- a/compat_arch_x86.c +++ b/compat_arch_x86.c @@ -201,6 +201,31 @@ unsigned long _compat_uatomic_cmpxchg(void *addr, unsigned long old, return retval; } +void _compat_uatomic_or(void *addr, unsigned long v, int len) +{ + sigset_t mask; + + mutex_lock_signal_save(&compat_mutex, &mask); + switch (len) { + case 1: + *(unsigned char *)addr |= (unsigned char)v; + break; + case 2: + *(unsigned short *)addr |= (unsigned short)v; + break; + case 4: + *(unsigned int *)addr |= (unsigned int)v; + break; + default: + /* + * generate an illegal instruction. Cannot catch this with + * linker tricks when optimizations are disabled. + */ + __asm__ __volatile__("ud2"); + } + mutex_lock_signal_restore(&compat_mutex, &mask); +} + unsigned long _compat_uatomic_add_return(void *addr, unsigned long v, int len) { sigset_t mask; diff --git a/tests/test_uatomic.c b/tests/test_uatomic.c index 5682655..37f95a6 100644 --- a/tests/test_uatomic.c +++ b/tests/test_uatomic.c @@ -33,8 +33,10 @@ do { \ assert(uatomic_read(ptr) == 23); \ uatomic_dec(ptr); \ assert(uatomic_read(ptr) == 22); \ - v = uatomic_add_return(ptr, 100); \ - assert(v == 122); \ + v = uatomic_add_return(ptr, 74); \ + assert(v == 96); \ + assert(uatomic_read(ptr) == 96); \ + uatomic_or(ptr, 58); \ assert(uatomic_read(ptr) == 122); \ v = uatomic_sub_return(ptr, 1); \ assert(v == 121); \ diff --git a/urcu/uatomic_arch_x86.h b/urcu/uatomic_arch_x86.h index 09a5bbb..f57d46d 100644 --- a/urcu/uatomic_arch_x86.h +++ b/urcu/uatomic_arch_x86.h @@ -231,6 +231,60 @@ unsigned long __uatomic_add_return(void *addr, unsigned long val, (unsigned long)(v), \ sizeof(*(addr)))) +/* uatomic_or */ + +static inline __attribute__((always_inline)) +void __uatomic_or(void *addr, unsigned long val, int len) +{ + switch (len) { + case 1: + { + __asm__ __volatile__( + "lock; orb %1, %0" + : "=m"(*__hp(addr)) + : "iq" ((unsigned char)val) + : "memory"); + return; + } + case 2: + { + __asm__ __volatile__( + "lock; orw %1, %0" + : "=m"(*__hp(addr)) + : "ir" ((unsigned short)val) + : "memory"); + return; + } + case 4: + { + __asm__ __volatile__( + "lock; orl %1, %0" + : "=m"(*__hp(addr)) + : "ir" ((unsigned int)val) + : "memory"); + return; + } +#if (CAA_BITS_PER_LONG == 64) + case 8: + { + __asm__ __volatile__( + "lock; orq %1, %0" + : "=m"(*__hp(addr)) + : "er" ((unsigned long)val) + : "memory"); + return; + } +#endif + } + /* generate an illegal instruction. Cannot catch this with linker tricks + * when optimizations are disabled. */ + __asm__ __volatile__("ud2"); + return; +} + +#define _uatomic_or(addr, v) \ + (__uatomic_or((addr), (unsigned long)(v), sizeof(*(addr)))) + /* uatomic_add */ static inline __attribute__((always_inline)) @@ -428,6 +482,13 @@ extern unsigned long _compat_uatomic_cmpxchg(void *addr, unsigned long old, (unsigned long)(_new), \ sizeof(*(addr)))) +extern unsigned long _compat_uatomic_or(void *addr, + unsigned long _new, int len); +#define compat_uatomic_or(addr, v) \ + ((__typeof__(*(addr))) _compat_uatomic_or((addr), \ + (unsigned long)(v), \ + sizeof(*(addr)))) + extern unsigned long _compat_uatomic_add_return(void *addr, unsigned long _new, int len); #define compat_uatomic_add_return(addr, v) \ @@ -454,6 +515,8 @@ extern unsigned long _compat_uatomic_add_return(void *addr, UATOMIC_COMPAT(cmpxchg(addr, old, _new)) #define uatomic_xchg(addr, v) \ UATOMIC_COMPAT(xchg(addr, v)) +#define uatomic_or(addr, v) \ + UATOMIC_COMPAT(or(addr, v)) #define uatomic_add_return(addr, v) \ UATOMIC_COMPAT(add_return(addr, v)) diff --git a/urcu/uatomic_generic.h b/urcu/uatomic_generic.h index 347e73f..556846f 100644 --- a/urcu/uatomic_generic.h +++ b/urcu/uatomic_generic.h @@ -87,6 +87,39 @@ unsigned long _uatomic_cmpxchg(void *addr, unsigned long old, sizeof(*(addr)))) +/* uatomic_or */ + +#ifndef uatomic_or +static inline __attribute__((always_inline)) +void _uatomic_or(void *addr, unsigned long val, + int len) +{ + switch (len) { +#ifdef UATOMIC_HAS_ATOMIC_BYTE + case 1: + __sync_or_and_fetch_1(addr, val); +#endif +#ifdef UATOMIC_HAS_ATOMIC_SHORT + case 2: + __sync_or_and_fetch_2(addr, val); +#endif + case 4: + __sync_or_and_fetch_4(addr, val); +#if (CAA_BITS_PER_LONG == 64) + case 8: + __sync_or_and_fetch_8(addr, val); +#endif + } + _uatomic_link_error(); + return 0; +} + +#define uatomic_or(addr, v) \ + (_uatomic_or((addr), \ + (unsigned long)(v), \ + sizeof(*(addr)))) +#endif + /* uatomic_add_return */ #ifndef uatomic_add_return @@ -186,6 +219,70 @@ unsigned long _uatomic_exchange(void *addr, unsigned long val, int len) #else /* #ifndef uatomic_cmpxchg */ +#ifndef uatomic_or +/* uatomic_or */ + +static inline __attribute__((always_inline)) +void _uatomic_or(void *addr, unsigned long val, int len) +{ + switch (len) { +#ifdef UATOMIC_HAS_ATOMIC_BYTE + case 1: + { + unsigned char old, oldt; + + oldt = uatomic_read((unsigned char *)addr); + do { + old = oldt; + oldt = _uatomic_cmpxchg(addr, old, old | val, 1); + } while (oldt != old); + } +#endif +#ifdef UATOMIC_HAS_ATOMIC_SHORT + case 2: + { + unsigned short old, oldt; + + oldt = uatomic_read((unsigned short *)addr); + do { + old = oldt; + oldt = _uatomic_cmpxchg(addr, old, old | val, 2); + } while (oldt != old); + } +#endif + case 4: + { + unsigned int old, oldt; + + oldt = uatomic_read((unsigned int *)addr); + do { + old = oldt; + oldt = _uatomic_cmpxchg(addr, old, old | val, 4); + } while (oldt != old); + } +#if (CAA_BITS_PER_LONG == 64) + case 8: + { + unsigned long old, oldt; + + oldt = uatomic_read((unsigned long *)addr); + do { + old = oldt; + oldt = _uatomic_cmpxchg(addr, old, old | val, 8); + } while (oldt != old); + } +#endif + } + _uatomic_link_error(); + return 0; +} + +#define uatomic_or(addr, v) \ + (uatomic_or((addr), \ + (unsigned long)(v), \ + sizeof(*(addr)))) +#endif /* #ifndef uatomic_or */ + #ifndef uatomic_add_return /* uatomic_add_return */ -- 2.34.1