diff options
Diffstat (limited to 'boost/thread')
-rw-r--r-- | boost/thread/detail/config.hpp | 2 | ||||
-rw-r--r-- | boost/thread/detail/thread.hpp | 15 | ||||
-rw-r--r-- | boost/thread/exceptions.hpp | 16 | ||||
-rw-r--r-- | boost/thread/executors/executor.hpp | 2 | ||||
-rw-r--r-- | boost/thread/executors/generic_executor_ref.hpp | 2 | ||||
-rw-r--r-- | boost/thread/executors/loop_executor.hpp | 40 | ||||
-rw-r--r-- | boost/thread/future.hpp | 4 | ||||
-rw-r--r-- | boost/thread/futures/wait_for_all.hpp | 2 | ||||
-rw-r--r-- | boost/thread/pthread/condition_variable_fwd.hpp | 16 | ||||
-rw-r--r-- | boost/thread/pthread/timespec.hpp | 29 | ||||
-rw-r--r-- | boost/thread/scoped_thread.hpp | 38 | ||||
-rw-r--r-- | boost/thread/thread_functors.hpp | 21 | ||||
-rw-r--r-- | boost/thread/thread_guard.hpp | 6 | ||||
-rw-r--r-- | boost/thread/win32/interlocked_read.hpp | 151 | ||||
-rw-r--r-- | boost/thread/win32/thread_primitives.hpp | 14 |
15 files changed, 285 insertions, 73 deletions
diff --git a/boost/thread/detail/config.hpp b/boost/thread/detail/config.hpp index b060b81c95..6d1595ebc7 100644 --- a/boost/thread/detail/config.hpp +++ b/boost/thread/detail/config.hpp @@ -12,6 +12,8 @@ #include <boost/detail/workaround.hpp> #include <boost/thread/detail/platform.hpp> +//#define BOOST_THREAD_USEFIXES_TIMESPEC +//#define BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC //#define BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS // ATTRIBUTE_MAY_ALIAS diff --git a/boost/thread/detail/thread.hpp b/boost/thread/detail/thread.hpp index 9e7e8b8f5e..bd2f149a0e 100644 --- a/boost/thread/detail/thread.hpp +++ b/boost/thread/detail/thread.hpp @@ -482,13 +482,20 @@ namespace boost return try_join_until(chrono::steady_clock::now() + rel_time); } #endif + +#if defined(BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC) && defined(BOOST_THREAD_USEFIXES_TIMESPEC) + typedef chrono::steady_clock my_clock_t; +#else + typedef chrono::system_clock my_clock_t; +#endif + template <class Clock, class Duration> bool try_join_until(const chrono::time_point<Clock, Duration>& t) { using namespace chrono; bool joined= false; do { - system_clock::time_point s_now = system_clock::now(); + my_clock_t::time_point s_now = my_clock_t::now(); typename Clock::duration d = ceil<nanoseconds>(t-Clock::now()); if (d <= Clock::duration::zero()) return false; // in case the Clock::time_point t is already reached joined = try_join_until(s_now + d); @@ -496,10 +503,10 @@ namespace boost return true; } template <class Duration> - bool try_join_until(const chrono::time_point<chrono::system_clock, Duration>& t) + bool try_join_until(const chrono::time_point<my_clock_t, Duration>& t) { using namespace chrono; - typedef time_point<system_clock, nanoseconds> nano_sys_tmpt; + typedef time_point<my_clock_t, nanoseconds> nano_sys_tmpt; return try_join_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch()))); } #endif @@ -514,7 +521,7 @@ namespace boost //} #ifdef BOOST_THREAD_USES_CHRONO - bool try_join_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp) + bool try_join_until(const chrono::time_point<my_clock_t, chrono::nanoseconds>& tp) { chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now()); return do_try_join_until(rel_time.count()); diff --git a/boost/thread/exceptions.hpp b/boost/thread/exceptions.hpp index d97465b754..a3934f0799 100644 --- a/boost/thread/exceptions.hpp +++ b/boost/thread/exceptions.hpp @@ -40,19 +40,19 @@ namespace boost typedef system::system_error base_type; public: thread_exception() - : base_type(0,system::system_category()) + : base_type(0,system::generic_category()) {} thread_exception(int sys_error_code) - : base_type(sys_error_code, system::system_category()) + : base_type(sys_error_code, system::generic_category()) {} thread_exception( int ev, const char * what_arg ) - : base_type(system::error_code(ev, system::system_category()), what_arg) + : base_type(system::error_code(ev, system::generic_category()), what_arg) { } thread_exception( int ev, const std::string & what_arg ) - : base_type(system::error_code(ev, system::system_category()), what_arg) + : base_type(system::error_code(ev, system::generic_category()), what_arg) { } @@ -74,18 +74,18 @@ namespace boost typedef system::system_error base_type; public: condition_error() - : base_type(system::error_code(0, system::system_category()), "Condition error") + : base_type(system::error_code(0, system::generic_category()), "Condition error") {} condition_error( int ev ) - : base_type(system::error_code(ev, system::system_category()), "Condition error") + : base_type(system::error_code(ev, system::generic_category()), "Condition error") { } condition_error( int ev, const char * what_arg ) - : base_type(system::error_code(ev, system::system_category()), what_arg) + : base_type(system::error_code(ev, system::generic_category()), what_arg) { } condition_error( int ev, const std::string & what_arg ) - : base_type(system::error_code(ev, system::system_category()), what_arg) + : base_type(system::error_code(ev, system::generic_category()), what_arg) { } }; diff --git a/boost/thread/executors/executor.hpp b/boost/thread/executors/executor.hpp index 96198201f0..1c751dd094 100644 --- a/boost/thread/executors/executor.hpp +++ b/boost/thread/executors/executor.hpp @@ -38,7 +38,7 @@ namespace boost * \par Synchronization * The completion of all the closures happen before the completion of the executor destructor. */ - virtual ~executor() {}; + virtual ~executor() {} /** * \par Effects diff --git a/boost/thread/executors/generic_executor_ref.hpp b/boost/thread/executors/generic_executor_ref.hpp index da0382c160..1353dd3277 100644 --- a/boost/thread/executors/generic_executor_ref.hpp +++ b/boost/thread/executors/generic_executor_ref.hpp @@ -41,7 +41,7 @@ namespace boost * \par Synchronization * The completion of all the closures happen before the completion of the executor destructor. */ - ~executor_ref() {}; + ~executor_ref() {} /** * \par Effects diff --git a/boost/thread/executors/loop_executor.hpp b/boost/thread/executors/loop_executor.hpp index b08ff76f57..aee7a8d477 100644 --- a/boost/thread/executors/loop_executor.hpp +++ b/boost/thread/executors/loop_executor.hpp @@ -16,6 +16,7 @@ #include <boost/thread/detail/move.hpp> #include <boost/thread/concurrent_queues/sync_queue.hpp> #include <boost/thread/executors/work.hpp> +#include <boost/assert.hpp> #include <boost/config/abi_prefix.hpp> @@ -41,14 +42,32 @@ namespace executors */ bool try_executing_one() { + return execute_one(/*wait:*/false); + } + + private: + /** + * Effects: Execute one task. + * Remark: If wait is true, waits until a task is available or the executor + * is closed. If wait is false, returns false immediately if no + * task is available. + * Returns: whether a task has been executed (if wait is true, only returns false if closed). + * Throws: whatever the current task constructor throws or the task() throws. + */ + bool execute_one(bool wait) + { work task; try { - if (work_queue.try_pull(task) == queue_op_status::success) + queue_op_status status = wait ? + work_queue.wait_pull(task) : + work_queue.try_pull(task); + if (status == queue_op_status::success) { task(); return true; } + BOOST_ASSERT(!wait || status == queue_op_status::closed); return false; } catch (...) @@ -57,21 +76,6 @@ namespace executors //return false; } } - private: - /** - * Effects: schedule one task or yields - * Throws: whatever the current task constructor throws or the task() throws. - */ - void schedule_one_or_yield() - { - if ( ! try_executing_one()) - { - this_thread::yield(); - } - } - - - public: /// loop_executor is not copyable. @@ -101,10 +105,10 @@ namespace executors */ void loop() { - while (!closed()) + while (execute_one(/*wait:*/true)) { - schedule_one_or_yield(); } + BOOST_ASSERT(closed()); while (try_executing_one()) { } diff --git a/boost/thread/future.hpp b/boost/thread/future.hpp index b98ff3d338..59712c7e2f 100644 --- a/boost/thread/future.hpp +++ b/boost/thread/future.hpp @@ -1355,7 +1355,7 @@ namespace boost boost::throw_exception(future_uninitialized()); } return future_->mutex; - }; + } notify_when_ready_handle notify_when_ready(boost::condition_variable_any& cv) { @@ -5656,5 +5656,5 @@ namespace detail #endif // BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY } -#endif // BOOST_NO_EXCEPTION +#endif // BOOST_NO_EXCEPTIONS #endif // header diff --git a/boost/thread/futures/wait_for_all.hpp b/boost/thread/futures/wait_for_all.hpp index 90cc2b77cb..398eb4adee 100644 --- a/boost/thread/futures/wait_for_all.hpp +++ b/boost/thread/futures/wait_for_all.hpp @@ -60,7 +60,7 @@ namespace boost } #else template<typename F1, typename... Fs> - void wait_for_all(F1& f1, Fs&... fs) + typename boost::enable_if<is_future_type<F1>,void>::type wait_for_all(F1& f1, Fs&... fs) { bool dummy[] = { (f1.wait(), true), (fs.wait(), true)... }; diff --git a/boost/thread/pthread/condition_variable_fwd.hpp b/boost/thread/pthread/condition_variable_fwd.hpp index 652a8c0baa..802a5cc674 100644 --- a/boost/thread/pthread/condition_variable_fwd.hpp +++ b/boost/thread/pthread/condition_variable_fwd.hpp @@ -17,6 +17,7 @@ #if defined BOOST_THREAD_USES_DATETIME #include <boost/thread/xtime.hpp> #endif + #ifdef BOOST_THREAD_USES_CHRONO #include <boost/chrono/system_clocks.hpp> #include <boost/chrono/ceil.hpp> @@ -68,7 +69,20 @@ namespace boost unique_lock<mutex>& lock, struct timespec const &timeout) { - return do_wait_until(lock, boost::detail::timespec_plus(timeout, boost::detail::timespec_now())); +#if ! defined BOOST_THREAD_USEFIXES_TIMESPEC + return do_wait_until(lock, boost::detail::timespec_plus(timeout, boost::detail::timespec_now())); +#elif ! defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC + //using namespace chrono; + //nanoseconds ns = chrono::system_clock::now().time_since_epoch(); + + struct timespec ts = boost::detail::timespec_now_realtime(); + //ts.tv_sec = static_cast<long>(chrono::duration_cast<chrono::seconds>(ns).count()); + //ts.tv_nsec = static_cast<long>((ns - chrono::duration_cast<chrono::seconds>(ns)).count()); + return do_wait_until(lock, boost::detail::timespec_plus(timeout, ts)); +#else + // old behavior was fine for monotonic + return do_wait_until(lock, boost::detail::timespec_plus(timeout, boost::detail::timespec_now_realtime())); +#endif } public: diff --git a/boost/thread/pthread/timespec.hpp b/boost/thread/pthread/timespec.hpp index 82f50f6ca7..74583ed0eb 100644 --- a/boost/thread/pthread/timespec.hpp +++ b/boost/thread/pthread/timespec.hpp @@ -75,6 +75,33 @@ namespace boost { timespec ts; +#if defined CLOCK_MONOTONIC && defined BOOST_THREAD_USEFIXES_TIMESPEC + if ( ::clock_gettime( CLOCK_MONOTONIC, &ts ) ) + { + ts.tv_sec = 0; + ts.tv_nsec = 0; + BOOST_ASSERT(0 && "Boost::Thread - Internal Error"); + } +#elif defined(BOOST_THREAD_TIMESPEC_MAC_API) + timeval tv; + ::gettimeofday(&tv, 0); + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = tv.tv_usec * 1000; +#else + if ( ::clock_gettime( CLOCK_REALTIME, &ts ) ) + { + ts.tv_sec = 0; + ts.tv_nsec = 0; + BOOST_ASSERT(0 && "Boost::Thread - Internal Error"); + } +#endif + return ts; + } + + inline timespec timespec_now_realtime() + { + timespec ts; + #if defined(BOOST_THREAD_TIMESPEC_MAC_API) timeval tv; ::gettimeofday(&tv, 0); @@ -83,6 +110,8 @@ namespace boost #else if ( ::clock_gettime( CLOCK_REALTIME, &ts ) ) { + ts.tv_sec = 0; + ts.tv_nsec = 0; BOOST_ASSERT(0 && "Boost::Thread - Internal Error"); } #endif diff --git a/boost/thread/scoped_thread.hpp b/boost/thread/scoped_thread.hpp index c2da919728..6cda931a5f 100644 --- a/boost/thread/scoped_thread.hpp +++ b/boost/thread/scoped_thread.hpp @@ -34,10 +34,10 @@ namespace boost * boost::strict_scoped_thread<> t((boost::thread(F))); * */ - template <class CallableThread = join_if_joinable> + template <class CallableThread = join_if_joinable, class Thread=::boost::thread> class strict_scoped_thread { - thread t_; + Thread t_; struct dummy; public: @@ -47,13 +47,13 @@ namespace boost * */ #if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, thread>, void* >::type> + template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, Thread>, void* >::type> explicit strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Args)... args) : t_(boost::forward<F>(f), boost::forward<Args>(args)...) {} #else template <class F> explicit strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, - typename disable_if<is_same<typename decay<F>::type, thread>, void* >::type=0) : + typename disable_if<is_same<typename decay<F>::type, Thread>, void* >::type=0) : t_(boost::forward<F>(f)) {} template <class F, class A1> strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1) : @@ -73,7 +73,7 @@ namespace boost * * Effects: move the thread to own @c t. */ - explicit strict_scoped_thread(BOOST_THREAD_RV_REF(thread) t) BOOST_NOEXCEPT : + explicit strict_scoped_thread(BOOST_THREAD_RV_REF(Thread) t) BOOST_NOEXCEPT : t_(boost::move(t)) { } @@ -111,14 +111,15 @@ namespace boost * t.interrupt(); * */ - template <class CallableThread = join_if_joinable> + template <class CallableThread = join_if_joinable, class Thread=::boost::thread> class scoped_thread { - thread t_; + Thread t_; struct dummy; public: - typedef thread::id id; + typedef typename Thread::id id; + typedef typename Thread::native_handle_type native_handle_type; BOOST_THREAD_MOVABLE_ONLY( scoped_thread) /// Movable only @@ -137,13 +138,13 @@ namespace boost */ #if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) - template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, thread>, void* >::type> + template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, Thread>, void* >::type> explicit scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Args)... args) : t_(boost::forward<F>(f), boost::forward<Args>(args)...) {} #else template <class F> explicit scoped_thread(BOOST_THREAD_FWD_REF(F) f, - typename disable_if<is_same<typename decay<F>::type, thread>, void* >::type=0) : + typename disable_if<is_same<typename decay<F>::type, Thread>, void* >::type=0) : t_(boost::forward<F>(f)) {} template <class F, class A1> scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1) : @@ -163,12 +164,12 @@ namespace boost * * Effects: move the thread to own @c t. */ - explicit scoped_thread(BOOST_THREAD_RV_REF(thread) t) BOOST_NOEXCEPT : + explicit scoped_thread(BOOST_THREAD_RV_REF(Thread) t) BOOST_NOEXCEPT : t_(boost::move(t)) { } -// explicit operator thread() +// explicit operator Thread() // { // return boost::move(t_); // } @@ -213,7 +214,7 @@ namespace boost } // forwarded thread functions - inline thread::id get_id() const BOOST_NOEXCEPT + inline id get_id() const BOOST_NOEXCEPT { return t_.get_id(); } @@ -242,7 +243,7 @@ namespace boost } #endif - thread::native_handle_type native_handle()BOOST_NOEXCEPT + native_handle_type native_handle()BOOST_NOEXCEPT { return t_.native_handle(); } @@ -266,13 +267,13 @@ namespace boost static unsigned hardware_concurrency() BOOST_NOEXCEPT { - return thread::hardware_concurrency(); + return Thread::hardware_concurrency(); } #ifdef BOOST_THREAD_PROVIDES_PHYSICAL_CONCURRENCY static unsigned physical_concurrency() BOOST_NOEXCEPT { - return thread::physical_concurrency(); + return Thread::physical_concurrency(); } #endif }; @@ -280,12 +281,13 @@ namespace boost /** * Effects: swaps the contents of two scoped threads. */ - template <class Destroyer> - void swap(scoped_thread<Destroyer>& lhs, scoped_thread<Destroyer>& rhs) + template <class Destroyer, class Thread > + void swap(scoped_thread<Destroyer, Thread>& lhs, scoped_thread<Destroyer, Thread>& rhs) BOOST_NOEXCEPT { return lhs.swap(rhs); } + typedef scoped_thread<> joining_thread; } #include <boost/config/abi_suffix.hpp> diff --git a/boost/thread/thread_functors.hpp b/boost/thread/thread_functors.hpp index bba129f767..f134593ffe 100644 --- a/boost/thread/thread_functors.hpp +++ b/boost/thread/thread_functors.hpp @@ -21,15 +21,29 @@ namespace boost struct detach { - void operator()(thread& t) + template <class Thread> + void operator()(Thread& t) { t.detach(); } }; + struct detach_if_joinable + { + template <class Thread> + void operator()(Thread& t) + { + if (t.joinable()) + { + t.detach(); + } + } + }; + struct join_if_joinable { - void operator()(thread& t) + template <class Thread> + void operator()(Thread& t) { if (t.joinable()) { @@ -41,7 +55,8 @@ namespace boost #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS struct interrupt_and_join_if_joinable { - void operator()(thread& t) + template <class Thread> + void operator()(Thread& t) { if (t.joinable()) { diff --git a/boost/thread/thread_guard.hpp b/boost/thread/thread_guard.hpp index 85157f101e..64eb453c73 100644 --- a/boost/thread/thread_guard.hpp +++ b/boost/thread/thread_guard.hpp @@ -21,14 +21,14 @@ namespace boost /** * Non-copyable RAII scoped thread guard joiner which join the thread if joinable when destroyed. */ - template <class CallableThread = join_if_joinable> + template <class CallableThread = join_if_joinable, class Thread=::boost::thread> class thread_guard { - thread& t_; + Thread& t_; public: BOOST_THREAD_NO_COPYABLE( thread_guard) - explicit thread_guard(thread& t) : + explicit thread_guard(Thread& t) : t_(t) { } 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); } } } diff --git a/boost/thread/win32/thread_primitives.hpp b/boost/thread/win32/thread_primitives.hpp index c9e279faa0..133cc9c761 100644 --- a/boost/thread/win32/thread_primitives.hpp +++ b/boost/thread/win32/thread_primitives.hpp @@ -18,6 +18,7 @@ #include <boost/detail/interlocked.hpp> #include <boost/detail/winapi/config.hpp> //#include <boost/detail/winapi/synchronization.hpp> +#include <boost/thread/win32/interlocked_read.hpp> #include <algorithm> #if BOOST_PLAT_WINDOWS_RUNTIME @@ -244,19 +245,19 @@ namespace boost // Borrowed from https://stackoverflow.com/questions/8211820/userland-interrupt-timer-access-such-as-via-kequeryinterrupttime-or-similar inline ticks_type __stdcall GetTickCount64emulation() { - static volatile long count = 0xFFFFFFFF; + static long count = -1l; unsigned long previous_count, current_tick32, previous_count_zone, current_tick32_zone; ticks_type current_tick64; - previous_count = (unsigned long) _InterlockedCompareExchange(&count, 0, 0); + previous_count = (unsigned long) boost::detail::interlocked_read_acquire(&count); current_tick32 = GetTickCount(); - if(previous_count == 0xFFFFFFFF) + if(previous_count == (unsigned long)-1l) { // count has never been written unsigned long initial_count; initial_count = current_tick32 >> 28; - previous_count = (unsigned long) _InterlockedCompareExchange(&count, initial_count, 0xFFFFFFFF); + previous_count = (unsigned long) _InterlockedCompareExchange(&count, (long)initial_count, -1l); current_tick64 = initial_count; current_tick64 <<= 28; @@ -279,8 +280,9 @@ namespace boost if(current_tick32_zone == previous_count_zone + 1 || (current_tick32_zone == 0 && previous_count_zone == 15)) { // The top four bits of the 32-bit tick count have been incremented since count was last written. - _InterlockedCompareExchange(&count, previous_count + 1, previous_count); - current_tick64 = previous_count + 1; + unsigned long new_count = previous_count + 1; + _InterlockedCompareExchange(&count, (long)new_count, (long)previous_count); + current_tick64 = new_count; current_tick64 <<= 28; current_tick64 += current_tick32 & 0x0FFFFFFF; return current_tick64; |