summaryrefslogtreecommitdiff
path: root/boost/thread/win32/interlocked_read.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/thread/win32/interlocked_read.hpp')
-rw-r--r--boost/thread/win32/interlocked_read.hpp151
1 files changed, 144 insertions, 7 deletions
diff --git a/boost/thread/win32/interlocked_read.hpp b/boost/thread/win32/interlocked_read.hpp
index 2ad3fe9017..775555e184 100644
--- a/boost/thread/win32/interlocked_read.hpp
+++ b/boost/thread/win32/interlocked_read.hpp
@@ -5,6 +5,7 @@
//
// (C) Copyright 2005-8 Anthony Williams
// (C) Copyright 2012 Vicente J. Botet Escriba
+// (C) Copyright 2017 Andrey Semashev
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -15,36 +16,172 @@
#include <boost/config/abi_prefix.hpp>
-#ifdef BOOST_MSVC
+// Define compiler barriers
+#if defined(__INTEL_COMPILER)
+#define BOOST_THREAD_DETAIL_COMPILER_BARRIER() __memory_barrier()
+#elif defined(_MSC_VER) && !defined(_WIN32_WCE)
+extern "C" void _ReadWriteBarrier(void);
+#pragma intrinsic(_ReadWriteBarrier)
+#define BOOST_THREAD_DETAIL_COMPILER_BARRIER() _ReadWriteBarrier()
+#endif
+
+#ifndef BOOST_THREAD_DETAIL_COMPILER_BARRIER
+#define BOOST_THREAD_DETAIL_COMPILER_BARRIER()
+#endif
+
+#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
+
+// Since VS2005 and until VS2012 volatile reads always acquire and volatile writes are always release.
+// But VS2012 adds a compiler switch that can change behavior to the standard. On x86 though
+// the compiler generates a single instruction for the load/store, which is enough synchronization
+// as far as uarch is concerned. To prevent compiler reordering code around the load/store we add
+// compiler barriers.
namespace boost
{
namespace detail
{
- // Since VS2005 volatile reads always acquire
inline long interlocked_read_acquire(long volatile* x) BOOST_NOEXCEPT
{
long const res=*x;
+ BOOST_THREAD_DETAIL_COMPILER_BARRIER();
return res;
}
inline void* interlocked_read_acquire(void* volatile* x) BOOST_NOEXCEPT
{
void* const res=*x;
+ BOOST_THREAD_DETAIL_COMPILER_BARRIER();
return res;
}
- // Since VS2005 volatile writes always release
inline void interlocked_write_release(long volatile* x,long value) BOOST_NOEXCEPT
{
+ BOOST_THREAD_DETAIL_COMPILER_BARRIER();
*x=value;
}
inline void interlocked_write_release(void* volatile* x,void* value) BOOST_NOEXCEPT
{
+ BOOST_THREAD_DETAIL_COMPILER_BARRIER();
*x=value;
}
}
}
+#elif defined(_MSC_VER) && _MSC_VER >= 1700 && (defined(_M_ARM) || defined(_M_ARM64))
+
+#include <intrin.h>
+
+namespace boost
+{
+ namespace detail
+ {
+ inline long interlocked_read_acquire(long volatile* x) BOOST_NOEXCEPT
+ {
+ long const res=__iso_volatile_load32((const volatile __int32*)x);
+ BOOST_THREAD_DETAIL_COMPILER_BARRIER();
+ __dmb(0xB); // _ARM_BARRIER_ISH, see armintr.h from MSVC 11 and later
+ BOOST_THREAD_DETAIL_COMPILER_BARRIER();
+ return res;
+ }
+ inline void* interlocked_read_acquire(void* volatile* x) BOOST_NOEXCEPT
+ {
+ void* const res=
+#if defined(_M_ARM64)
+ __iso_volatile_load64((const volatile __int64*)x);
+#else
+ __iso_volatile_load32((const volatile __int32*)x);
+#endif
+ BOOST_THREAD_DETAIL_COMPILER_BARRIER();
+ __dmb(0xB); // _ARM_BARRIER_ISH, see armintr.h from MSVC 11 and later
+ BOOST_THREAD_DETAIL_COMPILER_BARRIER();
+ return res;
+ }
+
+ inline void interlocked_write_release(long volatile* x,long value) BOOST_NOEXCEPT
+ {
+ BOOST_THREAD_DETAIL_COMPILER_BARRIER();
+ __dmb(0xB); // _ARM_BARRIER_ISH, see armintr.h from MSVC 11 and later
+ BOOST_THREAD_DETAIL_COMPILER_BARRIER();
+ __iso_volatile_store32((volatile __int32*)x, (__int32)value);
+ }
+ inline void interlocked_write_release(void* volatile* x,void* value) BOOST_NOEXCEPT
+ {
+ BOOST_THREAD_DETAIL_COMPILER_BARRIER();
+ __dmb(0xB); // _ARM_BARRIER_ISH, see armintr.h from MSVC 11 and later
+ BOOST_THREAD_DETAIL_COMPILER_BARRIER();
+#if defined(_M_ARM64)
+ __iso_volatile_store64((volatile __int64*)x, (__int64)value);
+#else
+ __iso_volatile_store32((volatile __int32*)x, (__int32)value);
+#endif
+ }
+ }
+}
+
+#elif defined(__GNUC__) && (((__GNUC__ * 100 + __GNUC_MINOR__) >= 407) || (defined(__clang__) && (__clang_major__ * 100 + __clang_minor__) >= 302))
+
+namespace boost
+{
+ namespace detail
+ {
+ inline long interlocked_read_acquire(long volatile* x) BOOST_NOEXCEPT
+ {
+ return __atomic_load_n((long*)x, __ATOMIC_ACQUIRE);
+ }
+ inline void* interlocked_read_acquire(void* volatile* x) BOOST_NOEXCEPT
+ {
+ return __atomic_load_n((void**)x, __ATOMIC_ACQUIRE);
+ }
+
+ inline void interlocked_write_release(long volatile* x,long value) BOOST_NOEXCEPT
+ {
+ __atomic_store_n((long*)x, value, __ATOMIC_RELEASE);
+ }
+ inline void interlocked_write_release(void* volatile* x,void* value) BOOST_NOEXCEPT
+ {
+ __atomic_store_n((void**)x, value, __ATOMIC_RELEASE);
+ }
+ }
+}
+
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+
+namespace boost
+{
+ namespace detail
+ {
+ inline long interlocked_read_acquire(long volatile* x) BOOST_NOEXCEPT
+ {
+ long res;
+ __asm__ __volatile__ ("movl %1, %0" : "=r" (res) : "m" (*x) : "memory");
+ return res;
+ }
+ inline void* interlocked_read_acquire(void* volatile* x) BOOST_NOEXCEPT
+ {
+ void* res;
+#if defined(__x86_64__)
+ __asm__ __volatile__ ("movq %1, %0" : "=r" (res) : "m" (*x) : "memory");
+#else
+ __asm__ __volatile__ ("movl %1, %0" : "=r" (res) : "m" (*x) : "memory");
+#endif
+ return res;
+ }
+
+ inline void interlocked_write_release(long volatile* x,long value) BOOST_NOEXCEPT
+ {
+ __asm__ __volatile__ ("movl %1, %0" : "=m" (*x) : "r" (value) : "memory");
+ }
+ inline void interlocked_write_release(void* volatile* x,void* value) BOOST_NOEXCEPT
+ {
+#if defined(__x86_64__)
+ __asm__ __volatile__ ("movq %1, %0" : "=m" (*x) : "r" (value) : "memory");
+#else
+ __asm__ __volatile__ ("movl %1, %0" : "=m" (*x) : "r" (value) : "memory");
+#endif
+ }
+ }
+}
+
#else
namespace boost
@@ -53,19 +190,19 @@ namespace boost
{
inline long interlocked_read_acquire(long volatile* x) BOOST_NOEXCEPT
{
- return BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,0,0);
+ return BOOST_INTERLOCKED_COMPARE_EXCHANGE((long*)x,0,0);
}
inline void* interlocked_read_acquire(void* volatile* x) BOOST_NOEXCEPT
{
- return BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(x,0,0);
+ return BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER((void**)x,0,0);
}
inline void interlocked_write_release(long volatile* x,long value) BOOST_NOEXCEPT
{
- BOOST_INTERLOCKED_EXCHANGE(x,value);
+ BOOST_INTERLOCKED_EXCHANGE((long*)x,value);
}
inline void interlocked_write_release(void* volatile* x,void* value) BOOST_NOEXCEPT
{
- BOOST_INTERLOCKED_EXCHANGE_POINTER(x,value);
+ BOOST_INTERLOCKED_EXCHANGE_POINTER((void**)x,value);
}
}
}