diff options
Diffstat (limited to 'ACE/ace/Atomic_Op.cpp')
-rw-r--r-- | ACE/ace/Atomic_Op.cpp | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/ACE/ace/Atomic_Op.cpp b/ACE/ace/Atomic_Op.cpp new file mode 100644 index 00000000000..9076b9f67ed --- /dev/null +++ b/ACE/ace/Atomic_Op.cpp @@ -0,0 +1,310 @@ +// $Id$ + +#include "ace/Atomic_Op.h" +#include "ace/OS_NS_unistd.h" + +ACE_RCSID (ace, + Atomic_Op, + "$Id$") + +#if !defined (__ACE_INLINE__) +#include "ace/Atomic_Op.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_HAS_BUILTIN_ATOMIC_OP) + +#if defined (ACE_INCLUDE_ATOMIC_OP_SPARC) +# include "ace/Atomic_Op_Sparc.h" +#endif /* ACE_INCLUDE_ATOMIC_OP_SPARC */ + +namespace { + +#if defined (_MSC_VER) +// Disable "no return value" warning, as we will be putting +// the return values directly into the EAX register. +#pragma warning (push) +#pragma warning (disable: 4035) +#endif /* _MSC_VER */ + +long +single_cpu_increment (volatile long *value) +{ +#if defined (ACE_HAS_INTEL_ASSEMBLY) + long tmp = 1; + unsigned long addr = reinterpret_cast<unsigned long> (value); + asm( "xadd %0, (%1)" : "+r"(tmp) : "r"(addr) ); + return tmp + 1; +#elif defined (sun) || \ + (defined (__SUNPRO_CC) && (defined (__i386) || defined (__x86_64))) + return ace_atomic_add_long ( + reinterpret_cast<volatile unsigned long*> (value), 1); +#elif defined(__GNUC__) && defined(PPC) + long tmp; + asm("lwz %0,%1" : "=r" (tmp) : "m" (*value) ); + asm("addi %0,%0,1" : "+r" (tmp) ); + asm("stw %0,%1" : "+r" (tmp), "=m" (*value) ); + return tmp; +#else /* ACE_HAS_INTEL_ASSEMBLY*/ + ACE_UNUSED_ARG (value); + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_INTEL_ASSEMBLY*/ +} + +long +single_cpu_decrement (volatile long *value) +{ +#if defined (ACE_HAS_INTEL_ASSEMBLY) + long tmp = -1; + unsigned long addr = reinterpret_cast<unsigned long> (value); + asm( "xadd %0, (%1)" : "+r"(tmp) : "r"(addr) ); + return tmp - 1; +#elif defined (sun) || \ + (defined (__SUNPRO_CC) && (defined (__i386) || defined (__x86_64))) + return ace_atomic_add_long ( + reinterpret_cast<volatile unsigned long*> (value), -1); +#elif defined(__GNUC__) && defined(PPC) + long tmp; + asm("lwz %0,%1" : "=r" (tmp) : "m" (*value) ); + asm("addi %0,%0,-1" : "+r" (tmp) ); + asm("stw %0,%1" : "+r" (tmp), "=m" (*value) ); + return tmp; +#else /* ACE_HAS_INTEL_ASSEMBLY*/ + ACE_UNUSED_ARG (value); + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_INTEL_ASSEMBLY*/ +} + +long +single_cpu_exchange (volatile long *value, long rhs) +{ +#if defined (ACE_HAS_INTEL_ASSEMBLY) + unsigned long addr = reinterpret_cast<unsigned long> (value); + asm( "xchg %0, (%1)" : "+r"(rhs) : "r"(addr) ); + return rhs; +#elif defined (sun) || \ + (defined (__SUNPRO_CC) && (defined (__i386) || defined (__x86_64))) + return ace_atomic_swap_long ( + reinterpret_cast<volatile unsigned long*> (value), rhs); +#elif defined(__GNUC__) && defined(PPC) + long tmp; + asm("lwz %0,%1" : "=r" (tmp) : "m" (rhs) ); + asm("stw %0,%1" : "+r" (tmp), "=m" (*value) ); + return tmp; +#else /* ACE_HAS_INTEL_ASSEMBLY*/ + ACE_UNUSED_ARG (value); + ACE_UNUSED_ARG (rhs); + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_INTEL_ASSEMBLY*/ +} + +long +single_cpu_exchange_add (volatile long *value, long rhs) +{ +#if defined (ACE_HAS_INTEL_ASSEMBLY) + unsigned long addr = reinterpret_cast<unsigned long> (value); + asm( "xadd %0, (%1)" : "+r"(rhs) : "r"(addr) ); + return rhs; +#elif defined (sun) || \ + (defined (__SUNPRO_CC) && (defined (__i386) || defined (__x86_64))) + return ace_atomic_swap_add_long ( + reinterpret_cast<volatile unsigned long*> (value), rhs); +#elif defined(__GNUC__) && defined(PPC) + long tmp; + asm("add %0,%1,%2" : "=r" (tmp) : "r" (*value), "r" (rhs) ); + asm("stw %0,%1" : "+r" (tmp), "=m" (*value) ); + return tmp; +#elif defined (WIN32) && !defined (ACE_HAS_INTERLOCKED_EXCHANGEADD) +# if defined (_MSC_VER) + __asm + { + mov eax, rhs + mov edx, value + xadd [edx], eax + } + // Return value is already in EAX register. +# elif defined (__BORLANDC__) + _EAX = rhs; + _EDX = reinterpret_cast<unsigned long> (value); + __emit__(0x0F, 0xC1, 0x02); // xadd [edx], eax + // Return value is already in EAX register. +# else /* _MSC_VER */ + ACE_UNUSED_ARG (value); + ACE_UNUSED_ARG (rhs); + ACE_NOTSUP_RETURN (-1); +# endif /* _MSC_VER */ +#else /* ACE_HAS_INTEL_ASSEMBLY*/ + ACE_UNUSED_ARG (value); + ACE_UNUSED_ARG (rhs); + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_INTEL_ASSEMBLY*/ +} + +long +multi_cpu_increment (volatile long *value) +{ +#if defined (ACE_HAS_INTEL_ASSEMBLY) + long tmp = 1; + unsigned long addr = reinterpret_cast<unsigned long> (value); + asm( "lock ; xadd %0, (%1)" : "+r"(tmp) : "r"(addr) ); + return tmp + 1; +#elif defined (sun) || \ + (defined (__SUNPRO_CC) && (defined (__i386) || defined (__x86_64))) + return ace_atomic_add_long ( + reinterpret_cast<volatile unsigned long*> (value), 1); +#else /* ACE_HAS_INTEL_ASSEMBLY*/ + ACE_UNUSED_ARG (value); + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_INTEL_ASSEMBLY*/ +} + +long +multi_cpu_decrement (volatile long *value) +{ +#if defined (ACE_HAS_INTEL_ASSEMBLY) + long tmp = -1; + unsigned long addr = reinterpret_cast<unsigned long> (value); + asm( "lock ; xadd %0, (%1)" : "+r"(tmp) : "r"(addr) ); + return tmp - 1; +#elif defined (sun) || \ + (defined (__SUNPRO_CC) && (defined (__i386) || defined (__x86_64))) + return ace_atomic_add_long ( + reinterpret_cast<volatile unsigned long*> (value), -1); +#else /* ACE_HAS_INTEL_ASSEMBLY*/ + ACE_UNUSED_ARG (value); + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_INTEL_ASSEMBLY*/ +} + +long +multi_cpu_exchange (volatile long *value, long rhs) +{ +#if defined (ACE_HAS_INTEL_ASSEMBLY) + unsigned long addr = reinterpret_cast<unsigned long> (value); + // The XCHG instruction automatically follows LOCK semantics + asm( "xchg %0, (%1)" : "+r"(rhs) : "r"(addr) ); + return rhs; +#elif defined (sun) || \ + (defined (__SUNPRO_CC) && (defined (__i386) || defined (__x86_64))) + return ace_atomic_swap_long ( + reinterpret_cast<volatile unsigned long*> (value), rhs); +#else /* ACE_HAS_INTEL_ASSEMBLY*/ + ACE_UNUSED_ARG (value); + ACE_UNUSED_ARG (rhs); + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_INTEL_ASSEMBLY*/ +} + +long +multi_cpu_exchange_add (volatile long *value, long rhs) +{ +#if defined (ACE_HAS_INTEL_ASSEMBLY) + unsigned long addr = reinterpret_cast<unsigned long> (value); + asm( "lock ; xadd %0, (%1)" : "+r"(rhs) : "r"(addr) ); + return rhs; +#elif defined (sun) || \ + (defined (__SUNPRO_CC) && (defined (__i386) || defined (__x86_64))) + return ace_atomic_swap_add_long ( + reinterpret_cast<volatile unsigned long*> (value), rhs); +#elif defined (WIN32) && !defined (ACE_HAS_INTERLOCKED_EXCHANGEADD) +# if defined (_MSC_VER) + __asm + { + mov eax, rhs + mov edx, value + lock xadd [edx], eax + } + // Return value is already in EAX register. +# elif defined (__BORLANDC__) + _EAX = rhs; + _EDX = reinterpret_cast<unsigned long> (value); + __emit__(0xF0, 0x0F, 0xC1, 0x02); // lock xadd [edx], eax + // Return value is already in EAX register. +# else /* _MSC_VER */ + ACE_UNUSED_ARG (value); + ACE_UNUSED_ARG (rhs); + ACE_NOTSUP_RETURN (-1); +# endif /* _MSC_VER */ +#else /* ACE_HAS_INTEL_ASSEMBLY*/ + ACE_UNUSED_ARG (value); + ACE_UNUSED_ARG (rhs); + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_INTEL_ASSEMBLY*/ +} + +#if defined (_MSC_VER) +#pragma warning (pop) +#endif /* _MSC_VER */ + +} // end namespace + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +long (*ACE_Atomic_Op<ACE_Thread_Mutex, long>::increment_fn_) (volatile long *) = multi_cpu_increment; +long (*ACE_Atomic_Op<ACE_Thread_Mutex, long>::decrement_fn_) (volatile long *) = multi_cpu_decrement; +long (*ACE_Atomic_Op<ACE_Thread_Mutex, long>::exchange_fn_) (volatile long *, long) = multi_cpu_exchange; +long (*ACE_Atomic_Op<ACE_Thread_Mutex, long>::exchange_add_fn_) (volatile long *, long) = multi_cpu_exchange_add; + +void +ACE_Atomic_Op<ACE_Thread_Mutex, long>::init_functions (void) +{ + if (ACE_OS::num_processors () == 1) + { + increment_fn_ = single_cpu_increment; + decrement_fn_ = single_cpu_decrement; + exchange_fn_ = single_cpu_exchange; + exchange_add_fn_ = single_cpu_exchange_add; + } + else + { + increment_fn_ = multi_cpu_increment; + decrement_fn_ = multi_cpu_decrement; + exchange_fn_ = multi_cpu_exchange; + exchange_add_fn_ = multi_cpu_exchange_add; + } +} + +void +ACE_Atomic_Op<ACE_Thread_Mutex, long>::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +long (*ACE_Atomic_Op<ACE_Thread_Mutex, unsigned long>::increment_fn_) (volatile long *) = multi_cpu_increment; +long (*ACE_Atomic_Op<ACE_Thread_Mutex, unsigned long>::decrement_fn_) (volatile long *) = multi_cpu_decrement; +long (*ACE_Atomic_Op<ACE_Thread_Mutex, unsigned long>::exchange_fn_) (volatile long *, long) = multi_cpu_exchange; +long (*ACE_Atomic_Op<ACE_Thread_Mutex, unsigned long>::exchange_add_fn_) (volatile long *, long) = multi_cpu_exchange_add; + +void +ACE_Atomic_Op<ACE_Thread_Mutex, unsigned long>::init_functions (void) +{ + if (ACE_OS::num_processors () == 1) + { + increment_fn_ = single_cpu_increment; + decrement_fn_ = single_cpu_decrement; + exchange_fn_ = single_cpu_exchange; + exchange_add_fn_ = single_cpu_exchange_add; + } + else + { + increment_fn_ = multi_cpu_increment; + decrement_fn_ = multi_cpu_decrement; + exchange_fn_ = multi_cpu_exchange; + exchange_add_fn_ = multi_cpu_exchange_add; + } +} + +void +ACE_Atomic_Op<ACE_Thread_Mutex, unsigned long>::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_BUILTIN_ATOMIC_OP */ |