diff options
Diffstat (limited to 'boost/thread/win32/interlocked_read.hpp')
-rw-r--r-- | boost/thread/win32/interlocked_read.hpp | 151 |
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); } } } |