diff options
Diffstat (limited to 'boost/thread')
123 files changed, 24373 insertions, 3109 deletions
diff --git a/boost/thread/barrier.hpp b/boost/thread/barrier.hpp index 4fd89883b8..47daf07b35 100644 --- a/boost/thread/barrier.hpp +++ b/boost/thread/barrier.hpp @@ -1,6 +1,7 @@ // Copyright (C) 2002-2003 // David Moore, William E. Kempf // Copyright (C) 2007-8 Anthony Williams +// (C) Copyright 2013 Vicente J. Botet Escriba // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -9,55 +10,244 @@ #define BOOST_BARRIER_JDM030602_HPP #include <boost/thread/detail/config.hpp> -#include <boost/throw_exception.hpp> +#include <boost/thread/detail/delete.hpp> +#include <boost/throw_exception.hpp> #include <boost/thread/mutex.hpp> +#include <boost/thread/lock_types.hpp> #include <boost/thread/condition_variable.hpp> #include <string> #include <stdexcept> +#include <boost/thread/detail/nullary_function.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/type_traits/is_void.hpp> +#include <boost/core/enable_if.hpp> +#include <boost/utility/result_of.hpp> #include <boost/config/abi_prefix.hpp> namespace boost { + namespace thread_detail + { + typedef detail::nullary_function<void()> void_completion_function; + typedef detail::nullary_function<size_t()> size_completion_function; + + struct default_barrier_reseter + { + unsigned int size_; + default_barrier_reseter(unsigned int size) : + size_(size) + { + } + BOOST_THREAD_MOVABLE(default_barrier_reseter) + //BOOST_THREAD_COPYABLE_AND_MOVABLE(default_barrier_reseter) + + default_barrier_reseter(default_barrier_reseter const& other) BOOST_NOEXCEPT : + size_(other.size_) + { + } + default_barrier_reseter(BOOST_THREAD_RV_REF(default_barrier_reseter) other) BOOST_NOEXCEPT : + size_(BOOST_THREAD_RV(other).size_) + { + } + + unsigned int operator()() + { + return size_; + } + }; + + struct void_functor_barrier_reseter + { + unsigned int size_; + void_completion_function fct_; + template <typename F> + void_functor_barrier_reseter(unsigned int size, BOOST_THREAD_RV_REF(F) funct) + : size_(size), fct_(boost::move(funct)) + {} + template <typename F> + void_functor_barrier_reseter(unsigned int size, F& funct) + : size_(size), fct_(funct) + {} - class barrier + BOOST_THREAD_MOVABLE(void_functor_barrier_reseter) + //BOOST_THREAD_COPYABLE_AND_MOVABLE(void_functor_barrier_reseter) + + void_functor_barrier_reseter(void_functor_barrier_reseter const& other) BOOST_NOEXCEPT : + size_(other.size_), fct_(other.fct_) + { + } + void_functor_barrier_reseter(BOOST_THREAD_RV_REF(void_functor_barrier_reseter) other) BOOST_NOEXCEPT : + size_(BOOST_THREAD_RV(other).size_), fct_(BOOST_THREAD_RV(other).fct_) + //size_(BOOST_THREAD_RV(other).size_), fct_(boost::move(BOOST_THREAD_RV(other).fct_)) + { + } + + unsigned int operator()() + { + fct_(); + return size_; + } + }; + struct void_fct_ptr_barrier_reseter { - public: - barrier(unsigned int count) - : m_threshold(count), m_count(count), m_generation(0) - { - if (count == 0) - boost::throw_exception(thread_exception(system::errc::invalid_argument, "barrier constructor: count cannot be zero.")); - } - - bool wait() - { - boost::mutex::scoped_lock lock(m_mutex); - unsigned int gen = m_generation; - - if (--m_count == 0) - { - m_generation++; - m_count = m_threshold; - m_cond.notify_all(); - return true; - } - - while (gen == m_generation) - m_cond.wait(lock); - return false; - } - - private: - mutex m_mutex; - condition_variable m_cond; - unsigned int m_threshold; - unsigned int m_count; - unsigned int m_generation; + unsigned int size_; + void(*fct_)(); + void_fct_ptr_barrier_reseter(unsigned int size, void(*funct)()) : + size_(size), fct_(funct) + { + } + BOOST_THREAD_MOVABLE(void_fct_ptr_barrier_reseter) + //BOOST_THREAD_COPYABLE_AND_MOVABLE(void_fct_ptr_barrier_reseter) + + void_fct_ptr_barrier_reseter(void_fct_ptr_barrier_reseter const& other) BOOST_NOEXCEPT : + size_(other.size_), fct_(other.fct_) + { + } + void_fct_ptr_barrier_reseter(BOOST_THREAD_RV_REF(void_fct_ptr_barrier_reseter) other) BOOST_NOEXCEPT : + size_(BOOST_THREAD_RV(other).size_), fct_(BOOST_THREAD_RV(other).fct_) + { + } + unsigned int operator()() + { + fct_(); + return size_; + } }; + } + //BOOST_THREAD_DCL_MOVABLE(thread_detail::default_barrier_reseter) + //BOOST_THREAD_DCL_MOVABLE(thread_detail::void_functor_barrier_reseter) + //BOOST_THREAD_DCL_MOVABLE(thread_detail::void_fct_ptr_barrier_reseter) + + class barrier + { + static inline unsigned int check_counter(unsigned int count) + { + if (count == 0) boost::throw_exception( + thread_exception(system::errc::invalid_argument, "barrier constructor: count cannot be zero.")); + return count; + } + struct dummy + { + }; + + public: + BOOST_THREAD_NO_COPYABLE( barrier) + + explicit barrier(unsigned int count) : + m_count(check_counter(count)), m_generation(0), fct_(BOOST_THREAD_MAKE_RV_REF(thread_detail::default_barrier_reseter(count))) + { + } + + template <typename F> + barrier( + unsigned int count, + BOOST_THREAD_RV_REF(F) funct, + typename enable_if< + typename is_void<typename result_of<F>::type>::type, dummy* + >::type=0 + ) + : m_count(check_counter(count)), + m_generation(0), + fct_(BOOST_THREAD_MAKE_RV_REF(thread_detail::void_functor_barrier_reseter(count, + boost::move(funct))) + ) + { + } + template <typename F> + barrier( + unsigned int count, + F &funct, + typename enable_if< + typename is_void<typename result_of<F>::type>::type, dummy* + >::type=0 + ) + : m_count(check_counter(count)), + m_generation(0), + fct_(BOOST_THREAD_MAKE_RV_REF(thread_detail::void_functor_barrier_reseter(count, + funct)) + ) + { + } + + template <typename F> + barrier( + unsigned int count, + BOOST_THREAD_RV_REF(F) funct, + typename enable_if< + typename is_same<typename result_of<F>::type, unsigned int>::type, dummy* + >::type=0 + ) + : m_count(check_counter(count)), + m_generation(0), + fct_(boost::move(funct)) + { + } + template <typename F> + barrier( + unsigned int count, + F& funct, + typename enable_if< + typename is_same<typename result_of<F>::type, unsigned int>::type, dummy* + >::type=0 + ) + : m_count(check_counter(count)), + m_generation(0), + fct_(funct) + { + } + + barrier(unsigned int count, void(*funct)()) : + m_count(check_counter(count)), m_generation(0), + fct_(funct + ? BOOST_THREAD_MAKE_RV_REF(thread_detail::size_completion_function(BOOST_THREAD_MAKE_RV_REF(thread_detail::void_fct_ptr_barrier_reseter(count, funct)))) + : BOOST_THREAD_MAKE_RV_REF(thread_detail::size_completion_function(BOOST_THREAD_MAKE_RV_REF(thread_detail::default_barrier_reseter(count)))) + ) + { + } + barrier(unsigned int count, unsigned int(*funct)()) : + m_count(check_counter(count)), m_generation(0), + fct_(funct + ? BOOST_THREAD_MAKE_RV_REF(thread_detail::size_completion_function(funct)) + : BOOST_THREAD_MAKE_RV_REF(thread_detail::size_completion_function(BOOST_THREAD_MAKE_RV_REF(thread_detail::default_barrier_reseter(count)))) + ) + { + } + + bool wait() + { + boost::unique_lock < boost::mutex > lock(m_mutex); + unsigned int gen = m_generation; + + if (--m_count == 0) + { + m_generation++; + m_count = static_cast<unsigned int>(fct_()); + BOOST_ASSERT(m_count != 0); + m_cond.notify_all(); + return true; + } + + while (gen == m_generation) + m_cond.wait(lock); + return false; + } + + void count_down_and_wait() + { + wait(); + } + + private: + mutex m_mutex; + condition_variable m_cond; + unsigned int m_count; + unsigned int m_generation; + thread_detail::size_completion_function fct_; + }; -} // namespace boost +} // namespace boost #include <boost/config/abi_suffix.hpp> diff --git a/boost/thread/caller_context.hpp b/boost/thread/caller_context.hpp new file mode 100644 index 0000000000..1e341686b0 --- /dev/null +++ b/boost/thread/caller_context.hpp @@ -0,0 +1,56 @@ +// (C) Copyright 2013 Vicente J. Botet Escriba +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +#ifndef BOOST_THREAD_CALL_CONTEXT_HPP +#define BOOST_THREAD_CALL_CONTEXT_HPP + +#include <boost/thread/detail/config.hpp> +#if defined BOOST_THREAD_USES_LOG_THREAD_ID +#include <boost/thread/thread.hpp> +#endif +#include <boost/current_function.hpp> +#include <iomanip> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + + struct caller_context_t + { + const char * filename; + unsigned lineno; + const char * func; + caller_context_t(const char * filename, unsigned lineno, const char * func) : + filename(filename), lineno(lineno), func(func) + { + } + }; + +#define BOOST_CONTEXTOF boost::caller_context_t(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION) + + template <typename OStream> + OStream& operator<<(OStream& os, caller_context_t const& ctx) + { +#if defined BOOST_THREAD_USES_LOG_THREAD_ID + { + io::ios_flags_saver ifs( os ); + os << std::left << std::setw(14) << boost::this_thread::get_id() << " "; + } +#endif + { + io::ios_flags_saver ifs(os); + os << ctx.filename << "[" + << std::setw(4) << std::right << std::dec<< ctx.lineno << "] "; + os << ctx.func << " " ; + } + return os; + } +} + +#include <boost/config/abi_suffix.hpp> + +#endif // header diff --git a/boost/thread/completion_latch.hpp b/boost/thread/completion_latch.hpp new file mode 100644 index 0000000000..ea76474276 --- /dev/null +++ b/boost/thread/completion_latch.hpp @@ -0,0 +1,226 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2013 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_COMPLETION_LATCH_HPP +#define BOOST_THREAD_COMPLETION_LATCH_HPP + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/delete.hpp> +#include <boost/thread/detail/counter.hpp> + +#include <boost/thread/mutex.hpp> +#include <boost/thread/lock_types.hpp> +#include <boost/thread/condition_variable.hpp> +#include <boost/chrono/duration.hpp> +#include <boost/chrono/time_point.hpp> +#include <boost/assert.hpp> +//#include <boost/thread/detail/nullary_function.hpp> +#include <boost/thread/csbl/functional.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + namespace thread_detail + { + void noop() + { + } + } + class completion_latch + { + public: + /// the implementation defined completion function type + //typedef detail::nullary_function<void()> completion_function; + typedef csbl::function<void()> completion_function; + /// noop completion function factory + static completion_function noop() + { + return completion_function(&thread_detail::noop); + } + + private: + struct around_wait; + friend struct around_wait; + struct around_wait + { + completion_latch &that_; + boost::unique_lock<boost::mutex> &lk_; + around_wait(completion_latch &that, boost::unique_lock<boost::mutex> &lk) + : that_(that), lk_(lk) + { + that_.leavers_.cond_.wait(lk, detail::counter_is_zero(that_.leavers_)); + that_.waiters_.inc_and_notify_all(); + that_.leavers_.cond_.wait(lk, detail::counter_is_not_zero(that_.leavers_)); + } + ~around_wait() + { + that_.waiters_.dec_and_notify_all(); + } + }; + + bool count_down(unique_lock<mutex> &lk) + { + BOOST_ASSERT(count_ > 0); + if (--count_ == 0) + { + waiters_.cond_.wait(lk, detail::counter_is_not_zero(waiters_)); + leavers_.assign_and_notify_all(waiters_); + count_.cond_.notify_all(); + waiters_.cond_.wait(lk, detail::counter_is_zero(waiters_)); + leavers_.assign_and_notify_all(0); + lk.unlock(); + funct_(); + return true; + } + return false; + } + + public: + BOOST_THREAD_NO_COPYABLE( completion_latch ) + + /// Constructs a latch with a given count. + completion_latch(std::size_t count) : + count_(count), funct_(noop()), waiters_(0), leavers_(0) + { + } + + /// Constructs a latch with a given count and a completion function. + template <typename F> + completion_latch(std::size_t count, BOOST_THREAD_RV_REF(F) funct) : + count_(count), + funct_(boost::move(funct)), + waiters_(0), + leavers_(0) + { + } + template <typename F> + completion_latch(std::size_t count, void(*funct)()) : + count_(count), funct_(funct), waiters_(0), leavers_(0) + { + } + + /// + ~completion_latch() + { + } + + /// Blocks until the latch has counted down to zero. + void wait() + { + boost::unique_lock<boost::mutex> lk(mutex_); + around_wait aw(*this, lk); + count_.cond_.wait(lk, detail::counter_is_zero(count_)); + } + + /// @return true if the internal counter is already 0, false otherwise + bool try_wait() + { + boost::unique_lock<boost::mutex> lk(mutex_); + around_wait aw(*this, lk); + return (count_ == 0); + } + + /// try to wait for a specified amount of time + /// @return whether there is a timeout or not. + template <class Rep, class Period> + cv_status wait_for(const chrono::duration<Rep, Period>& rel_time) + { + boost::unique_lock<boost::mutex> lk(mutex_); + around_wait aw(*this, lk); + return count_.cond_.wait_for(lk, rel_time, detail::counter_is_zero(count_)) + ? cv_status::no_timeout + : cv_status::timeout; + } + + /// try to wait until the specified time_point is reached + /// @return whether there is a timeout or not. + template <class Clock, class Duration> + cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) + { + boost::unique_lock<boost::mutex> lk(mutex_); + around_wait aw(*this, lk); + return count_.cond_.wait_until(lk, abs_time, detail::counter_is_zero(count_)) + ? cv_status::no_timeout + : cv_status::timeout; + } + + /// Decrement the count and notify anyone waiting if we reach zero. + /// @Requires count must be greater than 0 + void count_down() + { + unique_lock<mutex> lk(mutex_); + count_down(lk); + } + void signal() + { + count_down(); + } + + /// Decrement the count and notify anyone waiting if we reach zero. + /// Blocks until the latch has counted down to zero. + /// @Requires count must be greater than 0 + void count_down_and_wait() + { + boost::unique_lock<boost::mutex> lk(mutex_); + if (count_down(lk)) + { + return; + } + around_wait aw(*this, lk); + count_.cond_.wait(lk, detail::counter_is_zero(count_)); + } + void sync() + { + count_down_and_wait(); + } + + /// Reset the counter + /// #Requires This method may only be invoked when there are no other threads currently inside the count_down_and_wait() method. + void reset(std::size_t count) + { + boost::lock_guard<boost::mutex> lk(mutex_); + //BOOST_ASSERT(count_ == 0); + count_ = count; + } + + /// Resets the latch with the new completion function. + /// The next time the internal count reaches 0, this function will be invoked. + /// This completion function may only be invoked when there are no other threads + /// currently inside the count_down and wait related functions. + /// It may also be invoked from within the registered completion function. + /// @Returns the old completion function if any or noop if + +#ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL + template <typename F> + completion_function then(BOOST_THREAD_RV_REF(F) funct) + { + boost::lock_guard<boost::mutex> lk(mutex_); + completion_function tmp(funct_); + funct_ = boost::move(funct); + return tmp; + } +#endif + completion_function then(void(*funct)()) + { + boost::lock_guard<boost::mutex> lk(mutex_); + completion_function tmp(funct_); + funct_ = completion_function(funct); + return tmp; + } + + private: + mutex mutex_; + detail::counter count_; + completion_function funct_; + detail::counter waiters_; + detail::counter leavers_; + }; + +} // namespace boost + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/concurrent_queues/queue_adaptor.hpp b/boost/thread/concurrent_queues/queue_adaptor.hpp new file mode 100644 index 0000000000..c729276f99 --- /dev/null +++ b/boost/thread/concurrent_queues/queue_adaptor.hpp @@ -0,0 +1,209 @@ +#ifndef BOOST_THREAD_QUEUE_ADAPTOR_HPP +#define BOOST_THREAD_QUEUE_ADAPTOR_HPP + +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/concurrent_queues/queue_op_status.hpp> +#include <boost/thread/concurrent_queues/queue_base.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ +namespace concurrent +{ +namespace detail +{ + + template <typename Queue> + class queue_adaptor_copyable_only : + public boost::queue_base<typename Queue::value_type> + { + Queue queue; + public: + typedef typename Queue::value_type value_type; + typedef std::size_t size_type; + + // Constructors/Assignment/Destructors + queue_adaptor_copyable_only() {} + + // Observers + bool empty() const { return queue.empty(); } + bool full() const { return queue.full(); } + size_type size() const { return queue.size(); } + bool closed() const { return queue.closed(); } + + // Modifiers + void close() { queue.close(); } + + void push_back(const value_type& x) { queue.push_back(x); } + + void pull_front(value_type& x) { queue.pull_front(x); }; + value_type pull_front() { return queue.pull_front(); } + + queue_op_status try_push_back(const value_type& x) { return queue.try_push_back(x); } + queue_op_status try_pull_front(value_type& x) { return queue.try_pull_front(x); } + + queue_op_status nonblocking_push_back(const value_type& x) { return queue.nonblocking_push_back(x); } + queue_op_status nonblocking_pull_front(value_type& x) { return queue.nonblocking_pull_front(x); } + + queue_op_status wait_push_back(const value_type& x) { return queue.wait_push_back(x); } + queue_op_status wait_pull_front(value_type& x) { return queue.wait_pull_front(x); } + + }; + template <typename Queue> + class queue_adaptor_movable_only : + public boost::queue_base<typename Queue::value_type> + { + Queue queue; + public: + typedef typename Queue::value_type value_type; + typedef std::size_t size_type; + + // Constructors/Assignment/Destructors + + queue_adaptor_movable_only() {} + + // Observers + bool empty() const { return queue.empty(); } + bool full() const { return queue.full(); } + size_type size() const { return queue.size(); } + bool closed() const { return queue.closed(); } + + // Modifiers + void close() { queue.close(); } + + + void pull_front(value_type& x) { queue.pull_front(x); }; + // enable_if is_nothrow_copy_movable<value_type> + value_type pull_front() { return queue.pull_front(); } + + queue_op_status try_pull_front(value_type& x) { return queue.try_pull_front(x); } + + queue_op_status nonblocking_pull_front(value_type& x) { return queue.nonblocking_pull_front(x); } + + queue_op_status wait_pull_front(value_type& x) { return queue.wait_pull_front(x); } + + void push_back(BOOST_THREAD_RV_REF(value_type) x) { queue.push_back(boost::move(x)); } + queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.try_push_back(boost::move(x)); } + queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.nonblocking_push_back(boost::move(x)); } + queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.wait_push_back(boost::move(x)); } + }; + + template <typename Queue> + class queue_adaptor_copyable_and_movable : + public boost::queue_base<typename Queue::value_type> + { + Queue queue; + public: + typedef typename Queue::value_type value_type; + typedef std::size_t size_type; + + // Constructors/Assignment/Destructors + + queue_adaptor_copyable_and_movable() {} + + // Observers + bool empty() const { return queue.empty(); } + bool full() const { return queue.full(); } + size_type size() const { return queue.size(); } + bool closed() const { return queue.closed(); } + + // Modifiers + void close() { queue.close(); } + + + void push_back(const value_type& x) { queue.push_back(x); } + + void pull_front(value_type& x) { queue.pull_front(x); }; + // enable_if is_nothrow_copy_movable<value_type> + value_type pull_front() { return queue.pull_front(); } + + queue_op_status try_push_back(const value_type& x) { return queue.try_push_back(x); } + queue_op_status try_pull_front(value_type& x) { return queue.try_pull_front(x); } + + queue_op_status nonblocking_push_back(const value_type& x) { return queue.nonblocking_push_back(x); } + queue_op_status nonblocking_pull_front(value_type& x) { return queue.nonblocking_pull_front(x); } + + queue_op_status wait_push_back(const value_type& x) { return queue.wait_push_back(x); } + queue_op_status wait_pull_front(value_type& x) { return queue.wait_pull_front(x); } + + void push_back(BOOST_THREAD_RV_REF(value_type) x) { queue.push_back(boost::move(x)); } + queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.try_push_back(boost::move(x)); } + queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.nonblocking_push_back(boost::move(x)); } + queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.wait_push_back(boost::move(x)); } + }; + + + template <class Q, class T, +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES +#if defined __GNUC__ +#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5) || !defined(__GXX_EXPERIMENTAL_CXX0X__) + bool Copyable = is_copy_constructible<T>::value, + bool Movable = true +#else + bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value, + bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value +#endif // __GNUC__ +#elif defined _MSC_VER +#if _MSC_VER < 1700 + bool Copyable = is_copy_constructible<T>::value, + bool Movable = true +#else + bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value, + bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value +#endif // _MSC_VER +#else + bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value, + bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value +#endif +#else + bool Copyable = is_copy_constructible<T>::value, + bool Movable = has_move_emulation_enabled<T>::value +#endif + > + struct queue_adaptor; + + template <class Q, class T> + struct queue_adaptor<Q, T, true, true> { + typedef queue_adaptor_copyable_and_movable<Q> type; + }; + template <class Q, class T> + struct queue_adaptor<Q, T, true, false> { + typedef queue_adaptor_copyable_only<Q> type; + }; + template <class Q, class T> + struct queue_adaptor<Q, T, false, true> { + typedef queue_adaptor_movable_only<Q> type; + }; + +} + + template <typename Queue> + class queue_adaptor : + public detail::queue_adaptor<Queue, typename Queue::value_type>::type + { + public: + typedef typename Queue::value_type value_type; + typedef std::size_t size_type; + // Constructors/Assignment/Destructors + virtual ~queue_adaptor() {}; + }; +} +using concurrent::queue_adaptor; + +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/concurrent_queues/queue_base.hpp b/boost/thread/concurrent_queues/queue_base.hpp new file mode 100755 index 0000000000..5ed14fd393 --- /dev/null +++ b/boost/thread/concurrent_queues/queue_base.hpp @@ -0,0 +1,202 @@ +#ifndef BOOST_THREAD_QUEUE_BASE_HPP +#define BOOST_THREAD_QUEUE_BASE_HPP + +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/concurrent_queues/queue_op_status.hpp> +#include <boost/type_traits/conditional.hpp> +#include <boost/type_traits/is_copy_constructible.hpp> + + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ +namespace concurrent +{ +namespace detail +{ + + template <typename ValueType> + class queue_base_copyable_only + { + public: + typedef ValueType value_type; + typedef std::size_t size_type; + + // Constructors/Assignment/Destructors + virtual ~queue_base_copyable_only() {}; + + // Observers + virtual bool empty() const = 0; + virtual bool full() const = 0; + virtual size_type size() const = 0; + virtual bool closed() const = 0; + + // Modifiers + virtual void close() = 0; + + virtual void push_back(const value_type& x) = 0; + + virtual void pull_front(value_type&) = 0; + virtual value_type pull_front() = 0; + + virtual queue_op_status try_push_back(const value_type& x) = 0; + virtual queue_op_status try_pull_front(value_type&) = 0; + + virtual queue_op_status nonblocking_push_back(const value_type& x) = 0; + virtual queue_op_status nonblocking_pull_front(value_type&) = 0; + + virtual queue_op_status wait_push_back(const value_type& x) = 0; + virtual queue_op_status wait_pull_front(ValueType& elem) = 0; + + }; + + template <typename ValueType> + class queue_base_movable_only + { + public: + typedef ValueType value_type; + typedef std::size_t size_type; + // Constructors/Assignment/Destructors + virtual ~queue_base_movable_only() {}; + + // Observers + virtual bool empty() const = 0; + virtual bool full() const = 0; + virtual size_type size() const = 0; + virtual bool closed() const = 0; + + // Modifiers + virtual void close() = 0; + + virtual void pull_front(value_type&) = 0; + // enable_if is_nothrow_movable<value_type> + virtual value_type pull_front() = 0; + + virtual queue_op_status try_pull_front(value_type&) = 0; + + virtual queue_op_status nonblocking_pull_front(value_type&) = 0; + + virtual queue_op_status wait_pull_front(ValueType& elem) = 0; + + virtual void push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; + virtual queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; + virtual queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; + virtual queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; + }; + + + template <typename ValueType> + class queue_base_copyable_and_movable + { + public: + typedef ValueType value_type; + typedef std::size_t size_type; + // Constructors/Assignment/Destructors + virtual ~queue_base_copyable_and_movable() {}; + + + // Observers + virtual bool empty() const = 0; + virtual bool full() const = 0; + virtual size_type size() const = 0; + virtual bool closed() const = 0; + + // Modifiers + virtual void close() = 0; + + virtual void push_back(const value_type& x) = 0; + + virtual void pull_front(value_type&) = 0; + // enable_if is_nothrow_copy_movable<value_type> + virtual value_type pull_front() = 0; + + virtual queue_op_status try_push_back(const value_type& x) = 0; + virtual queue_op_status try_pull_front(value_type&) = 0; + + virtual queue_op_status nonblocking_push_back(const value_type& x) = 0; + virtual queue_op_status nonblocking_pull_front(value_type&) = 0; + + virtual queue_op_status wait_push_back(const value_type& x) = 0; + virtual queue_op_status wait_pull_front(ValueType& elem) = 0; + + virtual void push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; + virtual queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; + virtual queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; + virtual queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0; + }; + + template <class T, +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES +#if defined __GNUC__ +#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5) || !defined(__GXX_EXPERIMENTAL_CXX0X__) + bool Copyable = is_copy_constructible<T>::value, + bool Movable = true +#else + bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value, + bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value +#endif // __GNUC__ +#elif defined _MSC_VER +#if _MSC_VER < 1700 + bool Copyable = is_copy_constructible<T>::value, + bool Movable = true +#else + bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value, + bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value +#endif // _MSC_VER +#else + bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value, + bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value +#endif +#else + bool Copyable = is_copy_constructible<T>::value, + bool Movable = has_move_emulation_enabled<T>::value +#endif + > + struct queue_base; + + template <class T> + struct queue_base<T, true, true> { + typedef queue_base_copyable_and_movable<T> type; + }; + template <class T> + struct queue_base<T, true, false> { + typedef queue_base_copyable_only<T> type; + }; + template <class T> + struct queue_base<T, false, true> { + typedef queue_base_movable_only<T> type; + }; + +} + + template <typename ValueType> + class queue_base : + public detail::queue_base<ValueType>::type + { + public: + typedef ValueType value_type; + typedef std::size_t size_type; + // Constructors/Assignment/Destructors + virtual ~queue_base() {}; + }; + +} +using concurrent::queue_base; + +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/concurrent_queues/queue_op_status.hpp b/boost/thread/concurrent_queues/queue_op_status.hpp new file mode 100644 index 0000000000..3a8f0d994d --- /dev/null +++ b/boost/thread/concurrent_queues/queue_op_status.hpp @@ -0,0 +1,46 @@ +#ifndef BOOST_THREAD_QUEUE_OP_STATUS_HPP +#define BOOST_THREAD_QUEUE_OP_STATUS_HPP + +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/move.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ +namespace concurrent +{ + + BOOST_SCOPED_ENUM_DECLARE_BEGIN(queue_op_status) + { success = 0, empty, full, closed, busy } + BOOST_SCOPED_ENUM_DECLARE_END(queue_op_status) + + struct sync_queue_is_closed : std::exception + { + }; + +} + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + struct no_block_tag{}; + BOOST_CONSTEXPR_OR_CONST no_block_tag no_block = {}; +#endif + + using concurrent::queue_op_status; + using concurrent::sync_queue_is_closed; + +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/concurrent_queues/queue_views.hpp b/boost/thread/concurrent_queues/queue_views.hpp new file mode 100644 index 0000000000..1c06af8297 --- /dev/null +++ b/boost/thread/concurrent_queues/queue_views.hpp @@ -0,0 +1,165 @@ +#ifndef BOOST_THREAD_QUEUE_VIEWS_HPP +#define BOOST_THREAD_QUEUE_VIEWS_HPP + +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/concurrent_queues/queue_op_status.hpp> +#include <boost/thread/concurrent_queues/queue_base.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ +namespace concurrent +{ + + template <typename Queue> + class queue_back_view + { + Queue* queue; + public: + typedef typename Queue::value_type value_type; + typedef typename Queue::size_type size_type; + + // Constructors/Assignment/Destructors + queue_back_view(Queue& q) BOOST_NOEXCEPT : queue(&q) {} + + // Observers + bool empty() const { return queue->empty(); } + bool full() const { return queue->full(); } + size_type size() const { return queue->size(); } + bool closed() const { return queue->closed(); } + + // Modifiers + void close() { queue->close(); } + + void push(const value_type& x) { queue->push_back(x); } + + void pull(value_type& x) { queue->pull_back(x); } + // enable_if is_nothrow_copy_movable<value_type> + value_type pull() { return queue->pull_back(); } + + queue_op_status try_push(const value_type& x) { return queue->try_push_back(x); } + + queue_op_status try_pull(value_type& x) { return queue->try_pull_back(x); } + + queue_op_status nonblocking_push(const value_type& x) { return queue->nonblocking_push_back(x); } + + queue_op_status nonblocking_pull(value_type& x) { return queue->nonblocking_pull_back(x); } + + queue_op_status wait_push(const value_type& x) { return queue->wait_push_back(x); } + queue_op_status wait_pull(value_type& x) { return queue->wait_pull_back(x); } + + void push(BOOST_THREAD_RV_REF(value_type) x) { queue->push_back(boost::move(x)); } + queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->try_push_back(boost::move(x)); } + queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->nonblocking_push_back(boost::move(x)); } + queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->wait_push_back(boost::move(x)); } + }; + + template <typename Queue> + class queue_front_view + { + Queue* queue; + public: + typedef typename Queue::value_type value_type; + typedef typename Queue::size_type size_type; + + // Constructors/Assignment/Destructors + queue_front_view(Queue& q) BOOST_NOEXCEPT : queue(&q) {} + + // Observers + bool empty() const { return queue->empty(); } + bool full() const { return queue->full(); } + size_type size() const { return queue->size(); } + bool closed() const { return queue->closed(); } + + // Modifiers + void close() { queue->close(); } + + void push(const value_type& x) { queue->push_front(x); } + + void pull(value_type& x) { queue->pull_front(x); }; + // enable_if is_nothrow_copy_movable<value_type> + value_type pull() { return queue->pull_front(); } + + queue_op_status try_push(const value_type& x) { return queue->try_push_front(x); } + + queue_op_status try_pull(value_type& x) { return queue->try_pull_front(x); } + + queue_op_status nonblocking_push(const value_type& x) { return queue->nonblocking_push_front(x); } + + queue_op_status nonblocking_pull(value_type& x) { return queue->nonblocking_pull_front(x); } + + queue_op_status wait_push(const value_type& x) { return queue->wait_push_front(x); } + queue_op_status wait_pull(value_type& x) { return queue->wait_pull_front(x); } + void push(BOOST_THREAD_RV_REF(value_type) x) { queue->push_front(forward<value_type>(x)); } + queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->try_push_front(forward<value_type>(x)); } + queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->nonblocking_push_front(forward<value_type>(x)); } + queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->wait_push_front(forward<value_type>(x)); } + + }; + +#if ! defined BOOST_NO_CXX11_TEMPLATE_ALIASES + + template <class T> + using queue_back = queue_back_view<queue_base<T> > ; + template <class T> + using queue_front = queue_front_view<queue_base<T> > ; + +#else + + template <class T> + struct queue_back : queue_back_view<queue_base<T> > + { + typedef queue_back_view<queue_base<T> > base_type; + queue_back(queue_base<T>& q) BOOST_NOEXCEPT : base_type(q) {} + }; + template <class T> + struct queue_front : queue_front_view<queue_base<T> > + { + typedef queue_front_view<queue_base<T> > base_type; + queue_front(queue_base<T>& q) BOOST_NOEXCEPT : base_type(q) {} + + }; + +#endif + +// template <class Queue> +// queue_back_view<Queue> back(Queue & q) { return queue_back_view<Queue>(q); } +// template <class Queue> +// queue_front_view<Queue> front(Queue & q) { return queue_front_view<Queue>(q); } +//#if 0 +// template <class T> +// queue_back<T> back(queue_base<T> & q) { return queue_back<T>(q); } +// template <class T> +// queue_front<T> front(queue_base<T> & q) { return queue_front<T>(q); } +//#else +// template <class T> +// typename queue_back<T>::type back(queue_base<T> & q) { return typename queue_back<T>::type(q); } +// template <class T> +// typename queue_front<T>::type front(queue_base<T> & q) { return typename queue_front<T>::type(q); } +//#endif +} + +using concurrent::queue_back_view; +using concurrent::queue_front_view; +using concurrent::queue_back; +using concurrent::queue_front; +//using concurrent::back; +//using concurrent::front; + +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/condition.hpp b/boost/thread/condition.hpp index 35b879fe03..9567df9825 100644 --- a/boost/thread/condition.hpp +++ b/boost/thread/condition.hpp @@ -1,11 +1,15 @@ #ifndef BOOST_THREAD_CONDITION_HPP #define BOOST_THREAD_CONDITION_HPP -// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2007 Anthony Williams // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#include <boost/thread/detail/config.hpp> + +#if defined BOOST_THREAD_PROVIDES_CONDITION + #include <boost/thread/condition_variable.hpp> namespace boost @@ -14,3 +18,4 @@ namespace boost } #endif +#endif diff --git a/boost/thread/csbl/deque.hpp b/boost/thread/csbl/deque.hpp new file mode 100644 index 0000000000..1e48903b1c --- /dev/null +++ b/boost/thread/csbl/deque.hpp @@ -0,0 +1,45 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2013/10 Vicente J. Botet Escriba +// Creation. + +#ifndef BOOST_CSBL_DEQUE_HPP +#define BOOST_CSBL_DEQUE_HPP + +#include <boost/config.hpp> +// MSVC has some trouble instantiating a non_copyable type +//C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\INCLUDE\xmemory0(606) : error C2248: 'non_copyable::non_copyable' : cannot access private member declared in class 'non_copyable' +// ..\libs\thread\test\sync\mutual_exclusion\queue_views\single_thread_pass.cpp(24) : see declaration of 'non_copyable::non_copyable' +// ..\libs\thread\test\sync\mutual_exclusion\queue_views\single_thread_pass.cpp(23) : see declaration of 'non_copyable' +// C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\INCLUDE\xmemory0(605) : while compiling class template member function 'void std::allocator<_Ty>::construct(_Ty *,const _Ty &)' +// with +// [ +// _Ty=non_copyable +// ] +#if defined BOOST_THREAD_USES_BOOST_DEQUE || defined BOOST_NO_CXX11_HDR_DEQUE || defined BOOST_NO_CXX11_RVALUE_REFERENCES || (defined _MSC_VER && _MSC_FULL_VER < 180020827) +#ifndef BOOST_THREAD_USES_BOOST_DEQUE +#define BOOST_THREAD_USES_BOOST_DEQUE +#endif +#include <boost/container/deque.hpp> +#else +#include <deque> +#endif + +namespace boost +{ + namespace csbl + { +#if defined BOOST_THREAD_USES_BOOST_DEQUE + using ::boost::container::deque; + +#else + using ::std::deque; + +#endif + + } +} +#endif // header diff --git a/boost/thread/csbl/functional.hpp b/boost/thread/csbl/functional.hpp new file mode 100644 index 0000000000..7a7e928b70 --- /dev/null +++ b/boost/thread/csbl/functional.hpp @@ -0,0 +1,49 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2013/10 Vicente J. Botet Escriba +// Creation. + +#ifndef BOOST_CSBL_FUNCTIONAL_HPP +#define BOOST_CSBL_FUNCTIONAL_HPP + +#include <boost/config.hpp> + +#include <functional> + +#if defined BOOST_THREAD_USES_BOOST_FUNCTIONAL || defined BOOST_NO_CXX11_HDR_FUNCTIONAL || defined BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_THREAD_USES_BOOST_FUNCTIONAL +#define BOOST_THREAD_USES_BOOST_FUNCTIONAL +#endif +#include <boost/function.hpp> +#endif + +namespace boost +{ + namespace csbl + { +#if defined BOOST_THREAD_USES_BOOST_FUNCTIONAL + using ::boost::function; +#else + // D.8.1, base (deprecated): + // 20.9.3, reference_wrapper: + // 20.9.4, arithmetic operations: + // 20.9.5, comparisons: + // 20.9.6, logical operations: + // 20.9.7, bitwise operations: + // 20.9.8, negators: + // 20.9.9, bind: + // D.9, binders (deprecated): + // D.8.2.1, adaptors (deprecated): + // D.8.2.2, adaptors (deprecated): + // 20.9.10, member function adaptors: + // 20.9.11 polymorphic function wrappers: + using ::std::function; + // 20.9.12, hash function primary template: +#endif + + } +} +#endif // header diff --git a/boost/thread/csbl/list.hpp b/boost/thread/csbl/list.hpp new file mode 100644 index 0000000000..c7f10a18d5 --- /dev/null +++ b/boost/thread/csbl/list.hpp @@ -0,0 +1,35 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2013/10 Vicente J. Botet Escriba +// Creation. + +#ifndef BOOST_CSBL_LIST_HPP +#define BOOST_CSBL_LIST_HPP + +#include <boost/config.hpp> + +#if defined BOOST_THREAD_USES_BOOST_LIST || defined BOOST_NO_CXX11_HDR_LIST || defined BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_THREAD_USES_BOOST_LIST +#define BOOST_THREAD_USES_BOOST_LIST +#endif +#include <boost/container/list.hpp> +#else +#include <list> +#endif + +namespace boost +{ + namespace csbl + { +#if defined BOOST_THREAD_USES_BOOST_LIST + using ::boost::container::list; +#else + using ::std::list; +#endif + + } +} +#endif // header diff --git a/boost/thread/csbl/memory.hpp b/boost/thread/csbl/memory.hpp new file mode 100644 index 0000000000..e076f11ad3 --- /dev/null +++ b/boost/thread/csbl/memory.hpp @@ -0,0 +1,61 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2013/10 Vicente J. Botet Escriba +// Creation. + +#ifndef BOOST_CSBL_MEMORY_HPP +#define BOOST_CSBL_MEMORY_HPP + +// 20.7.2 Header <memory> synopsis + +// 20.7.3, pointer traits +#include <boost/thread/csbl/memory/pointer_traits.hpp> + +// 20.7.4, pointer safety +// 20.7.5, pointer alignment function + +// 20.7.6, allocator argument tag +#include <boost/thread/csbl/memory/allocator_arg.hpp> + +// 20.7.8, allocator traits +#include <boost/thread/csbl/memory/allocator_traits.hpp> + +// 20.7.7, uses_allocator +#include <boost/thread/csbl/memory/scoped_allocator.hpp> + +// 20.7.9, the default allocator: +namespace boost +{ + namespace csbl + { + using ::std::allocator; + } +} +// 20.7.10, raw storage iterator: +// 20.7.11, temporary buffers: +// 20.7.12, specialized algorithms: + +// 20.8.1 class template unique_ptr: +// default_delete +#include <boost/thread/csbl/memory/default_delete.hpp> +#include <boost/thread/csbl/memory/unique_ptr.hpp> + +// 20.8.2.1, class bad_weak_ptr: +// 20.8.2.2, class template shared_ptr: +// 20.8.2.2.6, shared_ptr creation +// 20.8.2.2.7, shared_ptr comparisons: +// 20.8.2.2.8, shared_ptr specialized algorithms: +// 20.8.2.2.9, shared_ptr casts: +// 20.8.2.2.10, shared_ptr get_deleter: +// 20.8.2.2.11, shared_ptr I/O: +// 20.8.2.3, class template weak_ptr: +// 20.8.2.3.6, weak_ptr specialized algorithms: +// 20.8.2.3.7, class template owner_less: +// 20.8.2.4, class template enable_shared_from_this: +// 20.8.2.5, shared_ptr atomic access: +// 20.8.2.6 hash support + +#endif // header diff --git a/boost/thread/csbl/memory/allocator_arg.hpp b/boost/thread/csbl/memory/allocator_arg.hpp new file mode 100644 index 0000000000..354cdaee88 --- /dev/null +++ b/boost/thread/csbl/memory/allocator_arg.hpp @@ -0,0 +1,41 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2013/10 Vicente J. Botet Escriba +// Creation. + +#ifndef BOOST_CSBL_MEMORY_ALLOCATOR_ARG_HPP +#define BOOST_CSBL_MEMORY_ALLOCATOR_ARG_HPP + +#include <boost/thread/csbl/memory/config.hpp> + +// 20.7.6, allocator argument tag +#if defined BOOST_NO_CXX11_ALLOCATOR +#include <boost/container/scoped_allocator.hpp> + +namespace boost +{ + namespace csbl + { + using ::boost::container::allocator_arg_t; + using ::boost::container::allocator_arg; + } +} +#else +namespace boost +{ + namespace csbl + { + using ::std::allocator_arg_t; + using ::std::allocator_arg; + } +} +#endif // BOOST_NO_CXX11_ALLOCATOR +namespace boost +{ + using ::boost::csbl::allocator_arg_t; + using ::boost::csbl::allocator_arg; +} +#endif // header diff --git a/boost/thread/csbl/memory/allocator_traits.hpp b/boost/thread/csbl/memory/allocator_traits.hpp new file mode 100644 index 0000000000..3737cd85de --- /dev/null +++ b/boost/thread/csbl/memory/allocator_traits.hpp @@ -0,0 +1,35 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2013/10 Vicente J. Botet Escriba +// Creation. + +#ifndef BOOST_CSBL_MEMORY_ALLOCATOR_TRAITS_HPP +#define BOOST_CSBL_MEMORY_ALLOCATOR_TRAITS_HPP + +#include <boost/thread/csbl/memory/config.hpp> + +// 20.7.8, allocator traits +#if defined BOOST_NO_CXX11_ALLOCATOR +#include <boost/container/allocator_traits.hpp> + +namespace boost +{ + namespace csbl + { + using ::boost::container::allocator_traits; + } +} +#else +namespace boost +{ + namespace csbl + { + using ::std::allocator_traits; + } +} +#endif // BOOST_NO_CXX11_POINTER_TRAITS + +#endif // header diff --git a/boost/thread/csbl/memory/config.hpp b/boost/thread/csbl/memory/config.hpp new file mode 100644 index 0000000000..7b0596ac49 --- /dev/null +++ b/boost/thread/csbl/memory/config.hpp @@ -0,0 +1,16 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2013/10 Vicente J. Botet Escriba +// Creation. + +#ifndef BOOST_CSBL_MEMORY_CONFIG_HPP +#define BOOST_CSBL_MEMORY_CONFIG_HPP + +#include <boost/config.hpp> + +#include <memory> + +#endif // header diff --git a/boost/thread/csbl/memory/default_delete.hpp b/boost/thread/csbl/memory/default_delete.hpp new file mode 100644 index 0000000000..d20153b309 --- /dev/null +++ b/boost/thread/csbl/memory/default_delete.hpp @@ -0,0 +1,41 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2013/10 Vicente J. Botet Escriba +// Creation. + +#ifndef BOOST_CSBL_MEMORY_DEFAULT_DELETE_HPP +#define BOOST_CSBL_MEMORY_DEFAULT_DELETE_HPP + +#include <boost/thread/csbl/memory/config.hpp> + +// 20.8.1 class template unique_ptr: +// default_delete + +#if defined BOOST_NO_CXX11_SMART_PTR +#include <boost/move/unique_ptr.hpp> + +namespace boost +{ + namespace csbl + { + using ::boost::movelib::default_delete; + } +} +#else +namespace boost +{ + namespace csbl + { + using ::std::default_delete; + } +} +#endif // defined BOOST_NO_CXX11_SMART_PTR + +namespace boost +{ + using ::boost::csbl::default_delete; +} +#endif // header diff --git a/boost/thread/csbl/memory/pointer_traits.hpp b/boost/thread/csbl/memory/pointer_traits.hpp new file mode 100644 index 0000000000..320f8e9e77 --- /dev/null +++ b/boost/thread/csbl/memory/pointer_traits.hpp @@ -0,0 +1,35 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2013/10 Vicente J. Botet Escriba +// Creation. + +#ifndef BOOST_CSBL_MEMORY_POINTER_TRAITS_HPP +#define BOOST_CSBL_MEMORY_POINTER_TRAITS_HPP + +#include <boost/thread/csbl/memory/config.hpp> + +// 20.7.3, pointer traits +#if defined BOOST_NO_CXX11_ALLOCATOR +#include <boost/intrusive/pointer_traits.hpp> + +namespace boost +{ + namespace csbl + { + using ::boost::intrusive::pointer_traits; + } +} +#else +namespace boost +{ + namespace csbl + { + using ::std::pointer_traits; + } +} +#endif // BOOST_NO_CXX11_ALLOCATOR + +#endif // header diff --git a/boost/thread/csbl/memory/scoped_allocator.hpp b/boost/thread/csbl/memory/scoped_allocator.hpp new file mode 100644 index 0000000000..a92f3d8514 --- /dev/null +++ b/boost/thread/csbl/memory/scoped_allocator.hpp @@ -0,0 +1,35 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2013/10 Vicente J. Botet Escriba +// Creation. + +#ifndef BOOST_CSBL_MEMORY_SCOPED_ALLOCATOR_HPP +#define BOOST_CSBL_MEMORY_SCOPED_ALLOCATOR_HPP + +#include <boost/thread/csbl/memory/config.hpp> + +// 20.7.7, uses_allocator +#if defined BOOST_NO_CXX11_ALLOCATOR +#include <boost/container/scoped_allocator.hpp> + +namespace boost +{ + namespace csbl + { + using ::boost::container::uses_allocator; + } +} +#else +namespace boost +{ + namespace csbl + { + using ::std::uses_allocator; + } +} +#endif // BOOST_NO_CXX11_POINTER_TRAITS + +#endif // header diff --git a/boost/thread/csbl/memory/shared_ptr.hpp b/boost/thread/csbl/memory/shared_ptr.hpp new file mode 100644 index 0000000000..e9a9383723 --- /dev/null +++ b/boost/thread/csbl/memory/shared_ptr.hpp @@ -0,0 +1,42 @@ +// Copyright (C) 2014 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2014/10 Vicente J. Botet Escriba +// Creation. + +#ifndef BOOST_CSBL_MEMORY_SHARED_PTR_HPP +#define BOOST_CSBL_MEMORY_SHARED_PTR_HPP + +#include <boost/thread/csbl/memory/config.hpp> + +#if defined BOOST_NO_CXX11_SMART_PTR + +#include <boost/smart_ptr/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +namespace boost +{ + namespace csbl + { + using ::boost::shared_ptr; + using ::boost::make_shared; + } +} + +#else + +#include <boost/shared_ptr.hpp> + +namespace boost +{ + namespace csbl + { + using std::shared_ptr; + using std::make_shared; + } +} + +#endif +#endif // header diff --git a/boost/thread/csbl/memory/unique_ptr.hpp b/boost/thread/csbl/memory/unique_ptr.hpp new file mode 100644 index 0000000000..17abf54e92 --- /dev/null +++ b/boost/thread/csbl/memory/unique_ptr.hpp @@ -0,0 +1,28 @@ +// Copyright (C) 2013-2014 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2013/10 Vicente J. Botet Escriba +// Creation using interprocess::unique_ptr. +// 2014/09 Vicente J. Botet Escriba +// Adaptation to movelib::unique_ptr + +#ifndef BOOST_CSBL_MEMORY_UNIQUE_PTR_HPP +#define BOOST_CSBL_MEMORY_UNIQUE_PTR_HPP + +#include <boost/thread/csbl/memory/config.hpp> + +#include <boost/move/unique_ptr.hpp> +#include <boost/move/make_unique.hpp> + +namespace boost +{ + namespace csbl + { + using ::boost::movelib::unique_ptr; + using ::boost::movelib::make_unique; + + } +} +#endif // header diff --git a/boost/thread/csbl/tuple.hpp b/boost/thread/csbl/tuple.hpp new file mode 100644 index 0000000000..860229ebe0 --- /dev/null +++ b/boost/thread/csbl/tuple.hpp @@ -0,0 +1,49 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2013/10 Vicente J. Botet Escriba +// Creation. + +#ifndef BOOST_CSBL_TUPLE_HPP +#define BOOST_CSBL_TUPLE_HPP + +#include <boost/config.hpp> + +#if defined BOOST_THREAD_USES_BOOST_TUPLE || defined BOOST_NO_CXX11_HDR_TUPLE || defined BOOST_NO_CXX11_RVALUE_REFERENCES +#include <boost/tuple/tuple.hpp> +#ifndef BOOST_THREAD_USES_BOOST_TUPLE +#define BOOST_THREAD_USES_BOOST_TUPLE +#endif + +#else +#include <tuple> +#endif + +namespace boost +{ + namespace csbl + { +#if defined BOOST_THREAD_USES_BOOST_TUPLE + using ::boost::tuple; + using ::boost::get; + using ::boost::make_tuple; + //using ::boost::tuple_size; +#else + // 20.4.2, class template tuple: + using ::std::tuple; + using ::std::get; + using ::std::make_tuple; + using ::std::tuple_size; + // 20.4.2.4, tuple creation functions: + // 20.4.2.5, tuple helper classes: + // 20.4.2.6, element access: + // 20.4.2.7, relational operators: + // 20.4.2.8, allocator-related traits + // 20.4.2.9, specialized algorithms: +#endif + + } +} +#endif // header diff --git a/boost/thread/csbl/vector.hpp b/boost/thread/csbl/vector.hpp new file mode 100644 index 0000000000..d39c87d114 --- /dev/null +++ b/boost/thread/csbl/vector.hpp @@ -0,0 +1,35 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2013/10 Vicente J. Botet Escriba +// Creation. + +#ifndef BOOST_CSBL_VECTOR_HPP +#define BOOST_CSBL_VECTOR_HPP + +#include <boost/config.hpp> + +#if defined BOOST_THREAD_USES_BOOST_VECTOR || defined BOOST_NO_CXX11_HDR_VECTOR || defined BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_THREAD_USES_BOOST_VECTOR +#define BOOST_THREAD_USES_BOOST_VECTOR +#endif +#include <boost/container/vector.hpp> +#else +#include <vector> +#endif + +namespace boost +{ + namespace csbl + { +#if defined BOOST_THREAD_USES_BOOST_VECTOR + using ::boost::container::vector; +#else + using ::std::vector; +#endif + + } +} +#endif // header diff --git a/boost/thread/cv_status.hpp b/boost/thread/cv_status.hpp index 99b3c0c218..e52de4a522 100644 --- a/boost/thread/cv_status.hpp +++ b/boost/thread/cv_status.hpp @@ -9,7 +9,7 @@ #ifndef BOOST_THREAD_CV_STATUS_HPP #define BOOST_THREAD_CV_STATUS_HPP -#include <boost/detail/scoped_enum_emulation.hpp> +#include <boost/core/scoped_enum.hpp> namespace boost { diff --git a/boost/thread/detail/config.hpp b/boost/thread/detail/config.hpp index d9270df8af..475dadbaaa 100644 --- a/boost/thread/detail/config.hpp +++ b/boost/thread/detail/config.hpp @@ -1,6 +1,6 @@ // Copyright (C) 2001-2003 // William E. Kempf -// Copyright (C) 2011-2012 Vicente J. Botet Escriba +// Copyright (C) 2011-2013 Vicente J. Botet Escriba // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -10,118 +10,353 @@ #include <boost/config.hpp> #include <boost/detail/workaround.hpp> +#include <boost/thread/detail/platform.hpp> + +//#define BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS +// ATTRIBUTE_MAY_ALIAS + +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) + + // GCC since 3.3 has may_alias attribute that helps to alleviate optimizer issues with + // regard to violation of the strict aliasing rules. + + #define BOOST_THREAD_DETAIL_USE_ATTRIBUTE_MAY_ALIAS + #define BOOST_THREAD_ATTRIBUTE_MAY_ALIAS __attribute__((__may_alias__)) +#else + #define BOOST_THREAD_ATTRIBUTE_MAY_ALIAS +#endif + + +#if defined BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED +#define BOOST_THREAD_ASSERT_PRECONDITION(EXPR, EX) \ + if (EXPR) {} else boost::throw_exception(EX) +#define BOOST_THREAD_VERIFY_PRECONDITION(EXPR, EX) \ + if (EXPR) {} else boost::throw_exception(EX) +#define BOOST_THREAD_THROW_ELSE_RETURN(EX, RET) \ + boost::throw_exception(EX) +#else +#define BOOST_THREAD_ASSERT_PRECONDITION(EXPR, EX) +#define BOOST_THREAD_VERIFY_PRECONDITION(EXPR, EX) \ + (void)(EXPR) +#define BOOST_THREAD_THROW_ELSE_RETURN(EX, RET) \ + return (RET) +#endif // This compiler doesn't support Boost.Chrono -#if defined __IBMCPP__ && (__IBMCPP__ < 1100) +#if defined __IBMCPP__ && (__IBMCPP__ < 1100) \ + && ! defined BOOST_THREAD_DONT_USE_CHRONO #define BOOST_THREAD_DONT_USE_CHRONO +#if ! defined BOOST_THREAD_USES_DATETIME +#define BOOST_THREAD_USES_DATETIME +#endif #endif // This compiler doesn't support Boost.Move -#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) +#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) \ + && ! defined BOOST_THREAD_DONT_USE_MOVE #define BOOST_THREAD_DONT_USE_MOVE #endif // This compiler doesn't support Boost.Container Allocators files -#if defined __SUNPRO_CC +#if defined __SUNPRO_CC \ + && ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS #define BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS #endif -#if defined _WIN32_WCE && _WIN32_WCE==0x501 +#if defined _WIN32_WCE && _WIN32_WCE==0x501 \ + && ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS #define BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS #endif -#if ! defined BOOST_THREAD_DONT_PROVIDE_BASIC_THREAD_ID + +#if defined BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX || defined BOOST_NO_CXX11_HDR_INITIALIZER_LIST +#define BOOST_THREAD_NO_CXX11_HDR_INITIALIZER_LIST +#define BOOST_THREAD_NO_MAKE_LOCK_GUARD +#define BOOST_THREAD_NO_MAKE_STRICT_LOCK +#define BOOST_THREAD_NO_MAKE_NESTED_STRICT_LOCK +#endif + +#if defined(BOOST_NO_CXX11_HDR_TUPLE) || defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#define BOOST_THREAD_NO_MAKE_UNIQUE_LOCKS +#define BOOST_THREAD_NO_SYNCHRONIZE +#elif defined _MSC_VER && _MSC_VER <= 1600 +// C++ features supported by VC++ 10 (aka 2010) +#define BOOST_THREAD_NO_MAKE_UNIQUE_LOCKS +#define BOOST_THREAD_NO_SYNCHRONIZE +#endif + +/// BASIC_THREAD_ID +#if ! defined BOOST_THREAD_DONT_PROVIDE_BASIC_THREAD_ID \ + && ! defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID #define BOOST_THREAD_PROVIDES_BASIC_THREAD_ID #endif -// Default version is 2 +/// RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR +//#if defined BOOST_NO_CXX11_RVALUE_REFERENCES || defined BOOST_MSVC +#define BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR +//#endif + +// Default version #if !defined BOOST_THREAD_VERSION #define BOOST_THREAD_VERSION 2 #else -#if BOOST_THREAD_VERSION!=2 && BOOST_THREAD_VERSION!=3 -#error "BOOST_THREAD_VERSION must be 2 or 3" +#if BOOST_THREAD_VERSION!=2 && BOOST_THREAD_VERSION!=3 && BOOST_THREAD_VERSION!=4 +#error "BOOST_THREAD_VERSION must be 2, 3 or 4" #endif #endif -// Uses Boost.System by default if not stated the opposite defining BOOST_THREAD_DONT_USE_SYSTEM -#if ! defined BOOST_THREAD_DONT_USE_SYSTEM -#define BOOST_THREAD_USES_SYSTEM +// CHRONO +// Uses Boost.Chrono by default if not stated the opposite defining BOOST_THREAD_DONT_USE_CHRONO +#if ! defined BOOST_THREAD_DONT_USE_CHRONO \ + && ! defined BOOST_THREAD_USES_CHRONO +#define BOOST_THREAD_USES_CHRONO #endif -// Uses Boost.Chrono by default if not stated the opposite defining BOOST_THREAD_DONT_USE_CHRONO or BOOST_THREAD_DONT_USE_SYSTEM -#if ! defined BOOST_THREAD_DONT_USE_CHRONO && ! defined BOOST_THREAD_DONT_USE_SYSTEM -#define BOOST_THREAD_USES_CHRONO +#if ! defined BOOST_THREAD_DONT_USE_ATOMIC \ + && ! defined BOOST_THREAD_USES_ATOMIC +#define BOOST_THREAD_USES_ATOMIC +//#define BOOST_THREAD_DONT_USE_ATOMIC #endif -// Don't provided by default in version 1. -#if defined BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION -#define BOOST_THREAD_EXPLICIT_LOCK_CONVERSION explicit +#if defined BOOST_THREAD_USES_ATOMIC +// Andrey Semashev +#define BOOST_THREAD_ONCE_ATOMIC #else -#define BOOST_THREAD_EXPLICIT_LOCK_CONVERSION +//#elif ! defined BOOST_NO_CXX11_THREAD_LOCAL && ! defined BOOST_NO_THREAD_LOCAL && ! defined BOOST_THREAD_NO_UINT32_PSEUDO_ATOMIC +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2444.html#Appendix +#define BOOST_THREAD_ONCE_FAST_EPOCH #endif +#if BOOST_THREAD_VERSION==2 - -// Uses Boost.Move by default if not stated the opposite defining BOOST_THREAD_DONT_USE_MOVE -#if ! defined BOOST_THREAD_DONT_USE_MOVE -#if ! defined BOOST_THREAD_USES_MOVE -//#define BOOST_THREAD_USES_MOVE -#endif +// PROVIDE_PROMISE_LAZY +#if ! defined BOOST_THREAD_DONT_PROVIDE_PROMISE_LAZY \ + && ! defined BOOST_THREAD_PROVIDES_PROMISE_LAZY +#define BOOST_THREAD_PROVIDES_PROMISE_LAZY #endif -#if BOOST_THREAD_VERSION==2 -#if ! defined BOOST_THREAD_DONT_PROVIDE_PROMISE_LAZY -#define BOOST_THREAD_PROMISE_LAZY -#endif -#if ! defined BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0 -#define BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 +// PROVIDE_THREAD_EQ +#if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_EQ \ + && ! defined BOOST_THREAD_PROVIDES_THREAD_EQ +#define BOOST_THREAD_PROVIDES_THREAD_EQ #endif + #endif -#if BOOST_THREAD_VERSION==3 -#if ! defined BOOST_THREAD_DONT_PROVIDE_ONCE_CXX11 -#define BOOST_THREAD_PROVIDES_ONCE_CXX11 +#if BOOST_THREAD_VERSION>=3 + +// ONCE_CXX11 +// fixme BOOST_THREAD_PROVIDES_ONCE_CXX11 doesn't works when thread.cpp is compiled BOOST_THREAD_VERSION 3 +#if ! defined BOOST_THREAD_DONT_PROVIDE_ONCE_CXX11 \ + && ! defined BOOST_THREAD_PROVIDES_ONCE_CXX11 +#define BOOST_THREAD_DONT_PROVIDE_ONCE_CXX11 #endif -#if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE + +// THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE +#if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE \ + && ! defined BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE #define BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE #endif -#if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE + +// THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE +#if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE \ + && ! defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE #define BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE #endif -#if ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE + +// PROVIDE_FUTURE +#if ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE \ + && ! defined BOOST_THREAD_PROVIDES_FUTURE #define BOOST_THREAD_PROVIDES_FUTURE #endif -#if ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS + +// FUTURE_CTOR_ALLOCATORS +#if ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS \ + && ! defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS #define BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS #endif -#if ! defined BOOST_THREAD_DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSIONS + +// SHARED_MUTEX_UPWARDS_CONVERSIONS +#if ! defined BOOST_THREAD_DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSIONS \ + && ! defined BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS #define BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS #endif -#if ! defined BOOST_THREAD_DONT_PROVIDE_EXPLICIT_LOCK_CONVERSION + +// PROVIDE_EXPLICIT_LOCK_CONVERSION +#if ! defined BOOST_THREAD_DONT_PROVIDE_EXPLICIT_LOCK_CONVERSION \ + && ! defined BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION #define BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION #endif -#if ! defined BOOST_THREAD_DONT_PROVIDE_GENERIC_SHARED_MUTEX_ON_WIN + +// GENERIC_SHARED_MUTEX_ON_WIN +#if ! defined BOOST_THREAD_DONT_PROVIDE_GENERIC_SHARED_MUTEX_ON_WIN \ + && ! defined BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN #define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN #endif -#if ! defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 -#define BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0 -#endif -#if ! defined BOOST_THREAD_DONT_USE_MOVE -#if ! defined BOOST_THREAD_USES_MOVE + +// USE_MOVE +#if ! defined BOOST_THREAD_DONT_USE_MOVE \ + && ! defined BOOST_THREAD_USES_MOVE #define BOOST_THREAD_USES_MOVE #endif + +#endif + +// deprecated since version 4 +#if BOOST_THREAD_VERSION < 4 + +// NESTED_LOCKS +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS \ + && ! defined BOOST_THREAD_DONT_PROVIDE_NESTED_LOCKS +#define BOOST_THREAD_PROVIDES_NESTED_LOCKS +#endif + +// CONDITION +#if ! defined BOOST_THREAD_PROVIDES_CONDITION \ + && ! defined BOOST_THREAD_DONT_PROVIDE_CONDITION +#define BOOST_THREAD_PROVIDES_CONDITION #endif +// USE_DATETIME +#if ! defined BOOST_THREAD_DONT_USE_DATETIME \ + && ! defined BOOST_THREAD_USES_DATETIME +#define BOOST_THREAD_USES_DATETIME +#endif +#endif + +#if BOOST_THREAD_VERSION>=4 + +// SIGNATURE_PACKAGED_TASK +#if ! defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK \ + && ! defined BOOST_THREAD_DONT_PROVIDE_SIGNATURE_PACKAGED_TASK +#define BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK +#endif + +// VARIADIC_THREAD +#if ! defined BOOST_THREAD_PROVIDES_VARIADIC_THREAD \ + && ! defined BOOST_THREAD_DONT_PROVIDE_VARIADIC_THREAD + +#if ! defined(BOOST_NO_SFINAE_EXPR) && \ + ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ + ! defined(BOOST_NO_CXX11_DECLTYPE) && \ + ! defined(BOOST_NO_CXX11_DECLTYPE_N3276) && \ + ! defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) && \ + ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \ + ! defined(BOOST_NO_CXX11_HDR_TUPLE) + +#define BOOST_THREAD_PROVIDES_VARIADIC_THREAD +#endif +#endif + +#if ! defined BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY \ + && ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_WHEN_ALL_WHEN_ANY + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ + ! defined(BOOST_NO_CXX11_HDR_TUPLE) + +#define BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY +#endif +#endif + +// ! defined(BOOST_NO_SFINAE_EXPR) && +// ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && +// ! defined(BOOST_NO_CXX11_AUTO) && +// ! defined(BOOST_NO_CXX11_DECLTYPE) && +// ! defined(BOOST_NO_CXX11_DECLTYPE_N3276) && + + +// MAKE_READY_AT_THREAD_EXIT +#if ! defined BOOST_THREAD_PROVIDES_MAKE_READY_AT_THREAD_EXIT \ + && ! defined BOOST_THREAD_DONT_PROVIDE_MAKE_READY_AT_THREAD_EXIT + +//#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) +#define BOOST_THREAD_PROVIDES_MAKE_READY_AT_THREAD_EXIT +//#endif +#endif + +// FUTURE_CONTINUATION +#if ! defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION \ + && ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CONTINUATION +#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION +#endif + +#if ! defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP \ + && ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_UNWRAP +#define BOOST_THREAD_PROVIDES_FUTURE_UNWRAP +#endif + +// FUTURE_INVALID_AFTER_GET +#if ! defined BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET \ + && ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET +#define BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET +#endif + +// NESTED_LOCKS +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS \ + && ! defined BOOST_THREAD_DONT_PROVIDE_NESTED_LOCKS +#define BOOST_THREAD_DONT_PROVIDE_NESTED_LOCKS +#endif + +// CONDITION +#if ! defined BOOST_THREAD_PROVIDES_CONDITION \ + && ! defined BOOST_THREAD_DONT_PROVIDE_CONDITION +#define BOOST_THREAD_DONT_PROVIDE_CONDITION +#endif + +#endif // BOOST_THREAD_VERSION>=4 + +// INTERRUPTIONS +#if ! defined BOOST_THREAD_PROVIDES_INTERRUPTIONS \ + && ! defined BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS +#define BOOST_THREAD_PROVIDES_INTERRUPTIONS +#endif + +// CORRELATIONS + +// EXPLICIT_LOCK_CONVERSION. +#if defined BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION +#define BOOST_THREAD_EXPLICIT_LOCK_CONVERSION explicit +#else +#define BOOST_THREAD_EXPLICIT_LOCK_CONVERSION #endif // BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN is defined if BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS -#if defined BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS +#if defined BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS \ +&& ! defined BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN #define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN #endif -// BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 defined by default up to Boost 1.52 +// For C++11 call_once interface the compiler MUST support constexpr. +// Otherwise once_flag would be initialized during dynamic initialization stage, which is not thread-safe. +#if defined(BOOST_THREAD_PROVIDES_ONCE_CXX11) +#if defined(BOOST_NO_CXX11_CONSTEXPR) +#undef BOOST_THREAD_PROVIDES_ONCE_CXX11 +#endif +#endif + +#if defined(BOOST_THREAD_PLATFORM_WIN32) && defined BOOST_THREAD_DONT_USE_DATETIME +#undef BOOST_THREAD_DONT_USE_DATETIME +#define BOOST_THREAD_USES_DATETIME +#endif + +#if defined(BOOST_THREAD_PLATFORM_WIN32) && defined BOOST_THREAD_DONT_USE_CHRONO +#undef BOOST_THREAD_DONT_USE_CHRONO +#define BOOST_THREAD_USES_CHRONO +#endif + +// BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 defined by default up to Boost 1.55 // BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0 defined by default up to Boost 1.55 -#if ! defined BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0 -#define BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 +#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 + +#if ! defined BOOST_THREAD_PROVIDES_THREAD_EQ +#define BOOST_THREAD_PROVIDES_THREAD_EQ +#endif + +#endif + + +//#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES || defined BOOST_THREAD_USES_MOVE +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES +#define BOOST_THREAD_FUTURE_USES_OPTIONAL #endif #if BOOST_WORKAROUND(__BORLANDC__, < 0x600) @@ -133,16 +368,25 @@ #include <boost/thread/detail/platform.hpp> +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#else + # if defined(BOOST_HAS_PTHREAD_DELAY_NP) || defined(BOOST_HAS_NANOSLEEP) + # define BOOST_THREAD_SLEEP_FOR_IS_STEADY + # endif +#endif + // provided for backwards compatibility, since this // macro was used for several releases by mistake. -#if defined(BOOST_THREAD_DYN_DLL) +#if defined(BOOST_THREAD_DYN_DLL) && ! defined BOOST_THREAD_DYN_LINK # define BOOST_THREAD_DYN_LINK #endif // compatibility with the rest of Boost's auto-linking code: #if defined(BOOST_THREAD_DYN_LINK) || defined(BOOST_ALL_DYN_LINK) # undef BOOST_THREAD_USE_LIB -# define BOOST_THREAD_USE_DLL +# if !defined(BOOST_THREAD_USE_DLL) +# define BOOST_THREAD_USE_DLL +# endif #endif #if defined(BOOST_THREAD_BUILD_DLL) //Build dll @@ -151,8 +395,9 @@ #elif defined(BOOST_THREAD_USE_LIB) //Use lib #else //Use default # if defined(BOOST_THREAD_PLATFORM_WIN32) -# if defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN) - //For compilers supporting auto-tss cleanup +# if defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN) \ + || defined(__MINGW32__) || defined(MINGW32) || defined(BOOST_MINGW32) + //For compilers supporting auto-tss cleanup //with Boost.Threads lib, use Boost.Threads lib # define BOOST_THREAD_USE_LIB # else diff --git a/boost/thread/detail/counter.hpp b/boost/thread/detail/counter.hpp new file mode 100644 index 0000000000..38e1597c57 --- /dev/null +++ b/boost/thread/detail/counter.hpp @@ -0,0 +1,106 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2013 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_COUNTER_HPP +#define BOOST_THREAD_COUNTER_HPP + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/delete.hpp> + +//#include <boost/thread/mutex.hpp> +//#include <boost/thread/lock_types.hpp> +#include <boost/thread/condition_variable.hpp> +#include <boost/chrono/duration.hpp> +#include <boost/chrono/time_point.hpp> +#include <boost/assert.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + namespace detail { + struct counter + { + condition_variable cond_; + std::size_t value_; + + counter(std::size_t value) + : value_(value) + { + + } + counter& operator=(counter const& rhs) + { + value_ = rhs.value_; + return *this; + } + counter& operator=(std::size_t value) + { + value_ = value; + return *this; + } + + operator std::size_t() const + { + return value_; + } + operator std::size_t&() + { + return value_; + } + + void inc_and_notify_all() + { + ++value_; + cond_.notify_all(); + } + + void dec_and_notify_all() + { + --value_; + cond_.notify_all(); + } + void assign_and_notify_all(counter const& rhs) + { + value_ = rhs.value_; + cond_.notify_all(); + } + void assign_and_notify_all(std::size_t value) + { + value_ = value; + cond_.notify_all(); + } + }; + struct counter_is_not_zero + { + counter_is_not_zero(counter const& count) : count_(count) {} + bool operator()() const { return count_ != 0; } + counter const& count_; + }; + struct counter_is_zero + { + counter_is_zero(counter const& count) : count_(count) {} + bool operator()() const { return count_ == 0; } + counter const& count_; + }; + struct is_zero + { + is_zero(std::size_t& count) : count_(count) {} + bool operator()() const { return count_ == 0; } + std::size_t& count_; + }; + struct not_equal + { + not_equal(std::size_t& x, std::size_t& y) : x_(x), y_(y) {} + bool operator()() const { return x_ != y_; } + std::size_t& x_; + std::size_t& y_; + }; + } +} // namespace boost + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/detail/delete.hpp b/boost/thread/detail/delete.hpp index 9e56d4429e..8f8113f4e8 100644 --- a/boost/thread/detail/delete.hpp +++ b/boost/thread/detail/delete.hpp @@ -15,14 +15,26 @@ * BOOST_THREAD_DELETE_COPY_ASSIGN deletes the copy assignment when the compiler supports it or * makes it private. */ -#ifndef BOOST_NO_DELETED_FUNCTIONS + +#if ! defined BOOST_NO_CXX11_DELETED_FUNCTIONS && ! defined BOOST_NO_CXX11_RVALUE_REFERENCES #define BOOST_THREAD_DELETE_COPY_CTOR(CLASS) \ CLASS(CLASS const&) = delete; \ #define BOOST_THREAD_DELETE_COPY_ASSIGN(CLASS) \ CLASS& operator=(CLASS const&) = delete; -#else // BOOST_NO_DELETED_FUNCTIONS +#else // BOOST_NO_CXX11_DELETED_FUNCTIONS +#if defined(BOOST_MSVC) && _MSC_VER >= 1600 +#define BOOST_THREAD_DELETE_COPY_CTOR(CLASS) \ + private: \ + CLASS(CLASS const&); \ + public: + +#define BOOST_THREAD_DELETE_COPY_ASSIGN(CLASS) \ + private: \ + CLASS& operator=(CLASS const&); \ + public: +#else #define BOOST_THREAD_DELETE_COPY_CTOR(CLASS) \ private: \ CLASS(CLASS&); \ @@ -32,7 +44,8 @@ private: \ CLASS& operator=(CLASS&); \ public: -#endif // BOOST_NO_DELETED_FUNCTIONS +#endif +#endif // BOOST_NO_CXX11_DELETED_FUNCTIONS /** * BOOST_THREAD_NO_COPYABLE deletes the copy constructor and assignment when the compiler supports it or diff --git a/boost/thread/detail/function_wrapper.hpp b/boost/thread/detail/function_wrapper.hpp new file mode 100644 index 0000000000..355f726762 --- /dev/null +++ b/boost/thread/detail/function_wrapper.hpp @@ -0,0 +1,93 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2013/09 Vicente J. Botet Escriba +// Adapt to boost from CCIA C++11 implementation +// Make use of Boost.Move + +#ifndef BOOST_THREAD_DETAIL_FUNCTION_WRAPPER_HPP +#define BOOST_THREAD_DETAIL_FUNCTION_WRAPPER_HPP + +#include <boost/config.hpp> +#include <boost/thread/detail/memory.hpp> +#include <boost/thread/detail/move.hpp> + +#include <boost/thread/csbl/memory/unique_ptr.hpp> + +#include <memory> +#include <functional> + +namespace boost +{ + namespace detail + { + class function_wrapper + { + struct impl_base + { + virtual void call()=0; + virtual ~impl_base() + { + } + }; + typedef boost::csbl::unique_ptr<impl_base> impl_base_type; + impl_base_type impl; + template <typename F> + struct impl_type: impl_base + { + F f; + impl_type(F const &f_) + : f(f_) + {} + impl_type(BOOST_THREAD_RV_REF(F) f_) + : f(boost::move(f_)) + {} + + void call() + { + if (impl) f(); + } + }; + public: + BOOST_THREAD_MOVABLE_ONLY(function_wrapper) + +//#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + template<typename F> + function_wrapper(F const& f): + impl(new impl_type<F>(f)) + {} +//#endif + template<typename F> + function_wrapper(BOOST_THREAD_RV_REF(F) f): + impl(new impl_type<F>(boost::forward<F>(f))) + {} + function_wrapper(BOOST_THREAD_RV_REF(function_wrapper) other) BOOST_NOEXCEPT : + impl(other.impl) + { + other.impl = 0; + } + function_wrapper() + : impl(0) + { + } + ~function_wrapper() + { + } + + function_wrapper& operator=(BOOST_THREAD_RV_REF(function_wrapper) other) BOOST_NOEXCEPT + { + impl=other.impl; + other.impl=0; + return *this; + } + + void operator()() + { impl->call();} + + }; + } +} + +#endif // header diff --git a/boost/thread/detail/invoke.hpp b/boost/thread/detail/invoke.hpp new file mode 100644 index 0000000000..e772da29ee --- /dev/null +++ b/boost/thread/detail/invoke.hpp @@ -0,0 +1,1604 @@ +// Copyright (C) 2012-2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// 2013/04 Vicente J. Botet Escriba +// Provide implementation up to 9 parameters when BOOST_NO_CXX11_VARIADIC_TEMPLATES is defined. +// Make use of Boost.Move +// Make use of Boost.Tuple (movable) +// 2012 Vicente J. Botet Escriba +// Provide implementation _RET using bind when BOOST_NO_CXX11_HDR_FUNCTIONAL and BOOST_NO_SFINAE_EXPR are not defined +// 2012 Vicente J. Botet Escriba +// Adapt to boost libc++ implementation + +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// The invoke code is based on the one from libcxx. +//===----------------------------------------------------------------------===// + +#ifndef BOOST_THREAD_DETAIL_INVOKE_HPP +#define BOOST_THREAD_DETAIL_INVOKE_HPP + +#include <boost/config.hpp> +#include <boost/static_assert.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/core/enable_if.hpp> +#include <boost/mpl/bool.hpp> +#include <boost/type_traits/is_base_of.hpp> +#include <boost/type_traits/is_pointer.hpp> +#include <boost/type_traits/is_member_function_pointer.hpp> +#include <boost/type_traits/remove_reference.hpp> +#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL +#include <functional> +#endif + +namespace boost +{ + namespace detail + { + + +#if ! defined(BOOST_NO_SFINAE_EXPR) && \ + ! defined(BOOST_NO_CXX11_DECLTYPE) && \ + ! defined(BOOST_NO_CXX11_DECLTYPE_N3276) && \ + ! defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) + +#define BOOST_THREAD_PROVIDES_INVOKE + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + // bullets 1 and 2 + + template <class Fp, class A0, class ...Args> + inline auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args) + -> decltype((boost::forward<A0>(a0).*f)(boost::forward<Args>(args)...)) + { + return (boost::forward<A0>(a0).*f)(boost::forward<Args>(args)...); + } + template <class R, class Fp, class A0, class ...Args> + inline auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args) + -> decltype((boost::forward<A0>(a0).*f)(boost::forward<Args>(args)...)) + { + return (boost::forward<A0>(a0).*f)(boost::forward<Args>(args)...); + } + + template <class Fp, class A0, class ...Args> + inline auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args) + -> decltype(((*boost::forward<A0>(a0)).*f)(boost::forward<Args>(args)...)) + { + return ((*boost::forward<A0>(a0)).*f)(boost::forward<Args>(args)...); + } + template <class R, class Fp, class A0, class ...Args> + inline auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args) + -> decltype(((*boost::forward<A0>(a0)).*f)(boost::forward<Args>(args)...)) + { + return ((*boost::forward<A0>(a0)).*f)(boost::forward<Args>(args)...); + } + + // bullets 3 and 4 + + template <class Fp, class A0> + inline auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0) + -> decltype(boost::forward<A0>(a0).*f) + { + return boost::forward<A0>(a0).*f; + } + + template <class Fp, class A0> + inline auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0) + -> decltype((*boost::forward<A0>(a0)).*f) + { + return (*boost::forward<A0>(a0)).*f; + } + + template <class R, class Fp, class A0> + inline auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0) + -> decltype(boost::forward<A0>(a0).*f) + { + return boost::forward<A0>(a0).*f; + } + + template <class R, class Fp, class A0> + inline auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0) + -> decltype((*boost::forward<A0>(a0)).*f) + { + return (*boost::forward<A0>(a0)).*f; + } + + + // bullet 5 + + template <class R, class Fp, class ...Args> + inline auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) ...args) + -> decltype(boost::forward<Fp>(f)(boost::forward<Args>(args)...)) + { + return boost::forward<Fp>(f)(boost::forward<Args>(args)...); + } + template <class Fp, class ...Args> + inline auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) ...args) + -> decltype(boost::forward<Fp>(f)(boost::forward<Args>(args)...)) + { + return boost::forward<Fp>(f)(boost::forward<Args>(args)...); + } + +#else // BOOST_NO_CXX11_VARIADIC_TEMPLATES + + // bullets 1 and 2 + + template <class Fp, class A0> + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0) + -> decltype((boost::forward<A0>(a0).*f)()) + { + return (boost::forward<A0>(a0).*f)(); + } + template <class R, class Fp, class A0> + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0) + -> decltype((boost::forward<A0>(a0).*f)()) + { + return (boost::forward<A0>(a0).*f)(); + } + template <class Fp, class A0, class A1> + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1) + -> decltype((boost::forward<A0>(a0).*f)(boost::forward<A1>(a1))) + { + return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1)); + } + template <class R, class Fp, class A0, class A1> + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1) + -> decltype((boost::forward<A0>(a0).*f)(boost::forward<A1>(a1))) + { + return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1)); + } + template <class Fp, class A0, class A1, class A2> + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + -> decltype((boost::forward<A0>(a0).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2))) + { + return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2)); + } + template <class R, class Fp, class A0, class A1, class A2> + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + -> decltype((boost::forward<A0>(a0).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2))) + { + return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2)); + } + + template <class Fp, class A0> + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0) + -> decltype(((*boost::forward<A0>(a0)).*f)()) + { + return ((*boost::forward<A0>(a0)).*f)(); + } + template <class R, class Fp, class A0> + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0) + -> decltype(((*boost::forward<A0>(a0)).*f)()) + { + return ((*boost::forward<A0>(a0)).*f)(); + } + template <class Fp, class A0, class A1> + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1) + -> decltype(((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1))) + { + return ((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1)); + } + template <class R, class Fp, class A0, class A1> + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1) + -> decltype(((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1))) + { + return ((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1)); + } + template <class Fp, class A0, class A1, class A2> + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + -> decltype(((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2))) + { + return ((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2)); + } + template <class R, class Fp, class A0, class A1, class A2> + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + -> decltype(((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2))) + { + return ((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2)); + } + + // bullets 3 and 4 + + template <class Fp, class A0> + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0) + -> decltype(boost::forward<A0>(a0).*f) + { + return boost::forward<A0>(a0).*f; + } + template <class R, class Fp, class A0> + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0) + -> decltype(boost::forward<A0>(a0).*f) + { + return boost::forward<A0>(a0).*f; + } + + template <class Fp, class A0> + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0) + -> decltype((*boost::forward<A0>(a0)).*f) + { + return (*boost::forward<A0>(a0)).*f; + } + template <class R, class Fp, class A0> + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0) + -> decltype((*boost::forward<A0>(a0)).*f) + { + return (*boost::forward<A0>(a0)).*f; + } + + // bullet 5 + + template <class Fp> + inline + auto invoke(BOOST_THREAD_RV_REF(Fp) f) + -> decltype(boost::forward<Fp>(f)()) + { + return boost::forward<Fp>(f)(); + } + template <class Fp, class A1> + inline + auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1) + -> decltype(boost::forward<Fp>(f)(boost::forward<A1>(a1))) + { + return boost::forward<Fp>(f)(boost::forward<A1>(a1)); + } template <class Fp, class A1, class A2> + inline + auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + -> decltype(boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2))) + { + return boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2)); + } + template <class Fp, class A1, class A2, class A3> + inline + auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3) + -> decltype(boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3))) + { + return boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)); + } + + + template <class R, class Fp> + inline + auto invoke(BOOST_THREAD_RV_REF(Fp) f) + -> decltype(boost::forward<Fp>(f)()) + { + return boost::forward<Fp>(f)(); + } + template <class R, class Fp, class A1> + inline + auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1) + -> decltype(boost::forward<Fp>(f)(boost::forward<A1>(a1))) + { + return boost::forward<Fp>(f)(boost::forward<A1>(a1)); + } + template <class R, class Fp, class A1, class A2> + inline + auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + -> decltype(boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2))) + { + return boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2)); + } + template <class R, class Fp, class A1, class A2, class A3> + inline + auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3) + -> decltype(boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3))) + { + return boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)); + } + +#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES + +#elif ! defined(BOOST_NO_SFINAE_EXPR) && \ + ! defined BOOST_NO_CXX11_HDR_FUNCTIONAL && \ + defined BOOST_MSVC + + template <class Ret, class Fp> + inline + Ret invoke(BOOST_THREAD_RV_REF(Fp) f) + { + return f(); + } + template <class Ret, class Fp, class A1> + inline + Ret invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1) + { + return std::bind(boost::forward<Fp>(f), boost::forward<A1>(a1))(); + } + template <class Ret, class Fp, class A1, class A2> + inline + Ret invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + { + return std::bind(boost::forward<Fp>(f), boost::forward<A1>(a1), boost::forward<A2>(a2))(); + } + template <class Ret, class Fp, class A1, class A2, class A3> + inline + Ret invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3) + { + return std::bind(boost::forward<Fp>(f), boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3))(); + } + +#define BOOST_THREAD_PROVIDES_INVOKE_RET + +#elif ! defined BOOST_MSVC +//!!!!! WARNING !!!!! THIS DOESN'T WORKS YET +#define BOOST_THREAD_PROVIDES_INVOKE_RET + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + // bullet 1 + // (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is an object of + // type T or a reference to an object of type T or a reference to an object of a type derived from T + template <class Ret, class A, class A0, class ...Args> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(Args...), BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args) + { + return (boost::forward<A0>(a0).*f)(boost::forward<Args>(args)...); + } + + template <class Ret, class A, class A0, class ...Args> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(Args...) const, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args) + { + return (boost::forward<A0>(a0).*f)(boost::forward<Args>(args)...); + } + + template <class Ret, class A, class A0, class ...Args> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(Args...) volatile, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args) + { + return (boost::forward<A0>(a0).*f)(boost::forward<Args>(args)...); + } + + template <class Ret, class A, class A0, class ...Args> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(Args...) const volatile, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args) + { + return (boost::forward<A0>(a0).*f)(boost::forward<Args>(args)...); + } + + // bullet 2 + // ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is not one of + // the types described in the previous item; + template <class Ret, class A, class A0, class ...Args> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(Args...), BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args) + { + return ((*boost::forward<A0>(a0)).*f)(boost::forward<Args>(args)...); + } + + template <class Ret, class A, class A0, class ...Args> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(Args...) const, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args) + { + return ((*boost::forward<A0>(a0)).*f)(boost::forward<Args>(args)...); + } + + template <class Ret, class A, class A0, class ...Args> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(Args...) volatile, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args) + { + return ((*boost::forward<A0>(a0)).*f)(boost::forward<Args>(args)...); + } + + template <class Ret, class A, class A0, class ...Args> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(Args...) const volatile, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args) + { + return ((*boost::forward<A0>(a0)).*f)(boost::forward<Args>(args)...); + } + + // bullet 3 + // t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is an object of type T or a + // reference to an object of type T or a reference to an object of a type derived from T; +// template <class Ret, class A, class A0> +// inline +// typename enable_if_c +// < +// is_base_of<A, typename remove_reference<A0>::type>::value, +// typename detail::apply_cv<A0, A>::type& +// >::type +// invoke(Ret A::* f, BOOST_THREAD_RV_REF(A0) a0) +// { +// return boost::forward<A0>(a0).*f; +// } + + // bullet 4 + // (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1 is not one of the types + //described in the previous item; + +// template <class A0, class Ret, bool> +// struct d4th_helper +// { +// }; +// +// template <class A0, class Ret> +// struct d4th_helper<A0, Ret, true> +// { +// typedef typename apply_cv<decltype(*declval<A0>()), Ret>::type type; +// }; +// +// template <class Ret, class A, class A0> +// inline +// typename detail::4th_helper<A, Ret, +// !is_base_of<A, +// typename remove_reference<A0>::type +// >::value +// >::type& +// invoke(Ret A::* f, BOOST_THREAD_RV_REF(A0) a0) +// { +// return (*boost::forward<A0>(a0)).*f; +// } + +// template <class Ret, class A, class A0> +// inline +// typename enable_if_c +// < +// !is_base_of<A, typename remove_reference<A0>::type>::value, +// typename detail::ref_return1<Ret A::*, A0>::type +// >::type +// invoke(Ret A::* f, BOOST_THREAD_RV_REF(A0) a0) +// { +// return (*boost::forward<A0>(a0)).*f; +// } + + // bullet 5 + // f(t1, t2, ..., tN) in all other cases. + + template <class Ret, class Fp, class ...Args> + inline Ret do_invoke(mpl::false_, BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) ...args) + { + return boost::forward<Fp>(f)(boost::forward<Args>(args)...); + } + + template <class Ret, class Fp, class ...Args> + inline Ret do_invoke(mpl::true_, BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) ...args) + { + return f(boost::forward<Args>(args)...); + } + + template <class Ret, class Fp, class ...Args> + inline + typename disable_if_c + < + is_member_function_pointer<Fp>::value, + Ret + >::type + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) ...args) + { + return boost::detail::do_invoke<Ret>(boost::is_pointer<Fp>(), boost::forward<Fp>(f), boost::forward<Args>(args)...); + } +#else // BOOST_NO_CXX11_VARIADIC_TEMPLATES + // bullet 1 + // (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is an object of + // type T or a reference to an object of type T or a reference to an object of a type derived from T + + template <class Ret, class A, class A0> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(), A0& a0) + { + return (a0.*f)(); + } + template <class Ret, class A, class A0> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(), A0* a0) + { + return ((*a0).*f)(); + } + + template <class Ret, class A, class A0, class A1> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1), + A0& a0, BOOST_THREAD_RV_REF(A1) a1 + ) + { + return (a0.*f)(boost::forward<A1>(a1)); + } + template <class Ret, class A, class A0, class A1> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1), A0& a0, A1 a1) + { + return (a0.*f)(a1); + } + template <class Ret, class A, class A0, class A1> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1), A0* a0, BOOST_THREAD_RV_REF(A1) a1 + ) + { + return (*(a0).*f)(boost::forward<A1>(a1)); + } + template <class Ret, class A, class A0, class A1> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1), A0* a0, A1 a1) + { + return (*a0.*f)(a1); + } + template <class Ret, class A, class A0, class A1, class A2> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2), + A0& a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2 + ) + { + return (a0.*f)(boost::forward<A1>(a1), boost::forward<A2>(a2)); + } + template <class Ret, class A, class A0, class A1, class A2> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2), A0* a0, A1 a1, A2 a2) + { + return ((*a0).*f)(a1, a2); + } + template <class Ret, class A, class A0, class A1, class A2, class A3> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3), + A0& a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3) + { + return (a0.*f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)); + } + template <class Ret, class A, class A0, class A1, class A2, class A3> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3), A0* a0, A1 a1, A2 a2, A3 a3) + { + return ((*a0).*f)(a1, a2, a3); + } + +/// + template <class Ret, class A, class A0> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)() const, A0 const& a0) + { + return (a0.*f)(); + } + template <class Ret, class A, class A0> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)() const, A0 const* a0) + { + return ((*a0).*f)(); + } + template <class Ret, class A, class A0, class A1> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) const, A0 const& a0, BOOST_THREAD_RV_REF(A1) a1) + { + return (a0.*f)(boost::forward<A1>(a1)); + } + template <class Ret, class A, class A0, class A1> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) const, A0 const* a0, BOOST_THREAD_RV_REF(A1) a1) + { + return ((*a0).*f)(boost::forward<A1>(a1)); + } + + template <class Ret, class A, class A0, class A1> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) const, A0 const& a0, A1 a1) + { + return (a0.*f)(a1); + } + template <class Ret, class A, class A0, class A1, class A2> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2) const, + A0 const& a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2 + ) + { + return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2) + ); + } + template <class Ret, class A, class A0, class A1, class A2> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2) const, A0 const& a0, A1 a1, A2 a2) + { + return (a0.*f)(a1, a2); + } + template <class Ret, class A, class A0, class A1, class A2, class A3> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3) const, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3 + ) + { + return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)); + } + template <class Ret, class A, class A0, class A1, class A2, class A3> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3) const, A0 a0, A1 a1, A2 a2, A3 a3) + { + return (a0.*f)(a1, a2, a3); + } + /// + template <class Ret, class A, class A0> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)() volatile, BOOST_THREAD_RV_REF(A0) a0) + { + return (boost::forward<A0>(a0).*f)(); + } + template <class Ret, class A, class A0, class A1> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) volatile, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1) + { + return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1)); + } + template <class Ret, class A, class A0, class A1> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) volatile, A0 a0, A1 a1) + { + return (a0.*f)(a1); + } + template <class Ret, class A, class A0, class A1, class A2> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2) volatile, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + { + return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2)); + } + template <class Ret, class A, class A0, class A1, class A2> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2) volatile, A0 a0, A1 a1, A2 a2 ) + { + return (a0.*f)(a1, a2); + } + template <class Ret, class A, class A0, class A1, class A2, class A3> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3) volatile, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3 + ) + { + return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)); + } + template <class Ret, class A, class A0, class A1, class A2, class A3> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3) volatile, A0 a0, A1 a1, A2 a2, A3 a3) + { + return (a0.*f)(a1, a2, a3); + } + /// + template <class Ret, class A, class A0> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)() const volatile, BOOST_THREAD_RV_REF(A0) a0) + { + return (boost::forward<A0>(a0).*f)(); + } + template <class Ret, class A, class A0, class A1> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) const volatile, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1) + { + return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1)); + } + template <class Ret, class A, class A0, class A1> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) const volatile, A0 a0, A1 a1) + { + return (a0.*f)(a1); + } + template <class Ret, class A, class A0, class A1, class A2> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2) const volatile, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2 + ) + { + return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2)); + } + template <class Ret, class A, class A0, class A1, class A2> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2) const volatile, + A0 a0, A1 a1, A2 a2 + ) + { + return (a0.*f)(a1, a2); + } + template <class Ret, class A, class A0, class A1, class A2, class A3> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3) const volatile, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3 + ) + { + return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)); + } + template <class Ret, class A, class A0, class A1, class A2, class A3> + inline + typename enable_if_c + < + is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3) const volatile, + A0 a0, A1 a1, A2 a2, A3 a3 + ) + { + return (a0.*f)(a1, a2, a3); + } + + // bullet 2 + // ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is not one of + // the types described in the previous item; + template <class Ret, class A, class A0> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(), BOOST_THREAD_RV_REF(A0) a0) + { + return ((*boost::forward<A0>(a0)).*f)(); + } + template <class Ret, class A, class A0, class A1> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1), BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1) + { + return ((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1)); + } + template <class Ret, class A, class A0, class A1> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1), A0 a0, A1 a1) + { + return ((*a0).*f)(a1); + } + template <class Ret, class A, class A0, class A1, class A2> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, BOOST_THREAD_RV_REF(A2)), + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + { + return ((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2)); + } + template <class Ret, class A, class A0, class A1, class A2> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2), A0 a0, A1 a1, A2 a2) + { + return ((*a0).*f)(a1, a2); + } + template <class Ret, class A, class A0, class A1, class A2, class A3> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, BOOST_THREAD_RV_REF(A2), BOOST_THREAD_RV_REF(A3)), + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3) + { + return ((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3) + ); + } + template <class Ret, class A, class A0, class A1, class A2, class A3> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3), A0 a0, A1 a1, A2 a2, A3 a3) + { + return ((*a0).*f)(a1, a2, a3); + } + +/// + template <class Ret, class A, class A0> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)() const, BOOST_THREAD_RV_REF(A0) a0) + { + return ((*boost::forward<A0>(a0)).*f)(); + } + template <class Ret, class A, class A0, class A1> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) const, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1) + { + return ((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1)); + } + template <class Ret, class A, class A0, class A1> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) const, BOOST_THREAD_RV_REF(A0) a0, A1 a1) + { + return ((*boost::forward<A0>(a0)).*f)(a1); + } + template <class Ret, class A, class A0, class A1> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) const, A0 a0, A1 a1) + { + return ((*a0).*f)(a1); + } + template <class Ret, class A, class A0, class A1, class A2> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2) const, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + { + return ((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2)); + } + template <class Ret, class A, class A0, class A1, class A2> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2) const, A0 a0, A1 a1, A2 a2) + { + return ((*a0).*f)(a1, a2); + } + template <class Ret, class A, class A0, class A1, class A2, class A3> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3) const, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3) + { + return ((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)); + } + template <class Ret, class A, class A0, class A1, class A2, class A3> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3) const, + A0 a0, A1 a1, A2 a2, A3 a3) + { + return ((*a0).*f)(a1, a2, a3); + } + /// + template <class Ret, class A, class A0> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)() volatile, BOOST_THREAD_RV_REF(A0) a0) + { + return ((*boost::forward<A0>(a0)).*f)(); + } + template <class Ret, class A, class A0, class A1> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) volatile, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1) + { + return ((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1)); + } + template <class Ret, class A, class A0, class A1> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) volatile, A0 a0, A1 a1) + { + return ((*a0).*f)(a1); + } + template <class Ret, class A, class A0, class A1, class A2> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2) volatile, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + { + return ((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2)); + } + template <class Ret, class A, class A0, class A1, class A2> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2) volatile, A0 a0, A1 a1, A2 a2) + { + return ((*a0).*f)(a1, a2); + } + template <class Ret, class A, class A0, class A1, class A2, class A3> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3) volatile, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3) + { + return ((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)); + } + template <class Ret, class A, class A0, class A1, class A2, class A3> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3) volatile, A0 a0, A1 a1, A2 a2, A3 a3) + { + return ((*a0).*f)(a1, a2, a3); + } + /// + template <class Ret, class A, class A0> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)() const volatile, BOOST_THREAD_RV_REF(A0) a0) + { + return ((*boost::forward<A0>(a0)).*f)(); + } + template <class Ret, class A, class A0> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)() const volatile, A0 a0) + { + return ((*a0).*f)(); + } + template <class Ret, class A, class A0, class A1> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) const volatile, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1) + { + return ((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1)); + } + template <class Ret, class A, class A0, class A1> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) const volatile, A0 a0, A1 a1) + { + return ((*a0).*f)(a1); + } + template <class Ret, class A, class A0, class A1, class A2> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2) const volatile, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + { + return ((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2)); + } + template <class Ret, class A, class A0, class A1, class A2> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2) const volatile, + A0 a0, A1 a1, A2 a2) + { + return ((*a0).*f)(a1, a2); + } + template <class Ret, class A, class A0, class A1, class A2, class A3> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3) const volatile, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3) + { + return ((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)); + } + template <class Ret, class A, class A0, class A1, class A2, class A3> + inline + typename enable_if_c + < + ! is_base_of<A, typename remove_reference<A0>::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3) const volatile, + A0 a0, A1 a1, A2 a2, A3 a3) + { + return ((*a0).*f)(a1, a2, a3); + } + // bullet 3 + // t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is an object of type T or a + // reference to an object of type T or a reference to an object of a type derived from T; +// template <class Ret, class A, class A0> +// inline +// typename enable_if_c +// < +// is_base_of<A, typename remove_reference<A0>::type>::value, +// typename detail::apply_cv<A0, A>::type& +// >::type +// invoke(Ret A::* f, BOOST_THREAD_RV_REF(A0) a0) +// { +// return boost::forward<A0>(a0).*f; +// } + + // bullet 4 + // (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1 is not one of the types + //described in the previous item; + +// template <class A0, class Ret, bool> +// struct d4th_helper +// { +// }; +// +// template <class A0, class Ret> +// struct d4th_helper<A0, Ret, true> +// { +// typedef typename apply_cv<decltype(*declval<A0>()), Ret>::type type; +// }; +// +// template <class Ret, class A, class A0> +// inline +// typename detail::4th_helper<A, Ret, +// !is_base_of<A, +// typename remove_reference<A0>::type +// >::value +// >::type& +// invoke(Ret A::* f, BOOST_THREAD_RV_REF(A0) a0) +// { +// return (*boost::forward<A0>(a0)).*f; +// } + +// template <class Ret, class A, class A0> +// inline +// typename enable_if_c +// < +// !is_base_of<A, typename remove_reference<A0>::type>::value, +// typename detail::ref_return1<Ret A::*, A0>::type +// >::type +// invoke(Ret A::* f, BOOST_THREAD_RV_REF(A0) a0) +// { +// return (*boost::forward<A0>(a0)).*f; +// } + + // bullet 5 + // f(t1, t2, ..., tN) in all other cases. + + template <class Ret, class Fp> + inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f) + { + return boost::forward<Fp>(f)(); + } + template <class Ret, class Fp> + inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f) + { + return f(); + } + template <class Ret, class Fp> + inline + typename disable_if_c + < + is_member_function_pointer<Fp>::value, + Ret + >::type + invoke(BOOST_THREAD_FWD_REF(Fp) f) + { + return boost::detail::do_invoke<Ret>(boost::is_pointer<Fp>(), boost::forward<Fp>(f)); + } + + template <class Ret, class Fp, class A1> + inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1) + { + return boost::forward<Fp>(f)(boost::forward<A1>(a1)); + } + template <class Ret, class Fp, class A1> + inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1) + { + return f(boost::forward<A1>(a1)); + } + template <class Ret, class Fp, class A1> + inline + typename disable_if_c + < + is_member_function_pointer<Fp>::value, + Ret + >::type + invoke(BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1) + { + return boost::detail::do_invoke<Ret>(boost::is_pointer<Fp>(), boost::forward<Fp>(f), boost::forward<A1>(a1)); + } + + template <class Ret, class Fp, class A1, class A2> + inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + { + return boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2)); + } + template <class Ret, class Fp, class A1, class A2> + inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + { + return f(boost::forward<A1>(a1), boost::forward<A2>(a2)); + } + template <class Ret, class Fp, class A1, class A2> + inline + typename disable_if_c + < + is_member_function_pointer<Fp>::value, + Ret + >::type + invoke(BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + { + return boost::detail::do_invoke<Ret>(boost::is_pointer<Fp>(), boost::forward<Fp>(f), boost::forward<A1>(a1), boost::forward<A2>(a2)); + } + + template <class Ret, class Fp, class A1, class A2, class A3> + inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3) + { + return boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)); + } + template <class Ret, class Fp, class A1, class A2, class A3> + inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3) + { + return f(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)); + } + template <class Ret, class Fp, class A1, class A2, class A3> + inline + typename disable_if_c + < + is_member_function_pointer<Fp>::value, + Ret + >::type + invoke(BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3) + { + return boost::detail::do_invoke<Ret>(boost::is_pointer<Fp>(), boost::forward<Fp>(f), boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)); + } + + + template <class Ret, class Fp, class A1> + inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1) + { + return boost::forward<Fp>(f)(a1); + } + template <class Ret, class Fp, class A1> + inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1) + { + return f(a1); + } + template <class Ret, class Fp, class A1> + inline + typename disable_if_c + < + is_member_function_pointer<Fp>::value, + Ret + >::type + invoke(BOOST_THREAD_FWD_REF(Fp) f, A1 a1) + { + return boost::detail::do_invoke<Ret>(boost::is_pointer<Fp>(), boost::forward<Fp>(f), a1); + } + + template <class Ret, class Fp, class A1, class A2> + inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2) + { + return boost::forward<Fp>(f)(a1, a2); + } + template <class Ret, class Fp, class A1, class A2> + inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2) + { + return f(a1, a2); + } + template <class Ret, class Fp, class A1, class A2> + inline + typename disable_if_c + < + is_member_function_pointer<Fp>::value, + Ret + >::type + invoke(BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2) + { + return boost::detail::do_invoke<Ret>(boost::is_pointer<Fp>(), boost::forward<Fp>(f), a1, a2); + } + + template <class Ret, class Fp, class A1, class A2, class A3> + inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2, A3 a3) + { + return boost::forward<Fp>(f)(a1, a2, a3); + } + template <class Ret, class Fp, class A1, class A2, class A3> + inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2, A3 a3) + { + return f(a1, a2, a3); + } + template <class Ret, class Fp, class A1, class A2, class A3> + inline + typename disable_if_c + < + is_member_function_pointer<Fp>::value, + Ret + >::type + invoke(BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2, A3 a3) + { + return boost::detail::do_invoke<Ret>(boost::is_pointer<Fp>(), boost::forward<Fp>(f), a1, a2, a3); + } + + + /// + template <class Ret, class Fp> + inline + typename disable_if_c + < + is_member_function_pointer<Fp>::value, + Ret + >::type + invoke(Fp &f) + { + return f(); + } + template <class Ret, class Fp, class A1> + inline + typename disable_if_c + < + is_member_function_pointer<Fp>::value, + Ret + >::type + invoke(Fp &f, BOOST_THREAD_RV_REF(A1) a1) + { + return f(boost::forward<A1>(a1)); + } + template <class Ret, class Fp, class A1> + inline + typename disable_if_c + < + is_member_function_pointer<Fp>::value, + Ret + >::type + invoke(Fp &f, A1 a1) + { + return f(a1); + } + template <class Ret, class Fp, class A1, class A2> + inline + typename disable_if_c + < + is_member_function_pointer<Fp>::value, + Ret + >::type + invoke(Fp &f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + { + return f(boost::forward<A1>(a1), boost::forward<A2>(a2)); + } + template <class Ret, class Fp, class A1, class A2> + inline + typename disable_if_c + < + is_member_function_pointer<Fp>::value, + Ret + >::type + invoke(Fp &f, A1 a1, A2 a2) + { + return f(a1, a2); + } + template <class Ret, class Fp, class A1, class A2, class A3> + inline + typename disable_if_c + < + is_member_function_pointer<Fp>::value, + Ret + >::type + invoke(Fp &f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3) + { + return f(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)); + } + template <class Ret, class Fp, class A1, class A2, class A3> + inline + typename disable_if_c + < + is_member_function_pointer<Fp>::value, + Ret + >::type + invoke(Fp &f, A1 a1, A2 a2, A3 a3) + { + return f(a1, a2, a3); + } + /// + +#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES + +#endif // all + } + } + +#endif // header diff --git a/boost/thread/detail/invoker.hpp b/boost/thread/detail/invoker.hpp new file mode 100644 index 0000000000..44deb1645b --- /dev/null +++ b/boost/thread/detail/invoker.hpp @@ -0,0 +1,754 @@ +// Copyright (C) 2012 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// 2013/04 Vicente J. Botet Escriba +// Provide implementation up to 9 parameters when BOOST_NO_CXX11_VARIADIC_TEMPLATES is defined. +// Make use of Boost.Move +// Make use of Boost.Tuple (movable) +// 2012/11 Vicente J. Botet Escriba +// Adapt to boost libc++ implementation + +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// The invoker code is based on the one from libcxx. +//===----------------------------------------------------------------------===// + +#ifndef BOOST_THREAD_DETAIL_INVOKER_HPP +#define BOOST_THREAD_DETAIL_INVOKER_HPP + +#include <boost/config.hpp> + +#include <boost/utility/result_of.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/detail/invoke.hpp> +#include <boost/thread/detail/make_tuple_indices.hpp> +#include <boost/thread/csbl/tuple.hpp> +#include <boost/tuple/tuple.hpp> + +#include <boost/thread/detail/variadic_header.hpp> + +namespace boost +{ + namespace detail + { + +#if defined(BOOST_THREAD_PROVIDES_INVOKE) && ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && ! defined(BOOST_NO_CXX11_HDR_TUPLE) + + template <class Fp, class ... Args> + class invoker + { + //typedef typename decay<Fp>::type Fpd; + //typedef tuple<typename decay<Args>::type...> Argsd; + + //csbl::tuple<Fpd, Argsd...> f_; + csbl::tuple<Fp, Args...> f_; + + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE( invoker) + //typedef typename invoke_of<_Fp, _Args...>::type Rp; + typedef typename result_of<Fp(Args...)>::type result_type; + + template <class F, class ... As> + BOOST_SYMBOL_VISIBLE + explicit invoker(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(As)... args) + : f_(boost::forward<F>(f), boost::forward<As>(args)...) + {} + + BOOST_SYMBOL_VISIBLE + invoker(BOOST_THREAD_RV_REF(invoker) f) : f_(boost::move(BOOST_THREAD_RV(f).f_)) + {} + + BOOST_SYMBOL_VISIBLE + invoker( const invoker& f) : f_(f.f_) + {} + + BOOST_SYMBOL_VISIBLE + invoker& operator=(BOOST_THREAD_RV_REF(invoker) f) + { + f_ = boost::move(BOOST_THREAD_RV(f).f_); + } + + BOOST_SYMBOL_VISIBLE + invoker& operator=( BOOST_THREAD_COPY_ASSIGN_REF(invoker) f) + { + f_ = f.f_; + } + + result_type operator()() + { + typedef typename make_tuple_indices<1+sizeof...(Args), 1>::type Index; + return execute(Index()); + } + private: + template <size_t ...Indices> + result_type + execute(tuple_indices<Indices...>) + { + return invoke(boost::move(csbl::get<0>(f_)), boost::move(csbl::get<Indices>(f_))...); + } + }; + + template <class R, class Fp, class ... Args> + class invoker_ret + { + //typedef typename decay<Fp>::type Fpd; + //typedef tuple<typename decay<Args>::type...> Argsd; + + //csbl::tuple<Fpd, Argsd...> f_; + csbl::tuple<Fp, Args...> f_; + + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE( invoker_ret) + typedef R result_type; + + template <class F, class ... As> + BOOST_SYMBOL_VISIBLE + explicit invoker_ret(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(As)... args) + : f_(boost::forward<F>(f), boost::forward<As>(args)...) + {} + + BOOST_SYMBOL_VISIBLE + invoker_ret(BOOST_THREAD_RV_REF(invoker_ret) f) : f_(boost::move(BOOST_THREAD_RV(f).f_)) + {} + + result_type operator()() + { + typedef typename make_tuple_indices<1+sizeof...(Args), 1>::type Index; + return execute(Index()); + } + private: + template <size_t ...Indices> + result_type + execute(tuple_indices<Indices...>) + { + return invoke<R>(boost::move(csbl::get<0>(f_)), boost::move(csbl::get<Indices>(f_))...); + } + }; + //BOOST_THREAD_DCL_MOVABLE_BEG(X) invoker<Fp> BOOST_THREAD_DCL_MOVABLE_END +#else + +#if ! defined BOOST_MSVC + +#define BOOST_THREAD_RV_REF_ARG_T(z, n, unused) BOOST_PP_COMMA_IF(n) BOOST_THREAD_RV_REF(Arg##n) +#define BOOST_THREAD_RV_REF_A_T(z, n, unused) BOOST_PP_COMMA_IF(n) BOOST_THREAD_RV_REF(A##n) +#define BOOST_THREAD_RV_REF_ARG(z, n, unused) , BOOST_THREAD_RV_REF(Arg##n) arg##n +#define BOOST_THREAD_FWD_REF_A(z, n, unused) , BOOST_THREAD_FWD_REF(A##n) arg##n +#define BOOST_THREAD_FWD_REF_ARG(z, n, unused) , BOOST_THREAD_FWD_REF(Arg##n) arg##n +#define BOOST_THREAD_FWD_PARAM(z, n, unused) , boost::forward<Arg##n>(arg##n) +#define BOOST_THREAD_FWD_PARAM_A(z, n, unused) , boost::forward<A##n>(arg##n) +#define BOOST_THREAD_DCL(z, n, unused) Arg##n v##n; +#define BOOST_THREAD_MOVE_PARAM(z, n, unused) , v##n(boost::move(arg##n)) +#define BOOST_THREAD_FORWARD_PARAM_A(z, n, unused) , v##n(boost::forward<A##n>(arg##n)) +#define BOOST_THREAD_MOVE_RHS_PARAM(z, n, unused) , v##n(boost::move(x.v##n)) +#define BOOST_THREAD_MOVE_DCL(z, n, unused) , boost::move(v##n) +#define BOOST_THREAD_MOVE_DCL_T(z, n, unused) BOOST_PP_COMMA_IF(n) boost::move(v##n) +#define BOOST_THREAD_ARG_DEF(z, n, unused) , class Arg##n = tuples::null_type + + template <class Fp, class Arg = tuples::null_type + BOOST_PP_REPEAT(BOOST_THREAD_MAX_ARGS, BOOST_THREAD_ARG_DEF, ~) + > + class invoker; + +#define BOOST_THREAD_ASYNC_FUNCT(z, n, unused) \ + template <class Fp BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, class Arg) > \ + class invoker<Fp BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Arg)> \ + { \ + Fp fp_; \ + BOOST_PP_REPEAT(n, BOOST_THREAD_DCL, ~) \ + public: \ + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) \ + typedef typename result_of<Fp(BOOST_PP_ENUM_PARAMS(n, Arg))>::type result_type; \ + \ + template <class F BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, class A) > \ + BOOST_SYMBOL_VISIBLE \ + explicit invoker(BOOST_THREAD_FWD_REF(F) f \ + BOOST_PP_REPEAT(n, BOOST_THREAD_FWD_REF_A, ~) \ + ) \ + : fp_(boost::forward<F>(f)) \ + BOOST_PP_REPEAT(n, BOOST_THREAD_FORWARD_PARAM_A, ~) \ + {} \ + \ + BOOST_SYMBOL_VISIBLE \ + invoker(BOOST_THREAD_RV_REF(invoker) x) \ + : fp_(boost::move(x.fp_)) \ + BOOST_PP_REPEAT(n, BOOST_THREAD_MOVE_RHS_PARAM, ~) \ + {} \ + \ + result_type operator()() { \ + return invoke(boost::move(fp_) \ + BOOST_PP_REPEAT(n, BOOST_THREAD_MOVE_DCL, ~) \ + ); \ + } \ + }; \ + \ + template <class R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, class Arg) > \ + class invoker<R(*)(BOOST_PP_REPEAT(n, BOOST_THREAD_RV_REF_ARG_T, ~)) BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Arg)> \ + { \ + typedef R(*Fp)(BOOST_PP_REPEAT(n, BOOST_THREAD_RV_REF_ARG_T, ~)); \ + Fp fp_; \ + BOOST_PP_REPEAT(n, BOOST_THREAD_DCL, ~) \ + public: \ + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) \ + typedef typename result_of<Fp(BOOST_PP_ENUM_PARAMS(n, Arg))>::type result_type; \ + \ + template <class R2 BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, class A) > \ + BOOST_SYMBOL_VISIBLE \ + explicit invoker(R2(*f)(BOOST_PP_REPEAT(n, BOOST_THREAD_RV_REF_A_T, ~)) \ + BOOST_PP_REPEAT(n, BOOST_THREAD_FWD_REF_A, ~) \ + ) \ + : fp_(f) \ + BOOST_PP_REPEAT(n, BOOST_THREAD_FORWARD_PARAM_A, ~) \ + {} \ + \ + BOOST_SYMBOL_VISIBLE \ + invoker(BOOST_THREAD_RV_REF(invoker) x) \ + : fp_(x.fp_) \ + BOOST_PP_REPEAT(n, BOOST_THREAD_MOVE_RHS_PARAM, ~) \ + {} \ + \ + result_type operator()() { \ + return fp_( \ + BOOST_PP_REPEAT(n, BOOST_THREAD_MOVE_DCL_T, ~) \ + ); \ + } \ + }; + + BOOST_PP_REPEAT(BOOST_THREAD_MAX_ARGS, BOOST_THREAD_ASYNC_FUNCT, ~) + + #undef BOOST_THREAD_RV_REF_ARG_T + #undef BOOST_THREAD_RV_REF_ARG + #undef BOOST_THREAD_FWD_REF_ARG + #undef BOOST_THREAD_FWD_REF_A + #undef BOOST_THREAD_FWD_PARAM + #undef BOOST_THREAD_FWD_PARAM_A + #undef BOOST_THREAD_DCL + #undef BOOST_THREAD_MOVE_PARAM + #undef BOOST_THREAD_MOVE_RHS_PARAM + #undef BOOST_THREAD_MOVE_DCL + #undef BOOST_THREAD_ARG_DEF + #undef BOOST_THREAD_ASYNC_FUNCT + +#else + + template <class Fp, + class T0 = tuples::null_type, class T1 = tuples::null_type, class T2 = tuples::null_type, + class T3 = tuples::null_type, class T4 = tuples::null_type, class T5 = tuples::null_type, + class T6 = tuples::null_type, class T7 = tuples::null_type, class T8 = tuples::null_type + , class T9 = tuples::null_type + > + class invoker; + + template <class Fp, + class T0 , class T1 , class T2 , + class T3 , class T4 , class T5 , + class T6 , class T7 , class T8 > + class invoker<Fp, T0, T1, T2, T3, T4, T5, T6, T7, T8> + { + Fp fp_; + T0 v0_; + T1 v1_; + T2 v2_; + T3 v3_; + T4 v4_; + T5 v5_; + T6 v6_; + T7 v7_; + T8 v8_; + //::boost::tuple<Fp, T0, T1, T2, T3, T4, T5, T6, T7, T8> f_; + + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) + typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5, T6, T7, T8)>::type result_type; + + BOOST_SYMBOL_VISIBLE + explicit invoker(BOOST_THREAD_FWD_REF(Fp) f + , BOOST_THREAD_RV_REF(T0) a0 + , BOOST_THREAD_RV_REF(T1) a1 + , BOOST_THREAD_RV_REF(T2) a2 + , BOOST_THREAD_RV_REF(T3) a3 + , BOOST_THREAD_RV_REF(T4) a4 + , BOOST_THREAD_RV_REF(T5) a5 + , BOOST_THREAD_RV_REF(T6) a6 + , BOOST_THREAD_RV_REF(T7) a7 + , BOOST_THREAD_RV_REF(T8) a8 + ) + : fp_(boost::move(f)) + , v0_(boost::move(a0)) + , v1_(boost::move(a1)) + , v2_(boost::move(a2)) + , v3_(boost::move(a3)) + , v4_(boost::move(a4)) + , v5_(boost::move(a5)) + , v6_(boost::move(a6)) + , v7_(boost::move(a7)) + , v8_(boost::move(a8)) + {} + + BOOST_SYMBOL_VISIBLE + invoker(BOOST_THREAD_RV_REF(invoker) f) + : fp_(boost::move(BOOST_THREAD_RV(f).fp)) + , v0_(boost::move(BOOST_THREAD_RV(f).v0_)) + , v1_(boost::move(BOOST_THREAD_RV(f).v1_)) + , v2_(boost::move(BOOST_THREAD_RV(f).v2_)) + , v3_(boost::move(BOOST_THREAD_RV(f).v3_)) + , v4_(boost::move(BOOST_THREAD_RV(f).v4_)) + , v5_(boost::move(BOOST_THREAD_RV(f).v5_)) + , v6_(boost::move(BOOST_THREAD_RV(f).v6_)) + , v7_(boost::move(BOOST_THREAD_RV(f).v7_)) + , v8_(boost::move(BOOST_THREAD_RV(f).v8_)) + {} + + result_type operator()() + { + return invoke(boost::move(fp_) + , boost::move(v0_) + , boost::move(v1_) + , boost::move(v2_) + , boost::move(v3_) + , boost::move(v4_) + , boost::move(v5_) + , boost::move(v6_) + , boost::move(v7_) + , boost::move(v8_) + ); + } + }; + template <class Fp, class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7 > + class invoker<Fp, T0, T1, T2, T3, T4, T5, T6, T7> + { + Fp fp_; + T0 v0_; + T1 v1_; + T2 v2_; + T3 v3_; + T4 v4_; + T5 v5_; + T6 v6_; + T7 v7_; + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) + typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5, T6, T7)>::type result_type; + + BOOST_SYMBOL_VISIBLE + explicit invoker(BOOST_THREAD_FWD_REF(Fp) f + , BOOST_THREAD_RV_REF(T0) a0 + , BOOST_THREAD_RV_REF(T1) a1 + , BOOST_THREAD_RV_REF(T2) a2 + , BOOST_THREAD_RV_REF(T3) a3 + , BOOST_THREAD_RV_REF(T4) a4 + , BOOST_THREAD_RV_REF(T5) a5 + , BOOST_THREAD_RV_REF(T6) a6 + , BOOST_THREAD_RV_REF(T7) a7 + ) + : fp_(boost::move(f)) + , v0_(boost::move(a0)) + , v1_(boost::move(a1)) + , v2_(boost::move(a2)) + , v3_(boost::move(a3)) + , v4_(boost::move(a4)) + , v5_(boost::move(a5)) + , v6_(boost::move(a6)) + , v7_(boost::move(a7)) + {} + + BOOST_SYMBOL_VISIBLE + invoker(BOOST_THREAD_RV_REF(invoker) f) + : fp_(boost::move(BOOST_THREAD_RV(f).fp)) + , v0_(boost::move(BOOST_THREAD_RV(f).v0_)) + , v1_(boost::move(BOOST_THREAD_RV(f).v1_)) + , v2_(boost::move(BOOST_THREAD_RV(f).v2_)) + , v3_(boost::move(BOOST_THREAD_RV(f).v3_)) + , v4_(boost::move(BOOST_THREAD_RV(f).v4_)) + , v5_(boost::move(BOOST_THREAD_RV(f).v5_)) + , v6_(boost::move(BOOST_THREAD_RV(f).v6_)) + , v7_(boost::move(BOOST_THREAD_RV(f).v7_)) + {} + + result_type operator()() + { + return invoke(boost::move(fp_) + , boost::move(v0_) + , boost::move(v1_) + , boost::move(v2_) + , boost::move(v3_) + , boost::move(v4_) + , boost::move(v5_) + , boost::move(v6_) + , boost::move(v7_) + ); + } + }; + template <class Fp, class T0, class T1, class T2, class T3, class T4, class T5, class T6> + class invoker<Fp, T0, T1, T2, T3, T4, T5, T6> + { + Fp fp_; + T0 v0_; + T1 v1_; + T2 v2_; + T3 v3_; + T4 v4_; + T5 v5_; + T6 v6_; + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) + typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5, T6)>::type result_type; + + BOOST_SYMBOL_VISIBLE + explicit invoker(BOOST_THREAD_FWD_REF(Fp) f + , BOOST_THREAD_RV_REF(T0) a0 + , BOOST_THREAD_RV_REF(T1) a1 + , BOOST_THREAD_RV_REF(T2) a2 + , BOOST_THREAD_RV_REF(T3) a3 + , BOOST_THREAD_RV_REF(T4) a4 + , BOOST_THREAD_RV_REF(T5) a5 + , BOOST_THREAD_RV_REF(T6) a6 + ) + : fp_(boost::move(f)) + , v0_(boost::move(a0)) + , v1_(boost::move(a1)) + , v2_(boost::move(a2)) + , v3_(boost::move(a3)) + , v4_(boost::move(a4)) + , v5_(boost::move(a5)) + , v6_(boost::move(a6)) + {} + + BOOST_SYMBOL_VISIBLE + invoker(BOOST_THREAD_RV_REF(invoker) f) + : fp_(boost::move(BOOST_THREAD_RV(f).fp)) + , v0_(boost::move(BOOST_THREAD_RV(f).v0_)) + , v1_(boost::move(BOOST_THREAD_RV(f).v1_)) + , v2_(boost::move(BOOST_THREAD_RV(f).v2_)) + , v3_(boost::move(BOOST_THREAD_RV(f).v3_)) + , v4_(boost::move(BOOST_THREAD_RV(f).v4_)) + , v5_(boost::move(BOOST_THREAD_RV(f).v5_)) + , v6_(boost::move(BOOST_THREAD_RV(f).v6_)) + {} + + result_type operator()() + { + return invoke(boost::move(fp_) + , boost::move(v0_) + , boost::move(v1_) + , boost::move(v2_) + , boost::move(v3_) + , boost::move(v4_) + , boost::move(v5_) + , boost::move(v6_) + ); + } + }; + template <class Fp, class T0, class T1, class T2, class T3, class T4, class T5> + class invoker<Fp, T0, T1, T2, T3, T4, T5> + { + Fp fp_; + T0 v0_; + T1 v1_; + T2 v2_; + T3 v3_; + T4 v4_; + T5 v5_; + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) + typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5)>::type result_type; + + BOOST_SYMBOL_VISIBLE + explicit invoker(BOOST_THREAD_FWD_REF(Fp) f + , BOOST_THREAD_RV_REF(T0) a0 + , BOOST_THREAD_RV_REF(T1) a1 + , BOOST_THREAD_RV_REF(T2) a2 + , BOOST_THREAD_RV_REF(T3) a3 + , BOOST_THREAD_RV_REF(T4) a4 + , BOOST_THREAD_RV_REF(T5) a5 + ) + : fp_(boost::move(f)) + , v0_(boost::move(a0)) + , v1_(boost::move(a1)) + , v2_(boost::move(a2)) + , v3_(boost::move(a3)) + , v4_(boost::move(a4)) + , v5_(boost::move(a5)) + {} + + BOOST_SYMBOL_VISIBLE + invoker(BOOST_THREAD_RV_REF(invoker) f) + : fp_(boost::move(BOOST_THREAD_RV(f).fp)) + , v0_(boost::move(BOOST_THREAD_RV(f).v0_)) + , v1_(boost::move(BOOST_THREAD_RV(f).v1_)) + , v2_(boost::move(BOOST_THREAD_RV(f).v2_)) + , v3_(boost::move(BOOST_THREAD_RV(f).v3_)) + , v4_(boost::move(BOOST_THREAD_RV(f).v4_)) + , v5_(boost::move(BOOST_THREAD_RV(f).v5_)) + {} + + result_type operator()() + { + return invoke(boost::move(fp_) + , boost::move(v0_) + , boost::move(v1_) + , boost::move(v2_) + , boost::move(v3_) + , boost::move(v4_) + , boost::move(v5_) + ); + } + }; + template <class Fp, class T0, class T1, class T2, class T3, class T4> + class invoker<Fp, T0, T1, T2, T3, T4> + { + Fp fp_; + T0 v0_; + T1 v1_; + T2 v2_; + T3 v3_; + T4 v4_; + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) + typedef typename result_of<Fp(T0, T1, T2, T3, T4)>::type result_type; + + BOOST_SYMBOL_VISIBLE + explicit invoker(BOOST_THREAD_FWD_REF(Fp) f + , BOOST_THREAD_RV_REF(T0) a0 + , BOOST_THREAD_RV_REF(T1) a1 + , BOOST_THREAD_RV_REF(T2) a2 + , BOOST_THREAD_RV_REF(T3) a3 + , BOOST_THREAD_RV_REF(T4) a4 + ) + : fp_(boost::move(f)) + , v0_(boost::move(a0)) + , v1_(boost::move(a1)) + , v2_(boost::move(a2)) + , v3_(boost::move(a3)) + , v4_(boost::move(a4)) + {} + + BOOST_SYMBOL_VISIBLE + invoker(BOOST_THREAD_RV_REF(invoker) f) + : fp_(boost::move(BOOST_THREAD_RV(f).fp)) + , v0_(boost::move(BOOST_THREAD_RV(f).v0_)) + , v1_(boost::move(BOOST_THREAD_RV(f).v1_)) + , v2_(boost::move(BOOST_THREAD_RV(f).v2_)) + , v3_(boost::move(BOOST_THREAD_RV(f).v3_)) + , v4_(boost::move(BOOST_THREAD_RV(f).v4_)) + {} + + result_type operator()() + { + return invoke(boost::move(fp_) + , boost::move(v0_) + , boost::move(v1_) + , boost::move(v2_) + , boost::move(v3_) + , boost::move(v4_) + ); + } + }; + template <class Fp, class T0, class T1, class T2, class T3> + class invoker<Fp, T0, T1, T2, T3> + { + Fp fp_; + T0 v0_; + T1 v1_; + T2 v2_; + T3 v3_; + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) + typedef typename result_of<Fp(T0, T1, T2, T3)>::type result_type; + + BOOST_SYMBOL_VISIBLE + explicit invoker(BOOST_THREAD_FWD_REF(Fp) f + , BOOST_THREAD_RV_REF(T0) a0 + , BOOST_THREAD_RV_REF(T1) a1 + , BOOST_THREAD_RV_REF(T2) a2 + , BOOST_THREAD_RV_REF(T3) a3 + ) + : fp_(boost::move(f)) + , v0_(boost::move(a0)) + , v1_(boost::move(a1)) + , v2_(boost::move(a2)) + , v3_(boost::move(a3)) + {} + + BOOST_SYMBOL_VISIBLE + invoker(BOOST_THREAD_RV_REF(invoker) f) + : fp_(boost::move(BOOST_THREAD_RV(f).fp)) + , v0_(boost::move(BOOST_THREAD_RV(f).v0_)) + , v1_(boost::move(BOOST_THREAD_RV(f).v1_)) + , v2_(boost::move(BOOST_THREAD_RV(f).v2_)) + , v3_(boost::move(BOOST_THREAD_RV(f).v3_)) + {} + + result_type operator()() + { + return invoke(boost::move(fp_) + , boost::move(v0_) + , boost::move(v1_) + , boost::move(v2_) + , boost::move(v3_) + ); + } + }; + template <class Fp, class T0, class T1, class T2> + class invoker<Fp, T0, T1, T2> + { + Fp fp_; + T0 v0_; + T1 v1_; + T2 v2_; + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) + typedef typename result_of<Fp(T0, T1, T2)>::type result_type; + + BOOST_SYMBOL_VISIBLE + explicit invoker(BOOST_THREAD_FWD_REF(Fp) f + , BOOST_THREAD_RV_REF(T0) a0 + , BOOST_THREAD_RV_REF(T1) a1 + , BOOST_THREAD_RV_REF(T2) a2 + ) + : fp_(boost::move(f)) + , v0_(boost::move(a0)) + , v1_(boost::move(a1)) + , v2_(boost::move(a2)) + {} + + BOOST_SYMBOL_VISIBLE + invoker(BOOST_THREAD_RV_REF(invoker) f) + : fp_(boost::move(BOOST_THREAD_RV(f).fp)) + , v0_(boost::move(BOOST_THREAD_RV(f).v0_)) + , v1_(boost::move(BOOST_THREAD_RV(f).v1_)) + , v2_(boost::move(BOOST_THREAD_RV(f).v2_)) + {} + + result_type operator()() + { + return invoke(boost::move(fp_) + , boost::move(v0_) + , boost::move(v1_) + , boost::move(v2_) + ); + } + }; + template <class Fp, class T0, class T1> + class invoker<Fp, T0, T1> + { + Fp fp_; + T0 v0_; + T1 v1_; + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) + typedef typename result_of<Fp(T0, T1)>::type result_type; + + BOOST_SYMBOL_VISIBLE + explicit invoker(BOOST_THREAD_FWD_REF(Fp) f + , BOOST_THREAD_RV_REF(T0) a0 + , BOOST_THREAD_RV_REF(T1) a1 + ) + : fp_(boost::move(f)) + , v0_(boost::move(a0)) + , v1_(boost::move(a1)) + {} + + BOOST_SYMBOL_VISIBLE + invoker(BOOST_THREAD_RV_REF(invoker) f) + : fp_(boost::move(BOOST_THREAD_RV(f).fp)) + , v0_(boost::move(BOOST_THREAD_RV(f).v0_)) + , v1_(boost::move(BOOST_THREAD_RV(f).v1_)) + {} + + result_type operator()() + { + return invoke(boost::move(fp_) + , boost::move(v0_) + , boost::move(v1_) + ); + } + }; + template <class Fp, class T0> + class invoker<Fp, T0> + { + Fp fp_; + T0 v0_; + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) + typedef typename result_of<Fp(T0)>::type result_type; + + BOOST_SYMBOL_VISIBLE + explicit invoker(BOOST_THREAD_FWD_REF(Fp) f + , BOOST_THREAD_RV_REF(T0) a0 + ) + : fp_(boost::move(f)) + , v0_(boost::move(a0)) + {} + + BOOST_SYMBOL_VISIBLE + invoker(BOOST_THREAD_RV_REF(invoker) f) + : fp_(boost::move(BOOST_THREAD_RV(f).fp)) + , v0_(boost::move(BOOST_THREAD_RV(f).v0_)) + {} + + result_type operator()() + { + return invoke(boost::move(fp_) + , boost::move(v0_) + ); + } + }; + template <class Fp> + class invoker<Fp> + { + Fp fp_; + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) + typedef typename result_of<Fp()>::type result_type; + BOOST_SYMBOL_VISIBLE + explicit invoker(BOOST_THREAD_FWD_REF(Fp) f) + : fp_(boost::move(f)) + {} + + BOOST_SYMBOL_VISIBLE + invoker(BOOST_THREAD_RV_REF(invoker) f) + : fp_(boost::move(f.fp_)) + {} + result_type operator()() + { + return fp_(); + } + }; + template <class R> + class invoker<R(*)()> + { + typedef R(*Fp)(); + Fp fp_; + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) + typedef typename result_of<Fp()>::type result_type; + BOOST_SYMBOL_VISIBLE + explicit invoker(Fp f) + : fp_(f) + {} + + BOOST_SYMBOL_VISIBLE + invoker(BOOST_THREAD_RV_REF(invoker) f) + : fp_(f.fp_) + {} + result_type operator()() + { + return fp_(); + } + }; +#endif +#endif + + } +} + +#include <boost/thread/detail/variadic_footer.hpp> + +#endif // header diff --git a/boost/thread/detail/is_convertible.hpp b/boost/thread/detail/is_convertible.hpp new file mode 100644 index 0000000000..b77620cf17 --- /dev/null +++ b/boost/thread/detail/is_convertible.hpp @@ -0,0 +1,49 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2011-2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_THREAD_DETAIL_IS_CONVERTIBLE_HPP +#define BOOST_THREAD_DETAIL_IS_CONVERTIBLE_HPP + +#include <boost/type_traits/is_convertible.hpp> +#include <boost/thread/detail/move.hpp> + +namespace boost +{ + namespace thread_detail + { + template <typename T1, typename T2> + struct is_convertible : boost::is_convertible<T1,T2> {}; + +#if defined BOOST_NO_CXX11_RVALUE_REFERENCES + +#if defined(BOOST_INTEL_CXX_VERSION) && (BOOST_INTEL_CXX_VERSION <= 1300) + +#if defined BOOST_THREAD_USES_MOVE + template <typename T1, typename T2> + struct is_convertible< + rv<T1> &, + rv<rv<T2> > & + > : false_type {}; +#endif + +#elif defined __GNUC__ && (__GNUC__ < 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ <= 4 )) + + template <typename T1, typename T2> + struct is_convertible<T1&, T2&> : boost::is_convertible<T1, T2> {}; +#endif + +#endif + } + +} // namespace boost + + +#endif // BOOST_THREAD_DETAIL_MEMORY_HPP diff --git a/boost/thread/detail/lockable_wrapper.hpp b/boost/thread/detail/lockable_wrapper.hpp new file mode 100644 index 0000000000..8dc5a6cc78 --- /dev/null +++ b/boost/thread/detail/lockable_wrapper.hpp @@ -0,0 +1,45 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_DETAIL_LOCKABLE_WRAPPER_HPP +#define BOOST_THREAD_DETAIL_LOCKABLE_WRAPPER_HPP + +#include <boost/thread/detail/config.hpp> + +#if ! defined BOOST_THREAD_NO_CXX11_HDR_INITIALIZER_LIST +#include <initializer_list> +#endif +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + +#if ! defined BOOST_THREAD_NO_CXX11_HDR_INITIALIZER_LIST + namespace thread_detail + { + template <typename Mutex> + struct lockable_wrapper + { + Mutex* m; + explicit lockable_wrapper(Mutex& m_) : + m(&m_) + {} + }; + template <typename Mutex> + struct lockable_adopt_wrapper + { + Mutex* m; + explicit lockable_adopt_wrapper(Mutex& m_) : + m(&m_) + {} + }; + } +#endif + +} + +#include <boost/config/abi_suffix.hpp> + +#endif // header diff --git a/boost/thread/detail/log.hpp b/boost/thread/detail/log.hpp new file mode 100644 index 0000000000..84dcc8cb41 --- /dev/null +++ b/boost/thread/detail/log.hpp @@ -0,0 +1,83 @@ +// Copyright (C) 2012 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_THREAD_DETAIL_LOG_HPP +#define BOOST_THREAD_DETAIL_LOG_HPP + +#include <boost/thread/detail/config.hpp> +#if defined BOOST_THREAD_USES_LOG +#include <boost/thread/recursive_mutex.hpp> +#include <boost/thread/lock_guard.hpp> +#if defined BOOST_THREAD_USES_LOG_THREAD_ID +#include <boost/thread/thread.hpp> +#endif +#include <iostream> + +namespace boost +{ + namespace thread_detail + { + inline boost::recursive_mutex& terminal_mutex() + { + static boost::recursive_mutex mtx; + return mtx; + } + + } +} +#if defined BOOST_THREAD_USES_LOG_THREAD_ID + +#define BOOST_THREAD_LOG \ + { \ + boost::lock_guard<boost::recursive_mutex> _lk_(boost::thread_detail::terminal_mutex()); \ + std::cout << boost::this_thread::get_id() << " - "<<__FILE__<<"["<<__LINE__<<"] " <<std::dec +#else + +#define BOOST_THREAD_LOG \ +{ \ + boost::lock_guard<boost::recursive_mutex> _lk_(boost::thread_detail::terminal_mutex()); \ + std::cout << __FILE__<<"["<<__LINE__<<"] " <<std::dec + +#endif +#define BOOST_THREAD_END_LOG \ + std::dec << std::endl; \ + } + +#else + +namespace boost +{ + namespace thread_detail + { + struct dummy_stream_t + { + }; + + template <typename T> + inline dummy_stream_t const& operator<<(dummy_stream_t const& os, T) + { + return os; + } + + inline dummy_stream_t const& operator<<(dummy_stream_t const& os, dummy_stream_t const&) + { + return os; + } + + + BOOST_CONSTEXPR_OR_CONST dummy_stream_t dummy_stream = {}; + + } +} + +#define BOOST_THREAD_LOG if (true) {} else boost::thread_detail::dummy_stream +#define BOOST_THREAD_END_LOG boost::thread_detail::dummy_stream + +#endif + +#define BOOST_THREAD_TRACE BOOST_THREAD_LOG << BOOST_THREAD_END_LOG + + +#endif // header diff --git a/boost/thread/detail/make_tuple_indices.hpp b/boost/thread/detail/make_tuple_indices.hpp new file mode 100644 index 0000000000..73d54f11f8 --- /dev/null +++ b/boost/thread/detail/make_tuple_indices.hpp @@ -0,0 +1,224 @@ +// Copyright (C) 2012-2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// 2013/04 Vicente J. Botet Escriba +// Provide implementation up to 10 parameters when BOOST_NO_CXX11_VARIADIC_TEMPLATES is defined. +// 2012/11 Vicente J. Botet Escriba +// Adapt to boost libc++ implementation + +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// The make_tuple_indices C++11 code is based on the one from libcxx. +//===----------------------------------------------------------------------===// + +#ifndef BOOST_THREAD_DETAIL_MAKE_TUPLE_INDICES_HPP +#define BOOST_THREAD_DETAIL_MAKE_TUPLE_INDICES_HPP + +#include <boost/config.hpp> +#include <boost/static_assert.hpp> + +namespace boost +{ + namespace detail + { + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + // make_tuple_indices + + template <std::size_t...> struct tuple_indices + {}; + + template <std::size_t Sp, class IntTuple, std::size_t Ep> + struct make_indices_imp; + + template <std::size_t Sp, std::size_t ...Indices, std::size_t Ep> + struct make_indices_imp<Sp, tuple_indices<Indices...>, Ep> + { + typedef typename make_indices_imp<Sp+1, tuple_indices<Indices..., Sp>, Ep>::type type; + }; + + template <std::size_t Ep, std::size_t ...Indices> + struct make_indices_imp<Ep, tuple_indices<Indices...>, Ep> + { + typedef tuple_indices<Indices...> type; + }; + + template <std::size_t Ep, std::size_t Sp = 0> + struct make_tuple_indices + { + BOOST_STATIC_ASSERT_MSG(Sp <= Ep, "make_tuple_indices input error"); + typedef typename make_indices_imp<Sp, tuple_indices<>, Ep>::type type; + }; +#else + + // - tuple forward declaration ----------------------------------------------- + template < + std::size_t T0 = 0, std::size_t T1 = 0, std::size_t T2 = 0, + std::size_t T3 = 0, std::size_t T4 = 0, std::size_t T5 = 0, + std::size_t T6 = 0, std::size_t T7 = 0, std::size_t T8 = 0, + std::size_t T9 = 0> + class tuple_indices {}; + + template <std::size_t Sp, class IntTuple, std::size_t Ep> + struct make_indices_imp; + + template <std::size_t Sp, std::size_t Ep> + struct make_indices_imp<Sp, tuple_indices<>, Ep> + { + typedef typename make_indices_imp<Sp+1, tuple_indices<Sp>, Ep>::type type; + }; + template <std::size_t Sp, std::size_t I0, std::size_t Ep> + struct make_indices_imp<Sp, tuple_indices<I0>, Ep> + { + typedef typename make_indices_imp<Sp+1, tuple_indices<I0, Sp>, Ep>::type type; + }; + template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t Ep> + struct make_indices_imp<Sp, tuple_indices<I0, I1>, Ep> + { + typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, Sp>, Ep>::type type; + }; + template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t Ep> + struct make_indices_imp<Sp, tuple_indices<I0, I1 , I2>, Ep> + { + typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, I2, Sp>, Ep>::type type; + }; + template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t Ep> + struct make_indices_imp<Sp, tuple_indices<I0, I1 , I2, I3>, Ep> + { + typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, I2, I3, Sp>, Ep>::type type; + }; + template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t Ep> + struct make_indices_imp<Sp, tuple_indices<I0, I1 , I2, I3, I4>, Ep> + { + typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, I2, I3, I4, Sp>, Ep>::type type; + }; + template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5, std::size_t Ep> + struct make_indices_imp<Sp, tuple_indices<I0, I1 , I2, I3, I4, I5>, Ep> + { + typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, I2, I3, I4, I5, Sp>, Ep>::type type; + }; + template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5 + , std::size_t I6 + , std::size_t Ep> + struct make_indices_imp<Sp, tuple_indices<I0, I1 , I2, I3, I4, I5, I6>, Ep> + { + typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, I2, I3, I4, I5, I6, Sp>, Ep>::type type; + }; + template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5 + , std::size_t I6 + , std::size_t I7 + , std::size_t Ep> + struct make_indices_imp<Sp, tuple_indices<I0, I1 , I2, I3, I4, I5, I6, I7>, Ep> + { + typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7, Sp>, Ep>::type type; + }; + template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5 + , std::size_t I6 + , std::size_t I7 + , std::size_t I8 + , std::size_t Ep> + struct make_indices_imp<Sp, tuple_indices<I0, I1 , I2, I3, I4, I5, I6, I7, I8>, Ep> + { + typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7, I8, Sp>, Ep>::type type; + }; +// template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5 +// , std::size_t I6 +// , std::size_t I7 +// , std::size_t I8 +// , std::size_t I9 +// , std::size_t Ep> +// struct make_indices_imp<Sp, tuple_indices<I0, I1 , I2, I3, I4, I5, I6, I7, I8, I9>, Ep> +// { +// typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, Sp>, Ep>::type type; +// }; + + template <std::size_t Ep> + struct make_indices_imp<Ep, tuple_indices<>, Ep> + { + typedef tuple_indices<> type; + }; + template <std::size_t Ep, std::size_t I0> + struct make_indices_imp<Ep, tuple_indices<I0>, Ep> + { + typedef tuple_indices<I0> type; + }; + template <std::size_t Ep, std::size_t I0, std::size_t I1> + struct make_indices_imp<Ep, tuple_indices<I0, I1>, Ep> + { + typedef tuple_indices<I0, I1> type; + }; + template <std::size_t Ep, std::size_t I0, std::size_t I1, std::size_t I2> + struct make_indices_imp<Ep, tuple_indices<I0, I1, I2>, Ep> + { + typedef tuple_indices<I0, I1, I2> type; + }; + template <std::size_t Ep, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3> + struct make_indices_imp<Ep, tuple_indices<I0, I1, I2, I3>, Ep> + { + typedef tuple_indices<I0, I1, I2, I3> type; + }; + template <std::size_t Ep, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4> + struct make_indices_imp<Ep, tuple_indices<I0, I1, I2, I3, I4>, Ep> + { + typedef tuple_indices<I0, I1, I2, I3, I4> type; + }; + template <std::size_t Ep, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5> + struct make_indices_imp<Ep, tuple_indices<I0, I1, I2, I3, I4, I5>, Ep> + { + typedef tuple_indices<I0, I1, I2, I3, I4, I5> type; + }; + template <std::size_t Ep, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5 + , std::size_t I6 + > + struct make_indices_imp<Ep, tuple_indices<I0, I1, I2, I3, I4, I5, I6>, Ep> + { + typedef tuple_indices<I0, I1, I2, I3, I4, I5, I6> type; + }; + template <std::size_t Ep, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5 + , std::size_t I6 + , std::size_t I7 + > + struct make_indices_imp<Ep, tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7>, Ep> + { + typedef tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7> type; + }; + template <std::size_t Ep, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5 + , std::size_t I6 + , std::size_t I7 + , std::size_t I8 + > + struct make_indices_imp<Ep, tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7, I8>, Ep> + { + typedef tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7, I8> type; + }; + + template <std::size_t Ep, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5 + , std::size_t I6 + , std::size_t I7 + , std::size_t I8 + , std::size_t I9 + > + struct make_indices_imp<Ep, tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7, I8, I9>, Ep> + { + typedef tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7, I8, I9> type; + }; + + template <std::size_t Ep, std::size_t Sp = 0> + struct make_tuple_indices + { + BOOST_STATIC_ASSERT_MSG(Sp <= Ep, "make_tuple_indices input error"); + typedef typename make_indices_imp<Sp, tuple_indices<>, Ep>::type type; + }; + +#endif + } +} + +#endif // header diff --git a/boost/thread/detail/memory.hpp b/boost/thread/detail/memory.hpp index 7d47efc781..51ce84f40b 100644 --- a/boost/thread/detail/memory.hpp +++ b/boost/thread/detail/memory.hpp @@ -1,8 +1,9 @@ ////////////////////////////////////////////////////////////////////////////// // -// (C) Copyright 2011-2012 Vicente J. Botet Escriba -// Software License, Version 1.0. (See accompanying file -// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// Copyright (C) 2011-2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // See http://www.boost.org/libs/thread for documentation. // @@ -11,10 +12,13 @@ #ifndef BOOST_THREAD_DETAIL_MEMORY_HPP #define BOOST_THREAD_DETAIL_MEMORY_HPP -#include <boost/container/allocator_traits.hpp> -#include <boost/container/scoped_allocator.hpp> #include <boost/config.hpp> +#include <boost/thread/csbl/memory/pointer_traits.hpp> +#include <boost/thread/csbl/memory/allocator_arg.hpp> +#include <boost/thread/csbl/memory/allocator_traits.hpp> +#include <boost/thread/csbl/memory/scoped_allocator.hpp> + namespace boost { namespace thread_detail @@ -22,12 +26,12 @@ namespace boost template <class _Alloc> class allocator_destructor { - typedef container::allocator_traits<_Alloc> alloc_traits; + typedef csbl::allocator_traits<_Alloc> alloc_traits; public: typedef typename alloc_traits::pointer pointer; typedef typename alloc_traits::size_type size_type; private: - _Alloc& alloc_; + _Alloc alloc_; size_type s_; public: allocator_destructor(_Alloc& a, size_type s)BOOST_NOEXCEPT @@ -35,20 +39,10 @@ namespace boost {} void operator()(pointer p)BOOST_NOEXCEPT { + alloc_traits::destroy(alloc_, p); alloc_traits::deallocate(alloc_, p, s_); } }; } //namespace thread_detail - - typedef container::allocator_arg_t allocator_arg_t; - BOOST_CONSTEXPR_OR_CONST allocator_arg_t allocator_arg = {}; - - template <class T, class Alloc> - struct uses_allocator: public container::uses_allocator<T, Alloc> - { - }; - -} // namespace boost - - +} #endif // BOOST_THREAD_DETAIL_MEMORY_HPP diff --git a/boost/thread/detail/move.hpp b/boost/thread/detail/move.hpp index 748b8dc241..611557093e 100644 --- a/boost/thread/detail/move.hpp +++ b/boost/thread/detail/move.hpp @@ -9,24 +9,34 @@ #include <boost/thread/detail/config.hpp> #ifndef BOOST_NO_SFINAE -#include <boost/utility/enable_if.hpp> +#include <boost/core/enable_if.hpp> #include <boost/type_traits/is_convertible.hpp> #include <boost/type_traits/remove_reference.hpp> #include <boost/type_traits/remove_cv.hpp> #include <boost/type_traits/decay.hpp> +#include <boost/type_traits/conditional.hpp> +#include <boost/type_traits/remove_extent.hpp> +#include <boost/type_traits/is_array.hpp> +#include <boost/type_traits/is_function.hpp> +#include <boost/type_traits/remove_cv.hpp> +#include <boost/type_traits/add_pointer.hpp> +#include <boost/type_traits/decay.hpp> #endif #include <boost/thread/detail/delete.hpp> -#include <boost/move/move.hpp> +#include <boost/move/utility.hpp> +#include <boost/move/traits.hpp> #include <boost/config/abi_prefix.hpp> - +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#include <type_traits> +#endif namespace boost { namespace detail { template <typename T> - struct has_move_emulation_enabled_aux_dummy_specialization; + struct enable_move_utility_emulation_dummy_specialization; template<typename T> struct thread_move_t { @@ -49,6 +59,7 @@ namespace boost }; } +#if !defined BOOST_THREAD_USES_MOVE #ifndef BOOST_NO_SFINAE template<typename T> @@ -63,11 +74,15 @@ namespace boost { return t; } + +#endif //#if !defined BOOST_THREAD_USES_MOVE } -#if ! defined BOOST_NO_RVALUE_REFERENCES +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES +#define BOOST_THREAD_COPY_ASSIGN_REF(TYPE) BOOST_COPY_ASSIGN_REF(TYPE) #define BOOST_THREAD_RV_REF(TYPE) BOOST_RV_REF(TYPE) +#define BOOST_THREAD_RV_REF_2_TEMPL_ARGS(TYPE) BOOST_RV_REF_2_TEMPL_ARGS(TYPE) #define BOOST_THREAD_RV_REF_BEG BOOST_RV_REF_BEG #define BOOST_THREAD_RV_REF_END BOOST_RV_REF_END #define BOOST_THREAD_RV(V) V @@ -77,16 +92,18 @@ namespace boost #define BOOST_THREAD_DCL_MOVABLE_BEG(T) \ namespace detail { \ template <typename T> \ - struct has_move_emulation_enabled_aux_dummy_specialization< + struct enable_move_utility_emulation_dummy_specialization< #define BOOST_THREAD_DCL_MOVABLE_END > \ - : integral_constant<bool, true> \ + : integral_constant<bool, false> \ {}; \ } -#elif ! defined BOOST_NO_RVALUE_REFERENCES && defined BOOST_MSVC +#elif ! defined BOOST_NO_CXX11_RVALUE_REFERENCES && defined BOOST_MSVC +#define BOOST_THREAD_COPY_ASSIGN_REF(TYPE) BOOST_COPY_ASSIGN_REF(TYPE) #define BOOST_THREAD_RV_REF(TYPE) BOOST_RV_REF(TYPE) +#define BOOST_THREAD_RV_REF_2_TEMPL_ARGS(TYPE) BOOST_RV_REF_2_TEMPL_ARGS(TYPE) #define BOOST_THREAD_RV_REF_BEG BOOST_RV_REF_BEG #define BOOST_THREAD_RV_REF_END BOOST_RV_REF_END #define BOOST_THREAD_RV(V) V @@ -96,17 +113,19 @@ namespace boost #define BOOST_THREAD_DCL_MOVABLE_BEG(T) \ namespace detail { \ template <typename T> \ - struct has_move_emulation_enabled_aux_dummy_specialization< + struct enable_move_utility_emulation_dummy_specialization< #define BOOST_THREAD_DCL_MOVABLE_END > \ - : integral_constant<bool, true> \ + : integral_constant<bool, false> \ {}; \ } #else #if defined BOOST_THREAD_USES_MOVE +#define BOOST_THREAD_COPY_ASSIGN_REF(TYPE) BOOST_COPY_ASSIGN_REF(TYPE) #define BOOST_THREAD_RV_REF(TYPE) BOOST_RV_REF(TYPE) +#define BOOST_THREAD_RV_REF_2_TEMPL_ARGS(TYPE) BOOST_RV_REF_2_TEMPL_ARGS(TYPE) #define BOOST_THREAD_RV_REF_BEG BOOST_RV_REF_BEG #define BOOST_THREAD_RV_REF_END BOOST_RV_REF_END #define BOOST_THREAD_RV(V) V @@ -115,15 +134,16 @@ namespace boost #define BOOST_THREAD_DCL_MOVABLE_BEG(T) \ namespace detail { \ template <typename T> \ - struct has_move_emulation_enabled_aux_dummy_specialization< + struct enable_move_utility_emulation_dummy_specialization< #define BOOST_THREAD_DCL_MOVABLE_END > \ - : integral_constant<bool, true> \ + : integral_constant<bool, false> \ {}; \ } #else +#define BOOST_THREAD_COPY_ASSIGN_REF(TYPE) const TYPE& #define BOOST_THREAD_RV_REF(TYPE) boost::detail::thread_move_t< TYPE > #define BOOST_THREAD_RV_REF_BEG boost::detail::thread_move_t< #define BOOST_THREAD_RV_REF_END > @@ -132,17 +152,19 @@ namespace boost #define BOOST_THREAD_DCL_MOVABLE(TYPE) \ template <> \ -struct has_move_emulation_enabled_aux< TYPE > \ - : BOOST_MOVE_BOOST_NS::integral_constant<bool, true> \ -{}; +struct enable_move_utility_emulation< TYPE > \ +{ \ + static const bool value = false; \ +}; #define BOOST_THREAD_DCL_MOVABLE_BEG(T) \ template <typename T> \ -struct has_move_emulation_enabled_aux< +struct enable_move_utility_emulation< #define BOOST_THREAD_DCL_MOVABLE_END > \ - : BOOST_MOVE_BOOST_NS::integral_constant<bool, true> \ -{}; +{ \ + static const bool value = false; \ +}; #endif @@ -176,10 +198,12 @@ namespace detail #endif -#if ! defined BOOST_NO_RVALUE_REFERENCES +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES #define BOOST_THREAD_MOVABLE(TYPE) +#define BOOST_THREAD_COPYABLE(TYPE) + #else #if defined BOOST_THREAD_USES_MOVE @@ -202,6 +226,11 @@ namespace detail return *static_cast<const ::boost::rv<TYPE>* >(this); \ }\ +#define BOOST_THREAD_COPYABLE(TYPE) \ + TYPE& operator=(TYPE &t)\ + { this->operator=(static_cast<const ::boost::rv<TYPE> &>(const_cast<const TYPE &>(t))); return *this;} + + #else #define BOOST_THREAD_MOVABLE(TYPE) \ @@ -215,31 +244,111 @@ namespace detail return x; \ } \ +#define BOOST_THREAD_COPYABLE(TYPE) + #endif #endif #define BOOST_THREAD_MOVABLE_ONLY(TYPE) \ BOOST_THREAD_NO_COPYABLE(TYPE) \ BOOST_THREAD_MOVABLE(TYPE) \ + typedef int boost_move_no_copy_constructor_or_assign; \ + #define BOOST_THREAD_COPYABLE_AND_MOVABLE(TYPE) \ - BOOST_THREAD_MOVABLE(TYPE) \ + BOOST_THREAD_COPYABLE(TYPE) \ + BOOST_THREAD_MOVABLE(TYPE) \ -#ifndef BOOST_NO_RVALUE_REFERENCES namespace boost -{ namespace thread_detail +{ + namespace thread_detail + { + +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES +#elif defined BOOST_THREAD_USES_MOVE + template <class T> + struct is_rv + : ::boost::move_detail::is_rv<T> + {}; + +#else + template <class T> + struct is_rv + : ::boost::integral_constant<bool, false> + {}; + + template <class T> + struct is_rv< ::boost::detail::thread_move_t<T> > + : ::boost::integral_constant<bool, true> + {}; + + template <class T> + struct is_rv< const ::boost::detail::thread_move_t<T> > + : ::boost::integral_constant<bool, true> + {}; +#endif + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template <class Tp> + struct remove_reference : boost::remove_reference<Tp> {}; + template <class Tp> + struct decay : boost::decay<Tp> {}; +#else + template <class Tp> + struct remove_reference + { + typedef Tp type; + }; + template <class Tp> + struct remove_reference<Tp&> + { + typedef Tp type; + }; + template <class Tp> + struct remove_reference< rv<Tp> > { + typedef Tp type; + }; + + template <class Tp> + struct decay { + private: + typedef typename boost::move_detail::remove_rvalue_reference<Tp>::type Up0; + typedef typename boost::remove_reference<Up0>::type Up; + public: + typedef typename conditional + < + is_array<Up>::value, + typename remove_extent<Up>::type*, + typename conditional + < + is_function<Up>::value, + typename add_pointer<Up>::type, + typename remove_cv<Up>::type + >::type + >::type type; + }; +#endif + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template <class T> typename decay<T>::type decay_copy(T&& t) { return boost::forward<T>(t); } +#else + template <class T> + typename decay<T>::type + decay_copy(BOOST_THREAD_FWD_REF(T) t) + { + return boost::forward<T>(t); } -} #endif + } +} #include <boost/config/abi_suffix.hpp> diff --git a/boost/thread/detail/nullary_function.hpp b/boost/thread/detail/nullary_function.hpp new file mode 100644 index 0000000000..a0e9fd456a --- /dev/null +++ b/boost/thread/detail/nullary_function.hpp @@ -0,0 +1,234 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2013/09 Vicente J. Botet Escriba +// Adapt to boost from CCIA C++11 implementation +// Make use of Boost.Move + +#ifndef BOOST_THREAD_DETAIL_NULLARY_FUNCTION_HPP +#define BOOST_THREAD_DETAIL_NULLARY_FUNCTION_HPP + +#include <boost/config.hpp> +#include <boost/thread/detail/memory.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/csbl/memory/shared_ptr.hpp> +#include <boost/type_traits/decay.hpp> + +namespace boost +{ + namespace detail + { + + template <typename F> + class nullary_function; + template <> + class nullary_function<void()> + { + struct impl_base + { + virtual void call()=0; + virtual ~impl_base() + { + } + }; + csbl::shared_ptr<impl_base> impl; + template <typename F> + struct impl_type: impl_base + { + F f; +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + impl_type(F &f_) + : f(f_) + {} +#endif + impl_type(BOOST_THREAD_RV_REF(F) f_) + : f(boost::move(f_)) + {} + + void call() + { + f(); + } + }; + struct impl_type_ptr: impl_base + { + void (*f)(); + impl_type_ptr(void (*f_)()) + : f(f_) + {} + void call() + { + f(); + } + }; + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(nullary_function) + + explicit nullary_function(void (*f)()): + impl(new impl_type_ptr(f)) + {} + +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + template<typename F> + explicit nullary_function(F& f): + impl(new impl_type<F>(f)) + {} +#endif + template<typename F> + nullary_function(BOOST_THREAD_RV_REF(F) f): + impl(new impl_type<typename decay<F>::type>(thread_detail::decay_copy(boost::forward<F>(f)))) + {} + + nullary_function() + : impl() + { + } + nullary_function(nullary_function const& other) BOOST_NOEXCEPT : + impl(other.impl) + { + } + nullary_function(BOOST_THREAD_RV_REF(nullary_function) other) BOOST_NOEXCEPT : +#if defined BOOST_NO_CXX11_SMART_PTR + impl(BOOST_THREAD_RV(other).impl) + { + BOOST_THREAD_RV(other).impl.reset(); + } +#else + impl(boost::move(other.impl)) + { + } +#endif + ~nullary_function() + { + } + + nullary_function& operator=(BOOST_THREAD_COPY_ASSIGN_REF(nullary_function) other) BOOST_NOEXCEPT + { + impl=other.impl; + return *this; + } + nullary_function& operator=(BOOST_THREAD_RV_REF(nullary_function) other) BOOST_NOEXCEPT + { +#if defined BOOST_NO_CXX11_SMART_PTR + impl=BOOST_THREAD_RV(other).impl; + BOOST_THREAD_RV(other).impl.reset(); +#else + impl = boost::move(other.impl); +#endif + return *this; + } + + + void operator()() + { if (impl) impl->call();} + + }; + + template <typename R> + class nullary_function<R()> + { + struct impl_base + { + virtual R call()=0; + virtual ~impl_base() + { + } + }; + csbl::shared_ptr<impl_base> impl; + template <typename F> + struct impl_type: impl_base + { + F f; +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + impl_type(F &f_) + : f(f_) + {} +#endif + impl_type(BOOST_THREAD_RV_REF(F) f_) + : f(boost::move(f_)) + {} + + R call() + { + return f(); + } + }; + struct impl_type_ptr: impl_base + { + R (*f)(); + impl_type_ptr(R (*f_)()) + : f(f_) + {} + + R call() + { + return f(); + } + }; + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(nullary_function) + + nullary_function(R (*f)()): + impl(new impl_type_ptr(f)) + {} +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + template<typename F> + nullary_function(F& f): + impl(new impl_type<F>(f)) + {} +#endif + template<typename F> + nullary_function(BOOST_THREAD_RV_REF(F) f): + impl(new impl_type<typename decay<F>::type>(thread_detail::decay_copy(boost::forward<F>(f)))) + {} + + nullary_function(nullary_function const& other) BOOST_NOEXCEPT : + impl(other.impl) + { + } + nullary_function(BOOST_THREAD_RV_REF(nullary_function) other) BOOST_NOEXCEPT : +#if defined BOOST_NO_CXX11_SMART_PTR + impl(BOOST_THREAD_RV(other).impl) + { + BOOST_THREAD_RV(other).impl.reset(); + } +#else + impl(boost::move(other.impl)) + { + } +#endif + nullary_function() + : impl() + { + } + ~nullary_function() + { + } + + nullary_function& operator=(BOOST_THREAD_COPY_ASSIGN_REF(nullary_function) other) BOOST_NOEXCEPT + { + impl=other.impl; + return *this; + } + nullary_function& operator=(BOOST_THREAD_RV_REF(nullary_function) other) BOOST_NOEXCEPT + { +#if defined BOOST_NO_CXX11_SMART_PTR + impl=BOOST_THREAD_RV(other).impl; + BOOST_THREAD_RV(other).impl.reset(); +#else + impl = boost::move(other.impl); +#endif + return *this; + } + + R operator()() + { if (impl) return impl->call(); else return R();} + + }; + } + //BOOST_THREAD_DCL_MOVABLE_BEG(F) detail::nullary_function<F> BOOST_THREAD_DCL_MOVABLE_END +} + +#endif // header diff --git a/boost/thread/detail/thread.hpp b/boost/thread/detail/thread.hpp index 3c71b53cf7..b80eacfa1b 100644 --- a/boost/thread/detail/thread.hpp +++ b/boost/thread/detail/thread.hpp @@ -3,27 +3,34 @@ // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -// (C) Copyright 2007-10 Anthony Williams -// (C) Copyright 20011-12 Vicente J. Botet Escriba +// (C) Copyright 2007-2010 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba #include <boost/thread/detail/config.hpp> +#include <boost/predef/platform.h> + #include <boost/thread/exceptions.hpp> #ifndef BOOST_NO_IOSTREAM #include <ostream> #endif #include <boost/thread/detail/move.hpp> #include <boost/thread/mutex.hpp> +#if defined BOOST_THREAD_USES_DATETIME #include <boost/thread/xtime.hpp> +#endif #include <boost/thread/detail/thread_heap_alloc.hpp> +#include <boost/thread/detail/make_tuple_indices.hpp> +#include <boost/thread/detail/invoke.hpp> +#include <boost/thread/detail/is_convertible.hpp> #include <boost/assert.hpp> #include <list> #include <algorithm> -#include <boost/ref.hpp> +#include <boost/core/ref.hpp> #include <boost/cstdint.hpp> #include <boost/bind.hpp> #include <stdlib.h> #include <memory> -#include <boost/utility/enable_if.hpp> +#include <boost/core/enable_if.hpp> #include <boost/type_traits/remove_reference.hpp> #include <boost/io/ios_state.hpp> #include <boost/type_traits/is_same.hpp> @@ -34,6 +41,9 @@ #include <boost/chrono/ceil.hpp> #endif +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) +#include <tuple> +#endif #include <boost/config/abi_prefix.hpp> #ifdef BOOST_MSVC @@ -46,13 +56,43 @@ namespace boost namespace detail { + +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + + template<typename F, class ...ArgTypes> + class thread_data: + public detail::thread_data_base + { + public: + BOOST_THREAD_NO_COPYABLE(thread_data) + thread_data(BOOST_THREAD_RV_REF(F) f_, BOOST_THREAD_RV_REF(ArgTypes)... args_): + fp(boost::forward<F>(f_), boost::forward<ArgTypes>(args_)...) + {} + template <std::size_t ...Indices> + void run2(tuple_indices<Indices...>) + { + + invoke(std::move(std::get<0>(fp)), std::move(std::get<Indices>(fp))...); + } + void run() + { + typedef typename make_tuple_indices<std::tuple_size<std::tuple<F, ArgTypes...> >::value, 1>::type index_type; + + run2(index_type()); + } + + private: + std::tuple<typename decay<F>::type, typename decay<ArgTypes>::type...> fp; + }; +#else // defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template<typename F> class thread_data: public detail::thread_data_base { public: BOOST_THREAD_NO_COPYABLE(thread_data) -#ifndef BOOST_NO_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES thread_data(BOOST_THREAD_RV_REF(F) f_): f(boost::forward<F>(f_)) {} @@ -69,10 +109,13 @@ namespace boost f(f_) {} #endif + //thread_data() {} + void run() { f(); } + private: F f; }; @@ -110,6 +153,7 @@ namespace boost f(); } }; +#endif } class BOOST_THREAD_DECL thread @@ -120,24 +164,55 @@ namespace boost BOOST_THREAD_MOVABLE_ONLY(thread) private: + struct dummy; + void release_handle(); detail::thread_data_ptr thread_info; - void start_thread(); - void start_thread(const attributes& attr); + private: + bool start_thread_noexcept(); + bool start_thread_noexcept(const attributes& attr); + //public: + void start_thread() + { + if (!start_thread_noexcept()) + { + boost::throw_exception(thread_resource_error()); + } + } + void start_thread(const attributes& attr) + { + if (!start_thread_noexcept(attr)) + { + boost::throw_exception(thread_resource_error()); + } + } explicit thread(detail::thread_data_ptr data); detail::thread_data_ptr get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const; -#ifndef BOOST_NO_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template<typename F, class ...ArgTypes> + static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_RV_REF(ArgTypes)... args) + { + return detail::thread_data_ptr(detail::heap_new< + detail::thread_data<typename boost::remove_reference<F>::type, ArgTypes...> + >( + boost::forward<F>(f), boost::forward<ArgTypes>(args)... + ) + ); + } +#else template<typename F> static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f) { return detail::thread_data_ptr(detail::heap_new<detail::thread_data<typename boost::remove_reference<F>::type> >( boost::forward<F>(f))); } +#endif static inline detail::thread_data_ptr make_thread_info(void (*f)()) { return detail::thread_data_ptr(detail::heap_new<detail::thread_data<void(*)()> >( @@ -145,7 +220,12 @@ namespace boost } #else template<typename F> - static inline detail::thread_data_ptr make_thread_info(F f) + static inline detail::thread_data_ptr make_thread_info(F f + , typename disable_if_c< + //boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F)>::value || + is_same<typename decay<F>::type, thread>::value, + dummy* >::type=0 + ) { return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f)); } @@ -156,7 +236,6 @@ namespace boost } #endif - struct dummy; public: #if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF. #if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) @@ -166,6 +245,7 @@ namespace boost thread() BOOST_NOEXCEPT; ~thread() { + #if defined BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE if (joinable()) { std::terminate(); @@ -174,12 +254,12 @@ namespace boost detach(); #endif } -#ifndef BOOST_NO_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template < class F > explicit thread(BOOST_THREAD_RV_REF(F) f - , typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0 + //, typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0 ): thread_info(make_thread_info(thread_detail::decay_copy(boost::forward<F>(f)))) { @@ -188,7 +268,7 @@ namespace boost template < class F > - thread(attributes& attrs, BOOST_THREAD_RV_REF(F) f): + thread(attributes const& attrs, BOOST_THREAD_RV_REF(F) f): thread_info(make_thread_info(thread_detail::decay_copy(boost::forward<F>(f)))) { start_thread(attrs); @@ -203,7 +283,7 @@ namespace boost start_thread(); } template <class F> - thread(attributes& attrs, F f): + thread(attributes const& attrs, F f): thread_info(make_thread_info(f)) { start_thread(attrs); @@ -211,15 +291,21 @@ namespace boost #else template <class F> explicit thread(F f - // todo Disable also if Or is_same<typename decay<F>::type, thread> - , typename disable_if<boost::is_convertible<F&,BOOST_THREAD_RV_REF(F) >, dummy* >::type=0): + , typename disable_if_c< + boost::thread_detail::is_rv<F>::value // todo ass a thread_detail::is_rv + //boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F)>::value + //|| is_same<typename decay<F>::type, thread>::value + , dummy* >::type=0 + ): thread_info(make_thread_info(f)) { start_thread(); } template <class F> - thread(attributes& attrs, F f - , typename disable_if<boost::is_convertible<F&,BOOST_THREAD_RV_REF(F) >, dummy* >::type=0): + thread(attributes const& attrs, F f + , typename disable_if<boost::thread_detail::is_rv<F>, dummy* >::type=0 + //, typename disable_if<boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F) >, dummy* >::type=0 + ): thread_info(make_thread_info(f)) { start_thread(attrs); @@ -229,19 +315,27 @@ namespace boost explicit thread(BOOST_THREAD_RV_REF(F) f , typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0 ): - thread_info(make_thread_info(f)) +#ifdef BOOST_THREAD_USES_MOVE + thread_info(make_thread_info(boost::move<F>(f))) // todo : Add forward +#else + thread_info(make_thread_info(f)) // todo : Add forward +#endif { start_thread(); } template <class F> - thread(attributes& attrs, BOOST_THREAD_RV_REF(F) f): - thread_info(make_thread_info(f)) + thread(attributes const& attrs, BOOST_THREAD_RV_REF(F) f): +#ifdef BOOST_THREAD_USES_MOVE + thread_info(make_thread_info(boost::move<F>(f))) // todo : Add forward +#else + thread_info(make_thread_info(f)) // todo : Add forward +#endif { start_thread(attrs); } #endif - thread(BOOST_THREAD_RV_REF(thread) x) + thread(BOOST_THREAD_RV_REF(thread) x) BOOST_NOEXCEPT { thread_info=BOOST_THREAD_RV(x).thread_info; BOOST_THREAD_RV(x).thread_info.reset(); @@ -267,8 +361,32 @@ namespace boost return *this; } +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template <class F, class Arg, class ...Args> + thread(F&& f, Arg&& arg, Args&&... args) : + thread_info(make_thread_info( + thread_detail::decay_copy(boost::forward<F>(f)), + thread_detail::decay_copy(boost::forward<Arg>(arg)), + thread_detail::decay_copy(boost::forward<Args>(args))...) + ) + + { + start_thread(); + } + template <class F, class Arg, class ...Args> + thread(attributes const& attrs, F&& f, Arg&& arg, Args&&... args) : + thread_info(make_thread_info( + thread_detail::decay_copy(boost::forward<F>(f)), + thread_detail::decay_copy(boost::forward<Arg>(arg)), + thread_detail::decay_copy(boost::forward<Args>(args))...) + ) + + { + start_thread(attrs); + } +#else template <class F,class A1> - thread(F f,A1 a1,typename disable_if<boost::is_convertible<F&,thread_attributes >, dummy* >::type=0): + thread(F f,A1 a1,typename disable_if<boost::thread_detail::is_convertible<F&,thread_attributes >, dummy* >::type=0): thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1))) { start_thread(); @@ -328,31 +446,53 @@ namespace boost { start_thread(); } - +#endif void swap(thread& x) BOOST_NOEXCEPT { thread_info.swap(x.thread_info); } - class BOOST_SYMBOL_VISIBLE id; + class id; +#ifdef BOOST_THREAD_PLATFORM_PTHREAD + inline id get_id() const BOOST_NOEXCEPT; +#else id get_id() const BOOST_NOEXCEPT; +#endif bool joinable() const BOOST_NOEXCEPT; - void join(); + private: + bool join_noexcept(); + public: + inline void join(); + #ifdef BOOST_THREAD_USES_CHRONO +#if defined(BOOST_THREAD_PLATFORM_WIN32) + template <class Rep, class Period> + bool try_join_for(const chrono::duration<Rep, Period>& rel_time) + { + chrono::milliseconds rel_time2= chrono::ceil<chrono::milliseconds>(rel_time); + return do_try_join_until(rel_time2.count()); + } +#else template <class Rep, class Period> bool try_join_for(const chrono::duration<Rep, Period>& rel_time) { return try_join_until(chrono::steady_clock::now() + rel_time); } +#endif template <class Clock, class Duration> bool try_join_until(const chrono::time_point<Clock, Duration>& t) { using namespace chrono; system_clock::time_point s_now = system_clock::now(); - typename Clock::time_point c_now = Clock::now(); - return try_join_until(s_now + ceil<nanoseconds>(t - c_now)); + bool joined= false; + do { + 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); + } while (! joined); + return true; } template <class Duration> bool try_join_until(const chrono::time_point<chrono::system_clock, Duration>& t) @@ -363,57 +503,72 @@ namespace boost } #endif #if defined(BOOST_THREAD_PLATFORM_WIN32) + private: + bool do_try_join_until_noexcept(uintmax_t milli, bool& res); + inline bool do_try_join_until(uintmax_t milli); + public: bool timed_join(const system_time& abs_time); + //{ + // return do_try_join_until(get_milliseconds_until(wait_until)); + //} #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<chrono::system_clock, chrono::nanoseconds>& tp) + { + chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now()); + return do_try_join_until(rel_time.count()); + } #endif - public: + #else + private: + bool do_try_join_until_noexcept(struct timespec const &timeout, bool& res); + inline bool do_try_join_until(struct timespec const &timeout); + public: +#if defined BOOST_THREAD_USES_DATETIME bool timed_join(const system_time& abs_time) { - struct timespec const ts=detail::get_timespec(abs_time); + struct timespec const ts=detail::to_timespec(abs_time); return do_try_join_until(ts); } +#endif #ifdef BOOST_THREAD_USES_CHRONO bool try_join_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp) { using namespace chrono; nanoseconds d = tp.time_since_epoch(); - timespec ts; - seconds s = duration_cast<seconds>(d); - ts.tv_sec = static_cast<long>(s.count()); - ts.tv_nsec = static_cast<long>((d - s).count()); + timespec ts = boost::detail::to_timespec(d); return do_try_join_until(ts); } #endif - private: - bool do_try_join_until(struct timespec const &timeout); - public: #endif + public: +#if defined BOOST_THREAD_USES_DATETIME template<typename TimeDuration> inline bool timed_join(TimeDuration const& rel_time) { return timed_join(get_system_time()+rel_time); } - - void detach() BOOST_NOEXCEPT; +#endif + void detach(); static unsigned hardware_concurrency() BOOST_NOEXCEPT; + static unsigned physical_concurrency() BOOST_NOEXCEPT; #define BOOST_THREAD_DEFINES_THREAD_NATIVE_HANDLE typedef detail::thread_data_base::native_handle_type native_handle_type; native_handle_type native_handle(); -#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 +#if defined BOOST_THREAD_PROVIDES_THREAD_EQ // Use thread::id when comparisions are needed // backwards compatibility bool operator==(const thread& other) const; bool operator!=(const thread& other) const; #endif +#if defined BOOST_THREAD_USES_DATETIME static inline void yield() BOOST_NOEXCEPT { this_thread::yield(); @@ -423,10 +578,13 @@ namespace boost { this_thread::sleep(xt); } +#endif +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS // extensions void interrupt(); bool interruption_requested() const BOOST_NOEXCEPT; +#endif }; inline void swap(thread& lhs,thread& rhs) BOOST_NOEXCEPT @@ -434,7 +592,7 @@ namespace boost return lhs.swap(rhs); } -#ifndef BOOST_NO_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES inline thread&& move(thread& t) BOOST_NOEXCEPT { return static_cast<thread&&>(t); @@ -445,16 +603,24 @@ namespace boost namespace this_thread { +#ifdef BOOST_THREAD_PLATFORM_PTHREAD + inline thread::id get_id() BOOST_NOEXCEPT; +#else thread::id BOOST_THREAD_DECL get_id() BOOST_NOEXCEPT; +#endif +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS void BOOST_THREAD_DECL interruption_point(); bool BOOST_THREAD_DECL interruption_enabled() BOOST_NOEXCEPT; bool BOOST_THREAD_DECL interruption_requested() BOOST_NOEXCEPT; +#endif +#if defined BOOST_THREAD_USES_DATETIME inline BOOST_SYMBOL_VISIBLE void sleep(xtime const& abs_time) { sleep(system_time(abs_time)); } +#endif } class BOOST_SYMBOL_VISIBLE thread::id @@ -490,12 +656,8 @@ namespace boost public: id() BOOST_NOEXCEPT: #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID -#if defined(BOOST_THREAD_PLATFORM_WIN32) thread_data(0) #else - thread_data(0) -#endif -#else thread_data() #endif {} @@ -572,6 +734,61 @@ namespace boost #endif }; +#ifdef BOOST_THREAD_PLATFORM_PTHREAD + thread::id thread::get_id() const BOOST_NOEXCEPT + { + #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID + return const_cast<thread*>(this)->native_handle(); + #else + detail::thread_data_ptr const local_thread_info=(get_thread_info)(); + return (local_thread_info? id(local_thread_info) : id()); + #endif + } + + namespace this_thread + { + inline thread::id get_id() BOOST_NOEXCEPT + { + #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID + return pthread_self(); + #else + boost::detail::thread_data_base* const thread_info=get_or_make_current_thread_data(); + return (thread_info?thread::id(thread_info->shared_from_this()):thread::id()); + #endif + } + } +#endif + void thread::join() { + if (this_thread::get_id() == get_id()) + boost::throw_exception(thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself")); + + BOOST_THREAD_VERIFY_PRECONDITION( join_noexcept(), + thread_resource_error(static_cast<int>(system::errc::invalid_argument), "boost thread: thread not joinable") + ); + } + +#ifdef BOOST_THREAD_PLATFORM_PTHREAD + bool thread::do_try_join_until(struct timespec const &timeout) +#else + bool thread::do_try_join_until(uintmax_t timeout) +#endif + { + if (this_thread::get_id() == get_id()) + boost::throw_exception(thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself")); + bool res; + if (do_try_join_until_noexcept(timeout, res)) + { + return res; + } + else + { + BOOST_THREAD_THROW_ELSE_RETURN( + (thread_resource_error(static_cast<int>(system::errc::invalid_argument), "boost thread: thread not joinable")), + false + ); + } + } + #if !defined(BOOST_NO_IOSTREAM) && defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) template<class charT, class traits> BOOST_SYMBOL_VISIBLE @@ -582,7 +799,7 @@ namespace boost } #endif -#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 +#if defined BOOST_THREAD_PROVIDES_THREAD_EQ inline bool thread::operator==(const thread& other) const { return get_id()==other.get_id(); @@ -620,6 +837,19 @@ namespace boost }; void BOOST_THREAD_DECL add_thread_exit_function(thread_exit_function_base*); + struct shared_state_base; +#if defined(BOOST_THREAD_PLATFORM_WIN32) + inline void make_ready_at_thread_exit(shared_ptr<shared_state_base> as) + { + detail::thread_data_base* const current_thread_data(detail::get_current_thread_data()); + if(current_thread_data) + { + current_thread_data->make_ready_at_thread_exit(as); + } + } +#else + void BOOST_THREAD_DECL make_ready_at_thread_exit(shared_ptr<shared_state_base> as); +#endif } namespace this_thread diff --git a/boost/thread/detail/thread_group.hpp b/boost/thread/detail/thread_group.hpp index f1ccdf84e2..69ce991e78 100644 --- a/boost/thread/detail/thread_group.hpp +++ b/boost/thread/detail/thread_group.hpp @@ -8,6 +8,7 @@ #include <list> #include <boost/thread/shared_mutex.hpp> #include <boost/thread/mutex.hpp> +#include <boost/thread/lock_guard.hpp> #include <boost/config/abi_prefix.hpp> @@ -22,7 +23,7 @@ namespace boost { private: thread_group(thread_group const&); - thread_group& operator=(thread_group const&); + thread_group& operator=(thread_group const&); public: thread_group() {} ~thread_group() @@ -35,6 +36,41 @@ namespace boost } } + bool is_this_thread_in() + { + thread::id id = this_thread::get_id(); + boost::shared_lock<shared_mutex> guard(m); + for(std::list<thread*>::iterator it=threads.begin(),end=threads.end(); + it!=end; + ++it) + { + if ((*it)->get_id() == id) + return true; + } + return false; + } + + bool is_thread_in(thread* thrd) + { + if(thrd) + { + thread::id id = thrd->get_id(); + boost::shared_lock<shared_mutex> guard(m); + for(std::list<thread*>::iterator it=threads.begin(),end=threads.end(); + it!=end; + ++it) + { + if ((*it)->get_id() == id) + return true; + } + return false; + } + else + { + return false; + } + } + template<typename F> thread* create_thread(F threadfunc) { @@ -43,16 +79,20 @@ namespace boost threads.push_back(new_thread.get()); return new_thread.release(); } - + void add_thread(thread* thrd) { if(thrd) { + BOOST_THREAD_ASSERT_PRECONDITION( ! is_thread_in(thrd) , + thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost::thread_group: trying to add a duplicated thread") + ); + boost::lock_guard<shared_mutex> guard(m); threads.push_back(thrd); } } - + void remove_thread(thread* thrd) { boost::lock_guard<shared_mutex> guard(m); @@ -62,23 +102,28 @@ namespace boost threads.erase(it); } } - + void join_all() { + BOOST_THREAD_ASSERT_PRECONDITION( ! is_this_thread_in() , + thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost::thread_group: trying joining itself") + ); boost::shared_lock<shared_mutex> guard(m); - + for(std::list<thread*>::iterator it=threads.begin(),end=threads.end(); it!=end; ++it) { + if ((*it)->joinable()) (*it)->join(); } } - + +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS void interrupt_all() { boost::shared_lock<shared_mutex> guard(m); - + for(std::list<thread*>::iterator it=threads.begin(),end=threads.end(); it!=end; ++it) @@ -86,13 +131,14 @@ namespace boost (*it)->interrupt(); } } - +#endif + size_t size() const { boost::shared_lock<shared_mutex> guard(m); return threads.size(); } - + private: std::list<thread*> threads; mutable shared_mutex m; diff --git a/boost/thread/detail/thread_interruption.hpp b/boost/thread/detail/thread_interruption.hpp index f1a165c33e..5d7d10fecd 100644 --- a/boost/thread/detail/thread_interruption.hpp +++ b/boost/thread/detail/thread_interruption.hpp @@ -9,6 +9,8 @@ #include <boost/thread/detail/config.hpp> #include <boost/thread/detail/delete.hpp> +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + namespace boost { namespace this_thread @@ -33,4 +35,5 @@ namespace boost } } -#endif +#endif // BOOST_THREAD_PROVIDES_INTERRUPTIONS +#endif // header diff --git a/boost/thread/detail/variadic_footer.hpp b/boost/thread/detail/variadic_footer.hpp new file mode 100644 index 0000000000..9ae25a847c --- /dev/null +++ b/boost/thread/detail/variadic_footer.hpp @@ -0,0 +1,10 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + +#if defined BOOST_NO_CXX11_VARIADIC_TEMPLATES + + +#endif diff --git a/boost/thread/detail/variadic_header.hpp b/boost/thread/detail/variadic_header.hpp new file mode 100644 index 0000000000..8015ae33cc --- /dev/null +++ b/boost/thread/detail/variadic_header.hpp @@ -0,0 +1,19 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/config.hpp> + +//#if defined BOOST_NO_CXX11_VARIADIC_TEMPLATES + +#include <boost/preprocessor/facilities/intercept.hpp> +#include <boost/preprocessor/repetition/enum_params.hpp> +#include <boost/preprocessor/repetition/repeat_from_to.hpp> + +#ifndef BOOST_THREAD_MAX_ARGS +#define BOOST_THREAD_MAX_ARGS 9 +#endif + +//#endif + diff --git a/boost/thread/detail/work.hpp b/boost/thread/detail/work.hpp new file mode 100644 index 0000000000..1e10c837bb --- /dev/null +++ b/boost/thread/detail/work.hpp @@ -0,0 +1,23 @@ +// (C) Copyright 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_THREAD_DETAIL_WORK_HPP +#define BOOST_THREAD_DETAIL_WORK_HPP + + +#include <boost/thread/detail/nullary_function.hpp> + +namespace boost +{ + namespace thread_detail + { + + typedef detail::nullary_function<void()> work; + } + +} // namespace boost + +#endif // BOOST_THREAD_DETAIL_MEMORY_HPP diff --git a/boost/thread/exceptional_ptr.hpp b/boost/thread/exceptional_ptr.hpp new file mode 100644 index 0000000000..49547923d9 --- /dev/null +++ b/boost/thread/exceptional_ptr.hpp @@ -0,0 +1,44 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2014 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_EXCEPTIONAL_PTR_HPP +#define BOOST_THREAD_EXCEPTIONAL_PTR_HPP + +#include <boost/thread/detail/move.hpp> +#include <boost/exception_ptr.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + struct exceptional_ptr { + exception_ptr ptr_; + + exceptional_ptr() : ptr_() {} + explicit exceptional_ptr(exception_ptr ex) : ptr_(ex) {} + template <class E> + explicit exceptional_ptr(BOOST_FWD_REF(E) ex) : ptr_(boost::copy_exception(boost::forward<E>(ex))) {} + }; + + template <class E> + inline exceptional_ptr make_exceptional(BOOST_FWD_REF(E) ex) { + return exceptional_ptr(boost::forward<E>(ex)); + } + + inline exceptional_ptr make_exceptional(exception_ptr ex) + { + return exceptional_ptr(ex); + } + + inline exceptional_ptr make_exceptional() + { + return exceptional_ptr(); + } + +} // namespace boost + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/exceptions.hpp b/boost/thread/exceptions.hpp index 08c28d3d17..d97465b754 100644 --- a/boost/thread/exceptions.hpp +++ b/boost/thread/exceptions.hpp @@ -28,8 +28,10 @@ namespace boost { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS class BOOST_SYMBOL_VISIBLE thread_interrupted {}; +#endif class BOOST_SYMBOL_VISIBLE thread_exception: public system::system_error @@ -122,7 +124,7 @@ namespace boost typedef thread_exception base_type; public: thread_resource_error() - : base_type(system::errc::resource_unavailable_try_again, "boost::thread_resource_error") + : base_type(static_cast<int>(system::errc::resource_unavailable_try_again), "boost::thread_resource_error") {} thread_resource_error( int ev ) @@ -150,7 +152,7 @@ namespace boost typedef thread_exception base_type; public: unsupported_thread_option() - : base_type(system::errc::invalid_argument, "boost::unsupported_thread_option") + : base_type(static_cast<int>(system::errc::invalid_argument), "boost::unsupported_thread_option") {} unsupported_thread_option( int ev ) @@ -174,7 +176,7 @@ namespace boost typedef thread_exception base_type; public: invalid_thread_argument() - : base_type(system::errc::invalid_argument, "boost::invalid_thread_argument") + : base_type(static_cast<int>(system::errc::invalid_argument), "boost::invalid_thread_argument") {} invalid_thread_argument( int ev ) @@ -198,7 +200,7 @@ namespace boost typedef thread_exception base_type; public: thread_permission_error() - : base_type(system::errc::permission_denied, "boost::thread_permission_error") + : base_type(static_cast<int>(system::errc::permission_denied), "boost::thread_permission_error") {} thread_permission_error( int ev ) diff --git a/boost/thread/executor.hpp b/boost/thread/executor.hpp new file mode 100644 index 0000000000..c2b85a0eab --- /dev/null +++ b/boost/thread/executor.hpp @@ -0,0 +1,15 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2013/09 Vicente J. Botet Escriba +// Adapt to boost from CCIA C++11 implementation + +#ifndef BOOST_THREAD_EXECUTOR_HPP +#define BOOST_THREAD_EXECUTOR_HPP + +#include <boost/thread/executors/executor.hpp> +#include <boost/thread/executors/executor_adaptor.hpp> + +#endif diff --git a/boost/thread/executors/basic_thread_pool.hpp b/boost/thread/executors/basic_thread_pool.hpp new file mode 100644 index 0000000000..11283ddf42 --- /dev/null +++ b/boost/thread/executors/basic_thread_pool.hpp @@ -0,0 +1,317 @@ +// Copyright (C) 2013-2014 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2013/09 Vicente J. Botet Escriba +// Adapt to boost from CCIA C++11 implementation +// first implementation of a simple pool thread using a vector of threads and a sync_queue. + +#ifndef BOOST_THREAD_EXECUTORS_BASIC_THREAD_POOL_HPP +#define BOOST_THREAD_EXECUTORS_BASIC_THREAD_POOL_HPP + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/delete.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/scoped_thread.hpp> +#include <boost/thread/sync_queue.hpp> +#include <boost/thread/executors/work.hpp> +#include <boost/thread/csbl/vector.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ +namespace executors +{ + class basic_thread_pool + { + public: + /// type-erasure to store the works to do + typedef executors::work work; + private: + /// the kind of stored threads are scoped threads to ensure that the threads are joined. + /// A move aware vector type + typedef scoped_thread<> thread_t; + typedef csbl::vector<thread_t> thread_vector; + + /// the thread safe work queue + sync_queue<work > work_queue; + /// A move aware vector + thread_vector threads; + + public: + /** + * Effects: try to execute one task. + * Returns: whether a task has been executed. + * Throws: whatever the current task constructor throws or the task() throws. + */ + bool try_executing_one() + { + work task; + try + { + if (work_queue.try_pull_front(task) == queue_op_status::success) + { + task(); + return true; + } + return false; + } + catch (std::exception& ) + { + return false; + } + catch (...) + { + return false; + } + } + /** + * 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(); + } + } + private: + + /** + * The main loop of the worker threads + */ + void worker_thread() + { + try + { + for(;;) + { + work task; + queue_op_status st = work_queue.wait_pull_front(task); + if (st == queue_op_status::closed) return; + task(); + } + } + catch (std::exception& ) + { + return; + } + catch (...) + { + return; + } + } +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template <class AtThreadEntry> + void worker_thread1(AtThreadEntry& at_thread_entry) + { + at_thread_entry(*this); + worker_thread(); + } +#endif + void worker_thread2(void(*at_thread_entry)(basic_thread_pool&)) + { + at_thread_entry(*this); + worker_thread(); + } + template <class AtThreadEntry> + void worker_thread3(BOOST_THREAD_FWD_REF(AtThreadEntry) at_thread_entry) + { + at_thread_entry(*this); + worker_thread(); + } + static void do_nothing_at_thread_entry(basic_thread_pool&) {} + + public: + /// basic_thread_pool is not copyable. + BOOST_THREAD_NO_COPYABLE(basic_thread_pool) + + /** + * \b Effects: creates a thread pool that runs closures on \c thread_count threads. + * + * \b Throws: Whatever exception is thrown while initializing the needed resources. + */ + basic_thread_pool(unsigned const thread_count = thread::hardware_concurrency()) + { + try + { + threads.reserve(thread_count); + for (unsigned i = 0; i < thread_count; ++i) + { +#if 1 + thread th (&basic_thread_pool::worker_thread, this); + threads.push_back(thread_t(boost::move(th))); +#else + threads.push_back(thread_t(&basic_thread_pool::worker_thread, this)); // do not compile +#endif + } + } + catch (...) + { + close(); + throw; + } + } + /** + * \b Effects: creates a thread pool that runs closures on \c thread_count threads + * and executes the at_thread_entry function at the entry of each created thread. . + * + * \b Throws: Whatever exception is thrown while initializing the needed resources. + */ +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template <class AtThreadEntry> + basic_thread_pool( unsigned const thread_count, AtThreadEntry& at_thread_entry) + { + try + { + threads.reserve(thread_count); + for (unsigned i = 0; i < thread_count; ++i) + { + thread th (&basic_thread_pool::worker_thread1<AtThreadEntry>, this, at_thread_entry); + threads.push_back(thread_t(boost::move(th))); + //threads.push_back(thread_t(&basic_thread_pool::worker_thread, this)); // do not compile + } + } + catch (...) + { + close(); + throw; + } + } +#endif + basic_thread_pool( unsigned const thread_count, void(*at_thread_entry)(basic_thread_pool&)) + { + try + { + threads.reserve(thread_count); + for (unsigned i = 0; i < thread_count; ++i) + { + thread th (&basic_thread_pool::worker_thread2, this, at_thread_entry); + threads.push_back(thread_t(boost::move(th))); + //threads.push_back(thread_t(&basic_thread_pool::worker_thread, this)); // do not compile + } + } + catch (...) + { + close(); + throw; + } + } + template <class AtThreadEntry> + basic_thread_pool( unsigned const thread_count, BOOST_THREAD_FWD_REF(AtThreadEntry) at_thread_entry) + { + try + { + threads.reserve(thread_count); + for (unsigned i = 0; i < thread_count; ++i) + { + thread th (&basic_thread_pool::worker_thread3<AtThreadEntry>, this, boost::forward<AtThreadEntry>(at_thread_entry)); + threads.push_back(thread_t(boost::move(th))); + //threads.push_back(thread_t(&basic_thread_pool::worker_thread, this)); // do not compile + } + } + catch (...) + { + close(); + throw; + } + } + /** + * \b Effects: Destroys the thread pool. + * + * \b Synchronization: The completion of all the closures happen before the completion of the \c basic_thread_pool destructor. + */ + ~basic_thread_pool() + { + // signal to all the worker threads that there will be no more submissions. + close(); + // joins all the threads as the threads were scoped_threads + } + + /** + * \b Effects: join all the threads. + */ + void join() + { + for (unsigned i = 0; i < threads.size(); ++i) + { + threads[i].join(); + } + } + + /** + * \b Effects: close the \c basic_thread_pool for submissions. + * The worker threads will work until there is no more closures to run. + */ + void close() + { + work_queue.close(); + } + + /** + * \b Returns: whether the pool is closed for submissions. + */ + bool closed() + { + return work_queue.closed(); + } + + /** + * \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible. + * + * \b Effects: The specified \c closure will be scheduled for execution at some point in the future. + * If invoked closure throws an exception the \c basic_thread_pool will call \c std::terminate, as is the case with threads. + * + * \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables. + * + * \b Throws: \c sync_queue_is_closed if the thread pool is closed. + * Whatever exception that can be throw while storing the closure. + */ + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template <typename Closure> + void submit(Closure & closure) + { + work_queue.push_back(work(closure)); + } +#endif + void submit(void (*closure)()) + { + work_queue.push_back(work(closure)); + } + + template <typename Closure> + void submit(BOOST_THREAD_RV_REF(Closure) closure) + { + work_queue.push_back(work(boost::forward<Closure>(closure))); + } + + /** + * \b Requires: This must be called from an scheduled task. + * + * \b Effects: reschedule functions until pred() + */ + template <typename Pred> + bool reschedule_until(Pred const& pred) + { + do { + if ( ! try_executing_one()) + { + return false; + } + } while (! pred()); + return true; + } + + }; +} +using executors::basic_thread_pool; + +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/executors/executor.hpp b/boost/thread/executors/executor.hpp new file mode 100644 index 0000000000..1075bce733 --- /dev/null +++ b/boost/thread/executors/executor.hpp @@ -0,0 +1,147 @@ +// Copyright (C) 2013,2014 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2013/09 Vicente J. Botet Escriba +// Adapt to boost from CCIA C++11 implementation + +#ifndef BOOST_THREAD_EXECUTORS_EXECUTOR_HPP +#define BOOST_THREAD_EXECUTORS_EXECUTOR_HPP + +#include <boost/thread/detail/config.hpp> + +#include <boost/thread/detail/delete.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/executors/work.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + namespace executors + { + class executor + { + public: + /// type-erasure to store the works to do + typedef executors::work work; + + /// executor is not copyable. + BOOST_THREAD_NO_COPYABLE(executor) + executor() {} + + /** + * \par Effects + * Destroys the executor. + * + * \par Synchronization + * The completion of all the closures happen before the completion of the executor destructor. + */ + virtual ~executor() {}; + + /** + * \par Effects + * Close the \c executor for submissions. + * The worker threads will work until there is no more closures to run. + */ + virtual void close() = 0; + + /** + * \par Returns + * Whether the pool is closed for submissions. + */ + virtual bool closed() = 0; + + /** + * \par Effects + * The specified closure will be scheduled for execution at some point in the future. + * If invoked closure throws an exception the executor will call std::terminate, as is the case with threads. + * + * \par Synchronization + * Ccompletion of closure on a particular thread happens before destruction of thread's thread local variables. + * + * \par Throws + * \c sync_queue_is_closed if the thread pool is closed. + * Whatever exception that can be throw while storing the closure. + */ + virtual void submit(BOOST_THREAD_RV_REF(work) closure) = 0; +// virtual void submit(work& closure) = 0; + + /** + * \par Requires + * \c Closure is a model of Callable(void()) and a model of CopyConstructible/MoveConstructible. + * + * \par Effects + * The specified closure will be scheduled for execution at some point in the future. + * If invoked closure throws an exception the thread pool will call std::terminate, as is the case with threads. + * + * \par Synchronization + * Completion of closure on a particular thread happens before destruction of thread's thread local variables. + * + * \par Throws + * \c sync_queue_is_closed if the thread pool is closed. + * Whatever exception that can be throw while storing the closure. + */ + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template <typename Closure> + void submit(Closure & closure) + { + work w ((closure)); + submit(boost::move(w)); + } +#endif + void submit(void (*closure)()) + { + work w ((closure)); + submit(boost::move(w)); + } + + template <typename Closure> + void submit(BOOST_THREAD_RV_REF(Closure) closure) + { + work w = boost::move(closure); + submit(boost::move(w)); + } + + /** + * \par Effects + * Try to execute one task. + * + * \par Returns + * Whether a task has been executed. + * + * \par Throws + * Whatever the current task constructor throws or the task() throws. + */ + virtual bool try_executing_one() = 0; + + /** + * \par Requires + * This must be called from an scheduled task. + * + * \par Effects + * Reschedule functions until pred() + */ + template <typename Pred> + bool reschedule_until(Pred const& pred) + { + do { + //schedule_one_or_yield(); + if ( ! try_executing_one()) + { + return false; + } + } while (! pred()); + return true; + } + }; + + } + using executors::executor; +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/executors/executor_adaptor.hpp b/boost/thread/executors/executor_adaptor.hpp new file mode 100644 index 0000000000..ebe4e3476c --- /dev/null +++ b/boost/thread/executors/executor_adaptor.hpp @@ -0,0 +1,137 @@ +// Copyright (C) 2013,2014 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2013/09 Vicente J. Botet Escriba +// Adapt to boost from CCIA C++11 implementation + +#ifndef BOOST_THREAD_EXECUTORS_EXECUTOR_ADAPTOR_HPP +#define BOOST_THREAD_EXECUTORS_EXECUTOR_ADAPTOR_HPP + +#include <boost/thread/detail/config.hpp> + +#include <boost/thread/executors/executor.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ +namespace executors +{ + /** + * Polymorphic adaptor of a model of Executor to an executor. + */ + template <typename Executor> + class executor_adaptor : public executor + { + Executor ex; + public: + /// type-erasure to store the works to do + typedef executor::work work; + + /// executor is not copyable. + BOOST_THREAD_NO_COPYABLE(executor_adaptor) + + /** + * executor_adaptor constructor + */ +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template <typename ...Args> + executor_adaptor(BOOST_THREAD_RV_REF(Args) ... args) : ex(boost::forward<Args>(args)...) {} +#else + /** + * executor_adaptor constructor + */ + executor_adaptor() : ex() {} + + template <typename A1> + executor_adaptor( + BOOST_THREAD_FWD_REF(A1) a1 + ) : + ex( + boost::forward<A1>(a1) + ) {} + template <typename A1, typename A2> + executor_adaptor( + BOOST_THREAD_FWD_REF(A1) a1, + BOOST_THREAD_FWD_REF(A2) a2 + ) : + ex( + boost::forward<A1>(a1), + boost::forward<A2>(a2) + ) {} + template <typename A1, typename A2, typename A3> + executor_adaptor( + BOOST_THREAD_FWD_REF(A1) a1, + BOOST_THREAD_FWD_REF(A2) a2, + BOOST_THREAD_FWD_REF(A3) a3 + ) : + ex( + boost::forward<A1>(a1), + boost::forward<A2>(a2), + boost::forward<A3>(a3) + ) {} +#endif + Executor& underlying_executor() { return ex; } + + /** + * \b Effects: close the \c executor for submissions. + * The worker threads will work until there is no more closures to run. + */ + void close() { ex.close(); } + + /** + * \b Returns: whether the pool is closed for submissions. + */ + bool closed() { return ex.closed(); } + + /** + * \b Effects: The specified closure will be scheduled for execution at some point in the future. + * If invoked closure throws an exception the executor will call std::terminate, as is the case with threads. + * + * \b Synchronization: completion of closure on a particular thread happens before destruction of thread's thread local variables. + * + * \b Throws: \c sync_queue_is_closed if the thread pool is closed. + * Whatever exception that can be throw while storing the closure. + */ + void submit(BOOST_THREAD_RV_REF(work) closure) { + return ex.submit(boost::move(closure)); + } +// void submit(work & closure) { +// return ex.submit(closure); +// } + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template <typename Closure> + void submit(Closure & closure) + { + submit(work(closure)); + } +#endif + void submit(void (*closure)()) + { + submit(work(closure)); + } + + template <typename Closure> + void submit(BOOST_THREAD_RV_REF(Closure) closure) + { + submit(work(boost::forward<Closure>(closure))); + } + + /** + * Effects: try to execute one task. + * Returns: whether a task has been executed. + * Throws: whatever the current task constructor throws or the task() throws. + */ + bool try_executing_one() { return ex.try_executing_one(); } + + }; +} +using executors::executor_adaptor; +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/executors/generic_executor_ref.hpp b/boost/thread/executors/generic_executor_ref.hpp new file mode 100644 index 0000000000..57609c91f0 --- /dev/null +++ b/boost/thread/executors/generic_executor_ref.hpp @@ -0,0 +1,211 @@ +// Copyright (C) 2014 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_THREAD_EXECUTORS_GENERIC_EXECUTOR_REF_HPP +#define BOOST_THREAD_EXECUTORS_GENERIC_EXECUTOR_REF_HPP + +#include <boost/thread/detail/config.hpp> + +#include <boost/thread/detail/delete.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/executors/executor.hpp> + +#include <boost/shared_ptr.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + namespace executors + { + + template <class Executor> + class executor_ref : public executor + { + Executor& ex; + public: + /// type-erasure to store the works to do + typedef executors::work work; + + /// executor is not copyable. + BOOST_THREAD_NO_COPYABLE(executor_ref) + executor_ref(Executor& ex) : ex(ex) {} + + /** + * \par Effects + * Destroys the executor. + * + * \par Synchronization + * The completion of all the closures happen before the completion of the executor destructor. + */ + ~executor_ref() {}; + + /** + * \par Effects + * Close the \c executor for submissions. + * The worker threads will work until there is no more closures to run. + */ + void close() { ex.close(); } + + /** + * \par Returns + * Whether the pool is closed for submissions. + */ + bool closed() { return ex.closed(); } + + /** + * \par Effects + * The specified closure will be scheduled for execution at some point in the future. + * If invoked closure throws an exception the executor will call std::terminate, as is the case with threads. + * + * \par Synchronization + * Ccompletion of closure on a particular thread happens before destruction of thread's thread local variables. + * + * \par Throws + * \c sync_queue_is_closed if the thread pool is closed. + * Whatever exception that can be throw while storing the closure. + */ + void submit(BOOST_THREAD_RV_REF(work) closure) { + ex.submit(boost::move(closure)); + } +// void submit(work& closure) { +// ex.submit(closure); +// } + + + /** + * \par Effects + * Try to execute one task. + * + * \par Returns + * Whether a task has been executed. + * + * \par Throws + * Whatever the current task constructor throws or the task() throws. + */ + bool try_executing_one() { return ex.try_executing_one(); } + + }; + + class generic_executor_ref + { + shared_ptr<executor> ex; + public: + /// type-erasure to store the works to do + typedef executors::work work; + + template<typename Executor> + generic_executor_ref(Executor& ex) + //: ex(make_shared<executor_ref<Executor> >(ex)) // todo check why this doesn't works with C++03 + : ex( new executor_ref<Executor>(ex) ) + { + } + + //generic_executor_ref(generic_executor_ref const& other) noexcept {} + //generic_executor_ref& operator=(generic_executor_ref const& other) noexcept {} + + + /** + * \par Effects + * Close the \c executor for submissions. + * The worker threads will work until there is no more closures to run. + */ + void close() { ex->close(); } + + /** + * \par Returns + * Whether the pool is closed for submissions. + */ + bool closed() { return ex->closed(); } + + void submit(BOOST_THREAD_RV_REF(work) closure) + { + ex->submit(boost::forward<work>(closure)); + } + + /** + * \par Requires + * \c Closure is a model of Callable(void()) and a model of CopyConstructible/MoveConstructible. + * + * \par Effects + * The specified closure will be scheduled for execution at some point in the future. + * If invoked closure throws an exception the thread pool will call std::terminate, as is the case with threads. + * + * \par Synchronization + * Completion of closure on a particular thread happens before destruction of thread's thread local variables. + * + * \par Throws + * \c sync_queue_is_closed if the thread pool is closed. + * Whatever exception that can be throw while storing the closure. + */ + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template <typename Closure> + void submit(Closure & closure) + { + work w ((closure)); + submit(boost::move(w)); + } +#endif + void submit(void (*closure)()) + { + work w ((closure)); + submit(boost::move(w)); + } + + template <typename Closure> + void submit(BOOST_THREAD_RV_REF(Closure) closure) + { + work w = boost::move(closure); + submit(boost::move(w)); + } + +// size_t num_pending_closures() const +// { +// return ex->num_pending_closures(); +// } + + /** + * \par Effects + * Try to execute one task. + * + * \par Returns + * Whether a task has been executed. + * + * \par Throws + * Whatever the current task constructor throws or the task() throws. + */ + bool try_executing_one() { return ex->try_executing_one(); } + + /** + * \par Requires + * This must be called from an scheduled task. + * + * \par Effects + * reschedule functions until pred() + */ + template <typename Pred> + bool reschedule_until(Pred const& pred) + { + do { + //schedule_one_or_yield(); + if ( ! try_executing_one()) + { + return false; + } + } while (! pred()); + return true; + } + + }; + } + using executors::executor_ref; + using executors::generic_executor_ref; +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/executors/inline_executor.hpp b/boost/thread/executors/inline_executor.hpp new file mode 100644 index 0000000000..bc6bd9fe7e --- /dev/null +++ b/boost/thread/executors/inline_executor.hpp @@ -0,0 +1,131 @@ +// Copyright (C) 2014 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2013/11 Vicente J. Botet Escriba +// first implementation of a simple serial scheduler. + +#ifndef BOOST_THREAD_INLINE_EXECUTOR_HPP +#define BOOST_THREAD_INLINE_EXECUTOR_HPP + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/delete.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/executors/work.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ +namespace executors +{ + class inline_executor + { + public: + /// type-erasure to store the works to do + typedef executors::work work; + bool closed_; + /** + * Effects: try to execute one task. + * Returns: whether a task has been executed. + * Throws: whatever the current task constructor throws or the task() throws. + */ + bool try_executing_one() + { + return false; + } + + public: + /// inline_executor is not copyable. + BOOST_THREAD_NO_COPYABLE(inline_executor) + + /** + * \b Effects: creates a inline executor that runs closures immediately. + * + * \b Throws: Nothing. + */ + inline_executor() + : closed_(false) + { + } + /** + * \b Effects: Destroys the inline executor. + * + * \b Synchronization: The completion of all the closures happen before the completion of the \c inline_executor destructor. + */ + ~inline_executor() + { + // signal to all the worker thread that there will be no more submissions. + close(); + } + + /** + * \b Effects: close the \c inline_executor for submissions. + * The loop will work until there is no more closures to run. + */ + void close() + { + closed_ = true; + } + + /** + * \b Returns: whether the pool is closed for submissions. + */ + bool closed() + { + return closed_; + } + + /** + * \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible. + * + * \b Effects: The specified \c closure will be scheduled for execution at some point in the future. + * If invoked closure throws an exception the \c inline_executor will call \c std::terminate, as is the case with threads. + * + * \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables. + * + * \b Throws: \c sync_queue_is_closed if the thread pool is closed. + * Whatever exception that can be throw while storing the closure. + */ + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template <typename Closure> + void submit(Closure & closure) + { + if (closed()) return; + closure(); + } +#endif + void submit(void (*closure)()) + { + if (closed()) return; + closure(); + } + + template <typename Closure> + void submit(BOOST_THREAD_FWD_REF(Closure) closure) + { + if (closed()) return; + closure(); + } + + /** + * \b Requires: This must be called from an scheduled task. + * + * \b Effects: reschedule functions until pred() + */ + template <typename Pred> + bool reschedule_until(Pred const& ) + { + return false; + } + + }; +} +using executors::inline_executor; +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/executors/loop_executor.hpp b/boost/thread/executors/loop_executor.hpp new file mode 100644 index 0000000000..c2798b4461 --- /dev/null +++ b/boost/thread/executors/loop_executor.hpp @@ -0,0 +1,204 @@ +// Copyright (C) 2013,2014 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2013/11 Vicente J. Botet Escriba +// first implementation of a simple user scheduler. +// 2013/11 Vicente J. Botet Escriba +// rename loop_executor. + +#ifndef BOOST_THREAD_EXECUTORS_LOOP_EXECUTOR_HPP +#define BOOST_THREAD_EXECUTORS_LOOP_EXECUTOR_HPP + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/delete.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/sync_queue.hpp> +#include <boost/thread/executors/work.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ +namespace executors +{ + + class loop_executor + { + public: + /// type-erasure to store the works to do + typedef executors::work work; + private: + /// the thread safe work queue + sync_queue<work > work_queue; + + public: + /** + * Effects: try to execute one task. + * Returns: whether a task has been executed. + * Throws: whatever the current task constructor throws or the task() throws. + */ + bool try_executing_one() + { + work task; + try + { + if (work_queue.try_pull_front(task) == queue_op_status::success) + { + task(); + return true; + } + return false; + } + catch (std::exception& ) + { + return false; + } + catch (...) + { + 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(); + } + } + + + /** + * The main loop of the worker thread + */ + void worker_thread() + { + while (!closed()) + { + schedule_one_or_yield(); + } + while (try_executing_one()) + { + } + } + + public: + /// loop_executor is not copyable. + BOOST_THREAD_NO_COPYABLE(loop_executor) + + /** + * \b Effects: creates a thread pool that runs closures using one of its closure-executing methods. + * + * \b Throws: Whatever exception is thrown while initializing the needed resources. + */ + loop_executor() + { + } + /** + * \b Effects: Destroys the thread pool. + * + * \b Synchronization: The completion of all the closures happen before the completion of the \c loop_executor destructor. + */ + ~loop_executor() + { + // signal to all the worker thread that there will be no more submissions. + close(); + } + + /** + * loop + */ + void loop() { worker_thread(); } + /** + * \b Effects: close the \c loop_executor for submissions. + * The loop will work until there is no more closures to run. + */ + void close() + { + work_queue.close(); + } + + /** + * \b Returns: whether the pool is closed for submissions. + */ + bool closed() + { + return work_queue.closed(); + } + + /** + * \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible. + * + * \b Effects: The specified \c closure will be scheduled for execution at some point in the future. + * If invoked closure throws an exception the \c loop_executor will call \c std::terminate, as is the case with threads. + * + * \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables. + * + * \b Throws: \c sync_queue_is_closed if the thread pool is closed. + * Whatever exception that can be throw while storing the closure. + */ + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template <typename Closure> + void submit(Closure & closure) + { + work_queue.push_back(work(closure)); + } +#endif + void submit(void (*closure)()) + { + work_queue.push_back(work(closure)); + } + + template <typename Closure> + void submit(BOOST_THREAD_RV_REF(Closure) closure) + { + work_queue.push_back(work(boost::forward<Closure>(closure))); + } + + /** + * \b Requires: This must be called from an scheduled task. + * + * \b Effects: reschedule functions until pred() + */ + template <typename Pred> + bool reschedule_until(Pred const& pred) + { + do { + if ( ! try_executing_one()) + { + return false; + } + } while (! pred()); + return true; + } + + /** + * run queued closures + */ + void run_queued_closures() + { + sync_queue<work>::underlying_queue_type q = work_queue.underlying_queue(); + while (! q.empty()) + { + work& task = q.front(); + task(); + q.pop_front(); + } + } + + }; +} +using executors::loop_executor; + +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/executors/serial_executor.hpp b/boost/thread/executors/serial_executor.hpp new file mode 100644 index 0000000000..dae1014b47 --- /dev/null +++ b/boost/thread/executors/serial_executor.hpp @@ -0,0 +1,214 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2013/11 Vicente J. Botet Escriba +// first implementation of a simple serial scheduler. + +#ifndef BOOST_THREAD_SERIAL_EXECUTOR_HPP +#define BOOST_THREAD_SERIAL_EXECUTOR_HPP + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/delete.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/sync_queue.hpp> +#include <boost/thread/executors/work.hpp> +#include <boost/thread/executors/generic_executor_ref.hpp> +#include <boost/thread/future.hpp> +#include <boost/thread/scoped_thread.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ +namespace executors +{ + class serial_executor + { + public: + /// type-erasure to store the works to do + typedef executors::work work; + private: + typedef scoped_thread<> thread_t; + + /// the thread safe work queue + sync_queue<work > work_queue; + generic_executor_ref ex; + thread_t thr; + + struct try_executing_one_task { + work& task; + boost::promise<void> &p; + try_executing_one_task(work& task, boost::promise<void> &p) + : task(task), p(p) {} + void operator()() { + task(); // if task() throws promise is not set but as the the program terminates and should terminate there is no need to use try-catch here. + p.set_value(); + } + }; + public: + /** + * \par Returns + * The underlying executor wrapped on a generic executor reference. + */ + generic_executor_ref underlying_executor() BOOST_NOEXCEPT { return ex; } + + /** + * Effects: try to execute one task. + * Returns: whether a task has been executed. + * Throws: whatever the current task constructor throws or the task() throws. + */ + bool try_executing_one() + { + work task; + try + { + if (work_queue.try_pull_front(task) == queue_op_status::success) + { + boost::promise<void> p; + try_executing_one_task tmp(task,p); + ex.submit(tmp); +// ex.submit([&task, &p]() +// { +// task(); // if task() throws promise is not set but as the the program terminates and should terminate there is no need to use try-catch here. +// p.set_value(); +// }); + p.get_future().wait(); + return true; + } + return false; + } + catch (std::exception& ) + { + return false; + } + catch (...) + { + 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(); + } + } + + /** + * The main loop of the worker thread + */ + void worker_thread() + { + while (!closed()) + { + schedule_one_or_yield(); + } + while (try_executing_one()) + { + } + } + + public: + /// serial_executor is not copyable. + BOOST_THREAD_NO_COPYABLE(serial_executor) + + /** + * \b Effects: creates a thread pool that runs closures using one of its closure-executing methods. + * + * \b Throws: Whatever exception is thrown while initializing the needed resources. + */ + template <class Executor> + serial_executor(Executor& ex) + : ex(ex), thr(&serial_executor::worker_thread, this) + { + } + /** + * \b Effects: Destroys the thread pool. + * + * \b Synchronization: The completion of all the closures happen before the completion of the \c serial_executor destructor. + */ + ~serial_executor() + { + // signal to all the worker thread that there will be no more submissions. + close(); + } + + /** + * \b Effects: close the \c serial_executor for submissions. + * The loop will work until there is no more closures to run. + */ + void close() + { + work_queue.close(); + } + + /** + * \b Returns: whether the pool is closed for submissions. + */ + bool closed() + { + return work_queue.closed(); + } + + /** + * \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible. + * + * \b Effects: The specified \c closure will be scheduled for execution at some point in the future. + * If invoked closure throws an exception the \c serial_executor will call \c std::terminate, as is the case with threads. + * + * \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables. + * + * \b Throws: \c sync_queue_is_closed if the thread pool is closed. + * Whatever exception that can be throw while storing the closure. + */ + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template <typename Closure> + void submit(Closure & closure) + { + work_queue.push_back(work(closure)); + } +#endif + void submit(void (*closure)()) + { + work_queue.push_back(work(closure)); + } + + template <typename Closure> + void submit(BOOST_THREAD_RV_REF(Closure) closure) + { + work_queue.push_back(work(boost::forward<Closure>(closure))); + } + + /** + * \b Requires: This must be called from an scheduled task. + * + * \b Effects: reschedule functions until pred() + */ + template <typename Pred> + bool reschedule_until(Pred const& pred) + { + do { + if ( ! try_executing_one()) + { + return false; + } + } while (! pred()); + return true; + } + + }; +} +using executors::serial_executor; +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/executors/thread_executor.hpp b/boost/thread/executors/thread_executor.hpp new file mode 100644 index 0000000000..9fc3362fde --- /dev/null +++ b/boost/thread/executors/thread_executor.hpp @@ -0,0 +1,136 @@ +// Copyright (C) 2014 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2014/01 Vicente J. Botet Escriba +// first implementation of a thread_executor. + +#ifndef BOOST_THREAD_THREAD_EXECUTOR_HPP +#define BOOST_THREAD_THREAD_EXECUTOR_HPP + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/delete.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/executors/work.hpp> +#include <boost/thread/executors/executor.hpp> +#include <boost/thread/thread_only.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ +namespace executors +{ + class thread_executor + { + public: + /// type-erasure to store the works to do + typedef executors::work work; + bool closed_; + /** + * Effects: try to execute one task. + * Returns: whether a task has been executed. + * Throws: whatever the current task constructor throws or the task() throws. + */ + bool try_executing_one() + { + return false; + } + + public: + /// thread_executor is not copyable. + BOOST_THREAD_NO_COPYABLE(thread_executor) + + /** + * \b Effects: creates a inline executor that runs closures immediately. + * + * \b Throws: Nothing. + */ + thread_executor() + : closed_(false) + { + } + /** + * \b Effects: Destroys the inline executor. + * + * \b Synchronization: The completion of all the closures happen before the completion of the \c thread_executor destructor. + */ + ~thread_executor() + { + // signal to all the worker thread that there will be no more submissions. + close(); + } + + /** + * \b Effects: close the \c thread_executor for submissions. + * The loop will work until there is no more closures to run. + */ + void close() + { + closed_ = true; + } + + /** + * \b Returns: whether the pool is closed for submissions. + */ + bool closed() + { + return closed_; + } + + /** + * \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible. + * + * \b Effects: The specified \c closure will be scheduled for execution at some point in the future. + * If invoked closure throws an exception the \c thread_executor will call \c std::terminate, as is the case with threads. + * + * \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables. + * + * \b Throws: \c sync_queue_is_closed if the thread pool is closed. + * Whatever exception that can be throw while storing the closure. + */ + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template <typename Closure> + void submit(Closure & closure) + { + if (closed()) return; + thread th(closure); + th.detach(); + } +#endif + void submit(void (*closure)()) + { + if (closed()) return; + thread th(closure); + th.detach(); + } + + template <typename Closure> + void submit(BOOST_THREAD_FWD_REF(Closure) closure) + { + if (closed()) return; + thread th(boost::forward<Closure>(closure)); + th.detach(); + } + + /** + * \b Requires: This must be called from an scheduled task. + * + * \b Effects: reschedule functions until pred() + */ + template <typename Pred> + bool reschedule_until(Pred const&) + { + return false; + } + + }; +} +using executors::thread_executor; +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/executors/work.hpp b/boost/thread/executors/work.hpp new file mode 100644 index 0000000000..df1512cd95 --- /dev/null +++ b/boost/thread/executors/work.hpp @@ -0,0 +1,43 @@ +// (C) Copyright 2013,2014 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_THREAD_EXECUTORS_WORK_HPP +#define BOOST_THREAD_EXECUTORS_WORK_HPP + +#include <boost/thread/detail/config.hpp> + +#if ! defined BOOST_THREAD_EXECUTORS_WORK_ACCEPTS_MOVABLE \ + && ! defined BOOST_THREAD_EXECUTORS_WORK_DONT_ACCEPT_MOVABLE +#define BOOST_THREAD_EXECUTORS_WORK_ACCEPTS_MOVABLE +//#define BOOST_THREAD_EXECUTORS_WORK_DONT_ACCEPT_MOVABLE +#endif + +#if defined BOOST_THREAD_EXECUTORS_WORK_ACCEPTS_MOVABLE + +#include <boost/thread/detail/nullary_function.hpp> + +namespace boost +{ + namespace executors + { + typedef detail::nullary_function<void()> work; + } +} // namespace boost + +#else +#include <boost/thread/csbl/functional.hpp> + +namespace boost +{ + namespace executors + { + typedef csbl::function<void()> work; + } +} // namespace boost + +#endif + +#endif // BOOST_THREAD_EXECUTORS_WORK_HPP diff --git a/boost/thread/externally_locked.hpp b/boost/thread/externally_locked.hpp new file mode 100644 index 0000000000..0d4baaa512 --- /dev/null +++ b/boost/thread/externally_locked.hpp @@ -0,0 +1,351 @@ +// (C) Copyright 2012 Vicente J. Botet Escriba +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +#ifndef BOOST_THREAD_EXTERNALLY_LOCKED_HPP +#define BOOST_THREAD_EXTERNALLY_LOCKED_HPP + +#include <boost/thread/detail/config.hpp> + +#include <boost/thread/exceptions.hpp> +#include <boost/thread/lock_concepts.hpp> +#include <boost/thread/lock_traits.hpp> +#include <boost/thread/lockable_concepts.hpp> +#include <boost/thread/strict_lock.hpp> + +#include <boost/static_assert.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/throw_exception.hpp> +#include <boost/core/swap.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + + /** + * externally_locked cloaks an object of type T, and actually provides full + * access to that object through the get and set member functions, provided you + * pass a reference to a strict lock object + */ + + //[externally_locked + template <typename T, typename MutexType = boost::mutex> + class externally_locked; + template <typename T, typename MutexType> + class externally_locked + { + //BOOST_CONCEPT_ASSERT(( CopyConstructible<T> )); + BOOST_CONCEPT_ASSERT(( BasicLockable<MutexType> )); + + public: + typedef MutexType mutex_type; + + BOOST_THREAD_COPYABLE_AND_MOVABLE( externally_locked ) + /** + * Requires: T is a model of CopyConstructible. + * Effects: Constructs an externally locked object copying the cloaked type. + */ + externally_locked(mutex_type& mtx, const T& obj) : + obj_(obj), mtx_(&mtx) + { + } + + /** + * Requires: T is a model of Movable. + * Effects: Constructs an externally locked object by moving the cloaked type. + */ + externally_locked(mutex_type& mtx, BOOST_THREAD_RV_REF(T) obj) : + obj_(move(obj)), mtx_(&mtx) + { + } + + /** + * Requires: T is a model of DefaultConstructible. + * Effects: Constructs an externally locked object initializing the cloaked type with the default constructor. + */ + externally_locked(mutex_type& mtx) // BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(T())) + : obj_(), mtx_(&mtx) + { + } + + /** + * Copy constructor + */ + externally_locked(externally_locked const& rhs) //BOOST_NOEXCEPT + : obj_(rhs.obj_), mtx_(rhs.mtx_) + { + } + /** + * Move constructor + */ + externally_locked(BOOST_THREAD_RV_REF(externally_locked) rhs) //BOOST_NOEXCEPT + : obj_(move(rhs.obj_)), mtx_(rhs.mtx_) + { + } + + /// assignment + externally_locked& operator=(externally_locked const& rhs) //BOOST_NOEXCEPT + { + obj_=rhs.obj_; + mtx_=rhs.mtx_; + return *this; + } + + /// move assignment + externally_locked& operator=(BOOST_THREAD_RV_REF(externally_locked) rhs) // BOOST_NOEXCEPT + { + obj_=move(BOOST_THREAD_RV(rhs).obj_); + mtx_=rhs.mtx_; + return *this; + } + + void swap(externally_locked& rhs) //BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR) + { + swap(obj_, rhs.obj_); + swap(mtx_, rhs.mtx_); + } + + /** + * Requires: The lk parameter must be locking the associated mtx. + * + * Returns: The address of the cloaked object.. + * + * Throws: lock_error if BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is not defined and the lk parameter doesn't satisfy the preconditions + */ + T& get(strict_lock<mutex_type>& lk) + { + BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ + return obj_; + } + + const T& get(strict_lock<mutex_type>& lk) const + { + BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ + return obj_; + } + + template <class Lock> + T& get(nested_strict_lock<Lock>& lk) + { + BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::value)); /*< that locks the same type >*/ + BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ + return obj_; + } + + template <class Lock> + const T& get(nested_strict_lock<Lock>& lk) const + { + BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::value)); /*< that locks the same type >*/ + BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ + return obj_; + } + + /** + * Requires: The lk parameter must be locking the associated mtx. + * Returns: The address of the cloaked object.. + * + * Throws: lock_error if BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is not defined and the lk parameter doesn't satisfy the preconditions + */ + template <class Lock> + T& get(Lock& lk) + { + BOOST_CONCEPT_ASSERT(( StrictLock<Lock> )); + BOOST_STATIC_ASSERT( (is_strict_lock<Lock>::value)); /*< lk is a strict lock "sur parolle" >*/ + BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::value)); /*< that locks the same type >*/ + + BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ + + return obj_; + } + + mutex_type* mutex() const BOOST_NOEXCEPT + { + return mtx_; + } + + // modifiers + + void lock() + { + mtx_->lock(); + } + void unlock() + { + mtx_->unlock(); + } + bool try_lock() + { + return mtx_->try_lock(); + } + // todo add time related functions + + private: + T obj_; + mutex_type* mtx_; + }; + //] + + /** + * externally_locked<T&,M> specialization for T& that cloaks an reference to an object of type T, and actually + * provides full access to that object through the get and set member functions, provided you + * pass a reference to a strict lock object. + */ + + //[externally_locked_ref + template <typename T, typename MutexType> + class externally_locked<T&, MutexType> + { + //BOOST_CONCEPT_ASSERT(( CopyConstructible<T> )); + BOOST_CONCEPT_ASSERT(( BasicLockable<MutexType> )); + + public: + typedef MutexType mutex_type; + + BOOST_THREAD_COPYABLE_AND_MOVABLE( externally_locked ) + + /** + * Effects: Constructs an externally locked object storing the cloaked reference object. + */ + externally_locked(T& obj, mutex_type& mtx) BOOST_NOEXCEPT : + obj_(&obj), mtx_(&mtx) + { + } + + /// copy constructor + externally_locked(externally_locked const& rhs) BOOST_NOEXCEPT : + obj_(rhs.obj_), mtx_(rhs.mtx_) + { + } + + /// move constructor + externally_locked(BOOST_THREAD_RV_REF(externally_locked) rhs) BOOST_NOEXCEPT : + obj_(rhs.obj_), mtx_(rhs.mtx_) + { + } + + /// assignment + externally_locked& operator=(externally_locked const& rhs) BOOST_NOEXCEPT + { + obj_=rhs.obj_; + mtx_=rhs.mtx_; + return *this; + } + + /// move assignment + externally_locked& operator=(BOOST_THREAD_RV_REF(externally_locked) rhs) BOOST_NOEXCEPT + { + obj_=rhs.obj_; + mtx_=rhs.mtx_; + return *this; + } + + void swap(externally_locked& rhs) BOOST_NOEXCEPT + { + swap(obj_, rhs.obj_); + swap(mtx_, rhs.mtx_); + } + /** + * Requires: The lk parameter must be locking the associated mtx. + * + * Returns: The address of the cloaked object.. + * + * Throws: lock_error if BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is not defined and the lk parameter doesn't satisfy the preconditions + */ + T& get(strict_lock<mutex_type> const& lk) + { + BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ + return *obj_; + } + + const T& get(strict_lock<mutex_type> const& lk) const + { + BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ + return *obj_; + } + + template <class Lock> + T& get(nested_strict_lock<Lock> const& lk) + { + BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::value)); /*< that locks the same type >*/ + BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ + return *obj_; + } + + template <class Lock> + const T& get(nested_strict_lock<Lock> const& lk) const + { + BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::value)); /*< that locks the same type >*/ + BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ + return *obj_; + } + + /** + * Requires: The lk parameter must be locking the associated mtx. + * Returns: The address of the cloaked object.. + * + * Throws: lock_error if BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is not defined and the lk parameter doesn't satisfy the preconditions + */ + template <class Lock> + T& get(Lock const& lk) + { + BOOST_CONCEPT_ASSERT(( StrictLock<Lock> )); + BOOST_STATIC_ASSERT( (is_strict_lock<Lock>::value)); /*< lk is a strict lock "sur parolle" >*/ + BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::value)); /*< that locks the same type >*/ + BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ + return *obj_; + } + + /** + * Requires: The lk parameter must be locking the associated mtx. + * Returns: The address of the cloaked object.. + * + * Throws: lock_error if BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is not defined and the lk parameter doesn't satisfy the preconditions + */ + template <class Lock> + T const& get(Lock const& lk) const + { + BOOST_CONCEPT_ASSERT(( StrictLock<Lock> )); + BOOST_STATIC_ASSERT( (is_strict_lock<Lock>::value)); /*< lk is a strict lock "sur parolle" >*/ + BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::value)); /*< that locks the same type >*/ + BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ + return *obj_; + } + mutex_type* mutex() const BOOST_NOEXCEPT + { + return mtx_; + } + + void lock() + { + mtx_->lock(); + } + void unlock() + { + mtx_->unlock(); + } + bool try_lock() + { + return mtx_->try_lock(); + } + // todo add time related functions + + protected: + T* obj_; + mutex_type* mtx_; + }; + //] + + template <typename T, typename MutexType> + void swap(externally_locked<T, MutexType> & lhs, externally_locked<T, MutexType> & rhs) // BOOST_NOEXCEPT + { + lhs.swap(rhs); + } + +} + +#include <boost/config/abi_suffix.hpp> + +#endif // header diff --git a/boost/thread/externally_locked_stream.hpp b/boost/thread/externally_locked_stream.hpp new file mode 100644 index 0000000000..aa9aeff79d --- /dev/null +++ b/boost/thread/externally_locked_stream.hpp @@ -0,0 +1,170 @@ +// (C) Copyright 2012 Vicente J. Botet Escriba +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +#ifndef BOOST_THREAD_EXTERNALLY_LOCKED_STREAM_HPP +#define BOOST_THREAD_EXTERNALLY_LOCKED_STREAM_HPP + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/detail/delete.hpp> + +#include <boost/thread/externally_locked.hpp> +#include <boost/thread/lock_traits.hpp> +#include <boost/thread/recursive_mutex.hpp> +#include <boost/thread/strict_lock.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + + template <typename Stream, typename RecursiveMutex=recursive_mutex> + class externally_locked_stream; + + template <class Stream, typename RecursiveMutex=recursive_mutex> + class stream_guard + { + + friend class externally_locked_stream<Stream, RecursiveMutex> ; + public: + typedef typename externally_locked_stream<Stream, RecursiveMutex>::mutex_type mutex_type; + + BOOST_THREAD_MOVABLE_ONLY( stream_guard) + + stream_guard(externally_locked_stream<Stream, RecursiveMutex>& mtx) : + mtx_(&mtx) + { + mtx.lock(); + } + + stream_guard(externally_locked_stream<Stream, RecursiveMutex>& mtx, adopt_lock_t) : + mtx_(&mtx) + { + } + + stream_guard(BOOST_THREAD_RV_REF(stream_guard) rhs) BOOST_NOEXCEPT + : mtx_(rhs.mtx_) + { + rhs.mtx_= 0; + } + + ~stream_guard() + { + if (mtx_ != 0) mtx_->unlock(); + } + + bool owns_lock(const mutex_type * l) const BOOST_NOEXCEPT + { + return l == mtx_->mutex(); + } + + /** + * @Requires mtx_ + */ + Stream& get() const + { + BOOST_THREAD_ASSERT_PRECONDITION( mtx_, lock_error() ); + return mtx_->get(*this); + } + Stream& bypass() const + { + return get(); + } + + + private: + externally_locked_stream<Stream, RecursiveMutex>* mtx_; + }; + + template <typename Stream, typename RecursiveMutex> + struct is_strict_lock_sur_parole<stream_guard<Stream, RecursiveMutex> > : true_type + { + }; + + /** + * externally_locked_stream cloaks a reference to an stream of type Stream, and actually + * provides full access to that object through the get and set member functions, provided you + * pass a reference to a strict lock object. + */ + + //[externally_locked_stream + template <typename Stream, typename RecursiveMutex> + class externally_locked_stream: public externally_locked<Stream&, RecursiveMutex> + { + typedef externally_locked<Stream&, RecursiveMutex> base_type; + public: + BOOST_THREAD_NO_COPYABLE( externally_locked_stream) + + /** + * Effects: Constructs an externally locked object storing the cloaked reference object. + */ + externally_locked_stream(Stream& stream, RecursiveMutex& mtx) BOOST_NOEXCEPT : + base_type(stream, mtx) + { + } + + stream_guard<Stream, RecursiveMutex> hold() BOOST_NOEXCEPT + { + return stream_guard<Stream, RecursiveMutex> (*this); + } + Stream& bypass() const + { + stream_guard<Stream, RecursiveMutex> lk(*this); + return get(lk); + } + }; + //] + + template <typename Stream, typename RecursiveMutex, typename T> + inline const stream_guard<Stream, RecursiveMutex>& operator<<(const stream_guard<Stream, RecursiveMutex>& lck, T arg) + { + lck.get() << arg; + return lck; + } + + template <typename Stream, typename RecursiveMutex> + inline const stream_guard<Stream, RecursiveMutex>& operator<<(const stream_guard<Stream, RecursiveMutex>& lck, Stream& (*arg)(Stream&)) + { + lck.get() << arg; + return lck; + } + + template <typename Stream, typename RecursiveMutex, typename T> + inline const stream_guard<Stream, RecursiveMutex>& operator>>(const stream_guard<Stream, RecursiveMutex>& lck, T& arg) + { + lck.get() >> arg; + return lck; + } + + template <typename Stream, typename RecursiveMutex, typename T> + inline stream_guard<Stream, RecursiveMutex> operator<<(externally_locked_stream<Stream, RecursiveMutex>& mtx, T arg) + { + stream_guard<Stream, RecursiveMutex> lk(mtx); + mtx.get(lk) << arg; + return boost::move(lk); + } + + template <typename Stream, typename RecursiveMutex> + inline stream_guard<Stream, RecursiveMutex> operator<<(externally_locked_stream<Stream, RecursiveMutex>& mtx, Stream& (*arg)(Stream&)) + { + stream_guard<Stream, RecursiveMutex> lk(mtx); + mtx.get(lk) << arg; + return boost::move(lk); + } + + template <typename Stream, typename RecursiveMutex, typename T> + inline stream_guard<Stream, RecursiveMutex> operator>>(externally_locked_stream<Stream, RecursiveMutex>& mtx, T& arg) + { + stream_guard<Stream, RecursiveMutex> lk(mtx); + mtx.get(lk) >> arg; + return boost::move(lk); + } + +} + +#include <boost/config/abi_suffix.hpp> + +#endif // header diff --git a/boost/thread/future.hpp b/boost/thread/future.hpp index 8cad994de5..a1e69c355a 100644 --- a/boost/thread/future.hpp +++ b/boost/thread/future.hpp @@ -1,5 +1,5 @@ // (C) Copyright 2008-10 Anthony Williams -// (C) Copyright 2011-2012 Vicente J. Botet Escriba +// (C) Copyright 2011-2014 Vicente J. Botet Escriba // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -15,42 +15,65 @@ #ifndef BOOST_NO_EXCEPTIONS -#include <boost/detail/scoped_enum_emulation.hpp> +#include <boost/core/scoped_enum.hpp> #include <stdexcept> +#include <iostream> +#include <boost/thread/exceptional_ptr.hpp> #include <boost/thread/detail/move.hpp> +#include <boost/thread/detail/invoker.hpp> +#include <boost/thread/detail/invoke.hpp> #include <boost/thread/thread_time.hpp> #include <boost/thread/mutex.hpp> #include <boost/thread/condition_variable.hpp> +#include <boost/thread/lock_algorithms.hpp> +#include <boost/thread/lock_types.hpp> #include <boost/exception_ptr.hpp> #include <boost/shared_ptr.hpp> -#include <boost/scoped_ptr.hpp> +#if defined BOOST_THREAD_FUTURE_USES_OPTIONAL +#include <boost/optional.hpp> +#else +#include <boost/thread/csbl/memory/unique_ptr.hpp> +//#include <boost/move/make_unique.hpp> +#endif #include <boost/type_traits/is_fundamental.hpp> -#include <boost/type_traits/is_convertible.hpp> -#include <boost/type_traits/remove_reference.hpp> -#include <boost/type_traits/remove_cv.hpp> -#include <boost/mpl/if.hpp> +#include <boost/thread/detail/is_convertible.hpp> +#include <boost/type_traits/decay.hpp> +#include <boost/type_traits/is_void.hpp> +#include <boost/type_traits/conditional.hpp> #include <boost/config.hpp> #include <boost/throw_exception.hpp> #include <algorithm> #include <boost/function.hpp> #include <boost/bind.hpp> -#include <boost/ref.hpp> +#include <boost/core/ref.hpp> #include <boost/scoped_array.hpp> -#include <boost/utility/enable_if.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <boost/core/enable_if.hpp> + #include <list> #include <boost/next_prior.hpp> #include <vector> -#include <boost/system/error_code.hpp> + +#include <boost/thread/future_error_code.hpp> #ifdef BOOST_THREAD_USES_CHRONO #include <boost/chrono/system_clocks.hpp> #endif #if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS #include <boost/thread/detail/memory.hpp> +#include <boost/container/scoped_allocator.hpp> +#if ! defined BOOST_NO_CXX11_ALLOCATOR +#include <memory> +#endif #endif #include <boost/utility/result_of.hpp> -//#include <boost/thread.hpp> +#include <boost/thread/thread_only.hpp> + +#if defined BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY +#include <boost/thread/csbl/tuple.hpp> +#include <boost/thread/csbl/vector.hpp> +#endif #if defined BOOST_THREAD_PROVIDES_FUTURE #define BOOST_THREAD_FUTURE future @@ -58,36 +81,18 @@ #define BOOST_THREAD_FUTURE unique_future #endif - namespace boost { - //enum class future_errc - BOOST_SCOPED_ENUM_DECLARE_BEGIN(future_errc) - { - broken_promise, - future_already_retrieved, - promise_already_satisfied, - no_state - } - BOOST_SCOPED_ENUM_DECLARE_END(future_errc) - - namespace system - { - template <> - struct BOOST_SYMBOL_VISIBLE is_error_code_enum<future_errc> : public true_type {}; - - #ifdef BOOST_NO_SCOPED_ENUMS - template <> - struct BOOST_SYMBOL_VISIBLE is_error_code_enum<future_errc::enum_type> : public true_type { }; - #endif - } - //enum class launch BOOST_SCOPED_ENUM_DECLARE_BEGIN(launch) { + none = 0, async = 1, deferred = 2, +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + executor = 4, +#endif any = async | deferred } BOOST_SCOPED_ENUM_DECLARE_END(launch) @@ -101,26 +106,6 @@ namespace boost } BOOST_SCOPED_ENUM_DECLARE_END(future_status) - BOOST_THREAD_DECL - const system::error_category& future_category(); - - namespace system - { - inline BOOST_THREAD_DECL - error_code - make_error_code(future_errc e) - { - return error_code(underlying_cast<int>(e), boost::future_category()); - } - - inline BOOST_THREAD_DECL - error_condition - make_error_condition(future_errc e) - { - return error_condition(underlying_cast<int>(e), future_category()); - } - } - class BOOST_SYMBOL_VISIBLE future_error : public std::logic_error { @@ -136,15 +121,13 @@ namespace boost { return ec_; } - - //virtual ~future_error() BOOST_NOEXCEPT; }; class BOOST_SYMBOL_VISIBLE future_uninitialized: public future_error { public: - future_uninitialized(): + future_uninitialized() : future_error(system::make_error_code(future_errc::no_state)) {} }; @@ -179,69 +162,148 @@ namespace boost public: task_already_started(): future_error(system::make_error_code(future_errc::promise_already_satisfied)) - //std::logic_error("Task already started") {} }; - class BOOST_SYMBOL_VISIBLE task_moved: - public future_error - { - public: - task_moved(): - future_error(system::make_error_code(future_errc::no_state)) - //std::logic_error("Task moved") - {} - }; + class BOOST_SYMBOL_VISIBLE task_moved: + public future_error + { + public: + task_moved(): + future_error(system::make_error_code(future_errc::no_state)) + {} + }; - class promise_moved: - public future_error - { - public: - promise_moved(): - future_error(system::make_error_code(future_errc::no_state)) - //std::logic_error("Promise moved") - {} - }; + class promise_moved: + public future_error + { + public: + promise_moved(): + future_error(system::make_error_code(future_errc::no_state)) + {} + }; namespace future_state { - enum state { uninitialized, waiting, ready, moved }; + enum state { uninitialized, waiting, ready, moved, deferred }; } namespace detail { - struct future_object_base + struct relocker + { + boost::unique_lock<boost::mutex>& lock_; + bool unlocked_; + + relocker(boost::unique_lock<boost::mutex>& lk): + lock_(lk) + { + lock_.unlock(); + unlocked_=true; + } + ~relocker() + { + if (unlocked_) { + lock_.lock(); + } + } + void lock() { + if (unlocked_) { + lock_.lock(); + unlocked_=false; + } + } + private: + relocker& operator=(relocker const&); + }; + + struct shared_state_base : enable_shared_from_this<shared_state_base> { + typedef std::list<boost::condition_variable_any*> waiter_list; + // This type should be only included conditionally if interruptions are allowed, but is included to maintain the same layout. + typedef shared_ptr<shared_state_base> continuation_ptr_type; + boost::exception_ptr exception; bool done; - bool thread_was_interrupted; - boost::mutex mutex; + bool is_deferred_; + launch policy_; + bool is_constructed; + mutable boost::mutex mutex; boost::condition_variable waiters; - typedef std::list<boost::condition_variable_any*> waiter_list; waiter_list external_waiters; boost::function<void()> callback; + // This declaration should be only included conditionally, but is included to maintain the same layout. + continuation_ptr_type continuation_ptr; + + // This declaration should be only included conditionally, but is included to maintain the same layout. + virtual void launch_continuation(boost::unique_lock<boost::mutex>&) + { + } - future_object_base(): + shared_state_base(): done(false), - thread_was_interrupted(false) + is_deferred_(false), + policy_(launch::none), + is_constructed(false), + continuation_ptr() {} - virtual ~future_object_base() + virtual ~shared_state_base() {} + void set_deferred() + { + is_deferred_ = true; + policy_ = launch::deferred; + } + void set_async() + { + is_deferred_ = false; + policy_ = launch::async; + } +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + void set_executor() + { + is_deferred_ = false; + policy_ = launch::executor; + } +#endif waiter_list::iterator register_external_waiter(boost::condition_variable_any& cv) { - boost::unique_lock<boost::mutex> lock(mutex); + boost::unique_lock<boost::mutex> lock(this->mutex); do_callback(lock); return external_waiters.insert(external_waiters.end(),&cv); } void remove_external_waiter(waiter_list::iterator it) { - boost::lock_guard<boost::mutex> lock(mutex); + boost::lock_guard<boost::mutex> lock(this->mutex); external_waiters.erase(it); } - void mark_finished_internal() +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + void do_continuation(boost::unique_lock<boost::mutex>& lock) + { + if (continuation_ptr) { + continuation_ptr_type this_continuation_ptr = continuation_ptr; + continuation_ptr.reset(); + this_continuation_ptr->launch_continuation(lock); + } + } +#else + void do_continuation(boost::unique_lock<boost::mutex>&) + { + } +#endif +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + void set_continuation_ptr(continuation_ptr_type continuation, boost::unique_lock<boost::mutex>& lock) + { + continuation_ptr= continuation; + if (done) { + do_continuation(lock); + } + } +#endif + void mark_finished_internal(boost::unique_lock<boost::mutex>& lock) { done=true; waiters.notify_all(); @@ -250,24 +312,13 @@ namespace boost { (*it)->notify_all(); } + do_continuation(lock); } - - struct relocker + void make_ready() { - boost::unique_lock<boost::mutex>& lock; - - relocker(boost::unique_lock<boost::mutex>& lock_): - lock(lock_) - { - lock.unlock(); - } - ~relocker() - { - lock.lock(); - } - private: - relocker& operator=(relocker const&); - }; + boost::unique_lock<boost::mutex> lock(this->mutex); + mark_finished_internal(lock); + } void do_callback(boost::unique_lock<boost::mutex>& lock) { @@ -279,28 +330,62 @@ namespace boost } } + virtual bool run_if_is_deferred() + { + boost::unique_lock<boost::mutex> lk(this->mutex); + if (is_deferred_) + { + is_deferred_=false; + execute(lk); + return true; + } + else + return false; + } + virtual bool run_if_is_deferred_or_ready() + { + boost::unique_lock<boost::mutex> lk(this->mutex); + if (is_deferred_) + { + is_deferred_=false; + execute(lk); - void wait(bool rethrow=true) + return true; + } + else + return done; + } + void wait_internal(boost::unique_lock<boost::mutex> &lk, bool rethrow=true) { - boost::unique_lock<boost::mutex> lock(mutex); - do_callback(lock); - while(!done) - { - waiters.wait(lock); - } - if(rethrow && thread_was_interrupted) - { - throw boost::thread_interrupted(); - } - if(rethrow && exception) - { - boost::rethrow_exception(exception); - } + do_callback(lk); + if (is_deferred_) + { + is_deferred_=false; + execute(lk); + } + while(!done) + { + waiters.wait(lk); + } + if(rethrow && exception) + { + boost::rethrow_exception(exception); + } } + virtual void wait(bool rethrow=true) + { + boost::unique_lock<boost::mutex> lock(this->mutex); + wait_internal(lock, rethrow); + } + +#if defined BOOST_THREAD_USES_DATETIME bool timed_wait_until(boost::system_time const& target_time) { - boost::unique_lock<boost::mutex> lock(mutex); + boost::unique_lock<boost::mutex> lock(this->mutex); + if (is_deferred_) + return false; + do_callback(lock); while(!done) { @@ -312,14 +397,16 @@ namespace boost } return true; } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template <class Clock, class Duration> future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) { - boost::unique_lock<boost::mutex> lock(mutex); + boost::unique_lock<boost::mutex> lock(this->mutex); + if (is_deferred_) + return future_status::deferred; do_callback(lock); while(!done) { @@ -332,281 +419,604 @@ namespace boost return future_status::ready; } #endif - void mark_exceptional_finish_internal(boost::exception_ptr const& e) + void mark_exceptional_finish_internal(boost::exception_ptr const& e, boost::unique_lock<boost::mutex>& lock) { exception=e; - mark_finished_internal(); + mark_finished_internal(lock); } + void mark_exceptional_finish() { - boost::lock_guard<boost::mutex> lock(mutex); - mark_exceptional_finish_internal(boost::current_exception()); + boost::unique_lock<boost::mutex> lock(this->mutex); + mark_exceptional_finish_internal(boost::current_exception(), lock); } + +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS void mark_interrupted_finish() { - boost::lock_guard<boost::mutex> lock(mutex); - thread_was_interrupted=true; - mark_finished_internal(); + boost::unique_lock<boost::mutex> lock(this->mutex); + exception = boost::copy_exception(boost::thread_interrupted()); + mark_finished_internal(lock); + } + + void set_interrupted_at_thread_exit() + { + unique_lock<boost::mutex> lk(this->mutex); + if (has_value(lk)) + { + throw_exception(promise_already_satisfied()); + } + exception = boost::copy_exception(boost::thread_interrupted()); + this->is_constructed = true; + detail::make_ready_at_thread_exit(shared_from_this()); + } +#endif + + void set_exception_at_thread_exit(exception_ptr e) + { + unique_lock<boost::mutex> lk(this->mutex); + if (has_value(lk)) + { + throw_exception(promise_already_satisfied()); + } + exception=e; + this->is_constructed = true; + detail::make_ready_at_thread_exit(shared_from_this()); + } + + bool has_value() const + { + boost::lock_guard<boost::mutex> lock(this->mutex); + return done && ! exception; + } + + bool has_value(unique_lock<boost::mutex>& ) const + { + return done && ! exception; + } + + bool has_exception() const + { + boost::lock_guard<boost::mutex> lock(this->mutex); + return done && exception; + } + + bool has_exception(unique_lock<boost::mutex>&) const + { + return done && exception; + } + + bool is_deferred(boost::lock_guard<boost::mutex>&) const { + return is_deferred_; + } + + launch launch_policy(boost::unique_lock<boost::mutex>&) const + { + return policy_; + } + + future_state::state get_state() const + { + boost::lock_guard<boost::mutex> guard(this->mutex); + if(!done) + { + return future_state::waiting; + } + else + { + return future_state::ready; + } } - bool has_value() + + exception_ptr get_exception_ptr() { - boost::lock_guard<boost::mutex> lock(mutex); - return done && !(exception || thread_was_interrupted); + boost::unique_lock<boost::mutex> lock(this->mutex); + return get_exception_ptr(lock); } - bool has_exception() + exception_ptr get_exception_ptr(boost::unique_lock<boost::mutex>& lock) { - boost::lock_guard<boost::mutex> lock(mutex); - return done && (exception || thread_was_interrupted); + wait_internal(lock, false); + return exception; } template<typename F,typename U> void set_wait_callback(F f,U* u) { + boost::lock_guard<boost::mutex> lock(this->mutex); callback=boost::bind(f,boost::ref(*u)); } + virtual void execute(boost::unique_lock<boost::mutex>&) {} + private: - future_object_base(future_object_base const&); - future_object_base& operator=(future_object_base const&); + shared_state_base(shared_state_base const&); + shared_state_base& operator=(shared_state_base const&); }; + // Used to create stand-alone futures template<typename T> - struct future_traits + struct shared_state: + detail::shared_state_base { - typedef boost::scoped_ptr<T> storage_type; -#ifndef BOOST_NO_RVALUE_REFERENCES +#if defined BOOST_THREAD_FUTURE_USES_OPTIONAL + typedef boost::optional<T> storage_type; +#else + typedef boost::csbl::unique_ptr<T> storage_type; +#endif +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES typedef T const& source_reference_type; - struct dummy; - typedef typename boost::mpl::if_<boost::is_fundamental<T>,dummy&,BOOST_THREAD_RV_REF(T)>::type rvalue_source_type; - typedef typename boost::mpl::if_<boost::is_fundamental<T>,T,BOOST_THREAD_RV_REF(T)>::type move_dest_type; + typedef BOOST_THREAD_RV_REF(T) rvalue_source_type; + typedef T move_dest_type; #elif defined BOOST_THREAD_USES_MOVE - typedef T& source_reference_type; - typedef typename boost::mpl::if_<boost::has_move_emulation_enabled<T>,BOOST_THREAD_RV_REF(T),T const&>::type rvalue_source_type; - typedef typename boost::mpl::if_<boost::has_move_emulation_enabled<T>,BOOST_THREAD_RV_REF(T),T>::type move_dest_type; + typedef typename conditional<boost::is_fundamental<T>::value,T,T const&>::type source_reference_type; + typedef BOOST_THREAD_RV_REF(T) rvalue_source_type; + typedef T move_dest_type; #else typedef T& source_reference_type; - typedef typename boost::mpl::if_<boost::is_convertible<T&,BOOST_THREAD_RV_REF(T) >,BOOST_THREAD_RV_REF(T),T const&>::type rvalue_source_type; - typedef typename boost::mpl::if_<boost::is_convertible<T&,BOOST_THREAD_RV_REF(T) >,BOOST_THREAD_RV_REF(T),T>::type move_dest_type; + typedef typename conditional<boost::thread_detail::is_convertible<T&,BOOST_THREAD_RV_REF(T) >::value, BOOST_THREAD_RV_REF(T),T const&>::type rvalue_source_type; + typedef typename conditional<boost::thread_detail::is_convertible<T&,BOOST_THREAD_RV_REF(T) >::value, BOOST_THREAD_RV_REF(T),T>::type move_dest_type; #endif typedef const T& shared_future_get_result_type; - static void init(storage_type& storage,source_reference_type t) + storage_type result; + + shared_state(): + result() + {} + + ~shared_state() + {} + + void mark_finished_with_result_internal(source_reference_type result_, boost::unique_lock<boost::mutex>& lock) { - storage.reset(new T(t)); +#if defined BOOST_THREAD_FUTURE_USES_OPTIONAL + result = result_; +#else + result.reset(new T(result_)); +#endif + this->mark_finished_internal(lock); } - static void init(storage_type& storage,rvalue_source_type t) + void mark_finished_with_result_internal(rvalue_source_type result_, boost::unique_lock<boost::mutex>& lock) { - storage.reset(new T(static_cast<rvalue_source_type>(t))); +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES +#if defined BOOST_THREAD_FUTURE_USES_OPTIONAL + result = boost::move(result_); +#else + result.reset(new T(boost::move(result_))); +#endif +#else +#if defined BOOST_THREAD_FUTURE_USES_OPTIONAL + result = boost::move(result_); +#else + result.reset(new T(static_cast<rvalue_source_type>(result_))); +#endif +#endif + this->mark_finished_internal(lock); } - static void cleanup(storage_type& storage) + void mark_finished_with_result(source_reference_type result_) { - storage.reset(); + boost::unique_lock<boost::mutex> lock(this->mutex); + this->mark_finished_with_result_internal(result_, lock); } + + void mark_finished_with_result(rvalue_source_type result_) + { + boost::unique_lock<boost::mutex> lock(this->mutex); + +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + mark_finished_with_result_internal(boost::move(result_), lock); +#else + mark_finished_with_result_internal(static_cast<rvalue_source_type>(result_), lock); +#endif + } + + storage_type& get_storage(boost::unique_lock<boost::mutex>& lock) + { + wait_internal(lock); + return result; + } + virtual move_dest_type get() + { + boost::unique_lock<boost::mutex> lock(this->mutex); + return boost::move(*get_storage(lock)); + } + + virtual shared_future_get_result_type get_sh() + { + boost::unique_lock<boost::mutex> lock(this->mutex); + return *get_storage(lock); + } + + void set_value_at_thread_exit(source_reference_type result_) + { + unique_lock<boost::mutex> lk(this->mutex); + if (this->has_value(lk)) + { + throw_exception(promise_already_satisfied()); + } +#if defined BOOST_THREAD_FUTURE_USES_OPTIONAL + result = result_; +#else + result.reset(new T(result_)); +#endif + + this->is_constructed = true; + detail::make_ready_at_thread_exit(shared_from_this()); + } + void set_value_at_thread_exit(rvalue_source_type result_) + { + unique_lock<boost::mutex> lk(this->mutex); + if (this->has_value(lk)) + throw_exception(promise_already_satisfied()); + +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES +#if defined BOOST_THREAD_FUTURE_USES_OPTIONAL + result = boost::move(result_); +#else + result.reset(new T(boost::move(result_))); +#endif +#else +#if defined BOOST_THREAD_FUTURE_USES_OPTIONAL + result = boost::move(result_); +#else + result.reset(new T(static_cast<rvalue_source_type>(result_))); +#endif +#endif + this->is_constructed = true; + detail::make_ready_at_thread_exit(shared_from_this()); + } + + private: + shared_state(shared_state const&); + shared_state& operator=(shared_state const&); }; template<typename T> - struct future_traits<T&> + struct shared_state<T&>: + detail::shared_state_base { typedef T* storage_type; typedef T& source_reference_type; - struct rvalue_source_type - {}; typedef T& move_dest_type; typedef T& shared_future_get_result_type; - static void init(storage_type& storage,T& t) + T* result; + + shared_state(): + result(0) + {} + + ~shared_state() { - storage=&t; } - static void cleanup(storage_type& storage) + void mark_finished_with_result_internal(source_reference_type result_, boost::unique_lock<boost::mutex>& lock) { - storage=0; + result= &result_; + mark_finished_internal(lock); } - }; - template<> - struct future_traits<void> - { - typedef bool storage_type; - typedef void move_dest_type; - typedef void shared_future_get_result_type; + void mark_finished_with_result(source_reference_type result_) + { + boost::unique_lock<boost::mutex> lock(this->mutex); + mark_finished_with_result_internal(result_, lock); + } - static void init(storage_type& storage) + virtual T& get() { - storage=true; + boost::unique_lock<boost::mutex> lock(this->mutex); + wait_internal(lock); + return *result; } - static void cleanup(storage_type& storage) + virtual T& get_sh() { - storage=false; + boost::unique_lock<boost::mutex> lock(this->mutex); + wait_internal(lock); + return *result; } + void set_value_at_thread_exit(T& result_) + { + unique_lock<boost::mutex> lk(this->mutex); + if (this->has_value(lk)) + throw_exception(promise_already_satisfied()); + result= &result_; + this->is_constructed = true; + detail::make_ready_at_thread_exit(shared_from_this()); + } + + private: + shared_state(shared_state const&); + shared_state& operator=(shared_state const&); }; - template<typename T> - struct future_object: - detail::future_object_base + template<> + struct shared_state<void>: + detail::shared_state_base { - typedef typename future_traits<T>::storage_type storage_type; - typedef typename future_traits<T>::source_reference_type source_reference_type; - typedef typename future_traits<T>::rvalue_source_type rvalue_source_type; - typedef typename future_traits<T>::move_dest_type move_dest_type; - typedef typename future_traits<T>::shared_future_get_result_type shared_future_get_result_type; - - storage_type result; + typedef void shared_future_get_result_type; + typedef void move_dest_type; - future_object(): - result(0) + shared_state() {} - void mark_finished_with_result_internal(source_reference_type result_) + void mark_finished_with_result_internal(boost::unique_lock<boost::mutex>& lock) { - future_traits<T>::init(result,result_); - mark_finished_internal(); + mark_finished_internal(lock); } - void mark_finished_with_result_internal(rvalue_source_type result_) + void mark_finished_with_result() { - future_traits<T>::init(result,static_cast<rvalue_source_type>(result_)); - mark_finished_internal(); + boost::unique_lock<boost::mutex> lock(this->mutex); + mark_finished_with_result_internal(lock); } - void mark_finished_with_result(source_reference_type result_) + virtual void get() { - boost::lock_guard<boost::mutex> lock(mutex); - mark_finished_with_result_internal(result_); + boost::unique_lock<boost::mutex> lock(this->mutex); + this->wait_internal(lock); } - void mark_finished_with_result(rvalue_source_type result_) + virtual void get_sh() { - boost::lock_guard<boost::mutex> lock(mutex); - mark_finished_with_result_internal(static_cast<rvalue_source_type>(result_)); + boost::unique_lock<boost::mutex> lock(this->mutex); + this->wait_internal(lock); } - move_dest_type get() + void set_value_at_thread_exit() { - wait(); - return static_cast<move_dest_type>(*result); + unique_lock<boost::mutex> lk(this->mutex); + if (this->has_value(lk)) + { + throw_exception(promise_already_satisfied()); + } + this->is_constructed = true; + detail::make_ready_at_thread_exit(shared_from_this()); } + private: + shared_state(shared_state const&); + shared_state& operator=(shared_state const&); + }; + + ///////////////////////// + /// future_async_shared_state_base + ///////////////////////// + template<typename Rp> + struct future_async_shared_state_base: shared_state<Rp> + { + typedef shared_state<Rp> base_type; + protected: + boost::thread thr_; + void join() + { + if (thr_.joinable()) thr_.join(); + } + public: + future_async_shared_state_base() + { + this->set_async(); + } + + ~future_async_shared_state_base() + { + join(); + } + + virtual void wait(bool rethrow) + { + join(); + this->base_type::wait(rethrow); + } + }; - shared_future_get_result_type get_sh() + ///////////////////////// + /// future_async_shared_state + ///////////////////////// + template<typename Rp, typename Fp> + struct future_async_shared_state: future_async_shared_state_base<Rp> + { + explicit future_async_shared_state(BOOST_THREAD_FWD_REF(Fp) f) + { + this->thr_ = thread(&future_async_shared_state::run, this, boost::forward<Fp>(f)); + } + + static void run(future_async_shared_state* that, BOOST_THREAD_FWD_REF(Fp) f) + { + try + { + that->mark_finished_with_result(f()); + } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + catch(thread_interrupted& ) { - wait(); - return static_cast<shared_future_get_result_type>(*result); + that->mark_interrupted_finish(); } +#endif + catch(...) + { + that->mark_exceptional_finish(); + } + } + }; - future_state::state get_state() + template<typename Fp> + struct future_async_shared_state<void, Fp>: public future_async_shared_state_base<void> + { + explicit future_async_shared_state(BOOST_THREAD_FWD_REF(Fp) f) + { + this->thr_ = thread(&future_async_shared_state::run, this, boost::move(f)); + } + + static void run(future_async_shared_state* that, BOOST_THREAD_FWD_REF(Fp) f) + { + try { - boost::lock_guard<boost::mutex> guard(mutex); - if(!done) - { - return future_state::waiting; - } - else - { - return future_state::ready; - } + f(); + that->mark_finished_with_result(); + } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + catch(thread_interrupted& ) + { + that->mark_interrupted_finish(); } +#endif + catch(...) + { + that->mark_exceptional_finish(); + } + } + }; - private: - future_object(future_object const&); - future_object& operator=(future_object const&); + template<typename Rp, typename Fp> + struct future_async_shared_state<Rp&, Fp>: future_async_shared_state_base<Rp&> + { + explicit future_async_shared_state(BOOST_THREAD_FWD_REF(Fp) f) + { + this->thr_ = thread(&future_async_shared_state::run, this, boost::move(f)); + } + + static void run(future_async_shared_state* that, BOOST_THREAD_FWD_REF(Fp) f) + { + try + { + that->mark_finished_with_result(f()); + } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + catch(thread_interrupted& ) + { + that->mark_interrupted_finish(); + } +#endif + catch(...) + { + that->mark_exceptional_finish(); + } + } }; - template<> - struct future_object<void>: - detail::future_object_base + ////////////////////////// + /// future_deferred_shared_state + ////////////////////////// + template<typename Rp, typename Fp> + struct future_deferred_shared_state: shared_state<Rp> { - typedef void shared_future_get_result_type; + typedef shared_state<Rp> base_type; + Fp func_; - future_object() - {} + public: + explicit future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f) + : func_(boost::move(f)) + { + this->set_deferred(); + } - void mark_finished_with_result_internal() + virtual void execute(boost::unique_lock<boost::mutex>& lck) { + try { - mark_finished_internal(); + Fp local_fuct=boost::move(func_); + relocker relock(lck); + Rp res = local_fuct(); + relock.lock(); + this->mark_finished_with_result_internal(boost::move(res), lck); } - - void mark_finished_with_result() + catch (...) { - boost::lock_guard<boost::mutex> lock(mutex); - mark_finished_with_result_internal(); + this->mark_exceptional_finish_internal(current_exception(), lck); } + } + }; + template<typename Rp, typename Fp> + struct future_deferred_shared_state<Rp&,Fp>: shared_state<Rp&> + { + typedef shared_state<Rp&> base_type; + Fp func_; + + public: + explicit future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f) + : func_(boost::move(f)) + { + this->set_deferred(); + } - void get() + virtual void execute(boost::unique_lock<boost::mutex>& lck) { + try { - wait(); + this->mark_finished_with_result_internal(func_(), lck); } - void get_sh() + catch (...) { - wait(); + this->mark_exceptional_finish_internal(current_exception(), lck); } - future_state::state get_state() + } + }; + + template<typename Fp> + struct future_deferred_shared_state<void,Fp>: shared_state<void> + { + typedef shared_state<void> base_type; + Fp func_; + + public: + explicit future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f) + : func_(boost::move(f)) + { + this->set_deferred(); + } + + virtual void execute(boost::unique_lock<boost::mutex>& lck) { + try { - boost::lock_guard<boost::mutex> guard(mutex); - if(!done) - { - return future_state::waiting; - } - else - { - return future_state::ready; - } + Fp local_fuct=boost::move(func_); + relocker relock(lck); + local_fuct(); + relock.lock(); + this->mark_finished_with_result_internal(lck); } - private: - future_object(future_object const&); - future_object& operator=(future_object const&); + catch (...) + { + this->mark_exceptional_finish_internal(current_exception(), lck); + } + } }; -// template<typename T, typename Allocator> -// struct future_object_alloc: public future_object<T> -// { -// typedef future_object<T> base; -// Allocator alloc_; -// -// public: -// explicit future_object_alloc(const Allocator& a) -// : alloc_(a) {} -// -// }; class future_waiter { struct registered_waiter; - typedef std::vector<registered_waiter>::size_type count_type; + typedef std::vector<int>::size_type count_type; struct registered_waiter { - boost::shared_ptr<detail::future_object_base> future_; - detail::future_object_base::waiter_list::iterator wait_iterator; + boost::shared_ptr<detail::shared_state_base> future_; + detail::shared_state_base::waiter_list::iterator wait_iterator; count_type index; - registered_waiter(boost::shared_ptr<detail::future_object_base> const& a_future, - detail::future_object_base::waiter_list::iterator wait_iterator_, + registered_waiter(boost::shared_ptr<detail::shared_state_base> const& a_future, + detail::shared_state_base::waiter_list::iterator wait_iterator_, count_type index_): future_(a_future),wait_iterator(wait_iterator_),index(index_) {} - }; struct all_futures_lock { - count_type count; - boost::scoped_array<boost::unique_lock<boost::mutex> > locks; +#ifdef _MANAGED + typedef std::ptrdiff_t count_type_portable; +#else + typedef count_type count_type_portable; +#endif + count_type_portable count; + boost::scoped_array<boost::unique_lock<boost::mutex> > locks; all_futures_lock(std::vector<registered_waiter>& futures): count(futures.size()),locks(new boost::unique_lock<boost::mutex>[count]) { - for(count_type i=0;i<count;++i) + for(count_type_portable i=0;i<count;++i) { -#if defined __DECCXX || defined __SUNPRO_CC - locks[i]=boost::unique_lock<boost::mutex>(futures[i].future_->mutex).move(); -#else - locks[i]=boost::unique_lock<boost::mutex>(futures[i].future_->mutex); -#endif + locks[i]=BOOST_THREAD_MAKE_RV_REF(boost::unique_lock<boost::mutex>(futures[i].future_->mutex)); } } @@ -617,7 +1027,7 @@ namespace boost void unlock() { - for(count_type i=0;i<count;++i) + for(count_type_portable i=0;i<count;++i) { locks[i].unlock(); } @@ -638,11 +1048,25 @@ namespace boost { if(f.future_) { - futures.push_back(registered_waiter(f.future_,f.future_->register_external_waiter(cv),future_count)); + registered_waiter waiter(f.future_,f.future_->register_external_waiter(cv),future_count); + try { + futures.push_back(waiter); + } catch(...) { + f.future_->remove_external_waiter(waiter.wait_iterator); + throw; + } } ++future_count; } +#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES + template<typename F1, typename... Fs> + void add(F1& f1, Fs&... fs) + { + add(f1); add(fs...); + } +#endif + count_type wait() { all_futures_lock lk(futures); @@ -666,7 +1090,6 @@ namespace boost futures[i].future_->remove_external_waiter(futures[i].wait_iterator); } } - }; } @@ -681,18 +1104,21 @@ namespace boost struct is_future_type { BOOST_STATIC_CONSTANT(bool, value=false); + typedef void type; }; template<typename T> struct is_future_type<BOOST_THREAD_FUTURE<T> > { BOOST_STATIC_CONSTANT(bool, value=true); + typedef T type; }; template<typename T> struct is_future_type<shared_future<T> > { BOOST_STATIC_CONSTANT(bool, value=true); + typedef T type; }; template<typename Iterator> @@ -704,6 +1130,7 @@ namespace boost } } +#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES template<typename F1,typename F2> typename boost::enable_if<is_future_type<F1>,void>::type wait_for_all(F1& f1,F2& f2) { @@ -737,6 +1164,16 @@ namespace boost f4.wait(); f5.wait(); } +#else + template<typename F1, typename... Fs> + void wait_for_all(F1& f1, Fs&... fs) + { + bool dummy[] = { (f1.wait(), true), (fs.wait(), true)... }; + + // prevent unused parameter warning + (void) dummy; + } +#endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template<typename Iterator> typename boost::disable_if<is_future_type<Iterator>,Iterator>::type wait_for_any(Iterator begin,Iterator end) @@ -752,6 +1189,7 @@ namespace boost return boost::next(begin,waiter.wait()); } +#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES template<typename F1,typename F2> typename boost::enable_if<is_future_type<F1>,unsigned>::type wait_for_any(F1& f1,F2& f2) { @@ -793,6 +1231,15 @@ namespace boost waiter.add(f5); return waiter.wait(); } +#else + template<typename F1, typename... Fs> + typename boost::enable_if<is_future_type<F1>, unsigned>::type wait_for_any(F1& f1, Fs&... fs) + { + detail::future_waiter waiter; + waiter.add(f1, fs...); + return waiter.wait(); + } +#endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) template <typename R> class promise; @@ -800,72 +1247,78 @@ namespace boost template <typename R> class packaged_task; - template <typename R> - class BOOST_THREAD_FUTURE + namespace detail { - private: + /// Common implementation for all the futures independently of the return type + class base_future + { + }; + /// Common implementation for future and shared_future. + template <typename R> + class basic_future : public base_future + { + protected: + public: - typedef boost::shared_ptr<detail::future_object<R> > future_ptr; + typedef boost::shared_ptr<detail::shared_state<R> > future_ptr; + typedef typename detail::shared_state<R>::move_dest_type move_dest_type; - future_ptr future_; + static //BOOST_CONSTEXPR + future_ptr make_exceptional_future_ptr(exceptional_ptr const& ex) { + promise<R> p; + p.set_exception(ex.ptr_); + return p.get_future().future_; + } - friend class shared_future<R>; - friend class promise<R>; - friend class packaged_task<R>; - friend class detail::future_waiter; + void set_exceptional_if_invalid() { + if (valid()) return; + promise<R> p; + p.set_exception(future_uninitialized()); + future_ = p.get_future().future_; + } - typedef typename detail::future_traits<R>::move_dest_type move_dest_type; - BOOST_THREAD_FUTURE(future_ptr a_future): - future_(a_future) - {} + future_ptr future_; - public: - BOOST_THREAD_MOVABLE_ONLY(BOOST_THREAD_FUTURE) + basic_future(future_ptr a_future): + future_(a_future) + { + } + // Copy construction from a shared_future + explicit basic_future(const shared_future<R>&) BOOST_NOEXCEPT; + + public: typedef future_state::state state; - BOOST_THREAD_FUTURE() - {} + BOOST_THREAD_MOVABLE_ONLY(basic_future) + basic_future(): future_() {} - ~BOOST_THREAD_FUTURE() - {} - BOOST_THREAD_FUTURE(BOOST_THREAD_RV_REF(BOOST_THREAD_FUTURE) other) BOOST_NOEXCEPT: - future_(BOOST_THREAD_RV(other).future_) + //BOOST_CONSTEXPR + basic_future(exceptional_ptr const& ex) + : future_(make_exceptional_future_ptr(ex)) { - BOOST_THREAD_RV(other).future_.reset(); } - BOOST_THREAD_FUTURE& operator=(BOOST_THREAD_RV_REF(BOOST_THREAD_FUTURE) other) BOOST_NOEXCEPT - { - future_=BOOST_THREAD_RV(other).future_; - BOOST_THREAD_RV(other).future_.reset(); - return *this; - } + ~basic_future() {} - shared_future<R> share() + basic_future(BOOST_THREAD_RV_REF(basic_future) other) BOOST_NOEXCEPT: + future_(BOOST_THREAD_RV(other).future_) { - return shared_future<R>(::boost::move(*this)); + BOOST_THREAD_RV(other).future_.reset(); } - - void swap(BOOST_THREAD_FUTURE& other) + basic_future& operator=(BOOST_THREAD_RV_REF(basic_future) other) BOOST_NOEXCEPT { - future_.swap(other.future_); + future_=BOOST_THREAD_RV(other).future_; + BOOST_THREAD_RV(other).future_.reset(); + return *this; } - - // retrieving the value - move_dest_type get() + void swap(basic_future& that) BOOST_NOEXCEPT { - if(!future_) - { - boost::throw_exception(future_uninitialized()); - } - - return future_->get(); + future_.swap(that.future_); } - // functions to check state, and wait for ready - state get_state() const BOOST_NOEXCEPT + state get_state() const { if(!future_) { @@ -874,27 +1327,39 @@ namespace boost return future_->get_state(); } - bool is_ready() const BOOST_NOEXCEPT + bool is_ready() const { return get_state()==future_state::ready; } - bool has_exception() const BOOST_NOEXCEPT + bool has_exception() const { return future_ && future_->has_exception(); } - bool has_value() const BOOST_NOEXCEPT + bool has_value() const { return future_ && future_->has_value(); } + launch launch_policy(boost::unique_lock<boost::mutex>& lk) const + { + if ( future_ ) return future_->launch_policy(lk); + else return launch(launch::none); + } + + exception_ptr get_exception_ptr() + { + return future_ + ? future_->get_exception_ptr() + : exception_ptr(); + } + bool valid() const BOOST_NOEXCEPT { return future_ != 0; } - void wait() const { if(!future_) @@ -904,6 +1369,7 @@ namespace boost future_->wait(false); } +#if defined BOOST_THREAD_USES_DATETIME template<typename Duration> bool timed_wait(Duration const& rel_time) const { @@ -918,6 +1384,7 @@ namespace boost } return future_->timed_wait_until(abs_time); } +#endif #ifdef BOOST_THREAD_USES_CHRONO template <class Rep, class Period> future_status @@ -937,177 +1404,764 @@ namespace boost return future_->wait_until(abs_time); } #endif + + }; + + } // detail + BOOST_THREAD_DCL_MOVABLE_BEG(R) detail::basic_future<R> BOOST_THREAD_DCL_MOVABLE_END + + namespace detail + { +#if (!defined _MSC_VER || _MSC_VER >= 1400) // _MSC_VER == 1400 on MSVC 2005 + template <class Rp, class Fp> + BOOST_THREAD_FUTURE<Rp> + make_future_async_shared_state(BOOST_THREAD_FWD_REF(Fp) f); + + template <class Rp, class Fp> + BOOST_THREAD_FUTURE<Rp> + make_future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f); +#endif // #if (!defined _MSC_VER || _MSC_VER >= 1400) +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + template<typename F, typename Rp, typename Fp> + struct future_deferred_continuation_shared_state; + template<typename F, typename Rp, typename Fp> + struct future_async_continuation_shared_state; + + template <class F, class Rp, class Fp> + BOOST_THREAD_FUTURE<Rp> + make_future_async_continuation_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); + + template <class F, class Rp, class Fp> + BOOST_THREAD_FUTURE<Rp> + make_future_deferred_continuation_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); +#endif +#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP + template<typename F, typename Rp> + struct future_unwrap_shared_state; + template <class F, class Rp> + inline BOOST_THREAD_FUTURE<Rp> + make_future_unwrap_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f); +#endif + } + + template <typename R> + class BOOST_THREAD_FUTURE : public detail::basic_future<R> + { + private: + typedef detail::basic_future<R> base_type; + typedef typename base_type::future_ptr future_ptr; + + friend class shared_future<R>; + friend class promise<R>; +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + template <typename, typename, typename> + friend struct detail::future_async_continuation_shared_state; + template <typename, typename, typename> + friend struct detail::future_deferred_continuation_shared_state; + + template <class F, class Rp, class Fp> + friend BOOST_THREAD_FUTURE<Rp> + detail::make_future_async_continuation_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); + + template <class F, class Rp, class Fp> + friend BOOST_THREAD_FUTURE<Rp> + detail::make_future_deferred_continuation_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); +#endif +#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP + template<typename F, typename Rp> + friend struct detail::future_unwrap_shared_state; + template <class F, class Rp> + friend BOOST_THREAD_FUTURE<Rp> + detail::make_future_unwrap_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f); +#endif +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + template <class> friend class packaged_task; // todo check if this works in windows +#else + friend class packaged_task<R>; +#endif + friend class detail::future_waiter; + + template <class Rp, class Fp> + friend BOOST_THREAD_FUTURE<Rp> + detail::make_future_async_shared_state(BOOST_THREAD_FWD_REF(Fp) f); + + template <class Rp, class Fp> + friend BOOST_THREAD_FUTURE<Rp> + detail::make_future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f); + + + typedef typename base_type::move_dest_type move_dest_type; + public: // when_all + + BOOST_THREAD_FUTURE(future_ptr a_future): + base_type(a_future) + { + } + + public: + BOOST_THREAD_MOVABLE_ONLY(BOOST_THREAD_FUTURE) + typedef future_state::state state; + typedef R value_type; // EXTENSION + + BOOST_CONSTEXPR BOOST_THREAD_FUTURE() {} + //BOOST_CONSTEXPR + BOOST_THREAD_FUTURE(exceptional_ptr const& ex): + base_type(ex) {} + + ~BOOST_THREAD_FUTURE() {} + + BOOST_THREAD_FUTURE(BOOST_THREAD_RV_REF(BOOST_THREAD_FUTURE) other) BOOST_NOEXCEPT: + base_type(boost::move(static_cast<base_type&>(BOOST_THREAD_RV(other)))) + { + } + inline BOOST_THREAD_FUTURE(BOOST_THREAD_RV_REF(BOOST_THREAD_FUTURE<BOOST_THREAD_FUTURE<R> >) other); // EXTENSION + + BOOST_THREAD_FUTURE& operator=(BOOST_THREAD_RV_REF(BOOST_THREAD_FUTURE) other) BOOST_NOEXCEPT + { + this->base_type::operator=(boost::move(static_cast<base_type&>(BOOST_THREAD_RV(other)))); + return *this; + } + + shared_future<R> share() + { + return shared_future<R>(::boost::move(*this)); + } + + void swap(BOOST_THREAD_FUTURE& other) + { + static_cast<base_type*>(this)->swap(other); + } + + // todo this function must be private and friendship provided to the internal users. + void set_async() + { + this->future_->set_async(); + } + // todo this function must be private and friendship provided to the internal users. + void set_deferred() + { + this->future_->set_deferred(); + } + bool run_if_is_deferred() { + return this->future_->run_if_is_deferred(); + } + bool run_if_is_deferred_or_ready() { + return this->future_->run_if_is_deferred_or_ready(); + } + // retrieving the value + move_dest_type get() + { + if(!this->future_) + { + boost::throw_exception(future_uninitialized()); + } + future_ptr fut_=this->future_; +#ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET + this->future_.reset(); +#endif + return fut_->get(); + } + + template <typename R2> + typename boost::disable_if< is_void<R2>, move_dest_type>::type + get_or(BOOST_THREAD_RV_REF(R2) v) + { + if(!this->future_) + { + boost::throw_exception(future_uninitialized()); + } + this->future_->wait(false); + future_ptr fut_=this->future_; +#ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET + this->future_.reset(); +#endif + if (fut_->has_value()) { + return fut_->get(); + } + else { + return boost::move(v); + } + } + + template <typename R2> + typename boost::disable_if< is_void<R2>, move_dest_type>::type + get_or(R2 const& v) // EXTENSION + { + if(!this->future_) + { + boost::throw_exception(future_uninitialized()); + } + this->future_->wait(false); + future_ptr fut_=this->future_; +#ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET + this->future_.reset(); +#endif + if (fut_->has_value()) { + return fut_->get(); + } + else { + return v; + } + } + +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + template<typename F> + inline BOOST_THREAD_FUTURE<typename boost::result_of<F(BOOST_THREAD_FUTURE)>::type> + then(BOOST_THREAD_FWD_REF(F) func); // EXTENSION + template<typename F> + inline BOOST_THREAD_FUTURE<typename boost::result_of<F(BOOST_THREAD_FUTURE)>::type> + then(launch policy, BOOST_THREAD_FWD_REF(F) func); // EXTENSION + #ifdef BOOST_THREAD_PROVIDES_EXECUTORS + template<typename Ex, typename F> + inline BOOST_THREAD_FUTURE<typename boost::result_of<F(BOOST_THREAD_FUTURE)>::type> + then(Ex& ex, BOOST_THREAD_FWD_REF(F) func); // EXTENSION + #endif + + template <typename R2> + inline typename boost::disable_if< is_void<R2>, BOOST_THREAD_FUTURE<R> >::type + fallback_to(BOOST_THREAD_RV_REF(R2) v); // EXTENSION + template <typename R2> + inline typename boost::disable_if< is_void<R2>, BOOST_THREAD_FUTURE<R> >::type + fallback_to(R2 const& v); // EXTENSION + +#endif + }; BOOST_THREAD_DCL_MOVABLE_BEG(T) BOOST_THREAD_FUTURE<T> BOOST_THREAD_DCL_MOVABLE_END + template <typename R2> + class BOOST_THREAD_FUTURE<BOOST_THREAD_FUTURE<R2> > : public detail::basic_future<BOOST_THREAD_FUTURE<R2> > + { + typedef BOOST_THREAD_FUTURE<R2> R; + + private: + typedef detail::basic_future<R> base_type; + typedef typename base_type::future_ptr future_ptr; + + friend class shared_future<R>; + friend class promise<R>; + #if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + template <typename, typename, typename> + friend struct detail::future_async_continuation_shared_state; + template <typename, typename, typename> + friend struct detail::future_deferred_continuation_shared_state; + + template <class F, class Rp, class Fp> + friend BOOST_THREAD_FUTURE<Rp> + detail::make_future_async_continuation_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); + + template <class F, class Rp, class Fp> + friend BOOST_THREAD_FUTURE<Rp> + detail::make_future_deferred_continuation_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); + #endif +#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP + template<typename F, typename Rp> + friend struct detail::future_unwrap_shared_state; + template <class F, class Rp> + friend BOOST_THREAD_FUTURE<Rp> + detail::make_future_unwrap_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f); +#endif + #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + template <class> friend class packaged_task; // todo check if this works in windows + #else + friend class packaged_task<R>; + #endif + friend class detail::future_waiter; + + template <class Rp, class Fp> + friend BOOST_THREAD_FUTURE<Rp> + detail::make_future_async_shared_state(BOOST_THREAD_FWD_REF(Fp) f); + + template <class Rp, class Fp> + friend BOOST_THREAD_FUTURE<Rp> + detail::make_future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f); + + typedef typename base_type::move_dest_type move_dest_type; + + BOOST_THREAD_FUTURE(future_ptr a_future): + base_type(a_future) + { + } + + public: + BOOST_THREAD_MOVABLE_ONLY(BOOST_THREAD_FUTURE) + typedef future_state::state state; + typedef R value_type; // EXTENSION + + BOOST_CONSTEXPR BOOST_THREAD_FUTURE() {} + //BOOST_CONSTEXPR + BOOST_THREAD_FUTURE(exceptional_ptr const& ex): + base_type(ex) {} + + ~BOOST_THREAD_FUTURE() {} + + BOOST_THREAD_FUTURE(BOOST_THREAD_RV_REF(BOOST_THREAD_FUTURE) other) BOOST_NOEXCEPT: + base_type(boost::move(static_cast<base_type&>(BOOST_THREAD_RV(other)))) + { + } + + BOOST_THREAD_FUTURE& operator=(BOOST_THREAD_RV_REF(BOOST_THREAD_FUTURE) other) BOOST_NOEXCEPT + { + this->base_type::operator=(boost::move(static_cast<base_type&>(BOOST_THREAD_RV(other)))); + return *this; + } + + shared_future<R> share() + { + return shared_future<R>(::boost::move(*this)); + } + + void swap(BOOST_THREAD_FUTURE& other) + { + static_cast<base_type*>(this)->swap(other); + } + + // todo this function must be private and friendship provided to the internal users. + void set_async() + { + this->future_->set_async(); + } + // todo this function must be private and friendship provided to the internal users. + void set_deferred() + { + this->future_->set_deferred(); + } + bool run_if_is_deferred() { + return this->future_->run_if_is_deferred(); + } + bool run_if_is_deferred_or_ready() { + return this->future_->run_if_is_deferred_or_ready(); + } + // retrieving the value + move_dest_type get() + { + if(!this->future_) + { + boost::throw_exception(future_uninitialized()); + } + future_ptr fut_=this->future_; + #ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET + this->future_.reset(); + #endif + return fut_->get(); + } + move_dest_type get_or(BOOST_THREAD_RV_REF(R) v) // EXTENSION + { + if(!this->future_) + { + boost::throw_exception(future_uninitialized()); + } + this->future_->wait(false); + future_ptr fut_=this->future_; + #ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET + this->future_.reset(); + #endif + if (fut_->has_value()) return fut_->get(); + else return boost::move(v); + } + + move_dest_type get_or(R const& v) // EXTENSION + { + if(!this->future_) + { + boost::throw_exception(future_uninitialized()); + } + this->future_->wait(false); + future_ptr fut_=this->future_; + #ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET + this->future_.reset(); + #endif + if (fut_->has_value()) return fut_->get(); + else return v; + } + + + #if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + template<typename F> + inline BOOST_THREAD_FUTURE<typename boost::result_of<F(BOOST_THREAD_FUTURE)>::type> + then(BOOST_THREAD_FWD_REF(F) func); // EXTENSION + template<typename F> + inline BOOST_THREAD_FUTURE<typename boost::result_of<F(BOOST_THREAD_FUTURE)>::type> + then(launch policy, BOOST_THREAD_FWD_REF(F) func); // EXTENSION + #ifdef BOOST_THREAD_PROVIDES_EXECUTORS + template<typename Ex, typename F> + inline BOOST_THREAD_FUTURE<typename boost::result_of<F(BOOST_THREAD_FUTURE)>::type> + then(Ex &ex, BOOST_THREAD_FWD_REF(F) func); // EXTENSION + #endif + #endif + + #if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP + inline + BOOST_THREAD_FUTURE<R2> + unwrap(); // EXTENSION + #endif + + }; + template <typename R> - class shared_future + class shared_future : public detail::basic_future<R> { - typedef boost::shared_ptr<detail::future_object<R> > future_ptr; - - future_ptr future_; + typedef detail::basic_future<R> base_type; + typedef typename base_type::future_ptr future_ptr; friend class detail::future_waiter; friend class promise<R>; - friend class packaged_task<R>; +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + template <typename, typename, typename> + friend struct detail::future_async_continuation_shared_state; + template <typename, typename, typename> + friend struct detail::future_deferred_continuation_shared_state; + + template <class F, class Rp, class Fp> + friend BOOST_THREAD_FUTURE<Rp> + detail::make_future_async_continuation_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); + + template <class F, class Rp, class Fp> + friend BOOST_THREAD_FUTURE<Rp> + detail::make_future_deferred_continuation_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); +#endif +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + template <class> friend class packaged_task;// todo check if this works in windows +#else + friend class packaged_task<R>; +#endif shared_future(future_ptr a_future): - future_(a_future) + base_type(a_future) {} public: - BOOST_THREAD_MOVABLE(shared_future) + BOOST_THREAD_COPYABLE_AND_MOVABLE(shared_future) + typedef R value_type; // EXTENSION shared_future(shared_future const& other): - future_(other.future_) + base_type(other) {} typedef future_state::state state; - shared_future() + BOOST_CONSTEXPR shared_future() {} - + //BOOST_CONSTEXPR + shared_future(exceptional_ptr const& ex): + base_type(ex) {} ~shared_future() {} - shared_future& operator=(shared_future const& other) + shared_future& operator=(BOOST_THREAD_COPY_ASSIGN_REF(shared_future) other) { - future_=other.future_; + shared_future(other).swap(*this); return *this; } + shared_future(BOOST_THREAD_RV_REF(shared_future) other) BOOST_NOEXCEPT : - future_(BOOST_THREAD_RV(other).future_) + base_type(boost::move(static_cast<base_type&>(BOOST_THREAD_RV(other)))) { BOOST_THREAD_RV(other).future_.reset(); } - shared_future(BOOST_THREAD_RV_REF_BEG BOOST_THREAD_FUTURE<R> BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT : - future_(BOOST_THREAD_RV(other).future_) + shared_future(BOOST_THREAD_RV_REF( BOOST_THREAD_FUTURE<R> ) other) BOOST_NOEXCEPT : + base_type(boost::move(static_cast<base_type&>(BOOST_THREAD_RV(other)))) { - BOOST_THREAD_RV(other).future_.reset(); } + shared_future& operator=(BOOST_THREAD_RV_REF(shared_future) other) BOOST_NOEXCEPT { - future_.swap(BOOST_THREAD_RV(other).future_); - BOOST_THREAD_RV(other).future_.reset(); + base_type::operator=(boost::move(static_cast<base_type&>(BOOST_THREAD_RV(other)))); return *this; } - shared_future& operator=(BOOST_THREAD_RV_REF_BEG BOOST_THREAD_FUTURE<R> BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT + shared_future& operator=(BOOST_THREAD_RV_REF( BOOST_THREAD_FUTURE<R> ) other) BOOST_NOEXCEPT { - future_.swap(BOOST_THREAD_RV(other).future_); - BOOST_THREAD_RV(other).future_.reset(); + base_type::operator=(boost::move(static_cast<base_type&>(BOOST_THREAD_RV(other)))); return *this; } void swap(shared_future& other) BOOST_NOEXCEPT { - future_.swap(other.future_); + static_cast<base_type*>(this)->swap(other); + } + bool run_if_is_deferred() { + return this->future_->run_if_is_deferred(); + } + bool run_if_is_deferred_or_ready() { + return this->future_->run_if_is_deferred_or_ready(); } - // retrieving the value - typename detail::future_object<R>::shared_future_get_result_type get() + typename detail::shared_state<R>::shared_future_get_result_type get() { - if(!future_) + if(!this->future_) { boost::throw_exception(future_uninitialized()); } + return this->future_->get_sh(); + } - return future_->get_sh(); + template <typename R2> + typename boost::disable_if< is_void<R2>, typename detail::shared_state<R>::shared_future_get_result_type>::type + get_or(BOOST_THREAD_RV_REF(R2) v) // EXTENSION + { + if(!this->future_) + { + boost::throw_exception(future_uninitialized()); + } + future_ptr fut_=this->future_; + fut_->wait(); + if (fut_->has_value()) return fut_->get_sh(); + else return boost::move(v); } - // functions to check state, and wait for ready - state get_state() const BOOST_NOEXCEPT +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + template<typename F> + inline BOOST_THREAD_FUTURE<typename boost::result_of<F(shared_future)>::type> + then(BOOST_THREAD_FWD_REF(F) func) const; // EXTENSION + template<typename F> + inline BOOST_THREAD_FUTURE<typename boost::result_of<F(shared_future)>::type> + then(launch policy, BOOST_THREAD_FWD_REF(F) func) const; // EXTENSION + #ifdef BOOST_THREAD_PROVIDES_EXECUTORS + template<typename Ex, typename F> + inline BOOST_THREAD_FUTURE<typename boost::result_of<F(shared_future)>::type> + then(Ex& ex, BOOST_THREAD_FWD_REF(F) func) const; // EXTENSION + #endif +#endif + + }; + + BOOST_THREAD_DCL_MOVABLE_BEG(T) shared_future<T> BOOST_THREAD_DCL_MOVABLE_END + + namespace detail + { + /// Copy construction from a shared_future + template <typename R> + inline basic_future<R>::basic_future(const shared_future<R>& other) BOOST_NOEXCEPT + : future_(other.future_) + { + } + } + + template <typename R> + class promise + { + typedef boost::shared_ptr<detail::shared_state<R> > future_ptr; + + typedef typename detail::shared_state<R>::source_reference_type source_reference_type; + typedef typename detail::shared_state<R>::rvalue_source_type rvalue_source_type; + typedef typename detail::shared_state<R>::move_dest_type move_dest_type; + typedef typename detail::shared_state<R>::shared_future_get_result_type shared_future_get_result_type; + + future_ptr future_; + bool future_obtained; + + void lazy_init() { - if(!future_) +#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY +#include <boost/detail/atomic_undef_macros.hpp> + if(!atomic_load(&future_)) { - return future_state::uninitialized; + future_ptr blank; + atomic_compare_exchange(&future_,&blank,future_ptr(new detail::shared_state<R>)); } - return future_->get_state(); +#include <boost/detail/atomic_redef_macros.hpp> +#endif } - bool valid() const BOOST_NOEXCEPT + public: + BOOST_THREAD_MOVABLE_ONLY(promise) +#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS + template <class Allocator> + promise(boost::allocator_arg_t, Allocator a) { - return future_ != 0; + typedef typename Allocator::template rebind<detail::shared_state<R> >::other A2; + A2 a2(a); + typedef thread_detail::allocator_destructor<A2> D; + + future_ = future_ptr(::new(a2.allocate(1)) detail::shared_state<R>(), D(a2, 1) ); + future_obtained = false; } +#endif + promise(): +#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY + future_(), +#else + future_(new detail::shared_state<R>()), +#endif + future_obtained(false) + {} - bool is_ready() const BOOST_NOEXCEPT + ~promise() { - return get_state()==future_state::ready; + if(future_) + { + boost::unique_lock<boost::mutex> lock(future_->mutex); + + if(!future_->done && !future_->is_constructed) + { + future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise()), lock); + } + } } - bool has_exception() const BOOST_NOEXCEPT + // Assignment + promise(BOOST_THREAD_RV_REF(promise) rhs) BOOST_NOEXCEPT : + future_(BOOST_THREAD_RV(rhs).future_),future_obtained(BOOST_THREAD_RV(rhs).future_obtained) { - return future_ && future_->has_exception(); + BOOST_THREAD_RV(rhs).future_.reset(); + BOOST_THREAD_RV(rhs).future_obtained=false; + } + promise & operator=(BOOST_THREAD_RV_REF(promise) rhs) BOOST_NOEXCEPT + { + future_=BOOST_THREAD_RV(rhs).future_; + future_obtained=BOOST_THREAD_RV(rhs).future_obtained; + BOOST_THREAD_RV(rhs).future_.reset(); + BOOST_THREAD_RV(rhs).future_obtained=false; + return *this; } - bool has_value() const BOOST_NOEXCEPT + void swap(promise& other) { - return future_ && future_->has_value(); + future_.swap(other.future_); + std::swap(future_obtained,other.future_obtained); } - void wait() const + // Result retrieval + BOOST_THREAD_FUTURE<R> get_future() { - if(!future_) + lazy_init(); + if (future_.get()==0) { - boost::throw_exception(future_uninitialized()); + boost::throw_exception(promise_moved()); } - future_->wait(false); + if (future_obtained) + { + boost::throw_exception(future_already_retrieved()); + } + future_obtained=true; + return BOOST_THREAD_FUTURE<R>(future_); } - template<typename Duration> - bool timed_wait(Duration const& rel_time) const +#if defined BOOST_NO_CXX11_RVALUE_REFERENCES + template <class TR> + typename boost::enable_if_c<is_copy_constructible<TR>::value && is_same<R, TR>::value, void>::type set_value(TR const & r) { - return timed_wait_until(boost::get_system_time()+rel_time); + lazy_init(); + boost::unique_lock<boost::mutex> lock(future_->mutex); + if(future_->done) + { + boost::throw_exception(promise_already_satisfied()); + } + future_->mark_finished_with_result_internal(r, lock); } - - bool timed_wait_until(boost::system_time const& abs_time) const +#else + void set_value(source_reference_type r) { - if(!future_) + lazy_init(); + boost::unique_lock<boost::mutex> lock(future_->mutex); + if(future_->done) { - boost::throw_exception(future_uninitialized()); + boost::throw_exception(promise_already_satisfied()); } - return future_->timed_wait_until(abs_time); + future_->mark_finished_with_result_internal(r, lock); } -#ifdef BOOST_THREAD_USES_CHRONO +#endif - template <class Rep, class Period> - future_status - wait_for(const chrono::duration<Rep, Period>& rel_time) const + void set_value(rvalue_source_type r) { - return wait_until(chrono::steady_clock::now() + rel_time); - + lazy_init(); + boost::unique_lock<boost::mutex> lock(future_->mutex); + if(future_->done) + { + boost::throw_exception(promise_already_satisfied()); + } +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + future_->mark_finished_with_result_internal(boost::move(r), lock); +#else + future_->mark_finished_with_result_internal(static_cast<rvalue_source_type>(r), lock); +#endif } - template <class Clock, class Duration> - future_status - wait_until(const chrono::time_point<Clock, Duration>& abs_time) const + void set_exception(boost::exception_ptr p) { - if(!future_) + lazy_init(); + boost::unique_lock<boost::mutex> lock(future_->mutex); + if(future_->done) + { + boost::throw_exception(promise_already_satisfied()); + } + future_->mark_exceptional_finish_internal(p, lock); + } + template <typename E> + void set_exception(E ex) + { + set_exception(boost::copy_exception(ex)); + } + // setting the result with deferred notification +#if defined BOOST_NO_CXX11_RVALUE_REFERENCES + template <class TR> + typename boost::enable_if_c<is_copy_constructible<TR>::value && is_same<R, TR>::value, void>::type set_value_at_thread_exit(TR const& r) + { + if (future_.get()==0) { - boost::throw_exception(future_uninitialized()); + boost::throw_exception(promise_moved()); } - return future_->wait_until(abs_time); + future_->set_value_at_thread_exit(r); + } +#else + void set_value_at_thread_exit(source_reference_type r) + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_value_at_thread_exit(r); } #endif - }; + void set_value_at_thread_exit(BOOST_THREAD_RV_REF(R) r) + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_value_at_thread_exit(boost::move(r)); + } + void set_exception_at_thread_exit(exception_ptr e) + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_exception_at_thread_exit(e); + } + template <typename E> + void set_exception_at_thread_exit(E ex) + { + set_exception_at_thread_exit(boost::copy_exception(ex)); + } - BOOST_THREAD_DCL_MOVABLE_BEG(T) shared_future<T> BOOST_THREAD_DCL_MOVABLE_END + template<typename F> + void set_wait_callback(F f) + { + lazy_init(); + future_->set_wait_callback(f,this); + } + + }; template <typename R> - class promise + class promise<R&> { - typedef boost::shared_ptr<detail::future_object<R> > future_ptr; + typedef boost::shared_ptr<detail::shared_state<R&> > future_ptr; future_ptr future_; bool future_obtained; void lazy_init() { -#if defined BOOST_THREAD_PROMISE_LAZY +#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY +#include <boost/detail/atomic_undef_macros.hpp> if(!atomic_load(&future_)) { future_ptr blank; - atomic_compare_exchange(&future_,&blank,future_ptr(new detail::future_object<R>)); + atomic_compare_exchange(&future_,&blank,future_ptr(new detail::shared_state<R&>)); } +#include <boost/detail/atomic_redef_macros.hpp> #endif } @@ -1117,19 +2171,19 @@ namespace boost template <class Allocator> promise(boost::allocator_arg_t, Allocator a) { - typedef typename Allocator::template rebind<detail::future_object<R> >::other A2; + typedef typename Allocator::template rebind<detail::shared_state<R&> >::other A2; A2 a2(a); typedef thread_detail::allocator_destructor<A2> D; - future_ = future_ptr(::new(a2.allocate(1)) detail::future_object<R>(), D(a2, 1) ); + future_ = future_ptr(::new(a2.allocate(1)) detail::shared_state<R&>(), D(a2, 1) ); future_obtained = false; } #endif promise(): -#if defined BOOST_THREAD_PROMISE_LAZY +#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY future_(), #else - future_(new detail::future_object<R>()), + future_(new detail::shared_state<R&>()), #endif future_obtained(false) {} @@ -1138,11 +2192,11 @@ namespace boost { if(future_) { - boost::lock_guard<boost::mutex> lock(future_->mutex); + boost::unique_lock<boost::mutex> lock(future_->mutex); - if(!future_->done) + if(!future_->done && !future_->is_constructed) { - future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise())); + future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise()), lock); } } } @@ -1170,7 +2224,7 @@ namespace boost } // Result retrieval - BOOST_THREAD_FUTURE<R> get_future() + BOOST_THREAD_FUTURE<R&> get_future() { lazy_init(); if (future_.get()==0) @@ -1182,41 +2236,58 @@ namespace boost boost::throw_exception(future_already_retrieved()); } future_obtained=true; - return BOOST_THREAD_FUTURE<R>(future_); + return BOOST_THREAD_FUTURE<R&>(future_); } - void set_value(typename detail::future_traits<R>::source_reference_type r) + void set_value(R& r) { lazy_init(); - boost::lock_guard<boost::mutex> lock(future_->mutex); + boost::unique_lock<boost::mutex> lock(future_->mutex); if(future_->done) { boost::throw_exception(promise_already_satisfied()); } - future_->mark_finished_with_result_internal(r); + future_->mark_finished_with_result_internal(r, lock); } -// void set_value(R && r); - void set_value(typename detail::future_traits<R>::rvalue_source_type r) + void set_exception(boost::exception_ptr p) { lazy_init(); - boost::lock_guard<boost::mutex> lock(future_->mutex); + boost::unique_lock<boost::mutex> lock(future_->mutex); if(future_->done) { boost::throw_exception(promise_already_satisfied()); } - future_->mark_finished_with_result_internal(static_cast<typename detail::future_traits<R>::rvalue_source_type>(r)); + future_->mark_exceptional_finish_internal(p, lock); + } + template <typename E> + void set_exception(E ex) + { + set_exception(boost::copy_exception(ex)); } - void set_exception(boost::exception_ptr p) + // setting the result with deferred notification + void set_value_at_thread_exit(R& r) { - lazy_init(); - boost::lock_guard<boost::mutex> lock(future_->mutex); - if(future_->done) - { - boost::throw_exception(promise_already_satisfied()); - } - future_->mark_exceptional_finish_internal(p); + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_value_at_thread_exit(r); + } + + void set_exception_at_thread_exit(exception_ptr e) + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_exception_at_thread_exit(e); + } + template <typename E> + void set_exception_at_thread_exit(E ex) + { + set_exception_at_thread_exit(boost::copy_exception(ex)); } template<typename F> @@ -1225,24 +2296,23 @@ namespace boost lazy_init(); future_->set_wait_callback(f,this); } - }; template <> class promise<void> { - typedef boost::shared_ptr<detail::future_object<void> > future_ptr; + typedef boost::shared_ptr<detail::shared_state<void> > future_ptr; future_ptr future_; bool future_obtained; void lazy_init() { -#if defined BOOST_THREAD_PROMISE_LAZY +#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY if(!atomic_load(&future_)) { future_ptr blank; - atomic_compare_exchange(&future_,&blank,future_ptr(new detail::future_object<void>)); + atomic_compare_exchange(&future_,&blank,future_ptr(new detail::shared_state<void>)); } #endif } @@ -1253,19 +2323,19 @@ namespace boost template <class Allocator> promise(boost::allocator_arg_t, Allocator a) { - typedef typename Allocator::template rebind<detail::future_object<void> >::other A2; + typedef typename Allocator::template rebind<detail::shared_state<void> >::other A2; A2 a2(a); typedef thread_detail::allocator_destructor<A2> D; - future_ = future_ptr(::new(a2.allocate(1)) detail::future_object<void>(), D(a2, 1) ); + future_ = future_ptr(::new(a2.allocate(1)) detail::shared_state<void>(), D(a2, 1) ); future_obtained = false; } #endif promise(): -#if defined BOOST_THREAD_PROMISE_LAZY +#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY future_(), #else - future_(new detail::future_object<void>), + future_(new detail::shared_state<void>), #endif future_obtained(false) {} @@ -1274,11 +2344,11 @@ namespace boost { if(future_) { - boost::lock_guard<boost::mutex> lock(future_->mutex); + boost::unique_lock<boost::mutex> lock(future_->mutex); - if(!future_->done) + if(!future_->done && !future_->is_constructed) { - future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise())); + future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise()), lock); } } } @@ -1321,29 +2391,59 @@ namespace boost boost::throw_exception(future_already_retrieved()); } future_obtained=true; + //return BOOST_THREAD_MAKE_RV_REF(BOOST_THREAD_FUTURE<void>(future_)); return BOOST_THREAD_FUTURE<void>(future_); } void set_value() { lazy_init(); - boost::lock_guard<boost::mutex> lock(future_->mutex); + boost::unique_lock<boost::mutex> lock(future_->mutex); if(future_->done) { boost::throw_exception(promise_already_satisfied()); } - future_->mark_finished_with_result_internal(); + future_->mark_finished_with_result_internal(lock); } void set_exception(boost::exception_ptr p) { lazy_init(); - boost::lock_guard<boost::mutex> lock(future_->mutex); + boost::unique_lock<boost::mutex> lock(future_->mutex); if(future_->done) { boost::throw_exception(promise_already_satisfied()); } - future_->mark_exceptional_finish_internal(p); + future_->mark_exceptional_finish_internal(p,lock); + } + template <typename E> + void set_exception(E ex) + { + set_exception(boost::copy_exception(ex)); + } + + // setting the result with deferred notification + void set_value_at_thread_exit() + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_value_at_thread_exit(); + } + + void set_exception_at_thread_exit(exception_ptr e) + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_exception_at_thread_exit(e); + } + template <typename E> + void set_exception_at_thread_exit(E ex) + { + set_exception_at_thread_exit(boost::copy_exception(ex)); } template<typename F> @@ -1354,28 +2454,50 @@ namespace boost } }; - +} #if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS - namespace container +namespace boost { namespace container { + template <class R, class Alloc> + struct uses_allocator< ::boost::promise<R> , Alloc> : true_type { - template <class R, class Alloc> - struct uses_allocator<promise<R> , Alloc> : true_type - { - }; - } + }; +}} +#if ! defined BOOST_NO_CXX11_ALLOCATOR +namespace std { + template <class R, class Alloc> + struct uses_allocator< ::boost::promise<R> , Alloc> : true_type + { + }; +} #endif +#endif + +namespace boost +{ BOOST_THREAD_DCL_MOVABLE_BEG(T) promise<T> BOOST_THREAD_DCL_MOVABLE_END namespace detail { - template<typename R> - struct task_base: - detail::future_object<R> +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + template<typename R> + struct task_base_shared_state; +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template<typename R, typename ...ArgTypes> + struct task_base_shared_state<R(ArgTypes...)>: +#else + template<typename R> + struct task_base_shared_state<R()>: +#endif +#else + template<typename R> + struct task_base_shared_state: +#endif + detail::shared_state<R> { bool started; - task_base(): + task_base_shared_state(): started(false) {} @@ -1383,7 +2505,13 @@ namespace boost { started=false; } +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + virtual void do_run(BOOST_THREAD_RV_REF(ArgTypes) ... args)=0; + void run(BOOST_THREAD_RV_REF(ArgTypes) ... args) +#else + virtual void do_run()=0; void run() +#endif { { boost::lock_guard<boost::mutex> lk(this->mutex); @@ -1393,54 +2521,212 @@ namespace boost } started=true; } +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + do_run(boost::move(args)...); +#else do_run(); +#endif + } + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + virtual void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args)=0; + void apply(BOOST_THREAD_RV_REF(ArgTypes) ... args) +#else + virtual void do_apply()=0; + void apply() +#endif + { + { + boost::lock_guard<boost::mutex> lk(this->mutex); + if(started) + { + boost::throw_exception(task_already_started()); + } + started=true; + } +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + do_apply(boost::move(args)...); +#else + do_apply(); +#endif } void owner_destroyed() { - boost::lock_guard<boost::mutex> lk(this->mutex); + boost::unique_lock<boost::mutex> lk(this->mutex); if(!started) { started=true; - this->mark_exceptional_finish_internal(boost::copy_exception(boost::broken_promise())); + this->mark_exceptional_finish_internal(boost::copy_exception(boost::broken_promise()), lk); } } - - - virtual void do_run()=0; }; - - template<typename R,typename F> - struct task_object: - task_base<R> +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + template<typename F, typename R> + struct task_shared_state; +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template<typename F, typename R, typename ...ArgTypes> + struct task_shared_state<F, R(ArgTypes...)>: + task_base_shared_state<R(ArgTypes...)> +#else + template<typename F, typename R> + struct task_shared_state<F, R()>: + task_base_shared_state<R()> +#endif +#else + template<typename F, typename R> + struct task_shared_state: + task_base_shared_state<R> +#endif { private: - task_object(task_object&); + task_shared_state(task_shared_state&); public: F f; - task_object(F const& f_): + task_shared_state(F const& f_): f(f_) {} -#ifndef BOOST_NO_RVALUE_REFERENCES - task_object(BOOST_THREAD_RV_REF(F) f_): - f(boost::forward<F>(f_)) + task_shared_state(BOOST_THREAD_RV_REF(F) f_): + f(boost::move(f_)) {} + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + this->set_value_at_thread_exit(f(boost::move(args)...)); + } +#else + void do_apply() + { + try + { + this->set_value_at_thread_exit(f()); + } +#endif +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + catch(thread_interrupted& ) + { + this->set_interrupted_at_thread_exit(); + } +#endif + catch(...) + { + this->set_exception_at_thread_exit(current_exception()); + } + } + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_run(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + this->mark_finished_with_result(f(boost::move(args)...)); + } +#else + void do_run() + { + try + { +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + R res((f())); + this->mark_finished_with_result(boost::move(res)); #else - task_object(BOOST_THREAD_RV_REF(F) f_): + this->mark_finished_with_result(f()); +#endif + } +#endif +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + catch(thread_interrupted& ) + { + this->mark_interrupted_finish(); + } +#endif + catch(...) + { + this->mark_exceptional_finish(); + } + } + }; + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template<typename F, typename R, typename ...ArgTypes> + struct task_shared_state<F, R&(ArgTypes...)>: + task_base_shared_state<R&(ArgTypes...)> +#else + template<typename F, typename R> + struct task_shared_state<F, R&()>: + task_base_shared_state<R&()> +#endif +#else + template<typename F, typename R> + struct task_shared_state<F,R&>: + task_base_shared_state<R&> +#endif + { + private: + task_shared_state(task_shared_state&); + public: + F f; + task_shared_state(F const& f_): + f(f_) + {} + task_shared_state(BOOST_THREAD_RV_REF(F) f_): f(boost::move(f_)) {} + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + this->set_value_at_thread_exit(f(boost::move(args)...)); + } +#else + void do_apply() + { + try + { + this->set_value_at_thread_exit(f()); + } #endif +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + catch(thread_interrupted& ) + { + this->set_interrupted_at_thread_exit(); + } +#endif + catch(...) + { + this->set_exception_at_thread_exit(current_exception()); + } + } + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_run(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + this->mark_finished_with_result(f(boost::move(args)...)); + } +#else void do_run() { try { - this->mark_finished_with_result(f()); + R& res((f())); + this->mark_finished_with_result(res); } +#endif +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS catch(thread_interrupted& ) { this->mark_interrupted_finish(); } +#endif catch(...) { this->mark_exceptional_finish(); @@ -1448,38 +2734,258 @@ namespace boost } }; +#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR) + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template<typename R, typename ...ArgTypes> + struct task_shared_state<R (*)(ArgTypes...), R(ArgTypes...)>: + task_base_shared_state<R(ArgTypes...)> +#else + template<typename R> + struct task_shared_state<R (*)(), R()>: + task_base_shared_state<R()> +#endif +#else + template<typename R> + struct task_shared_state<R (*)(), R> : + task_base_shared_state<R> +#endif + { + private: + task_shared_state(task_shared_state&); + public: +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + R (*f)(BOOST_THREAD_RV_REF(ArgTypes) ... ); + task_shared_state(R (*f_)(BOOST_THREAD_RV_REF(ArgTypes) ... )): + f(f_) + {} +#else + R (*f)(); + task_shared_state(R (*f_)()): + f(f_) + {} +#endif + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + this->set_value_at_thread_exit(f(boost::move(args)...)); + } +#else + void do_apply() + { + try + { + R r((f())); + this->set_value_at_thread_exit(boost::move(r)); + } +#endif +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + catch(thread_interrupted& ) + { + this->set_interrupted_at_thread_exit(); + } +#endif + catch(...) + { + this->set_exception_at_thread_exit(current_exception()); + } + } + + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_run(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + this->mark_finished_with_result(f(boost::move(args)...)); + } +#else + void do_run() + { + try + { + R res((f())); + this->mark_finished_with_result(boost::move(res)); + } +#endif +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + catch(thread_interrupted& ) + { + this->mark_interrupted_finish(); + } +#endif + catch(...) + { + this->mark_exceptional_finish(); + } + } + }; +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template<typename R, typename ...ArgTypes> + struct task_shared_state<R& (*)(ArgTypes...), R&(ArgTypes...)>: + task_base_shared_state<R&(ArgTypes...)> +#else + template<typename R> + struct task_shared_state<R& (*)(), R&()>: + task_base_shared_state<R&()> +#endif +#else + template<typename R> + struct task_shared_state<R& (*)(), R&> : + task_base_shared_state<R&> +#endif + { + private: + task_shared_state(task_shared_state&); + public: +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + R& (*f)(BOOST_THREAD_RV_REF(ArgTypes) ... ); + task_shared_state(R& (*f_)(BOOST_THREAD_RV_REF(ArgTypes) ... )): + f(f_) + {} +#else + R& (*f)(); + task_shared_state(R& (*f_)()): + f(f_) + {} +#endif + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + this->set_value_at_thread_exit(f(boost::move(args)...)); + } +#else + void do_apply() + { + try + { + this->set_value_at_thread_exit(f()); + } +#endif +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + catch(thread_interrupted& ) + { + this->set_interrupted_at_thread_exit(); + } +#endif + catch(...) + { + this->set_exception_at_thread_exit(current_exception()); + } + } + + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_run(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + this->mark_finished_with_result(f(boost::move(args)...)); + } +#else + void do_run() + { + try + { + this->mark_finished_with_result(f()); + } +#endif +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + catch(thread_interrupted& ) + { + this->mark_interrupted_finish(); + } +#endif + catch(...) + { + this->mark_exceptional_finish(); + } + } + }; +#endif +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template<typename F, typename ...ArgTypes> + struct task_shared_state<F, void(ArgTypes...)>: + task_base_shared_state<void(ArgTypes...)> +#else template<typename F> - struct task_object<void,F>: - task_base<void> + struct task_shared_state<F, void()>: + task_base_shared_state<void()> +#endif +#else + template<typename F> + struct task_shared_state<F,void>: + task_base_shared_state<void> +#endif { private: - task_object(task_object&); + task_shared_state(task_shared_state&); public: F f; - task_object(F const& f_): + task_shared_state(F const& f_): f(f_) {} -#ifndef BOOST_NO_RVALUE_REFERENCES - task_object(BOOST_THREAD_RV_REF(F) f_): - f(boost::forward<F>(f_)) - {} -#else - task_object(BOOST_THREAD_RV_REF(F) f_): + task_shared_state(BOOST_THREAD_RV_REF(F) f_): f(boost::move(f_)) {} + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + f(boost::move(args)...); +#else + void do_apply() + { + try + { + f(); #endif + this->set_value_at_thread_exit(); + } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + catch(thread_interrupted& ) + { + this->set_interrupted_at_thread_exit(); + } +#endif + catch(...) + { + this->set_exception_at_thread_exit(current_exception()); + } + } +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_run(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + f(boost::move(args)...); +#else void do_run() { try { f(); +#endif this->mark_finished_with_result(); } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS catch(thread_interrupted& ) { this->mark_interrupted_finish(); } +#endif catch(...) { this->mark_exceptional_finish(); @@ -1487,14 +2993,109 @@ namespace boost } }; +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template<typename ...ArgTypes> + struct task_shared_state<void (*)(ArgTypes...), void(ArgTypes...)>: + task_base_shared_state<void(ArgTypes...)> +#else + template<> + struct task_shared_state<void (*)(), void()>: + task_base_shared_state<void()> +#endif +#else + template<> + struct task_shared_state<void (*)(),void>: + task_base_shared_state<void> +#endif + { + private: + task_shared_state(task_shared_state&); + public: + void (*f)(); + task_shared_state(void (*f_)()): + f(f_) + {} + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + f(boost::move(args)...); +#else + void do_apply() + { + try + { + f(); +#endif + this->set_value_at_thread_exit(); + } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + catch(thread_interrupted& ) + { + this->set_interrupted_at_thread_exit(); + } +#endif + catch(...) + { + this->set_exception_at_thread_exit(current_exception()); + } + } + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_run(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + f(boost::move(args)...); +#else + void do_run() + { + try + { + f(); +#endif + this->mark_finished_with_result(); + } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + catch(thread_interrupted& ) + { + this->mark_interrupted_finish(); + } +#endif + catch(...) + { + this->mark_exceptional_finish(); + } + } + }; } +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template<typename R, typename ...ArgTypes> + class packaged_task<R(ArgTypes...)> + { + typedef boost::shared_ptr<detail::task_base_shared_state<R(ArgTypes...)> > task_ptr; + boost::shared_ptr<detail::task_base_shared_state<R(ArgTypes...)> > task; + #else + template<typename R> + class packaged_task<R()> + { + typedef boost::shared_ptr<detail::task_base_shared_state<R()> > task_ptr; + boost::shared_ptr<detail::task_base_shared_state<R()> > task; + #endif +#else template<typename R> class packaged_task { - typedef boost::shared_ptr<detail::task_base<R> > task_ptr; - boost::shared_ptr<detail::task_base<R> > task; + typedef boost::shared_ptr<detail::task_base_shared_state<R> > task_ptr; + boost::shared_ptr<detail::task_base_shared_state<R> > task; +#endif bool future_obtained; + struct dummy; public: typedef R result_type; @@ -1505,198 +3106,2078 @@ namespace boost {} // construction and destruction +#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR) - explicit packaged_task(R(*f)()): - task(new detail::task_object<R,R(*)()>(f)),future_obtained(false) - {} -#ifndef BOOST_NO_RVALUE_REFERENCES +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + explicit packaged_task(R(*f)(), BOOST_THREAD_FWD_REF(ArgTypes)... args) + { + typedef R(*FR)(BOOST_THREAD_FWD_REF(ArgTypes)...); + typedef detail::task_shared_state<FR,R(ArgTypes...)> task_shared_state_type; + task= task_ptr(new task_shared_state_type(f, boost::move(args)...)); + future_obtained=false; + } + #else + explicit packaged_task(R(*f)()) + { + typedef R(*FR)(); + typedef detail::task_shared_state<FR,R()> task_shared_state_type; + task= task_ptr(new task_shared_state_type(f)); + future_obtained=false; + } + #endif +#else + explicit packaged_task(R(*f)()) + { + typedef R(*FR)(); + typedef detail::task_shared_state<FR,R> task_shared_state_type; + task= task_ptr(new task_shared_state_type(f)); + future_obtained=false; + } +#endif +#endif +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template <class F> - explicit packaged_task(BOOST_THREAD_RV_REF(F) f): - task(new detail::task_object<R, - typename remove_cv<typename remove_reference<F>::type>::type - >(boost::forward<F>(f))),future_obtained(false) - {} + explicit packaged_task(BOOST_THREAD_FWD_REF(F) f + , typename boost::disable_if<is_same<typename decay<F>::type, packaged_task>, dummy* >::type=0 + ) + { + typedef typename decay<F>::type FR; +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + typedef detail::task_shared_state<FR,R(ArgTypes...)> task_shared_state_type; + #else + typedef detail::task_shared_state<FR,R()> task_shared_state_type; + #endif +#else + typedef detail::task_shared_state<FR,R> task_shared_state_type; +#endif + task = task_ptr(new task_shared_state_type(boost::forward<F>(f))); + future_obtained = false; + + } + #else template <class F> - explicit packaged_task(F const& f): - task(new detail::task_object<R,F>(f)),future_obtained(false) - {} + explicit packaged_task(F const& f + , typename boost::disable_if<is_same<typename decay<F>::type, packaged_task>, dummy* >::type=0 + ) + { +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + typedef detail::task_shared_state<F,R(ArgTypes...)> task_shared_state_type; + #else + typedef detail::task_shared_state<F,R()> task_shared_state_type; + #endif +#else + typedef detail::task_shared_state<F,R> task_shared_state_type; +#endif + task = task_ptr(new task_shared_state_type(f)); + future_obtained=false; + } template <class F> - explicit packaged_task(BOOST_THREAD_RV_REF(F) f): - task(new detail::task_object<R,F>(boost::move(f))),future_obtained(false) - {} + explicit packaged_task(BOOST_THREAD_RV_REF(F) f) + { +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + typedef detail::task_shared_state<F,R(ArgTypes...)> task_shared_state_type; + task = task_ptr(new task_shared_state_type(boost::move(f))); +#else + typedef detail::task_shared_state<F,R()> task_shared_state_type; + task = task_ptr(new task_shared_state_type(boost::move(f))); +#endif +#else + typedef detail::task_shared_state<F,R> task_shared_state_type; + task = task_ptr(new task_shared_state_type(boost::move(f))); +#endif + future_obtained=false; + + } #endif #if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS +#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR) template <class Allocator> packaged_task(boost::allocator_arg_t, Allocator a, R(*f)()) { typedef R(*FR)(); - typedef typename Allocator::template rebind<detail::task_object<R,FR> >::other A2; +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + typedef detail::task_shared_state<FR,R(ArgTypes...)> task_shared_state_type; + #else + typedef detail::task_shared_state<FR,R()> task_shared_state_type; + #endif +#else + typedef detail::task_shared_state<FR,R> task_shared_state_type; +#endif + typedef typename Allocator::template rebind<task_shared_state_type>::other A2; A2 a2(a); typedef thread_detail::allocator_destructor<A2> D; - task = task_ptr(::new(a2.allocate(1)) detail::task_object<R,FR>(f), D(a2, 1) ); + task = task_ptr(::new(a2.allocate(1)) task_shared_state_type(f), D(a2, 1) ); future_obtained = false; } -#ifndef BOOST_NO_RVALUE_REFERENCES +#endif // BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR + +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES template <class F, class Allocator> - packaged_task(boost::allocator_arg_t, Allocator a, BOOST_THREAD_RV_REF(F) f) + packaged_task(boost::allocator_arg_t, Allocator a, BOOST_THREAD_FWD_REF(F) f) { - typedef typename remove_cv<typename remove_reference<F>::type>::type FR; - typedef typename Allocator::template rebind<detail::task_object<R,FR> >::other A2; + typedef typename decay<F>::type FR; + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + typedef detail::task_shared_state<FR,R(ArgTypes...)> task_shared_state_type; + #else + typedef detail::task_shared_state<FR,R()> task_shared_state_type; + #endif +#else + typedef detail::task_shared_state<FR,R> task_shared_state_type; +#endif + typedef typename Allocator::template rebind<task_shared_state_type>::other A2; A2 a2(a); typedef thread_detail::allocator_destructor<A2> D; - task = task_ptr(::new(a2.allocate(1)) detail::task_object<R,FR>(boost::forward<F>(f)), D(a2, 1) ); + task = task_ptr(::new(a2.allocate(1)) task_shared_state_type(boost::forward<F>(f)), D(a2, 1) ); future_obtained = false; } -#else +#else // ! defined BOOST_NO_CXX11_RVALUE_REFERENCES template <class F, class Allocator> packaged_task(boost::allocator_arg_t, Allocator a, const F& f) { - typedef typename Allocator::template rebind<detail::task_object<R,F> >::other A2; +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + typedef detail::task_shared_state<F,R(ArgTypes...)> task_shared_state_type; + #else + typedef detail::task_shared_state<F,R()> task_shared_state_type; + #endif +#else + typedef detail::task_shared_state<F,R> task_shared_state_type; +#endif + typedef typename Allocator::template rebind<task_shared_state_type>::other A2; A2 a2(a); typedef thread_detail::allocator_destructor<A2> D; - task = task_ptr(::new(a2.allocate(1)) detail::task_object<R,F>(f), D(a2, 1) ); + task = task_ptr(::new(a2.allocate(1)) task_shared_state_type(f), D(a2, 1) ); future_obtained = false; } template <class F, class Allocator> packaged_task(boost::allocator_arg_t, Allocator a, BOOST_THREAD_RV_REF(F) f) { - typedef typename Allocator::template rebind<detail::task_object<R,F> >::other A2; +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + typedef detail::task_shared_state<F,R(ArgTypes...)> task_shared_state_type; + #else + typedef detail::task_shared_state<F,R()> task_shared_state_type; + #endif +#else + typedef detail::task_shared_state<F,R> task_shared_state_type; +#endif + typedef typename Allocator::template rebind<task_shared_state_type>::other A2; A2 a2(a); typedef thread_detail::allocator_destructor<A2> D; - task = task_ptr(::new(a2.allocate(1)) detail::task_object<R,F>(boost::move(f)), D(a2, 1) ); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + task = task_ptr(::new(a2.allocate(1)) task_shared_state_type(boost::move(f)), D(a2, 1) ); +#else + task = task_ptr(::new(a2.allocate(1)) task_shared_state_type(boost::move(f)), D(a2, 1) ); +#endif future_obtained = false; } -#endif //BOOST_NO_RVALUE_REFERENCES + +#endif //BOOST_NO_CXX11_RVALUE_REFERENCES #endif // BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS - ~packaged_task() - { - if(task) - { + ~packaged_task() { + if(task) { task->owner_destroyed(); } } // assignment - packaged_task(BOOST_THREAD_RV_REF(packaged_task) other) BOOST_NOEXCEPT : - future_obtained(BOOST_THREAD_RV(other).future_obtained) - { + packaged_task(BOOST_THREAD_RV_REF(packaged_task) other) BOOST_NOEXCEPT + : future_obtained(BOOST_THREAD_RV(other).future_obtained) { task.swap(BOOST_THREAD_RV(other).task); BOOST_THREAD_RV(other).future_obtained=false; } - packaged_task& operator=(BOOST_THREAD_RV_REF(packaged_task) other) BOOST_NOEXCEPT - { + packaged_task& operator=(BOOST_THREAD_RV_REF(packaged_task) other) BOOST_NOEXCEPT { + +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + packaged_task temp(boost::move(other)); +#else packaged_task temp(static_cast<BOOST_THREAD_RV_REF(packaged_task)>(other)); +#endif swap(temp); return *this; } - void reset() - { + void reset() { if (!valid()) throw future_error(system::make_error_code(future_errc::no_state)); task->reset(); future_obtained=false; } - void swap(packaged_task& other) BOOST_NOEXCEPT - { + void swap(packaged_task& other) BOOST_NOEXCEPT { task.swap(other.task); std::swap(future_obtained,other.future_obtained); } - bool valid() const BOOST_NOEXCEPT - { + bool valid() const BOOST_NOEXCEPT { return task.get()!=0; } // result retrieval - BOOST_THREAD_FUTURE<R> get_future() - { - if(!task) - { + BOOST_THREAD_FUTURE<R> get_future() { + if(!task) { boost::throw_exception(task_moved()); - } - else if(!future_obtained) - { + } else if(!future_obtained) { future_obtained=true; return BOOST_THREAD_FUTURE<R>(task); - } - else - { + } else { boost::throw_exception(future_already_retrieved()); } - return BOOST_THREAD_FUTURE<R>(); - } - // execution - void operator()() - { - if(!task) - { +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void operator()(BOOST_THREAD_RV_REF(ArgTypes)... args) { + if(!task) { + boost::throw_exception(task_moved()); + } + task->run(boost::move(args)...); + } + void make_ready_at_thread_exit(ArgTypes... args) { + if(!task) { + boost::throw_exception(task_moved()); + } + if (task->has_value()) { + boost::throw_exception(promise_already_satisfied()); + } + task->apply(boost::move(args)...); + } +#else + void operator()() { + if(!task) { boost::throw_exception(task_moved()); } task->run(); } - + void make_ready_at_thread_exit() { + if(!task) { + boost::throw_exception(task_moved()); + } + if (task->has_value()) boost::throw_exception(promise_already_satisfied()); + task->apply(); + } +#endif template<typename F> - void set_wait_callback(F f) - { + void set_wait_callback(F f) { task->set_wait_callback(f,this); } + }; +} +#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS +namespace boost { namespace container { + template <class R, class Alloc> + struct uses_allocator< ::boost::packaged_task<R> , Alloc> : true_type + {}; +}} +#if ! defined BOOST_NO_CXX11_ALLOCATOR +namespace std { + template <class R, class Alloc> + struct uses_allocator< ::boost::packaged_task<R> , Alloc> : true_type + {}; +} +#endif +#endif + +namespace boost +{ + BOOST_THREAD_DCL_MOVABLE_BEG(T) packaged_task<T> BOOST_THREAD_DCL_MOVABLE_END + +namespace detail +{ + //////////////////////////////// + // make_future_deferred_shared_state + //////////////////////////////// + template <class Rp, class Fp> + BOOST_THREAD_FUTURE<Rp> + make_future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f) { + shared_ptr<future_deferred_shared_state<Rp, Fp> > + h(new future_deferred_shared_state<Rp, Fp>(boost::forward<Fp>(f))); + return BOOST_THREAD_FUTURE<Rp>(h); + } + + //////////////////////////////// + // make_future_async_shared_state + //////////////////////////////// + template <class Rp, class Fp> + BOOST_THREAD_FUTURE<Rp> + make_future_async_shared_state(BOOST_THREAD_FWD_REF(Fp) f) { + shared_ptr<future_async_shared_state<Rp, Fp> > + h(new future_async_shared_state<Rp, Fp>(boost::forward<Fp>(f))); + return BOOST_THREAD_FUTURE<Rp>(h); + } +} + + //////////////////////////////// + // template <class F, class... ArgTypes> + // future<R> async(launch policy, F&&, ArgTypes&&...); + //////////////////////////////// + +#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR + +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template <class R, class... ArgTypes> + BOOST_THREAD_FUTURE<R> + async(launch policy, R(*f)(BOOST_THREAD_FWD_REF(ArgTypes)...), BOOST_THREAD_FWD_REF(ArgTypes)... args) { + typedef R(*F)(BOOST_THREAD_FWD_REF(ArgTypes)...); + typedef detail::invoker<typename decay<F>::type, typename decay<ArgTypes>::type...> BF; + typedef typename BF::result_type Rp; + + if (underlying_cast<int>(policy) & int(launch::async)) { + return BOOST_THREAD_MAKE_RV_REF(boost::detail::make_future_async_shared_state<Rp>( + BF( + f + , thread_detail::decay_copy(boost::forward<ArgTypes>(args))... + ) + )); + } else if (underlying_cast<int>(policy) & int(launch::deferred)) { + return BOOST_THREAD_MAKE_RV_REF(boost::detail::make_future_deferred_shared_state<Rp>( + BF( + f + , thread_detail::decay_copy(boost::forward<ArgTypes>(args))... + ) + )); + } else { + std::terminate(); + BOOST_THREAD_FUTURE<R> ret; + return ::boost::move(ret); + } + } + +#else // defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + + template <class R> + BOOST_THREAD_FUTURE<R> + async(launch policy, R(*f)()) { + #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + typedef packaged_task<R()> packaged_task_type; + #else + typedef packaged_task<R> packaged_task_type; + #endif + + if (underlying_cast<int>(policy) & int(launch::async)) { + packaged_task_type pt( f ); + BOOST_THREAD_FUTURE<R> ret = BOOST_THREAD_MAKE_RV_REF(pt.get_future()); + ret.set_async(); + boost::thread( boost::move(pt) ).detach(); + return ::boost::move(ret); + } else if (underlying_cast<int>(policy) & int(launch::deferred)) { + std::terminate(); + BOOST_THREAD_FUTURE<R> ret; + return ::boost::move(ret); + } else { + std::terminate(); + BOOST_THREAD_FUTURE<R> ret; + return ::boost::move(ret); + } + } +#endif +#endif // defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR) + +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + + template <class F, class ...ArgTypes> + BOOST_THREAD_FUTURE<typename boost::result_of<typename decay<F>::type( + typename decay<ArgTypes>::type... + )>::type> + async(launch policy, BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(ArgTypes)... args) { + typedef typename boost::result_of<typename decay<F>::type( + typename decay<ArgTypes>::type... + )>::type R; + typedef detail::invoker<typename decay<F>::type, typename decay<ArgTypes>::type...> BF; + typedef typename BF::result_type Rp; + + if (underlying_cast<int>(policy) & int(launch::async)) { + return BOOST_THREAD_MAKE_RV_REF(boost::detail::make_future_async_shared_state<Rp>( + BF( + thread_detail::decay_copy(boost::forward<F>(f)) + , thread_detail::decay_copy(boost::forward<ArgTypes>(args))... + ) + )); + } else if (underlying_cast<int>(policy) & int(launch::deferred)) { + return BOOST_THREAD_MAKE_RV_REF(boost::detail::make_future_deferred_shared_state<Rp>( + BF( + thread_detail::decay_copy(boost::forward<F>(f)) + , thread_detail::decay_copy(boost::forward<ArgTypes>(args))... + ) + )); + } else { + std::terminate(); + BOOST_THREAD_FUTURE<R> ret; + return ::boost::move(ret); + } + } + +#else // defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + + template <class F> + BOOST_THREAD_FUTURE<typename boost::result_of<typename decay<F>::type()>::type> + async(launch policy, BOOST_THREAD_FWD_REF(F) f) { + typedef typename boost::result_of<typename decay<F>::type()>::type R; +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + typedef packaged_task<R()> packaged_task_type; +#else // defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + typedef packaged_task<R> packaged_task_type; +#endif // defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + + if (underlying_cast<int>(policy) & int(launch::async)) { + packaged_task_type pt( boost::forward<F>(f) ); + BOOST_THREAD_FUTURE<R> ret = pt.get_future(); + ret.set_async(); + boost::thread( boost::move(pt) ).detach(); + return ::boost::move(ret); + } else if (underlying_cast<int>(policy) & int(launch::deferred)) { + std::terminate(); + BOOST_THREAD_FUTURE<R> ret; + return ::boost::move(ret); + // return boost::detail::make_future_deferred_shared_state<Rp>( + // BF( + // thread_detail::decay_copy(boost::forward<F>(f)) + // ) + // ); + } else { + std::terminate(); + BOOST_THREAD_FUTURE<R> ret; + return ::boost::move(ret); + } + } +#endif // defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS +namespace detail { + ///////////////////////// + /// shared_state_nullary_task + ///////////////////////// + template<typename Rp, typename Fp> + struct shared_state_nullary_task + { + shared_state<Rp>* that; + Fp f_; + public: + shared_state_nullary_task(shared_state<Rp>* st, BOOST_THREAD_FWD_REF(Fp) f) + : that(st), f_(boost::move(f)) + {}; +#if ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + BOOST_THREAD_COPYABLE_AND_MOVABLE(shared_state_nullary_task) + shared_state_nullary_task(shared_state_nullary_task const& x) //BOOST_NOEXCEPT + : that(x.that), f_(x.f_) + {} + shared_state_nullary_task& operator=(BOOST_THREAD_COPY_ASSIGN_REF(shared_state_nullary_task) x) //BOOST_NOEXCEPT + { + if (this != &x) { + that=x.that; + f_=x.f_; + } + return *this; + } + // move + shared_state_nullary_task(BOOST_THREAD_RV_REF(shared_state_nullary_task) x) //BOOST_NOEXCEPT + : that(x.that), f_(boost::move(x.f_)) + { + x.that=0; + } + shared_state_nullary_task& operator=(BOOST_THREAD_RV_REF(shared_state_nullary_task) x) //BOOST_NOEXCEPT + { + if (this != &x) { + that=x.that; + f_=boost::move(x.f_); + x.that=0; + } + return *this; + } +#endif + void operator()() { + try { + that->mark_finished_with_result(f_()); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + } catch(thread_interrupted& ) { + that->mark_interrupted_finish(); +#endif // defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + } catch(...) { + that->mark_exceptional_finish(); + } + } }; -#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS - namespace container + template<typename Fp> + struct shared_state_nullary_task<void, Fp> + { + shared_state<void>* that; + Fp f_; + public: + shared_state_nullary_task(shared_state<void>* st, BOOST_THREAD_FWD_REF(Fp) f) + : that(st), f_(boost::move(f)) + {}; +#if ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + BOOST_THREAD_COPYABLE_AND_MOVABLE(shared_state_nullary_task) + shared_state_nullary_task(shared_state_nullary_task const& x) //BOOST_NOEXCEPT + : that(x.that), f_(x.f_) + {} + shared_state_nullary_task& operator=(BOOST_THREAD_COPY_ASSIGN_REF(shared_state_nullary_task) x) //BOOST_NOEXCEPT + { + if (this != &x) { + that=x.that; + f_=x.f_; + } + return *this; + } + // move + shared_state_nullary_task(BOOST_THREAD_RV_REF(shared_state_nullary_task) x) BOOST_NOEXCEPT + : that(x.that), f_(boost::move(x.f_)) + { + x.that=0; + } + shared_state_nullary_task& operator=(BOOST_THREAD_RV_REF(shared_state_nullary_task) x) BOOST_NOEXCEPT { + if (this != &x) { + that=x.that; + f_=boost::move(x.f_); + x.that=0; + } + return *this; + } +#endif + void operator()() { + try { + f_(); + that->mark_finished_with_result(); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + } catch(thread_interrupted& ) { + that->mark_interrupted_finish(); +#endif // defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + } catch(...) { + that->mark_exceptional_finish(); + } + } + }; + + template<typename Rp, typename Fp> + struct shared_state_nullary_task<Rp&, Fp> { - template <class R, class Alloc> - struct uses_allocator<packaged_task<R>, Alloc> - : public true_type {}; + shared_state<Rp&>* that; + Fp f_; + public: + shared_state_nullary_task(shared_state<Rp&>* st, BOOST_THREAD_FWD_REF(Fp) f) + : that(st), f_(boost::move(f)) + {} +#if ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + BOOST_THREAD_COPYABLE_AND_MOVABLE(shared_state_nullary_task) + shared_state_nullary_task(shared_state_nullary_task const& x) BOOST_NOEXCEPT + : that(x.that), f_(x.f_) {} + + shared_state_nullary_task& operator=(BOOST_THREAD_COPY_ASSIGN_REF(shared_state_nullary_task) x) BOOST_NOEXCEPT { + if (this != &x){ + that=x.that; + f_=x.f_; + } + return *this; + } + // move + shared_state_nullary_task(BOOST_THREAD_RV_REF(shared_state_nullary_task) x) BOOST_NOEXCEPT + : that(x.that), f_(boost::move(x.f_)) + { + x.that=0; + } + shared_state_nullary_task& operator=(BOOST_THREAD_RV_REF(shared_state_nullary_task) x) BOOST_NOEXCEPT { + if (this != &x) { + that=x.that; + f_=boost::move(x.f_); + x.that=0; + } + return *this; + } +#endif + void operator()() { + try { + that->mark_finished_with_result(f_()); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + } catch(thread_interrupted& ) { + that->mark_interrupted_finish(); +#endif // defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + } catch(...) { + that->mark_exceptional_finish(); + } + } + }; + + ///////////////////////// + /// future_executor_shared_state_base + ///////////////////////// + template<typename Rp, typename Executor> + struct future_executor_shared_state: shared_state<Rp> + { + typedef shared_state<Rp> base_type; + protected: + public: + template<typename Fp> + future_executor_shared_state(Executor& ex, BOOST_THREAD_FWD_REF(Fp) f) { + this->set_executor(); + shared_state_nullary_task<Rp,Fp> t(this, boost::forward<Fp>(f)); + ex.submit(boost::move(t)); + } + + ~future_executor_shared_state() { + this->wait(false); + } + }; + + //////////////////////////////// + // make_future_executor_shared_state + //////////////////////////////// + template <class Rp, class Fp, class Executor> + BOOST_THREAD_FUTURE<Rp> + make_future_executor_shared_state(Executor& ex, BOOST_THREAD_FWD_REF(Fp) f) { + shared_ptr<future_executor_shared_state<Rp, Executor> > + h(new future_executor_shared_state<Rp, Executor>(ex, boost::forward<Fp>(f))); + return BOOST_THREAD_FUTURE<Rp>(h); } + +} // detail + + //////////////////////////////// + // template <class Executor, class F, class... ArgTypes> + // future<R> async(Executor& ex, F&&, ArgTypes&&...); + //////////////////////////////// + +//#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#if defined(BOOST_THREAD_PROVIDES_INVOKE) && ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && ! defined(BOOST_NO_CXX11_HDR_TUPLE) + +#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR + + template <class Executor, class R, class... ArgTypes> + BOOST_THREAD_FUTURE<R> + async(Executor& ex, R(*f)(BOOST_THREAD_FWD_REF(ArgTypes)...), BOOST_THREAD_FWD_REF(ArgTypes)... args) { + typedef R(*F)(BOOST_THREAD_FWD_REF(ArgTypes)...); + typedef detail::invoker<typename decay<F>::type, typename decay<ArgTypes>::type...> BF; + typedef typename BF::result_type Rp; + + return BOOST_THREAD_MAKE_RV_REF(boost::detail::make_future_executor_shared_state<Rp>(ex, + BF( + f + , thread_detail::decay_copy(boost::forward<ArgTypes>(args))... + ) + )); + } +#endif // defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR + + template <class Executor, class F, class ...ArgTypes> + BOOST_THREAD_FUTURE<typename boost::result_of<typename decay<F>::type( + typename decay<ArgTypes>::type... + )>::type> + async(Executor& ex, BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(ArgTypes)... args) { + typedef detail::invoker<typename decay<F>::type, typename decay<ArgTypes>::type...> BF; + typedef typename BF::result_type Rp; + + return BOOST_THREAD_MAKE_RV_REF(boost::detail::make_future_executor_shared_state<Rp>(ex, + BF( + thread_detail::decay_copy(boost::forward<F>(f)) + , thread_detail::decay_copy(boost::forward<ArgTypes>(args))... + ) + )); + } + +#else // ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR + + template <class Executor, class R> + BOOST_THREAD_FUTURE<R> + async(Executor& ex, R(*f)()) { + typedef R(*F)(); + typedef detail::invoker<F> BF; + typedef typename BF::result_type Rp; + + return BOOST_THREAD_MAKE_RV_REF(boost::detail::make_future_executor_shared_state<Rp>(ex, + BF( + f + ) + )); + } + + template <class Executor, class R, class A1> + BOOST_THREAD_FUTURE<R> + async(Executor& ex, R(*f)(BOOST_THREAD_FWD_REF(A1)), BOOST_THREAD_FWD_REF(A1) a1) { + typedef R(*F)(BOOST_THREAD_FWD_REF(A1)); + typedef detail::invoker<F, typename decay<A1>::type> BF; + typedef typename BF::result_type Rp; + + return BOOST_THREAD_MAKE_RV_REF(boost::detail::make_future_executor_shared_state<Rp>(ex, + BF( + f + , thread_detail::decay_copy(boost::forward<A1>(a1)) + ) + )); + } +#endif // defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR + + template <class Executor, class F> + BOOST_THREAD_FUTURE<typename boost::result_of<typename decay<F>::type()>::type> + async(Executor& ex, BOOST_THREAD_FWD_REF(F) f) { + typedef detail::invoker<typename decay<F>::type> BF; + typedef typename BF::result_type Rp; + + return boost::detail::make_future_executor_shared_state<Rp>(ex, + BF( + thread_detail::decay_copy(boost::forward<F>(f)) + ) + ); + } + + template <class Executor, class F, class A1> + BOOST_THREAD_FUTURE<typename boost::result_of<typename decay<F>::type( + typename decay<A1>::type + )>::type> + async(Executor& ex, BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1) { + typedef detail::invoker<typename decay<F>::type, typename decay<A1>::type> BF; + typedef typename BF::result_type Rp; + + return BOOST_THREAD_MAKE_RV_REF(boost::detail::make_future_executor_shared_state<Rp>(ex, + BF( + thread_detail::decay_copy(boost::forward<F>(f)) + , thread_detail::decay_copy(boost::forward<A1>(a1)) + ) + )); + } + + template <class Executor, class F, class A1, class A2> + BOOST_THREAD_FUTURE<typename boost::result_of<typename decay<F>::type( + typename decay<A1>::type, typename decay<A2>::type + )>::type> + async(Executor& ex, BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1, BOOST_THREAD_FWD_REF(A2) a2) { + typedef detail::invoker<typename decay<F>::type, typename decay<A1>::type, typename decay<A2>::type> BF; + typedef typename BF::result_type Rp; + + return BOOST_THREAD_MAKE_RV_REF(boost::detail::make_future_executor_shared_state<Rp>(ex, + BF( + thread_detail::decay_copy(boost::forward<F>(f)) + , thread_detail::decay_copy(boost::forward<A1>(a1)) + , thread_detail::decay_copy(boost::forward<A2>(a2)) + ) + )); + } + +#endif //! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #endif - BOOST_THREAD_DCL_MOVABLE_BEG(T) packaged_task<T> BOOST_THREAD_DCL_MOVABLE_END + //////////////////////////////// + // template <class F, class... ArgTypes> + // future<R> async(F&&, ArgTypes&&...); + //////////////////////////////// + +#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template <class R, class... ArgTypes> + BOOST_THREAD_FUTURE<R> + async(R(*f)(BOOST_THREAD_FWD_REF(ArgTypes)...), BOOST_THREAD_FWD_REF(ArgTypes)... args) { + return BOOST_THREAD_MAKE_RV_REF(async(launch(launch::any), f, boost::forward<ArgTypes>(args)...)); + } + #else + template <class R> + BOOST_THREAD_FUTURE<R> + async(R(*f)()) { + return BOOST_THREAD_MAKE_RV_REF(async(launch(launch::any), f)); + } + #endif +#endif -// template <class F> -// BOOST_THREAD_FUTURE<typename boost::result_of<F()>::type> -// async(launch policy, F f) -// { -// typedef typename boost::result_of<F()>::type R; -// typedef BOOST_THREAD_FUTURE<R> future; -// if (int(policy) & int(launch::async)) -// { -// packaged_task<R> pt( f ); -// -// BOOST_THREAD_FUTURE ret = pt.get_future(); -// boost::thread( boost::move(pt) ).detach(); -// return ::boost::move(ret); -// } -// else if (int(policy) & int(launch::deferred)) -// { -// packaged_task<R> pt( f ); -// -// BOOST_THREAD_FUTURE ret = pt.get_future(); -// return ::boost::move(ret); -// } -// } -// -// template <class F> -// BOOST_THREAD_FUTURE<typename boost::result_of<F()>::type> -// async(F f) -// { -// return async(launch::any, f); -// } +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template <class F, class ...ArgTypes> + BOOST_THREAD_FUTURE<typename boost::result_of<typename decay<F>::type( + typename decay<ArgTypes>::type... + )>::type> + async(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(ArgTypes)... args) { + return BOOST_THREAD_MAKE_RV_REF(async(launch(launch::any), boost::forward<F>(f), boost::forward<ArgTypes>(args)...)); + } +#else + template <class F> + BOOST_THREAD_FUTURE<typename boost::result_of<F()>::type> + async(BOOST_THREAD_FWD_REF(F) f) { + return BOOST_THREAD_MAKE_RV_REF(async(launch(launch::any), boost::forward<F>(f))); + } +#endif + + //////////////////////////////// + // make_future deprecated + //////////////////////////////// + template <typename T> + BOOST_THREAD_FUTURE<typename decay<T>::type> make_future(BOOST_THREAD_FWD_REF(T) value) { + typedef typename decay<T>::type future_value_type; + promise<future_value_type> p; + p.set_value(boost::forward<future_value_type>(value)); + return BOOST_THREAD_MAKE_RV_REF(p.get_future()); + } + +#if defined BOOST_THREAD_USES_MOVE + inline BOOST_THREAD_FUTURE<void> make_future() { + promise<void> p; + p.set_value(); + return BOOST_THREAD_MAKE_RV_REF(p.get_future()); + } +#endif + + //////////////////////////////// + // make_ready_future + //////////////////////////////// + template <typename T> + BOOST_THREAD_FUTURE<typename decay<T>::type> make_ready_future(BOOST_THREAD_FWD_REF(T) value) { + typedef typename decay<T>::type future_value_type; + promise<future_value_type> p; + p.set_value(boost::forward<future_value_type>(value)); + return BOOST_THREAD_MAKE_RV_REF(p.get_future()); + } + + template <typename T, typename T1> + BOOST_THREAD_FUTURE<T> make_ready_no_decay_future(T1 value) { + typedef T future_value_type; + promise<future_value_type> p; + p.set_value(value); + return BOOST_THREAD_MAKE_RV_REF(p.get_future()); + } + +#if defined BOOST_THREAD_USES_MOVE + inline BOOST_THREAD_FUTURE<void> make_ready_future() { + promise<void> p; + p.set_value(); + return BOOST_THREAD_MAKE_RV_REF(p.get_future()); + } +#endif + + template <typename T> + BOOST_THREAD_FUTURE<T> make_ready_future(exception_ptr ex) { + promise<T> p; + p.set_exception(ex); + return BOOST_THREAD_MAKE_RV_REF(p.get_future()); + } + + template <typename T> + BOOST_THREAD_FUTURE<T> make_exceptional_future(exception_ptr ex) { + promise<T> p; + p.set_exception(ex); + return BOOST_THREAD_MAKE_RV_REF(p.get_future()); + } + + template <typename T, typename E> + BOOST_THREAD_FUTURE<T> make_exceptional_future(E ex) { + promise<T> p; + p.set_exception(boost::copy_exception(ex)); + return BOOST_THREAD_MAKE_RV_REF(p.get_future()); + } + + template <typename T> + BOOST_THREAD_FUTURE<T> make_exceptional_future() { + promise<T> p; + p.set_exception(boost::current_exception()); + return BOOST_THREAD_MAKE_RV_REF(p.get_future()); + } + + template <typename T> + BOOST_THREAD_FUTURE<T> make_exceptional_future_if_invalid(BOOST_THREAD_FWD_REF(BOOST_THREAD_FUTURE<T>) fut) { + fut.set_exceptional_if_invalid(); + return boost::move(fut); + } + template <typename T> + shared_future<T> make_exceptional_future_if_invalid(shared_future<T> fut) { + fut.set_exceptional_if_invalid(); + return fut; + } + +#if 0 + template<typename CLOSURE> + make_future(CLOSURE closure) -> BOOST_THREAD_FUTURE<decltype(closure())> { + typedef decltype(closure()) T; + promise<T> p; + try { + p.set_value(closure()); + } catch(...) { + p.set_exception(std::current_exception()); + } + return BOOST_THREAD_MAKE_RV_REF(p.get_future()); + } +#endif + + //////////////////////////////// + // make_shared_future deprecated + //////////////////////////////// + template <typename T> + shared_future<typename decay<T>::type> make_shared_future(BOOST_THREAD_FWD_REF(T) value) { + typedef typename decay<T>::type future_type; + promise<future_type> p; + p.set_value(boost::forward<T>(value)); + return BOOST_THREAD_MAKE_RV_REF(p.get_future().share()); + } + + inline shared_future<void> make_shared_future() { + promise<void> p; + return BOOST_THREAD_MAKE_RV_REF(p.get_future().share()); + } + + //////////////////////////////// + // detail::future_async_continuation_shared_state + //////////////////////////////// +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION +namespace detail +{ + + ///////////////////////// + /// future_async_continuation_shared_state + ///////////////////////// + + template<typename F, typename Rp, typename Fp> + struct future_async_continuation_shared_state: future_async_shared_state_base<Rp> + { + F parent; + Fp continuation; + + public: + future_async_continuation_shared_state(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c) + : parent(boost::move(f)), + continuation(boost::move(c)) { + } + + void launch_continuation(boost::unique_lock<boost::mutex>& ) { + this->thr_ = thread(&future_async_continuation_shared_state::run, this); + } + + static void run(future_async_continuation_shared_state* that) { + try { + that->mark_finished_with_result(that->continuation(boost::move(that->parent))); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + } catch(thread_interrupted& ) { + that->mark_interrupted_finish(); +#endif + } catch(...) { + that->mark_exceptional_finish(); + } + } + + ~future_async_continuation_shared_state() { + this->join(); + } + }; + + template<typename F, typename Fp> + struct future_async_continuation_shared_state<F, void, Fp>: public future_async_shared_state_base<void> + { + F parent; + Fp continuation; + + public: + future_async_continuation_shared_state(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c) + : parent(boost::move(f)), + continuation(boost::move(c)) { + } + + void launch_continuation(boost::unique_lock<boost::mutex>& ) { + this->thr_ = thread(&future_async_continuation_shared_state::run, this); + } + + static void run(future_async_continuation_shared_state* that) { + try { + that->continuation(boost::move(that->parent)); + that->mark_finished_with_result(); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + } catch(thread_interrupted& ) { + that->mark_interrupted_finish(); +#endif + } catch(...) { + that->mark_exceptional_finish(); + } + } + + ~future_async_continuation_shared_state() { + this->join(); + } + }; + + ///////////////////////// + /// future_executor_continuation_shared_state + ///////////////////////// +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + + template <typename Ex> + struct run_it { + Ex* that; + + run_it(Ex* that) : that (that) {} + void operator()() { that->run(that); } + }; + + template<typename Ex, typename F, typename Rp, typename Fp> + struct future_executor_continuation_shared_state: shared_state<Rp> + { + Ex* ex; + F parent; + Fp continuation; + + public: + future_executor_continuation_shared_state(Ex& ex, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c) + : ex(&ex), parent(boost::move(f)), + continuation(boost::move(c)) { + this->set_executor(); + } + + void launch_continuation(boost::unique_lock<boost::mutex>& ) { + run_it<future_executor_continuation_shared_state> fct(this); + ex->submit(fct); + } + + static void run(future_executor_continuation_shared_state* that) { + try { + that->mark_finished_with_result(that->continuation(boost::move(that->parent))); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + } catch(thread_interrupted& ) { + that->mark_interrupted_finish(); +#endif + } catch(...) { + that->mark_exceptional_finish(); + } + } + + ~future_executor_continuation_shared_state() { + this->wait(false); + } + }; + + template<typename Ex, typename F, typename Fp> + struct future_executor_continuation_shared_state<Ex, F, void, Fp>: public shared_state<void> + { + Ex* ex; + F parent; + Fp continuation; + + public: + future_executor_continuation_shared_state(Ex& ex, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c) + : ex(&ex), parent(boost::move(f)), + continuation(boost::move(c)) { + this->set_executor(); + } + + void launch_continuation(boost::unique_lock<boost::mutex>& ) { + run_it<future_executor_continuation_shared_state> fct(this); + ex->submit(fct); + } + + static void run(future_executor_continuation_shared_state* that) { + try { + that->continuation(boost::move(that->parent)); + that->mark_finished_with_result(); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + } catch(thread_interrupted& ) { + that->mark_interrupted_finish(); +#endif + } catch(...) { + that->mark_exceptional_finish(); + } + } + + ~future_executor_continuation_shared_state() { + this->wait(false); + } + }; +#endif + + ///////////////////////// + /// shared_future_async_continuation_shared_state + ///////////////////////// + + template<typename F, typename Rp, typename Fp> + struct shared_future_async_continuation_shared_state: future_async_shared_state_base<Rp> + { + F parent; + Fp continuation; + + public: + shared_future_async_continuation_shared_state(F f, BOOST_THREAD_FWD_REF(Fp) c) + : parent(f), + continuation(boost::move(c)) { + } + + void launch_continuation(boost::unique_lock<boost::mutex>& ) { + this->thr_ = thread(&shared_future_async_continuation_shared_state::run, this); + } + + static void run(shared_future_async_continuation_shared_state* that) { + try { + that->mark_finished_with_result(that->continuation(that->parent)); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + } catch(thread_interrupted& ) { + that->mark_interrupted_finish(); +#endif + } catch(...) { + that->mark_exceptional_finish(); + } + } + + ~shared_future_async_continuation_shared_state() { + this->join(); + } + }; + + template<typename F, typename Fp> + struct shared_future_async_continuation_shared_state<F, void, Fp>: public future_async_shared_state_base<void> + { + F parent; + Fp continuation; + + public: + shared_future_async_continuation_shared_state(F f, BOOST_THREAD_FWD_REF(Fp) c) + : parent(f), + continuation(boost::move(c)) { + } + + void launch_continuation(boost::unique_lock<boost::mutex>& ) { + this->thr_ = thread(&shared_future_async_continuation_shared_state::run, this); + } + + static void run(shared_future_async_continuation_shared_state* that) { + try { + that->continuation(that->parent); + that->mark_finished_with_result(); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + } catch(thread_interrupted& ) { + that->mark_interrupted_finish(); +#endif + } catch(...) { + that->mark_exceptional_finish(); + } + } + + ~shared_future_async_continuation_shared_state() { + this->join(); + } + }; + + ///////////////////////// + /// shared_future_executor_continuation_shared_state + ///////////////////////// +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + + template<typename Ex, typename F, typename Rp, typename Fp> + struct shared_future_executor_continuation_shared_state: shared_state<Rp> + { + Ex* ex; + F parent; + Fp continuation; + + public: + shared_future_executor_continuation_shared_state(Ex& ex, F f, BOOST_THREAD_FWD_REF(Fp) c) + : ex(&ex), parent(f), + continuation(boost::move(c)) { + this->set_executor(); + } + + void launch_continuation(boost::unique_lock<boost::mutex>& ) { + run_it<shared_future_executor_continuation_shared_state> fct(this); + ex->submit(fct); + } + + static void run(shared_future_executor_continuation_shared_state* that) { + try { + that->mark_finished_with_result(that->continuation(that->parent)); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + } catch(thread_interrupted& ) { + that->mark_interrupted_finish(); +#endif + } catch(...) { + that->mark_exceptional_finish(); + } + } + + ~shared_future_executor_continuation_shared_state() { + this->wait(false); + } + }; + + template<typename Ex, typename F, typename Fp> + struct shared_future_executor_continuation_shared_state<Ex, F, void, Fp>: public shared_state<void> + { + Ex* ex; + F parent; + Fp continuation; + + public: + shared_future_executor_continuation_shared_state(Ex& ex, F f, BOOST_THREAD_FWD_REF(Fp) c) + : ex(&ex), parent(f), + continuation(boost::move(c)) { + } + + void launch_continuation(boost::unique_lock<boost::mutex>& ) { + run_it<shared_future_executor_continuation_shared_state> fct(this); + ex->submit(fct); + } + + static void run(shared_future_executor_continuation_shared_state* that) { + try { + that->continuation(that->parent); + that->mark_finished_with_result(); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + } catch(thread_interrupted& ) { + that->mark_interrupted_finish(); +#endif + } catch(...) { + that->mark_exceptional_finish(); + } + } + + ~shared_future_executor_continuation_shared_state() { + this->wait(false); + } + }; +#endif + ////////////////////////// + /// future_deferred_continuation_shared_state + ////////////////////////// + template<typename F, typename Rp, typename Fp> + struct future_deferred_continuation_shared_state: shared_state<Rp> + { + F parent; + Fp continuation; + + public: + future_deferred_continuation_shared_state(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c) + : parent(boost::move(f)), + continuation(boost::move(c)) { + this->set_deferred(); + } + + virtual void launch_continuation(boost::unique_lock<boost::mutex>& ) { + } + + virtual void execute(boost::unique_lock<boost::mutex>& lck) { + try { + Fp local_fuct=boost::move(continuation); + F ftmp = boost::move(parent); + relocker relock(lck); + Rp res = local_fuct(boost::move(ftmp)); + relock.lock(); + this->mark_finished_with_result_internal(boost::move(res), lck); + } catch (...) { + this->mark_exceptional_finish_internal(current_exception(), lck); + } + } + }; + + template<typename F, typename Fp> + struct future_deferred_continuation_shared_state<F,void,Fp>: shared_state<void> + { + F parent; + Fp continuation; + + public: + future_deferred_continuation_shared_state(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c) + : parent(boost::move(f)), + continuation(boost::move(c)) { + this->set_deferred(); + } + + virtual void launch_continuation(boost::unique_lock<boost::mutex>& ) { + } + + virtual void execute(boost::unique_lock<boost::mutex>& lck) { + try { + Fp local_fuct=boost::move(continuation); + F ftmp = boost::move(parent); + relocker relock(lck); + local_fuct(boost::move(ftmp)); + relock.lock(); + this->mark_finished_with_result_internal(lck); + } catch (...) { + this->mark_exceptional_finish_internal(current_exception(), lck); + } + } + }; + + ////////////////////////// + /// shared_future_deferred_continuation_shared_state + ////////////////////////// + template<typename F, typename Rp, typename Fp> + struct shared_future_deferred_continuation_shared_state: shared_state<Rp> + { + F parent; + Fp continuation; + + public: + shared_future_deferred_continuation_shared_state(F f, BOOST_THREAD_FWD_REF(Fp) c) + : parent(f), + continuation(boost::move(c)) { + this->set_deferred(); + } + + virtual void launch_continuation(boost::unique_lock<boost::mutex>& ) { + } + + virtual void execute(boost::unique_lock<boost::mutex>& lck) { + try { + Fp local_fuct=boost::move(continuation); + F ftmp = parent; + relocker relock(lck); + Rp res = local_fuct(ftmp); + relock.lock(); + this->mark_finished_with_result_internal(boost::move(res), lck); + } catch (...) { + this->mark_exceptional_finish_internal(current_exception(), lck); + } + } + }; + + template<typename F, typename Fp> + struct shared_future_deferred_continuation_shared_state<F,void,Fp>: shared_state<void> + { + F parent; + Fp continuation; + + public: + shared_future_deferred_continuation_shared_state(F f, BOOST_THREAD_FWD_REF(Fp) c) + : parent(f), + continuation(boost::move(c)) { + this->set_deferred(); + } + + virtual void launch_continuation(boost::unique_lock<boost::mutex>& ) { + } + + virtual void execute(boost::unique_lock<boost::mutex>& lck) { + try { + Fp local_fuct=boost::move(continuation); + F ftmp = parent; + relocker relock(lck); + local_fuct(ftmp); + relock.lock(); + this->mark_finished_with_result_internal(lck); + } catch (...) { + this->mark_exceptional_finish_internal(current_exception(), lck); + } + } + }; + + //////////////////////////////// + // make_future_deferred_continuation_shared_state + //////////////////////////////// + template<typename F, typename Rp, typename Fp> + BOOST_THREAD_FUTURE<Rp> + make_future_deferred_continuation_shared_state( + boost::unique_lock<boost::mutex> &lock, + BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c) { + shared_ptr<future_deferred_continuation_shared_state<F, Rp, Fp> > + h(new future_deferred_continuation_shared_state<F, Rp, Fp>(boost::move(f), boost::forward<Fp>(c))); + h->parent.future_->set_continuation_ptr(h, lock); + return BOOST_THREAD_FUTURE<Rp>(h); + } + + //////////////////////////////// + // make_future_async_continuation_shared_state + //////////////////////////////// + template<typename F, typename Rp, typename Fp> + BOOST_THREAD_FUTURE<Rp> + make_future_async_continuation_shared_state( + boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f, + BOOST_THREAD_FWD_REF(Fp) c) { + shared_ptr<future_async_continuation_shared_state<F,Rp, Fp> > + h(new future_async_continuation_shared_state<F,Rp, Fp>(boost::move(f), boost::forward<Fp>(c))); + h->parent.future_->set_continuation_ptr(h, lock); + + return BOOST_THREAD_FUTURE<Rp>(h); + } + + //////////////////////////////// + // make_future_executor_continuation_shared_state + //////////////////////////////// +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + + template<typename Ex, typename F, typename Rp, typename Fp> + BOOST_THREAD_FUTURE<Rp> + make_future_executor_continuation_shared_state(Ex& ex, + boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f, + BOOST_THREAD_FWD_REF(Fp) c) { + shared_ptr<future_executor_continuation_shared_state<Ex,F,Rp, Fp> > + h(new future_executor_continuation_shared_state<Ex, F,Rp, Fp>(ex, boost::move(f), boost::forward<Fp>(c))); + h->parent.future_->set_continuation_ptr(h, lock); + + return BOOST_THREAD_FUTURE<Rp>(h); + } +#endif + + //////////////////////////////// + // make_shared_future_deferred_continuation_shared_state + //////////////////////////////// + template<typename F, typename Rp, typename Fp> + BOOST_THREAD_FUTURE<Rp> + make_shared_future_deferred_continuation_shared_state( + boost::unique_lock<boost::mutex> &lock, + F f, BOOST_THREAD_FWD_REF(Fp) c) { + shared_ptr<shared_future_deferred_continuation_shared_state<F, Rp, Fp> > + h(new shared_future_deferred_continuation_shared_state<F, Rp, Fp>(f, boost::forward<Fp>(c))); + h->parent.future_->set_continuation_ptr(h, lock); + return BOOST_THREAD_FUTURE<Rp>(h); + } + //////////////////////////////// + // make_shared_future_async_continuation_shared_state + //////////////////////////////// + template<typename F, typename Rp, typename Fp> + BOOST_THREAD_FUTURE<Rp> + make_shared_future_async_continuation_shared_state( + boost::unique_lock<boost::mutex> &lock, F f, + BOOST_THREAD_FWD_REF(Fp) c) { + shared_ptr<shared_future_async_continuation_shared_state<F,Rp, Fp> > + h(new shared_future_async_continuation_shared_state<F,Rp, Fp>(f, boost::forward<Fp>(c))); + h->parent.future_->set_continuation_ptr(h, lock); + + return BOOST_THREAD_FUTURE<Rp>(h); + } + //////////////////////////////// + // make_shared_future_executor_continuation_shared_state + //////////////////////////////// +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + template<typename Ex, typename F, typename Rp, typename Fp> + BOOST_THREAD_FUTURE<Rp> + make_shared_future_executor_continuation_shared_state(Ex& ex, + boost::unique_lock<boost::mutex> &lock, F f, + BOOST_THREAD_FWD_REF(Fp) c) { + shared_ptr<shared_future_executor_continuation_shared_state<Ex, F, Rp, Fp> > + h(new shared_future_executor_continuation_shared_state<Ex, F, Rp, Fp>(ex, f, boost::forward<Fp>(c))); + h->parent.future_->set_continuation_ptr(h, lock); + + return BOOST_THREAD_FUTURE<Rp>(h); + } +#endif +} + + //////////////////////////////// + // template<typename F> + // auto future<R>::then(F&& func) -> BOOST_THREAD_FUTURE<decltype(func(*this))>; + //////////////////////////////// + + template <typename R> + template <typename F> + inline BOOST_THREAD_FUTURE<typename boost::result_of<F(BOOST_THREAD_FUTURE<R>)>::type> + BOOST_THREAD_FUTURE<R>::then(launch policy, BOOST_THREAD_FWD_REF(F) func) { + typedef typename boost::result_of<F(BOOST_THREAD_FUTURE<R>)>::type future_type; + BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); + + boost::unique_lock<boost::mutex> lock(this->future_->mutex); + if (underlying_cast<int>(policy) & int(launch::async)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>( + lock, boost::move(*this), boost::forward<F>(func) + ))); + } else if (underlying_cast<int>(policy) & int(launch::deferred)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_deferred_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>( + lock, boost::move(*this), boost::forward<F>(func) + ))); + } else { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>( + lock, boost::move(*this), boost::forward<F>(func) + ))); + } + } +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + template <typename R> + template <typename Ex, typename F> + inline BOOST_THREAD_FUTURE<typename boost::result_of<F(BOOST_THREAD_FUTURE<R>)>::type> + BOOST_THREAD_FUTURE<R>::then(Ex& ex, BOOST_THREAD_FWD_REF(F) func) { + typedef typename boost::result_of<F(BOOST_THREAD_FUTURE<R>)>::type future_type; + BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); + + boost::unique_lock<boost::mutex> lock(this->future_->mutex); + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_executor_continuation_shared_state<Ex, BOOST_THREAD_FUTURE<R>, future_type, F>(ex, + lock, boost::move(*this), boost::forward<F>(func) + ))); + } +#endif + template <typename R> + template <typename F> + inline BOOST_THREAD_FUTURE<typename boost::result_of<F(BOOST_THREAD_FUTURE<R>)>::type> + BOOST_THREAD_FUTURE<R>::then(BOOST_THREAD_FWD_REF(F) func) { + typedef typename boost::result_of<F(BOOST_THREAD_FUTURE<R>)>::type future_type; + BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); + + boost::unique_lock<boost::mutex> lock(this->future_->mutex); + if (underlying_cast<int>(this->launch_policy(lock)) & int(launch::async)) { + return boost::detail::make_future_async_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>( + lock, boost::move(*this), boost::forward<F>(func) + ); + } else if (underlying_cast<int>(this->launch_policy(lock)) & int(launch::deferred)) { + this->future_->wait_internal(lock); + return boost::detail::make_future_deferred_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>( + lock, boost::move(*this), boost::forward<F>(func) + ); + } else { + return boost::detail::make_future_async_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type, F>( + lock, boost::move(*this), boost::forward<F>(func) + ); + } + } + + template <typename R> + template <typename F> + inline BOOST_THREAD_FUTURE<typename boost::result_of<F(shared_future<R>)>::type> + shared_future<R>::then(launch policy, BOOST_THREAD_FWD_REF(F) func) const + { + typedef typename boost::result_of<F(shared_future<R>)>::type future_type; + BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); + + boost::unique_lock<boost::mutex> lock(this->future_->mutex); + + if (underlying_cast<int>(policy) & int(launch::async)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_shared_future_async_continuation_shared_state<shared_future<R>, future_type, F>( + lock, *this, boost::forward<F>(func) + ))); + } else if (underlying_cast<int>(policy) & int(launch::deferred)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_shared_future_deferred_continuation_shared_state<shared_future<R>, future_type, F>( + lock, *this, boost::forward<F>(func) + ))); + } else { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_shared_future_async_continuation_shared_state<shared_future<R>, future_type, F>( + lock, *this, boost::forward<F>(func) + ))); + } + } +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + template <typename R> + template <typename Ex, typename F> + inline BOOST_THREAD_FUTURE<typename boost::result_of<F(shared_future<R>)>::type> + shared_future<R>::then(Ex& ex, BOOST_THREAD_FWD_REF(F) func) const + { + typedef typename boost::result_of<F(shared_future<R>)>::type future_type; + BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); + + boost::unique_lock<boost::mutex> lock(this->future_->mutex); + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_shared_future_executor_continuation_shared_state<Ex, shared_future<R>, future_type, F>(ex, + lock, *this, boost::forward<F>(func) + ))); + } +#endif + + template <typename R> + template <typename F> + inline BOOST_THREAD_FUTURE<typename boost::result_of<F(shared_future<R>)>::type> + shared_future<R>::then(BOOST_THREAD_FWD_REF(F) func) const { + typedef typename boost::result_of<F(shared_future<R>)>::type future_type; + + BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); + + boost::unique_lock<boost::mutex> lock(this->future_->mutex); + if (underlying_cast<int>(this->launch_policy(lock)) & int(launch::async)) { + return boost::detail::make_shared_future_async_continuation_shared_state<shared_future<R>, future_type, F>( + lock, *this, boost::forward<F>(func)); + } else if (underlying_cast<int>(this->launch_policy(lock)) & int(launch::deferred)) { + this->future_->wait_internal(lock); + return boost::detail::make_shared_future_deferred_continuation_shared_state<shared_future<R>, future_type, F>( + lock, *this, boost::forward<F>(func)); + } else { + return boost::detail::make_shared_future_async_continuation_shared_state<shared_future<R>, future_type, F>( + lock, *this, boost::forward<F>(func)); + } + } + +namespace detail +{ + template <typename T> + struct mfallbacker_to + { + T value_; + typedef T result_type; + mfallbacker_to(BOOST_THREAD_RV_REF(T) v) + : value_(boost::move(v)) + {} + + T operator()(BOOST_THREAD_FUTURE<T> fut) { + return fut.get_or(boost::move(value_)); + } + }; + template <typename T> + struct cfallbacker_to + { + T value_; + typedef T result_type; + cfallbacker_to(T const& v) + : value_(v) + {} + + T operator()(BOOST_THREAD_FUTURE<T> fut) { + return fut.get_or(value_); + + } + }; +} + //////////////////////////////// + // future<R> future<R>::fallback_to(R&& v); + //////////////////////////////// + + template <typename R> + template <typename R2> + inline typename boost::disable_if< is_void<R2>, BOOST_THREAD_FUTURE<R> >::type + BOOST_THREAD_FUTURE<R>::fallback_to(BOOST_THREAD_RV_REF(R2) v) { + return then(detail::mfallbacker_to<R>(boost::move(v))); + } + + template <typename R> + template <typename R2> + inline typename boost::disable_if< is_void<R2>, BOOST_THREAD_FUTURE<R> >::type + BOOST_THREAD_FUTURE<R>::fallback_to(R2 const& v) { + return then(detail::cfallbacker_to<R>(v)); + } + +#endif + +#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP +namespace detail +{ + ///////////////////////// + /// future_unwrap_shared_state + ///////////////////////// + + template<typename F, typename Rp> + struct future_unwrap_shared_state: shared_state<Rp> + { + F parent; + public: + explicit future_unwrap_shared_state(BOOST_THREAD_RV_REF(F) f) + : parent(boost::move(f)) {} + + typename F::value_type parent_value(boost::unique_lock<boost::mutex>& ) { + typename F::value_type r = parent.get(); + r.set_exceptional_if_invalid(); + return boost::move(r); + } + virtual void wait(bool ) { // todo see if rethrow must be used + boost::unique_lock<boost::mutex> lk(this->mutex); + parent_value(lk).wait(); + } + virtual Rp get() { + boost::unique_lock<boost::mutex> lk(this->mutex); + return parent_value(lk).get(); + } + }; + + template <class F, class Rp> + BOOST_THREAD_FUTURE<Rp> + make_future_unwrap_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_RV_REF(F) f) { + shared_ptr<future_unwrap_shared_state<F, Rp> > + h(new future_unwrap_shared_state<F, Rp>(boost::move(f))); + h->parent.future_->set_continuation_ptr(h, lock); + return BOOST_THREAD_FUTURE<Rp>(h); + } +} + template <typename R> + inline BOOST_THREAD_FUTURE<R>::BOOST_THREAD_FUTURE(BOOST_THREAD_RV_REF(BOOST_THREAD_FUTURE<BOOST_THREAD_FUTURE<R> >) other) + : base_type(other.unwrap()) {} + template <typename R2> + BOOST_THREAD_FUTURE<R2> + BOOST_THREAD_FUTURE<BOOST_THREAD_FUTURE<R2> >::unwrap() + { + BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); + boost::unique_lock<boost::mutex> lock(this->future_->mutex); + return boost::detail::make_future_unwrap_shared_state<BOOST_THREAD_FUTURE<BOOST_THREAD_FUTURE<R2> >, R2>(lock, boost::move(*this)); + } +#endif + +#if defined BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY +namespace detail +{ + struct input_iterator_tag {}; + struct vector_tag {}; + struct values_tag {}; + template <typename T> + struct alias_t { typedef T type; }; + + BOOST_CONSTEXPR_OR_CONST input_iterator_tag input_iterator_tag_value = {}; + BOOST_CONSTEXPR_OR_CONST vector_tag vector_tag_value = {}; + BOOST_CONSTEXPR_OR_CONST values_tag values_tag_value = {}; + //////////////////////////////// + // detail::future_async_when_all_shared_state + //////////////////////////////// + template<typename F> + struct future_when_all_vector_shared_state: future_async_shared_state_base<csbl::vector<F> > + { + typedef csbl::vector<F> vector_type; + typedef typename F::value_type value_type; + vector_type vec_; + + static void run(future_when_all_vector_shared_state* that) { + try { + boost::wait_for_all(that->vec_.begin(), that->vec_.end()); + that->mark_finished_with_result(boost::move(that->vec_)); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + } catch(thread_interrupted& ) { + that->mark_interrupted_finish(); +#endif + } catch(...) { + that->mark_exceptional_finish(); + } + } + bool run_deferred() { + + bool res = false; + for (typename csbl::vector<F>::iterator it = vec_.begin(); it != vec_.end(); ++it) { + if (! it->run_if_is_deferred()) + { + res = true; + } + } + return res; + } + void init() { + if (! run_deferred()) + { + future_when_all_vector_shared_state::run(this); + return; + } + this->thr_ = thread(&future_when_all_vector_shared_state::run, this); + } + + public: + template< typename InputIterator> + future_when_all_vector_shared_state(input_iterator_tag, InputIterator first, InputIterator last) + : vec_(std::make_move_iterator(first), std::make_move_iterator(last)) + { + init(); + } + + future_when_all_vector_shared_state(vector_tag, BOOST_THREAD_RV_REF(csbl::vector<F>) v) + : vec_(boost::move(v)) + { + init(); + } + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template< typename T0, typename ...T> + future_when_all_vector_shared_state(values_tag, BOOST_THREAD_FWD_REF(T0) f, BOOST_THREAD_FWD_REF(T) ... futures) { + vec_.push_back(boost::forward<T0>(f)); + typename alias_t<char[]>::type{ + ( //first part of magic unpacker + vec_.push_back(boost::forward<T>(futures)),'0' + )..., '0' + }; //second part of magic unpacker + init(); + } +#endif + ~future_when_all_vector_shared_state() { + this->join(); + } + }; + + //////////////////////////////// + // detail::future_async_when_any_shared_state + //////////////////////////////// + template<typename F> + struct future_when_any_vector_shared_state: future_async_shared_state_base<csbl::vector<F> > + { + typedef csbl::vector<F> vector_type; + typedef typename F::value_type value_type; + vector_type vec_; + + static void run(future_when_any_vector_shared_state* that) + { + try { + boost::wait_for_any(that->vec_.begin(), that->vec_.end()); + that->mark_finished_with_result(boost::move(that->vec_)); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + } catch(thread_interrupted& ) { + that->mark_interrupted_finish(); +#endif + } catch(...) { + that->mark_exceptional_finish(); + } + } + bool run_deferred() { + + for (typename csbl::vector<F>::iterator it = vec_.begin(); it != vec_.end(); ++it) { + if (it->run_if_is_deferred_or_ready()) + { + return true; + } + } + return false; + } + void init() { + if (run_deferred()) + { + future_when_any_vector_shared_state::run(this); + return; + } + + this->thr_ = thread(&future_when_any_vector_shared_state::run, this); + } + + public: + template< typename InputIterator> + future_when_any_vector_shared_state(input_iterator_tag, InputIterator first, InputIterator last) + : vec_(std::make_move_iterator(first), std::make_move_iterator(last)) + { + init(); + } + + future_when_any_vector_shared_state(vector_tag, BOOST_THREAD_RV_REF(csbl::vector<F>) v) + : vec_(boost::move(v)) + { + init(); + } + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template< typename T0, typename ...T> + future_when_any_vector_shared_state(values_tag, + BOOST_THREAD_FWD_REF(T0) f, BOOST_THREAD_FWD_REF(T) ... futures + ) { + vec_.push_back(boost::forward<T0>(f)); + typename alias_t<char[]>::type{ + ( //first part of magic unpacker + vec_.push_back(boost::forward<T>(futures)) + ,'0' + )..., + '0' + }; //second part of magic unpacker + init(); + } +#endif + + ~future_when_any_vector_shared_state() { + this->join(); + } + }; + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + struct wait_for_all_fctr { + template <class ...T> + void operator()(T&&... v) { + boost::wait_for_all(boost::forward<T>(v)...); + } + }; + + struct wait_for_any_fctr { + template <class ...T> + void operator()(T&&... v) { + boost::wait_for_any(boost::forward<T>(v)...); + } + }; + + + template <class Tuple, std::size_t i=csbl::tuple_size<Tuple>::value> + struct accumulate_run_if_is_deferred { + bool operator ()(Tuple& t) + { + return (! csbl::get<i-1>(t).run_if_is_deferred()) || accumulate_run_if_is_deferred<Tuple,i-1>()(t); + } + }; + template <class Tuple> + struct accumulate_run_if_is_deferred<Tuple, 0> { + bool operator ()(Tuple& ) + { + return false; + } + }; + + + template< typename Tuple, typename T0, typename ...T> + struct future_when_all_tuple_shared_state: future_async_shared_state_base<Tuple> + { + Tuple tup_; + typedef typename make_tuple_indices<1+sizeof...(T)>::type Index; + + static void run(future_when_all_tuple_shared_state* that) { + try { + // TODO make use of apply(that->tup_, boost::detail::wait_for_all_fctor()); + that->wait_for_all(Index()); + + that->mark_finished_with_result(boost::move(that->tup_)); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + } catch(thread_interrupted& ) { + that->mark_interrupted_finish(); +#endif + } catch(...) { + that->mark_exceptional_finish(); + } + } + + template <size_t ...Indices> + void wait_for_all(tuple_indices<Indices...>) { +#if defined BOOST_THREAD_PROVIDES_INVOKE + return invoke<void>(wait_for_all_fctr(), csbl::get<Indices>(tup_)...); +#else + return wait_for_all_fctr()(csbl::get<Indices>(tup_)...); +#endif + } + + bool run_deferred() { + + return accumulate_run_if_is_deferred<Tuple>()(tup_); + } + void init() { + if (! run_deferred()) + { + future_when_all_tuple_shared_state::run(this); + return; + } + + this->thr_ = thread(&future_when_all_tuple_shared_state::run, this); + } + public: + template< typename F, typename ...Fs> + future_when_all_tuple_shared_state(values_tag, BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Fs) ... futures) : + tup_(boost::csbl::make_tuple(boost::forward<F>(f), boost::forward<Fs>(futures)...)) + { + init(); + } + ~future_when_all_tuple_shared_state() { + this->join(); + } + + }; + + + template <class Tuple, std::size_t i=csbl::tuple_size<Tuple>::value> + struct apply_any_run_if_is_deferred_or_ready { + bool operator ()(Tuple& t) + { + if (csbl::get<i-1>(t).run_if_is_deferred_or_ready()) return true; + return apply_any_run_if_is_deferred_or_ready<Tuple,i-1>()(t); + } + }; + template <class Tuple> + struct apply_any_run_if_is_deferred_or_ready<Tuple, 0> { + bool operator ()(Tuple& ) + { + return false; + } + }; + + template< typename Tuple, typename T0, typename ...T > + struct future_when_any_tuple_shared_state: future_async_shared_state_base<Tuple> + { + Tuple tup_; + typedef typename make_tuple_indices<1+sizeof...(T)>::type Index; + + static void run(future_when_any_tuple_shared_state* that) + { + try { + // TODO make use of apply(that->tup_, wait_for_any_fctr); + that->wait_for_any(Index()); + + that->mark_finished_with_result(boost::move(that->tup_)); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + } catch(thread_interrupted& ) { + that->mark_interrupted_finish(); +#endif + } catch(...) { + that->mark_exceptional_finish(); + } + } + template <size_t ...Indices> + void wait_for_any(tuple_indices<Indices...>) { +#if defined BOOST_THREAD_PROVIDES_INVOKE + return invoke<void>(wait_for_any_fctr(), csbl::get<Indices>(tup_)...); +#else + return wait_for_any_fctr()(csbl::get<Indices>(tup_)...); +#endif + } + bool run_deferred() { + return apply_any_run_if_is_deferred_or_ready<Tuple>()(tup_); + } + void init() { + if (run_deferred()) + { + future_when_any_tuple_shared_state::run(this); + return; + } + + this->thr_ = thread(&future_when_any_tuple_shared_state::run, this); + } + + public: + template< typename F, typename ...Fs> + future_when_any_tuple_shared_state(values_tag, + BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Fs) ... futures + ) : + tup_(boost::csbl::make_tuple(boost::forward<F>(f), boost::forward<Fs>(futures)...)) + { + init(); + } + + ~future_when_any_tuple_shared_state() { + this->join(); + } + }; +#endif + +} + + template< typename InputIterator> + typename boost::disable_if<is_future_type<InputIterator>, + BOOST_THREAD_FUTURE<csbl::vector<typename InputIterator::value_type> > + >::type + when_all(InputIterator first, InputIterator last) { + typedef typename InputIterator::value_type value_type; + typedef csbl::vector<value_type> container_type; + typedef detail::future_when_all_vector_shared_state<value_type> factory_type; + + if (first==last) return make_ready_future(container_type()); + shared_ptr<factory_type > + h(new factory_type(detail::input_iterator_tag_value, first,last)); + return BOOST_THREAD_FUTURE<container_type>(h); + } + + inline BOOST_THREAD_FUTURE<csbl::tuple<> > when_all() { + return make_ready_future(csbl::tuple<>()); + } + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template< typename T0, typename ...T> + BOOST_THREAD_FUTURE<csbl::tuple<typename decay<T0>::type, typename decay<T>::type...> > + when_all(BOOST_THREAD_FWD_REF(T0) f, BOOST_THREAD_FWD_REF(T) ... futures) { + typedef csbl::tuple<typename decay<T0>::type, typename decay<T>::type...> container_type; + typedef detail::future_when_all_tuple_shared_state<container_type, typename decay<T0>::type, typename decay<T>::type...> factory_type; + + shared_ptr<factory_type> + h(new factory_type(detail::values_tag_value, boost::forward<T0>(f), boost::forward<T>(futures)...)); + return BOOST_THREAD_FUTURE<container_type>(h); + } +#endif + + template< typename InputIterator> + typename boost::disable_if<is_future_type<InputIterator>, + BOOST_THREAD_FUTURE<csbl::vector<typename InputIterator::value_type> > + >::type + when_any(InputIterator first, InputIterator last) { + typedef typename InputIterator::value_type value_type; + typedef csbl::vector<value_type> container_type; + typedef detail::future_when_any_vector_shared_state<value_type> factory_type; + + if (first==last) return make_ready_future(container_type()); + shared_ptr<factory_type > + h(new factory_type(detail::input_iterator_tag_value, first,last)); + return BOOST_THREAD_FUTURE<container_type>(h); + } + + inline BOOST_THREAD_FUTURE<csbl::tuple<> > when_any() { + return make_ready_future(csbl::tuple<>()); + } + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template< typename T0, typename ...T> + BOOST_THREAD_FUTURE<csbl::tuple<typename decay<T0>::type, typename decay<T>::type...> > + when_any(BOOST_THREAD_FWD_REF(T0) f, BOOST_THREAD_FWD_REF(T) ... futures) { + typedef csbl::tuple<typename decay<T0>::type, typename decay<T>::type...> container_type; + typedef detail::future_when_any_tuple_shared_state<container_type, typename decay<T0>::type, typename decay<T>::type...> factory_type; + + shared_ptr<factory_type> + h(new factory_type(detail::values_tag_value, boost::forward<T0>(f), boost::forward<T>(futures)...)); + return BOOST_THREAD_FUTURE<container_type>(h); + } +#endif +#endif // BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY } #endif // BOOST_NO_EXCEPTION diff --git a/boost/thread/future_error_code.hpp b/boost/thread/future_error_code.hpp new file mode 100644 index 0000000000..6fe95541b7 --- /dev/null +++ b/boost/thread/future_error_code.hpp @@ -0,0 +1,61 @@ +// (C) Copyright 2008-10 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_THREAD_FUTURE_ERROR_CODE_HPP +#define BOOST_THREAD_FUTURE_ERROR_CODE_HPP + +#include <boost/thread/detail/config.hpp> +#include <boost/core/scoped_enum.hpp> +#include <boost/system/error_code.hpp> +#include <boost/type_traits/integral_constant.hpp> + +namespace boost +{ + + //enum class future_errc + BOOST_SCOPED_ENUM_DECLARE_BEGIN(future_errc) + { + broken_promise = 1, + future_already_retrieved, + promise_already_satisfied, + no_state + } + BOOST_SCOPED_ENUM_DECLARE_END(future_errc) + + namespace system + { + template <> + struct BOOST_SYMBOL_VISIBLE is_error_code_enum< ::boost::future_errc> : public true_type {}; + + #ifdef BOOST_NO_CXX11_SCOPED_ENUMS + template <> + struct BOOST_SYMBOL_VISIBLE is_error_code_enum< ::boost::future_errc::enum_type> : public true_type { }; + #endif + } // system + + BOOST_THREAD_DECL + const system::error_category& future_category() BOOST_NOEXCEPT; + + namespace system + { + inline + error_code + make_error_code(future_errc e) BOOST_NOEXCEPT + { + return error_code(underlying_cast<int>(e), boost::future_category()); + } + + inline + error_condition + make_error_condition(future_errc e) BOOST_NOEXCEPT + { + return error_condition(underlying_cast<int>(e), boost::future_category()); + } + } // system +} // boost + +#endif // header diff --git a/boost/thread/is_locked_by_this_thread.hpp b/boost/thread/is_locked_by_this_thread.hpp new file mode 100644 index 0000000000..6344c0ff6d --- /dev/null +++ b/boost/thread/is_locked_by_this_thread.hpp @@ -0,0 +1,39 @@ +// (C) Copyright 2012 Vicente J. Botet Escriba +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +#ifndef BOOST_THREAD_IS_LOCKED_BY_THIS_THREAD_HPP +#define BOOST_THREAD_IS_LOCKED_BY_THIS_THREAD_HPP + +#include <boost/thread/detail/config.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + template <typename Lockable> + class testable_mutex; + + /** + * Overloaded function used to check if the mutex is locked when it is testable and do nothing otherwise. + * + * This function is used usually to assert the pre-condition when the function can only be called when the mutex + * must be locked by the current thread. + */ + template <typename Lockable> + bool is_locked_by_this_thread(testable_mutex<Lockable> const& mtx) + { + return mtx.is_locked_by_this_thread(); + } + template <typename Lockable> + bool is_locked_by_this_thread(Lockable const&) + { + return true; + } +} + +#include <boost/config/abi_suffix.hpp> + +#endif // header diff --git a/boost/thread/latch.hpp b/boost/thread/latch.hpp new file mode 100644 index 0000000000..6caf521910 --- /dev/null +++ b/boost/thread/latch.hpp @@ -0,0 +1,167 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2013 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_LATCH_HPP +#define BOOST_THREAD_LATCH_HPP + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/delete.hpp> +#include <boost/thread/detail/counter.hpp> + +#include <boost/thread/mutex.hpp> +#include <boost/thread/lock_types.hpp> +#include <boost/thread/condition_variable.hpp> +#include <boost/chrono/duration.hpp> +#include <boost/chrono/time_point.hpp> +#include <boost/assert.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + class latch + { + /// @Requires: count_ must be greater than 0 + /// Effect: Decrement the count. Unlocks the lock and notify anyone waiting if we reached zero. + /// Returns: true if count_ reached the value 0. + /// @ThreadSafe ensured by the @c lk parameter + bool count_down(unique_lock<mutex> &lk) + /// pre_condition (count_ > 0) + { + BOOST_ASSERT(count_ > 0); + if (--count_ == 0) + { + ++generation_; + //lk.unlock(); + cond_.notify_all(); + return true; + } + return false; + } + /// Effect: Decrement the count is > 0. Unlocks the lock notify anyone waiting if we reached zero. + /// Returns: true if count_ is 0. + /// @ThreadSafe ensured by the @c lk parameter + bool try_count_down(unique_lock<mutex> &lk) + { + if (count_ > 0) + { + return count_down(lk); + } + return true; + } + public: + BOOST_THREAD_NO_COPYABLE( latch) + + /// Constructs a latch with a given count. + latch(std::size_t count) : + count_(count), generation_(0) + { + } + + /// Destructor + /// Precondition: No threads are waiting or invoking count_down on @c *this. + + ~latch() + { + + } + + /// Blocks until the latch has counted down to zero. + void wait() + { + boost::unique_lock<boost::mutex> lk(mutex_); + std::size_t generation(generation_); + cond_.wait(lk, detail::not_equal(generation, generation_)); + } + + /// @return true if the internal counter is already 0, false otherwise + bool try_wait() + { + boost::unique_lock<boost::mutex> lk(mutex_); + return (count_ == 0); + } + + /// try to wait for a specified amount of time is elapsed. + /// @return whether there is a timeout or not. + template <class Rep, class Period> + cv_status wait_for(const chrono::duration<Rep, Period>& rel_time) + { + boost::unique_lock<boost::mutex> lk(mutex_); + std::size_t generation(generation_); + return cond_.wait_for(lk, rel_time, detail::not_equal(generation, generation_)) + ? cv_status::no_timeout + : cv_status::timeout; + } + + /// try to wait until the specified time_point is reached + /// @return whether there were a timeout or not. + template <class Clock, class Duration> + cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) + { + boost::unique_lock<boost::mutex> lk(mutex_); + std::size_t generation(generation_); + return cond_.wait_until(lk, abs_time, detail::not_equal(generation, generation_)) + ? cv_status::no_timeout + : cv_status::timeout; + } + + /// Decrement the count and notify anyone waiting if we reach zero. + /// @Requires count must be greater than 0 + void count_down() + { + boost::unique_lock<boost::mutex> lk(mutex_); + count_down(lk); + } + /// Effect: Decrement the count if it is > 0 and notify anyone waiting if we reached zero. + /// Returns: true if count_ was 0 or reached 0. + bool try_count_down() + { + boost::unique_lock<boost::mutex> lk(mutex_); + return try_count_down(lk); + } + void signal() + { + count_down(); + } + + /// Decrement the count and notify anyone waiting if we reach zero. + /// Blocks until the latch has counted down to zero. + /// @Requires count must be greater than 0 + void count_down_and_wait() + { + boost::unique_lock<boost::mutex> lk(mutex_); + std::size_t generation(generation_); + if (count_down(lk)) + { + return; + } + cond_.wait(lk, detail::not_equal(generation, generation_)); + } + void sync() + { + count_down_and_wait(); + } + + /// Reset the counter + /// #Requires This method may only be invoked when there are no other threads currently inside the count_down_and_wait() method. + void reset(std::size_t count) + { + boost::lock_guard<boost::mutex> lk(mutex_); + //BOOST_ASSERT(count_ == 0); + count_ = count; + } + + private: + mutex mutex_; + condition_variable cond_; + std::size_t count_; + std::size_t generation_; + }; + +} // namespace boost + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/lock_algorithms.hpp b/boost/thread/lock_algorithms.hpp new file mode 100644 index 0000000000..7a55f92a28 --- /dev/null +++ b/boost/thread/lock_algorithms.hpp @@ -0,0 +1,468 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_LOCK_ALGORITHMS_HPP +#define BOOST_THREAD_LOCK_ALGORITHMS_HPP + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/lock_types.hpp> +#include <boost/thread/lockable_traits.hpp> + +#include <algorithm> +#include <iterator> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + namespace detail + { + template <typename MutexType1, typename MutexType2> + unsigned try_lock_internal(MutexType1& m1, MutexType2& m2) + { + boost::unique_lock<MutexType1> l1(m1, boost::try_to_lock); + if (!l1) + { + return 1; + } + if (!m2.try_lock()) + { + return 2; + } + l1.release(); + return 0; + } + + template <typename MutexType1, typename MutexType2, typename MutexType3> + unsigned try_lock_internal(MutexType1& m1, MutexType2& m2, MutexType3& m3) + { + boost::unique_lock<MutexType1> l1(m1, boost::try_to_lock); + if (!l1) + { + return 1; + } + if (unsigned const failed_lock=try_lock_internal(m2,m3)) + { + return failed_lock + 1; + } + l1.release(); + return 0; + } + + template <typename MutexType1, typename MutexType2, typename MutexType3, typename MutexType4> + unsigned try_lock_internal(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4) + { + boost::unique_lock<MutexType1> l1(m1, boost::try_to_lock); + if (!l1) + { + return 1; + } + if (unsigned const failed_lock=try_lock_internal(m2,m3,m4)) + { + return failed_lock + 1; + } + l1.release(); + return 0; + } + + template <typename MutexType1, typename MutexType2, typename MutexType3, typename MutexType4, typename MutexType5> + unsigned try_lock_internal(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4, MutexType5& m5) + { + boost::unique_lock<MutexType1> l1(m1, boost::try_to_lock); + if (!l1) + { + return 1; + } + if (unsigned const failed_lock=try_lock_internal(m2,m3,m4,m5)) + { + return failed_lock + 1; + } + l1.release(); + return 0; + } + + template <typename MutexType1, typename MutexType2> + unsigned lock_helper(MutexType1& m1, MutexType2& m2) + { + boost::unique_lock<MutexType1> l1(m1); + if (!m2.try_lock()) + { + return 1; + } + l1.release(); + return 0; + } + + template <typename MutexType1, typename MutexType2, typename MutexType3> + unsigned lock_helper(MutexType1& m1, MutexType2& m2, MutexType3& m3) + { + boost::unique_lock<MutexType1> l1(m1); + if (unsigned const failed_lock=try_lock_internal(m2,m3)) + { + return failed_lock; + } + l1.release(); + return 0; + } + + template <typename MutexType1, typename MutexType2, typename MutexType3, typename MutexType4> + unsigned lock_helper(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4) + { + boost::unique_lock<MutexType1> l1(m1); + if (unsigned const failed_lock=try_lock_internal(m2,m3,m4)) + { + return failed_lock; + } + l1.release(); + return 0; + } + + template <typename MutexType1, typename MutexType2, typename MutexType3, typename MutexType4, typename MutexType5> + unsigned lock_helper(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4, MutexType5& m5) + { + boost::unique_lock<MutexType1> l1(m1); + if (unsigned const failed_lock=try_lock_internal(m2,m3,m4,m5)) + { + return failed_lock; + } + l1.release(); + return 0; + } + } + + namespace detail + { + template <bool x> + struct is_mutex_type_wrapper + { + }; + + template <typename MutexType1, typename MutexType2> + void lock_impl(MutexType1& m1, MutexType2& m2, is_mutex_type_wrapper<true> ) + { + unsigned const lock_count = 2; + unsigned lock_first = 0; + for (;;) + { + switch (lock_first) + { + case 0: + lock_first = detail::lock_helper(m1, m2); + if (!lock_first) return; + break; + case 1: + lock_first = detail::lock_helper(m2, m1); + if (!lock_first) return; + lock_first = (lock_first + 1) % lock_count; + break; + } + } + } + + template <typename Iterator> + void lock_impl(Iterator begin, Iterator end, is_mutex_type_wrapper<false> ); + } + + template <typename MutexType1, typename MutexType2> + void lock(MutexType1& m1, MutexType2& m2) + { + detail::lock_impl(m1, m2, detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); + } + + template <typename MutexType1, typename MutexType2> + void lock(const MutexType1& m1, MutexType2& m2) + { + detail::lock_impl(m1, m2, detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); + } + + template <typename MutexType1, typename MutexType2> + void lock(MutexType1& m1, const MutexType2& m2) + { + detail::lock_impl(m1, m2, detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); + } + + template <typename MutexType1, typename MutexType2> + void lock(const MutexType1& m1, const MutexType2& m2) + { + detail::lock_impl(m1, m2, detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); + } + + template <typename MutexType1, typename MutexType2, typename MutexType3> + void lock(MutexType1& m1, MutexType2& m2, MutexType3& m3) + { + unsigned const lock_count = 3; + unsigned lock_first = 0; + for (;;) + { + switch (lock_first) + { + case 0: + lock_first = detail::lock_helper(m1, m2, m3); + if (!lock_first) return; + break; + case 1: + lock_first = detail::lock_helper(m2, m3, m1); + if (!lock_first) return; + lock_first = (lock_first + 1) % lock_count; + break; + case 2: + lock_first = detail::lock_helper(m3, m1, m2); + if (!lock_first) return; + lock_first = (lock_first + 2) % lock_count; + break; + } + } + } + + template <typename MutexType1, typename MutexType2, typename MutexType3, typename MutexType4> + void lock(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4) + { + unsigned const lock_count = 4; + unsigned lock_first = 0; + for (;;) + { + switch (lock_first) + { + case 0: + lock_first = detail::lock_helper(m1, m2, m3, m4); + if (!lock_first) return; + break; + case 1: + lock_first = detail::lock_helper(m2, m3, m4, m1); + if (!lock_first) return; + lock_first = (lock_first + 1) % lock_count; + break; + case 2: + lock_first = detail::lock_helper(m3, m4, m1, m2); + if (!lock_first) return; + lock_first = (lock_first + 2) % lock_count; + break; + case 3: + lock_first = detail::lock_helper(m4, m1, m2, m3); + if (!lock_first) return; + lock_first = (lock_first + 3) % lock_count; + break; + } + } + } + + template <typename MutexType1, typename MutexType2, typename MutexType3, typename MutexType4, typename MutexType5> + void lock(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4, MutexType5& m5) + { + unsigned const lock_count = 5; + unsigned lock_first = 0; + for (;;) + { + switch (lock_first) + { + case 0: + lock_first = detail::lock_helper(m1, m2, m3, m4, m5); + if (!lock_first) return; + break; + case 1: + lock_first = detail::lock_helper(m2, m3, m4, m5, m1); + if (!lock_first) return; + lock_first = (lock_first + 1) % lock_count; + break; + case 2: + lock_first = detail::lock_helper(m3, m4, m5, m1, m2); + if (!lock_first) return; + lock_first = (lock_first + 2) % lock_count; + break; + case 3: + lock_first = detail::lock_helper(m4, m5, m1, m2, m3); + if (!lock_first) return; + lock_first = (lock_first + 3) % lock_count; + break; + case 4: + lock_first = detail::lock_helper(m5, m1, m2, m3, m4); + if (!lock_first) return; + lock_first = (lock_first + 4) % lock_count; + break; + } + } + } + + namespace detail + { + template <typename Mutex, bool x = is_mutex_type<Mutex>::value> + struct try_lock_impl_return + { + typedef int type; + }; + + template <typename Iterator> + struct try_lock_impl_return<Iterator, false> + { + typedef Iterator type; + }; + + template <typename MutexType1, typename MutexType2> + int try_lock_impl(MutexType1& m1, MutexType2& m2, is_mutex_type_wrapper<true> ) + { + return ((int) detail::try_lock_internal(m1, m2)) - 1; + } + + template <typename Iterator> + Iterator try_lock_impl(Iterator begin, Iterator end, is_mutex_type_wrapper<false> ); + } + + template <typename MutexType1, typename MutexType2> + typename detail::try_lock_impl_return<MutexType1>::type try_lock(MutexType1& m1, MutexType2& m2) + { + return detail::try_lock_impl(m1, m2, detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); + } + + template <typename MutexType1, typename MutexType2> + typename detail::try_lock_impl_return<MutexType1>::type try_lock(const MutexType1& m1, MutexType2& m2) + { + return detail::try_lock_impl(m1, m2, detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); + } + + template <typename MutexType1, typename MutexType2> + typename detail::try_lock_impl_return<MutexType1>::type try_lock(MutexType1& m1, const MutexType2& m2) + { + return detail::try_lock_impl(m1, m2, detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); + } + + template <typename MutexType1, typename MutexType2> + typename detail::try_lock_impl_return<MutexType1>::type try_lock(const MutexType1& m1, const MutexType2& m2) + { + return detail::try_lock_impl(m1, m2, detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); + } + + template <typename MutexType1, typename MutexType2, typename MutexType3> + int try_lock(MutexType1& m1, MutexType2& m2, MutexType3& m3) + { + return ((int) detail::try_lock_internal(m1, m2, m3)) - 1; + } + + template <typename MutexType1, typename MutexType2, typename MutexType3, typename MutexType4> + int try_lock(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4) + { + return ((int) detail::try_lock_internal(m1, m2, m3, m4)) - 1; + } + + template <typename MutexType1, typename MutexType2, typename MutexType3, typename MutexType4, typename MutexType5> + int try_lock(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4, MutexType5& m5) + { + return ((int) detail::try_lock_internal(m1, m2, m3, m4, m5)) - 1; + } + + namespace detail + { + template <typename Iterator> + struct range_lock_guard + { + Iterator begin; + Iterator end; + + range_lock_guard(Iterator begin_, Iterator end_) : + begin(begin_), end(end_) + { + boost::lock(begin, end); + } + + void release() + { + begin = end; + } + + ~range_lock_guard() + { + for (; begin != end; ++begin) + { + begin->unlock(); + } + } + }; + + template <typename Iterator> + Iterator try_lock_impl(Iterator begin, Iterator end, is_mutex_type_wrapper<false> ) + + { + if (begin == end) + { + return end; + } + typedef typename std::iterator_traits<Iterator>::value_type lock_type; + unique_lock<lock_type> guard(*begin, try_to_lock); + + if (!guard.owns_lock()) + { + return begin; + } + Iterator const failed = boost::try_lock(++begin, end); + if (failed == end) + { + guard.release(); + } + + return failed; + } + } + + namespace detail + { + template <typename Iterator> + void lock_impl(Iterator begin, Iterator end, is_mutex_type_wrapper<false> ) + { + typedef typename std::iterator_traits<Iterator>::value_type lock_type; + + if (begin == end) + { + return; + } + bool start_with_begin = true; + Iterator second = begin; + ++second; + Iterator next = second; + + for (;;) + { + unique_lock<lock_type> begin_lock(*begin, defer_lock); + if (start_with_begin) + { + begin_lock.lock(); + Iterator const failed_lock = boost::try_lock(next, end); + if (failed_lock == end) + { + begin_lock.release(); + return; + } + start_with_begin = false; + next = failed_lock; + } + else + { + detail::range_lock_guard<Iterator> guard(next, end); + if (begin_lock.try_lock()) + { + Iterator const failed_lock = boost::try_lock(second, next); + if (failed_lock == next) + { + begin_lock.release(); + guard.release(); + return; + } + start_with_begin = false; + next = failed_lock; + } + else + { + start_with_begin = true; + next = second; + } + } + } + } + + } + +} +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/lock_concepts.hpp b/boost/thread/lock_concepts.hpp new file mode 100644 index 0000000000..d96c3dc1b9 --- /dev/null +++ b/boost/thread/lock_concepts.hpp @@ -0,0 +1,197 @@ +// (C) Copyright 2012 Vicente Botet +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_THREAD_LOCK_CONCEPTS_HPP +#define BOOST_THREAD_LOCK_CONCEPTS_HPP + +#include <boost/thread/lock_traits.hpp> +#include <boost/thread/lock_options.hpp> +#include <boost/thread/lockable_concepts.hpp> +#include <boost/thread/exceptions.hpp> +#include <boost/thread/detail/move.hpp> + +#include <boost/chrono/chrono.hpp> +#include <boost/concept_check.hpp> +#include <boost/static_assert.hpp> + +namespace boost +{ + + /** + * BasicLock object supports the basic features + * required to delimit a critical region + * Supports the basic lock, unlock and try_lock functions and + * defines the lock traits + */ + + template <typename Lk> + struct BasicLock + { + typedef typename Lk::mutex_type mutex_type; + void cvt_mutex_ptr(mutex_type*) {} + BOOST_CONCEPT_ASSERT(( BasicLockable<mutex_type> )); + + BOOST_CONCEPT_USAGE(BasicLock) + { + const Lk l1(mtx); + Lk l2(mtx, defer_lock); + Lk l3(mtx, adopt_lock); + Lk l4(( Lk())); + Lk l5(( boost::move(l2))); + cvt_mutex_ptr(l1.mutex()); + if (l1.owns_lock()) return; + if (l1) return; + if (!l1) return; + + l2.lock(); + l2.unlock(); + l2.release(); + + } + BasicLock() : + mtx(*static_cast<mutex_type*>(0)) + {} + private: + BasicLock operator=(BasicLock const&); + mutex_type& mtx; + } + ; + + template <typename Lk> + struct Lock + { + BOOST_CONCEPT_ASSERT(( BasicLock<Lk> )); + typedef typename Lk::mutex_type mutex_type; + BOOST_CONCEPT_ASSERT(( Lockable<mutex_type> )); + + BOOST_CONCEPT_USAGE(Lock) + { + Lk l1(mtx, try_to_lock); + if (l1.try_lock()) return; + } + Lock() : + mtx(*static_cast<mutex_type*>(0)) + {} + private: + Lock operator=(Lock const&); + mutex_type& mtx; + }; + + template <typename Lk> + struct TimedLock + { + BOOST_CONCEPT_ASSERT(( Lock<Lk> )); + typedef typename Lk::mutex_type mutex_type; + BOOST_CONCEPT_ASSERT(( TimedLockable<mutex_type> )); + + BOOST_CONCEPT_USAGE(TimedLock) + { + const Lk l1(mtx, t); + Lk l2(mtx, d); + if (l1.try_lock_until(t)) return; + if (l1.try_lock_for(d)) return; + } + TimedLock() : + mtx(*static_cast<mutex_type*>(0)) + {} + private: + TimedLock operator=(TimedLock const&); + mutex_type& mtx; + boost::chrono::system_clock::time_point t; + boost::chrono::system_clock::duration d; + }; + + template <typename Lk> + struct UniqueLock + { + BOOST_CONCEPT_ASSERT(( TimedLock<Lk> )); + typedef typename Lk::mutex_type mutex_type; + + BOOST_CONCEPT_USAGE(UniqueLock) + { + + } + UniqueLock() : + mtx(*static_cast<mutex_type*>(0)) + {} + private: + UniqueLock operator=(UniqueLock const&); + mutex_type& mtx; + }; + + template <typename Lk> + struct SharedLock + { + BOOST_CONCEPT_ASSERT(( TimedLock<Lk> )); + typedef typename Lk::mutex_type mutex_type; + + BOOST_CONCEPT_USAGE(SharedLock) + { + } + SharedLock() : + mtx(*static_cast<mutex_type*>(0)) + {} + private: + SharedLock operator=(SharedLock const&); + mutex_type& mtx; + + }; + + template <typename Lk> + struct UpgradeLock + { + BOOST_CONCEPT_ASSERT(( SharedLock<Lk> )); + typedef typename Lk::mutex_type mutex_type; + + BOOST_CONCEPT_USAGE(UpgradeLock) + { + } + UpgradeLock() : + mtx(*static_cast<mutex_type*>(0)) + {} + private: + UpgradeLock operator=(UpgradeLock const&); + mutex_type& mtx; + }; + + /** + * An StrictLock is a scoped lock guard ensuring the mutex is locked on the + * scope of the lock, by locking the mutex on construction and unlocking it on + * destruction. + * + * Essentially, a StrictLock's role is only to live on the stack as an + * automatic variable. strict_lock must adhere to a non-copy and non-alias + * policy. StrictLock disables copying by making the copy constructor and the + * assignment operator private. While we're at it, let's disable operator new + * and operator delete; strict locks are not intended to be allocated on the + * heap. StrictLock avoids aliasing by using a slightly less orthodox and + * less well-known technique: disable address taking. + */ + + template <typename Lk> + struct StrictLock + { + typedef typename Lk::mutex_type mutex_type; + BOOST_CONCEPT_ASSERT(( BasicLockable<mutex_type> )); + BOOST_STATIC_ASSERT(( is_strict_lock<Lk>::value )); + + BOOST_CONCEPT_USAGE( StrictLock) + { + if (l1.owns_lock(&mtx)) return; + } + StrictLock() : + l1(*static_cast<Lk*>(0)), + mtx(*static_cast<mutex_type*>(0)) + {} + private: + StrictLock operator=(StrictLock const&); + + Lk const& l1; + mutex_type const& mtx; + + }; + +} +#endif diff --git a/boost/thread/lock_factories.hpp b/boost/thread/lock_factories.hpp new file mode 100644 index 0000000000..523b90a5ea --- /dev/null +++ b/boost/thread/lock_factories.hpp @@ -0,0 +1,78 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_LOCK_FACTORIES_HPP +#define BOOST_THREAD_LOCK_FACTORIES_HPP + +#include <boost/thread/lock_types.hpp> +#include <boost/thread/lock_algorithms.hpp> +#if ! defined(BOOST_THREAD_NO_MAKE_UNIQUE_LOCKS) +#include <tuple> // todo change to <boost/tuple.hpp> once Boost.Tuple or Boost.Fusion provides Move semantics. +#endif +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + + template <typename Lockable> + unique_lock<Lockable> make_unique_lock(Lockable& mtx) + { + return unique_lock<Lockable> (mtx); + } + + template <typename Lockable> + unique_lock<Lockable> make_unique_lock(Lockable& mtx, adopt_lock_t) + { + return unique_lock<Lockable> (mtx, adopt_lock); + } + + template <typename Lockable> + unique_lock<Lockable> make_unique_lock(Lockable& mtx, defer_lock_t) + { + return unique_lock<Lockable> (mtx, defer_lock); + } + + template <typename Lockable> + unique_lock<Lockable> make_unique_lock(Lockable& mtx, try_to_lock_t) + { + return unique_lock<Lockable> (mtx, try_to_lock); + } +#if ! defined(BOOST_THREAD_NO_MAKE_UNIQUE_LOCKS) + +#if ! defined BOOST_NO_CXX11_VARIADIC_TEMPLATES + template <typename ...Lockable> + std::tuple<unique_lock<Lockable> ...> make_unique_locks(Lockable& ...mtx) + { + boost::lock(mtx...); + return std::tuple<unique_lock<Lockable> ...>(unique_lock<Lockable>(mtx, adopt_lock)...); + } +#else + template <typename L1, typename L2> + std::tuple<unique_lock<L1>, unique_lock<L2> > make_unique_locks(L1& m1, L2& m2) + { + boost::lock(m1, m2); + return std::tuple<unique_lock<L1>,unique_lock<L2> >( + unique_lock<L1>(m1, adopt_lock), + unique_lock<L2>(m2, adopt_lock) + ); + } + template <typename L1, typename L2, typename L3> + std::tuple<unique_lock<L1>, unique_lock<L2>, unique_lock<L3> > make_unique_locks(L1& m1, L2& m2, L3& m3) + { + boost::lock(m1, m2, m3); + return std::tuple<unique_lock<L1>,unique_lock<L2>,unique_lock<L3> >( + unique_lock<L1>(m1, adopt_lock), + unique_lock<L2>(m2, adopt_lock), + unique_lock<L3>(m3, adopt_lock) + ); + } + +#endif +#endif + +} + +#include <boost/config/abi_suffix.hpp> +#endif diff --git a/boost/thread/lock_guard.hpp b/boost/thread/lock_guard.hpp new file mode 100644 index 0000000000..4c2908af43 --- /dev/null +++ b/boost/thread/lock_guard.hpp @@ -0,0 +1,88 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_LOCK_GUARD_HPP +#define BOOST_THREAD_LOCK_GUARD_HPP + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/delete.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/detail/lockable_wrapper.hpp> +#include <boost/thread/lock_options.hpp> +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS +#include <boost/thread/is_locked_by_this_thread.hpp> +#include <boost/assert.hpp> +#endif + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + + template <typename Mutex> + class lock_guard + { + private: + Mutex& m; + + public: + typedef Mutex mutex_type; + BOOST_THREAD_NO_COPYABLE( lock_guard ) + + explicit lock_guard(Mutex& m_) : + m(m_) + { + m.lock(); + } + + lock_guard(Mutex& m_, adopt_lock_t) : + m(m_) + { +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + BOOST_ASSERT(is_locked_by_this_thread(m)); +#endif + } + +#if ! defined BOOST_THREAD_NO_CXX11_HDR_INITIALIZER_LIST + lock_guard(std::initializer_list<thread_detail::lockable_wrapper<Mutex> > l_) : + m(*(const_cast<thread_detail::lockable_wrapper<Mutex>*>(l_.begin())->m)) + { + m.lock(); + } + + lock_guard(std::initializer_list<thread_detail::lockable_adopt_wrapper<Mutex> > l_) : + m(*(const_cast<thread_detail::lockable_adopt_wrapper<Mutex>*>(l_.begin())->m)) + { +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + BOOST_ASSERT(is_locked_by_this_thread(m)); +#endif + } + +#endif + ~lock_guard() + { + m.unlock(); + } + }; + + +#if ! defined BOOST_THREAD_NO_MAKE_LOCK_GUARD + template <typename Lockable> + lock_guard<Lockable> make_lock_guard(Lockable& mtx) + { + return { thread_detail::lockable_wrapper<Lockable>(mtx) }; + } + template <typename Lockable> + lock_guard<Lockable> make_lock_guard(Lockable& mtx, adopt_lock_t) + { + return { thread_detail::lockable_adopt_wrapper<Lockable>(mtx) }; + } +#endif +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/lock_options.hpp b/boost/thread/lock_options.hpp new file mode 100644 index 0000000000..68899ca89f --- /dev/null +++ b/boost/thread/lock_options.hpp @@ -0,0 +1,31 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_LOCK_OPTIONS_HPP +#define BOOST_THREAD_LOCK_OPTIONS_HPP + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + struct defer_lock_t + { + }; + struct try_to_lock_t + { + }; + struct adopt_lock_t + { + }; + + BOOST_CONSTEXPR_OR_CONST defer_lock_t defer_lock = {}; + BOOST_CONSTEXPR_OR_CONST try_to_lock_t try_to_lock = {}; + BOOST_CONSTEXPR_OR_CONST adopt_lock_t adopt_lock = {}; + +} +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/lock_traits.hpp b/boost/thread/lock_traits.hpp new file mode 100644 index 0000000000..e45d822983 --- /dev/null +++ b/boost/thread/lock_traits.hpp @@ -0,0 +1,45 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2009-2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_LOCK_TRAITS_HPP +#define BOOST_THREAD_LOCK_TRAITS_HPP + +#include <boost/thread/detail/config.hpp> +//#include <boost/thread/detail/move.hpp> +//#include <boost/thread/exceptions.hpp> +// +//#ifdef BOOST_THREAD_USES_CHRONO +//#include <boost/chrono/time_point.hpp> +//#include <boost/chrono/duration.hpp> +//#endif + +#include <boost/type_traits/integral_constant.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + +/** + * An strict lock is a lock ensuring the mutex is locked on the scope of the lock + * There is no single way to define a strict lock as the strict_lock and + * nesteed_strict_lock shows. So we need a metafunction that states if a + * lock is a strict lock "sur parole". + */ + +template <typename Lock> +struct is_strict_lock_sur_parolle : false_type {}; + + +template <typename Lock> +struct is_strict_lock_sur_parole : is_strict_lock_sur_parolle<Lock> {}; + +template <typename Lock> +struct is_strict_lock : is_strict_lock_sur_parole<Lock> {}; + +} +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/lock_types.hpp b/boost/thread/lock_types.hpp new file mode 100644 index 0000000000..2b73edfb02 --- /dev/null +++ b/boost/thread/lock_types.hpp @@ -0,0 +1,1230 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_LOCK_TYPES_HPP +#define BOOST_THREAD_LOCK_TYPES_HPP + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/exceptions.hpp> +#include <boost/thread/lock_options.hpp> +#include <boost/thread/lockable_traits.hpp> +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS +#include <boost/thread/is_locked_by_this_thread.hpp> +#endif +#include <boost/thread/thread_time.hpp> + +#include <boost/assert.hpp> +#ifdef BOOST_THREAD_USES_CHRONO +#include <boost/chrono/time_point.hpp> +#include <boost/chrono/duration.hpp> +#endif +#include <boost/detail/workaround.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + struct xtime; + + template <typename Mutex> + class shared_lock; + + template <typename Mutex> + class upgrade_lock; + + template <typename Mutex> + class unique_lock; + + namespace detail + { + template <typename Mutex> + class try_lock_wrapper; + } + +#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES + namespace sync + { + template<typename T> + struct is_basic_lockable<unique_lock<T> > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<typename T> + struct is_lockable<unique_lock<T> > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + template<typename T> + struct is_basic_lockable<shared_lock<T> > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<typename T> + struct is_lockable<shared_lock<T> > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + template<typename T> + struct is_basic_lockable<upgrade_lock<T> > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<typename T> + struct is_lockable<upgrade_lock<T> > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + template<typename T> + struct is_basic_lockable<detail::try_lock_wrapper<T> > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<typename T> + struct is_lockable<detail::try_lock_wrapper<T> > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + } +#endif + + + template <typename Mutex> + class unique_lock + { + private: + Mutex* m; + bool is_locked; + + private: + explicit unique_lock(upgrade_lock<Mutex>&); + unique_lock& operator=(upgrade_lock<Mutex>& other); + public: + typedef Mutex mutex_type; + BOOST_THREAD_MOVABLE_ONLY( unique_lock) + +#if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF. +#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) + unique_lock(const volatile unique_lock&); +#endif +#endif + unique_lock()BOOST_NOEXCEPT : + m(0),is_locked(false) + {} + + explicit unique_lock(Mutex& m_) : + m(&m_), is_locked(false) + { + lock(); + } + unique_lock(Mutex& m_, adopt_lock_t) : + m(&m_), is_locked(true) + { +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + BOOST_ASSERT(is_locked_by_this_thread(m)); +#endif + } + unique_lock(Mutex& m_, defer_lock_t)BOOST_NOEXCEPT: + m(&m_),is_locked(false) + {} + unique_lock(Mutex& m_, try_to_lock_t) : + m(&m_), is_locked(false) + { + try_lock(); + } +#if defined BOOST_THREAD_USES_DATETIME + template<typename TimeDuration> + unique_lock(Mutex& m_,TimeDuration const& target_time): + m(&m_),is_locked(false) + { + timed_lock(target_time); + } + unique_lock(Mutex& m_,system_time const& target_time): + m(&m_),is_locked(false) + { + timed_lock(target_time); + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + template <class Clock, class Duration> + unique_lock(Mutex& mtx, const chrono::time_point<Clock, Duration>& t) + : m(&mtx), is_locked(mtx.try_lock_until(t)) + { + } + template <class Rep, class Period> + unique_lock(Mutex& mtx, const chrono::duration<Rep, Period>& d) + : m(&mtx), is_locked(mtx.try_lock_for(d)) + { + } +#endif + + unique_lock(BOOST_THREAD_RV_REF(unique_lock) other) BOOST_NOEXCEPT: + m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) + { + BOOST_THREAD_RV(other).is_locked=false; + BOOST_THREAD_RV(other).m=0; + } + + BOOST_THREAD_EXPLICIT_LOCK_CONVERSION unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other); + +#ifndef BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION + //std-2104 unique_lock move-assignment should not be noexcept + unique_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other) //BOOST_NOEXCEPT + { + unique_lock temp(::boost::move(other)); + swap(temp); + return *this; + } +#endif + + //std-2104 unique_lock move-assignment should not be noexcept + unique_lock& operator=(BOOST_THREAD_RV_REF(unique_lock) other) //BOOST_NOEXCEPT + { + unique_lock temp(::boost::move(other)); + swap(temp); + return *this; + } +#if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF. +#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) + unique_lock& operator=(unique_lock<Mutex> other) + { + swap(other); + return *this; + } +#endif // BOOST_WORKAROUND +#endif + + // Conversion from upgrade locking + unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock<mutex_type> BOOST_THREAD_RV_REF_END ul, try_to_lock_t) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(ul).owns_lock()) + { + if (BOOST_THREAD_RV(ul).mutex()->try_unlock_upgrade_and_lock()) + { + m = BOOST_THREAD_RV(ul).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(ul).release(); + } + } + +#ifdef BOOST_THREAD_USES_CHRONO + template <class Clock, class Duration> + unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock<mutex_type> BOOST_THREAD_RV_REF_END ul, + const chrono::time_point<Clock, Duration>& abs_time) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(ul).owns_lock()) + { + if (BOOST_THREAD_RV(ul).mutex()->try_unlock_upgrade_and_lock_until(abs_time)) + { + m = BOOST_THREAD_RV(ul).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(ul).release(); + } + } + + template <class Rep, class Period> + unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock<mutex_type> BOOST_THREAD_RV_REF_END ul, + const chrono::duration<Rep, Period>& rel_time) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(ul).owns_lock()) + { + if (BOOST_THREAD_RV(ul).mutex()->try_unlock_upgrade_and_lock_for(rel_time)) + { + m = BOOST_THREAD_RV(ul).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(ul).release(); + } + } +#endif + +#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS + // Conversion from shared locking + unique_lock(BOOST_THREAD_RV_REF_BEG shared_lock<mutex_type> BOOST_THREAD_RV_REF_END sl, try_to_lock_t) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(sl).owns_lock()) + { + if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock()) + { + m = BOOST_THREAD_RV(sl).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(sl).release(); + } + } + +#ifdef BOOST_THREAD_USES_CHRONO + template <class Clock, class Duration> + unique_lock(BOOST_THREAD_RV_REF_BEG shared_lock<mutex_type> BOOST_THREAD_RV_REF_END sl, + const chrono::time_point<Clock, Duration>& abs_time) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(sl).owns_lock()) + { + if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_until(abs_time)) + { + m = BOOST_THREAD_RV(sl).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(sl).release(); + } + } + + template <class Rep, class Period> + unique_lock(BOOST_THREAD_RV_REF_BEG shared_lock<mutex_type> BOOST_THREAD_RV_REF_END sl, + const chrono::duration<Rep, Period>& rel_time) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(sl).owns_lock()) + { + if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_for(rel_time)) + { + m = BOOST_THREAD_RV(sl).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(sl).release(); + } + } +#endif // BOOST_THREAD_USES_CHRONO +#endif // BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS + + void swap(unique_lock& other)BOOST_NOEXCEPT + { + std::swap(m,other.m); + std::swap(is_locked,other.is_locked); + } + + ~unique_lock() + { + if (owns_lock()) + { + m->unlock(); + } + } + void lock() + { + if (m == 0) + { + boost::throw_exception( + boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex")); + } + if (owns_lock()) + { + boost::throw_exception( + boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex")); + } + m->lock(); + is_locked = true; + } + bool try_lock() + { + if (m == 0) + { + boost::throw_exception( + boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex")); + } + if (owns_lock()) + { + boost::throw_exception( + boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex")); + } + is_locked = m->try_lock(); + return is_locked; + } +#if defined BOOST_THREAD_USES_DATETIME + template<typename TimeDuration> + bool timed_lock(TimeDuration const& relative_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex")); + } + is_locked=m->timed_lock(relative_time); + return is_locked; + } + + bool timed_lock(::boost::system_time const& absolute_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex")); + } + is_locked=m->timed_lock(absolute_time); + return is_locked; + } + bool timed_lock(::boost::xtime const& absolute_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex")); + } + is_locked=m->timed_lock(absolute_time); + return is_locked; + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + + template <class Rep, class Period> + bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex")); + } + is_locked=m->try_lock_for(rel_time); + return is_locked; + } + template <class Clock, class Duration> + bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex")); + } + is_locked=m->try_lock_until(abs_time); + return is_locked; + } +#endif + + void unlock() + { + if (m == 0) + { + boost::throw_exception( + boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex")); + } + if (!owns_lock()) + { + boost::throw_exception( + boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock doesn't own the mutex")); + } + m->unlock(); + is_locked = false; + } + +#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) + typedef void (unique_lock::*bool_type)(); + operator bool_type() const BOOST_NOEXCEPT + { + return is_locked?&unique_lock::lock:0; + } + bool operator!() const BOOST_NOEXCEPT + { + return !owns_lock(); + } +#else + explicit operator bool() const BOOST_NOEXCEPT + { + return owns_lock(); + } +#endif + bool owns_lock() const BOOST_NOEXCEPT + { + return is_locked; + } + + Mutex* mutex() const BOOST_NOEXCEPT + { + return m; + } + + Mutex* release()BOOST_NOEXCEPT + { + Mutex* const res=m; + m=0; + is_locked=false; + return res; + } + + friend class shared_lock<Mutex> ; + friend class upgrade_lock<Mutex> ; + }; + + template<typename Mutex> + void swap(unique_lock<Mutex>& lhs, unique_lock<Mutex>& rhs) + BOOST_NOEXCEPT + { + lhs.swap(rhs); + } + + BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) unique_lock<Mutex> BOOST_THREAD_DCL_MOVABLE_END + + template<typename Mutex> + class shared_lock + { + protected: + Mutex* m; + bool is_locked; + + public: + typedef Mutex mutex_type; + BOOST_THREAD_MOVABLE_ONLY(shared_lock) + + shared_lock() BOOST_NOEXCEPT: + m(0),is_locked(false) + {} + + explicit shared_lock(Mutex& m_): + m(&m_),is_locked(false) + { + lock(); + } + shared_lock(Mutex& m_,adopt_lock_t): + m(&m_),is_locked(true) + { +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + BOOST_ASSERT(is_locked_by_this_thread(m)); +#endif + } + shared_lock(Mutex& m_,defer_lock_t) BOOST_NOEXCEPT: + m(&m_),is_locked(false) + {} + shared_lock(Mutex& m_,try_to_lock_t): + m(&m_),is_locked(false) + { + try_lock(); + } +#if defined BOOST_THREAD_USES_DATETIME + shared_lock(Mutex& m_,system_time const& target_time): + m(&m_),is_locked(false) + { + timed_lock(target_time); + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + template <class Clock, class Duration> + shared_lock(Mutex& mtx, const chrono::time_point<Clock, Duration>& t) + : m(&mtx), is_locked(mtx.try_lock_shared_until(t)) + { + } + template <class Rep, class Period> + shared_lock(Mutex& mtx, const chrono::duration<Rep, Period>& d) + : m(&mtx), is_locked(mtx.try_lock_shared_for(d)) + { + } +#endif + + shared_lock(BOOST_THREAD_RV_REF_BEG shared_lock<Mutex> BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT: + m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) + { + BOOST_THREAD_RV(other).is_locked=false; + BOOST_THREAD_RV(other).m=0; + } + + BOOST_THREAD_EXPLICIT_LOCK_CONVERSION shared_lock(BOOST_THREAD_RV_REF_BEG unique_lock<Mutex> BOOST_THREAD_RV_REF_END other): + m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) + { + if(is_locked) + { + m->unlock_and_lock_shared(); + } + BOOST_THREAD_RV(other).is_locked=false; + BOOST_THREAD_RV(other).m=0; + } + + BOOST_THREAD_EXPLICIT_LOCK_CONVERSION shared_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other): + m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) + { + if(is_locked) + { + m->unlock_upgrade_and_lock_shared(); + } + BOOST_THREAD_RV(other).is_locked=false; + BOOST_THREAD_RV(other).m=0; + } + + //std-2104 unique_lock move-assignment should not be noexcept + shared_lock& operator=(BOOST_THREAD_RV_REF_BEG shared_lock<Mutex> BOOST_THREAD_RV_REF_END other) //BOOST_NOEXCEPT + { + shared_lock temp(::boost::move(other)); + swap(temp); + return *this; + } +#ifndef BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION + shared_lock& operator=(BOOST_THREAD_RV_REF_BEG unique_lock<Mutex> BOOST_THREAD_RV_REF_END other) + { + shared_lock temp(::boost::move(other)); + swap(temp); + return *this; + } + + shared_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other) + { + shared_lock temp(::boost::move(other)); + swap(temp); + return *this; + } +#endif + + void swap(shared_lock& other) BOOST_NOEXCEPT + { + std::swap(m,other.m); + std::swap(is_locked,other.is_locked); + } + + Mutex* mutex() const BOOST_NOEXCEPT + { + return m; + } + + Mutex* release() BOOST_NOEXCEPT + { + Mutex* const res=m; + m=0; + is_locked=false; + return res; + } + + ~shared_lock() + { + if(owns_lock()) + { + m->unlock_shared(); + } + } + void lock() + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex")); + } + m->lock_shared(); + is_locked=true; + } + bool try_lock() + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex")); + } + is_locked=m->try_lock_shared(); + return is_locked; + } +#if defined BOOST_THREAD_USES_DATETIME + bool timed_lock(boost::system_time const& target_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex")); + } + is_locked=m->timed_lock_shared(target_time); + return is_locked; + } + template<typename Duration> + bool timed_lock(Duration const& target_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex")); + } + is_locked=m->timed_lock_shared(target_time); + return is_locked; + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + template <class Rep, class Period> + bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex")); + } + is_locked=m->try_lock_shared_for(rel_time); + return is_locked; + } + template <class Clock, class Duration> + bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex")); + } + is_locked=m->try_lock_shared_until(abs_time); + return is_locked; + } +#endif + void unlock() + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex")); + } + if(!owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock doesn't own the mutex")); + } + m->unlock_shared(); + is_locked=false; + } + +#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) + typedef void (shared_lock<Mutex>::*bool_type)(); + operator bool_type() const BOOST_NOEXCEPT + { + return is_locked?&shared_lock::lock:0; + } + bool operator!() const BOOST_NOEXCEPT + { + return !owns_lock(); + } +#else + explicit operator bool() const BOOST_NOEXCEPT + { + return owns_lock(); + } +#endif + bool owns_lock() const BOOST_NOEXCEPT + { + return is_locked; + } + + }; + + BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) shared_lock<Mutex> BOOST_THREAD_DCL_MOVABLE_END + + template<typename Mutex> + void swap(shared_lock<Mutex>& lhs,shared_lock<Mutex>& rhs) BOOST_NOEXCEPT + { + lhs.swap(rhs); + } + + template <typename Mutex> + class upgrade_lock + { + protected: + Mutex* m; + bool is_locked; + + public: + typedef Mutex mutex_type; + BOOST_THREAD_MOVABLE_ONLY( upgrade_lock) + + upgrade_lock()BOOST_NOEXCEPT: + m(0),is_locked(false) + {} + + explicit upgrade_lock(Mutex& m_) : + m(&m_), is_locked(false) + { + lock(); + } + upgrade_lock(Mutex& m_, adopt_lock_t) : + m(&m_), is_locked(true) + { +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + BOOST_ASSERT(is_locked_by_this_thread(m)); +#endif + } + upgrade_lock(Mutex& m_, defer_lock_t)BOOST_NOEXCEPT: + m(&m_),is_locked(false) + {} + upgrade_lock(Mutex& m_, try_to_lock_t) : + m(&m_), is_locked(false) + { + try_lock(); + } + +#ifdef BOOST_THREAD_USES_CHRONO + template <class Clock, class Duration> + upgrade_lock(Mutex& mtx, const chrono::time_point<Clock, Duration>& t) + : m(&mtx), is_locked(mtx.try_lock_upgrade_until(t)) + { + } + template <class Rep, class Period> + upgrade_lock(Mutex& mtx, const chrono::duration<Rep, Period>& d) + : m(&mtx), is_locked(mtx.try_lock_upgrade_for(d)) + { + } +#endif + + upgrade_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT: + m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) + { + BOOST_THREAD_RV(other).is_locked=false; + BOOST_THREAD_RV(other).m=0; + } + + BOOST_THREAD_EXPLICIT_LOCK_CONVERSION upgrade_lock(BOOST_THREAD_RV_REF_BEG unique_lock<Mutex> BOOST_THREAD_RV_REF_END other): + m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) + { + if(is_locked) + { + m->unlock_and_lock_upgrade(); + } + BOOST_THREAD_RV(other).is_locked=false; + BOOST_THREAD_RV(other).m=0; + } + + //std-2104 unique_lock move-assignment should not be noexcept + upgrade_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other) //BOOST_NOEXCEPT + { + upgrade_lock temp(::boost::move(other)); + swap(temp); + return *this; + } + +#ifndef BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION + upgrade_lock& operator=(BOOST_THREAD_RV_REF_BEG unique_lock<Mutex> BOOST_THREAD_RV_REF_END other) + { + upgrade_lock temp(::boost::move(other)); + swap(temp); + return *this; + } +#endif + +#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS + // Conversion from shared locking + upgrade_lock(BOOST_THREAD_RV_REF_BEG shared_lock<mutex_type> BOOST_THREAD_RV_REF_END sl, try_to_lock_t) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(sl).owns_lock()) + { + if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_upgrade()) + { + m = BOOST_THREAD_RV(sl).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(sl).release(); + } + } + +#ifdef BOOST_THREAD_USES_CHRONO + template <class Clock, class Duration> + upgrade_lock(BOOST_THREAD_RV_REF_BEG shared_lock<mutex_type> BOOST_THREAD_RV_REF_END sl, + const chrono::time_point<Clock, Duration>& abs_time) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(sl).owns_lock()) + { + if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_upgrade_until(abs_time)) + { + m = BOOST_THREAD_RV(sl).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(sl).release(); + } + } + + template <class Rep, class Period> + upgrade_lock(BOOST_THREAD_RV_REF_BEG shared_lock<mutex_type> BOOST_THREAD_RV_REF_END sl, + const chrono::duration<Rep, Period>& rel_time) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(sl).owns_lock()) + { + if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_upgrade_for(rel_time)) + { + m = BOOST_THREAD_RV(sl).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(sl).release(); + } + } +#endif // BOOST_THREAD_USES_CHRONO +#endif // BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS + void swap(upgrade_lock& other)BOOST_NOEXCEPT + { + std::swap(m,other.m); + std::swap(is_locked,other.is_locked); + } + Mutex* mutex() const BOOST_NOEXCEPT + { + return m; + } + + Mutex* release()BOOST_NOEXCEPT + { + Mutex* const res=m; + m=0; + is_locked=false; + return res; + } + ~upgrade_lock() + { + if (owns_lock()) + { + m->unlock_upgrade(); + } + } + void lock() + { + if (m == 0) + { + boost::throw_exception( + boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex")); + } + if (owns_lock()) + { + boost::throw_exception( + boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost upgrade_lock owns already the mutex")); + } + m->lock_upgrade(); + is_locked = true; + } + bool try_lock() + { + if (m == 0) + { + boost::throw_exception( + boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex")); + } + if (owns_lock()) + { + boost::throw_exception( + boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost upgrade_lock owns already the mutex")); + } + is_locked = m->try_lock_upgrade(); + return is_locked; + } + void unlock() + { + if (m == 0) + { + boost::throw_exception( + boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex")); + } + if (!owns_lock()) + { + boost::throw_exception( + boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost upgrade_lock doesn't own the mutex")); + } + m->unlock_upgrade(); + is_locked = false; + } +#ifdef BOOST_THREAD_USES_CHRONO + template <class Rep, class Period> + bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex")); + } + is_locked=m->try_lock_upgrade_for(rel_time); + return is_locked; + } + template <class Clock, class Duration> + bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex")); + } + is_locked=m->try_lock_upgrade_until(abs_time); + return is_locked; + } +#endif +#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) + typedef void (upgrade_lock::*bool_type)(); + operator bool_type() const BOOST_NOEXCEPT + { + return is_locked?&upgrade_lock::lock:0; + } + bool operator!() const BOOST_NOEXCEPT + { + return !owns_lock(); + } +#else + explicit operator bool() const BOOST_NOEXCEPT + { + return owns_lock(); + } +#endif + bool owns_lock() const BOOST_NOEXCEPT + { + return is_locked; + } + friend class shared_lock<Mutex> ; + friend class unique_lock<Mutex> ; + }; + + template<typename Mutex> + void swap(upgrade_lock<Mutex>& lhs, upgrade_lock<Mutex>& rhs) + BOOST_NOEXCEPT + { + lhs.swap(rhs); + } + + BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) upgrade_lock<Mutex> BOOST_THREAD_DCL_MOVABLE_END + + template<typename Mutex> + unique_lock<Mutex>::unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other): + m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) + { + if(is_locked) + { + m->unlock_upgrade_and_lock(); + } + BOOST_THREAD_RV(other).release(); + } + + template <class Mutex> + class upgrade_to_unique_lock + { + private: + upgrade_lock<Mutex>* source; + unique_lock<Mutex> exclusive; + + public: + typedef Mutex mutex_type; + BOOST_THREAD_MOVABLE_ONLY( upgrade_to_unique_lock) + + explicit upgrade_to_unique_lock(upgrade_lock<Mutex>& m_) : + source(&m_), exclusive(::boost::move(*source)) + { + } + ~upgrade_to_unique_lock() + { + if (source) + { + *source = BOOST_THREAD_MAKE_RV_REF(upgrade_lock<Mutex> (::boost::move(exclusive))); + } + } + + upgrade_to_unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_to_unique_lock<Mutex> BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT: + source(BOOST_THREAD_RV(other).source),exclusive(::boost::move(BOOST_THREAD_RV(other).exclusive)) + { + BOOST_THREAD_RV(other).source=0; + } + + //std-2104 unique_lock move-assignment should not be noexcept + upgrade_to_unique_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_to_unique_lock<Mutex> BOOST_THREAD_RV_REF_END other) //BOOST_NOEXCEPT + { + upgrade_to_unique_lock temp(other); + swap(temp); + return *this; + } + + void swap(upgrade_to_unique_lock& other)BOOST_NOEXCEPT + { + std::swap(source,other.source); + exclusive.swap(other.exclusive); + } + +#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) + typedef void (upgrade_to_unique_lock::*bool_type)(upgrade_to_unique_lock&); + operator bool_type() const BOOST_NOEXCEPT + { + return exclusive.owns_lock()?&upgrade_to_unique_lock::swap:0; + } + bool operator!() const BOOST_NOEXCEPT + { + return !owns_lock(); + } +#else + explicit operator bool() const BOOST_NOEXCEPT + { + return owns_lock(); + } +#endif + + bool owns_lock() const BOOST_NOEXCEPT + { + return exclusive.owns_lock(); + } + Mutex* mutex() const BOOST_NOEXCEPT + { + return exclusive.mutex(); + } + }; + +BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) upgrade_to_unique_lock<Mutex> BOOST_THREAD_DCL_MOVABLE_END + +namespace detail +{ + template<typename Mutex> + class try_lock_wrapper: +private unique_lock<Mutex> + { + typedef unique_lock<Mutex> base; + public: + BOOST_THREAD_MOVABLE_ONLY(try_lock_wrapper) + + try_lock_wrapper() + {} + + explicit try_lock_wrapper(Mutex& m): + base(m,try_to_lock) + {} + + try_lock_wrapper(Mutex& m_,adopt_lock_t): + base(m_,adopt_lock) + { +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + BOOST_ASSERT(is_locked_by_this_thread(m_)); +#endif + } + try_lock_wrapper(Mutex& m_,defer_lock_t): + base(m_,defer_lock) + {} + try_lock_wrapper(Mutex& m_,try_to_lock_t): + base(m_,try_to_lock) + {} +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + try_lock_wrapper(BOOST_THREAD_RV_REF(try_lock_wrapper) other): + base(::boost::move(other)) + {} + +#elif defined BOOST_THREAD_USES_MOVE + try_lock_wrapper(BOOST_THREAD_RV_REF(try_lock_wrapper) other): + base(::boost::move(static_cast<base&>(other))) + {} + +#else + try_lock_wrapper(BOOST_THREAD_RV_REF(try_lock_wrapper) other): + base(BOOST_THREAD_RV_REF(base)(*other)) + {} +#endif + try_lock_wrapper& operator=(BOOST_THREAD_RV_REF_BEG try_lock_wrapper<Mutex> BOOST_THREAD_RV_REF_END other) + { + try_lock_wrapper temp(other); + swap(temp); + return *this; + } + void swap(try_lock_wrapper& other) + { + base::swap(other); + } + void lock() + { + base::lock(); + } + bool try_lock() + { + return base::try_lock(); + } + void unlock() + { + base::unlock(); + } + bool owns_lock() const + { + return base::owns_lock(); + } + Mutex* mutex() const BOOST_NOEXCEPT + { + return base::mutex(); + } + Mutex* release() + { + return base::release(); + } + +#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) + typedef typename base::bool_type bool_type; + operator bool_type() const + { + return base::operator bool_type(); + } + bool operator!() const + { + return !this->owns_lock(); + } +#else + explicit operator bool() const + { + return owns_lock(); + } +#endif + }; + + template<typename Mutex> + void swap(try_lock_wrapper<Mutex>& lhs,try_lock_wrapper<Mutex>& rhs) + { + lhs.swap(rhs); + } +} +} +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/lockable_adapter.hpp b/boost/thread/lockable_adapter.hpp new file mode 100644 index 0000000000..93d9ba5023 --- /dev/null +++ b/boost/thread/lockable_adapter.hpp @@ -0,0 +1,226 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2008-2009,2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_THREAD_LOCKABLE_ADAPTER_HPP +#define BOOST_THREAD_LOCKABLE_ADAPTER_HPP + +#include <boost/thread/detail/delete.hpp> +#include <boost/chrono/chrono.hpp> + +namespace boost +{ + + //[basic_lockable_adapter + template <typename BasicLockable> + class basic_lockable_adapter + { + public: + typedef BasicLockable mutex_type; + + protected: + mutex_type& lockable() const + { + return lockable_; + } + mutable mutex_type lockable_; /*< mutable so that it can be modified by const functions >*/ + public: + + BOOST_THREAD_NO_COPYABLE( basic_lockable_adapter) /*< no copyable >*/ + + basic_lockable_adapter() + {} + + void lock() const + { + lockable().lock(); + } + void unlock() const + { + lockable().unlock(); + } + + }; + //] + + //[lockable_adapter + template <typename Lockable> + class lockable_adapter : public basic_lockable_adapter<Lockable> + { + public: + typedef Lockable mutex_type; + + bool try_lock() const + { + return this->lockable().try_lock(); + } + }; + //] + + //[timed_lockable_adapter + template <typename TimedLock> + class timed_lockable_adapter: public lockable_adapter<TimedLock> + { + public: + typedef TimedLock mutex_type; + + template <typename Clock, typename Duration> + bool try_lock_until(chrono::time_point<Clock, Duration> const & abs_time) const + { + return this->lockable().try_lock_until(abs_time); + } + template <typename Rep, typename Period> + bool try_lock_for(chrono::duration<Rep, Period> const & rel_time) const + { + return this->lockable().try_lock_for(rel_time); + } + + }; + //] + + //[shared_lockable_adapter + template <typename SharableLock> + class shared_lockable_adapter: public timed_lockable_adapter<SharableLock> + { + public: + typedef SharableLock mutex_type; + + void lock_shared() const + { + this->lockable().lock_shared(); + } + bool try_lock_shared() const + { + return this->lockable().try_lock_shared(); + } + void unlock_shared() const + { + this->lockable().unlock_shared(); + } + + template <typename Clock, typename Duration> + bool try_lock_shared_until(chrono::time_point<Clock, Duration> const & abs_time) const + { + return this->lockable().try_lock_shared_until(abs_time); + } + template <typename Rep, typename Period> + bool try_lock_shared_for(chrono::duration<Rep, Period> const & rel_time) const + { + return this->lockable().try_lock_shared_for(rel_time); + } + + }; + + //] + + //[upgrade_lockable_adapter + template <typename UpgradableLock> + class upgrade_lockable_adapter: public shared_lockable_adapter<UpgradableLock> + { + public: + typedef UpgradableLock mutex_type; + + void lock_upgrade() const + { + this->lockable().lock_upgrade(); + } + + bool try_lock_upgrade() const + { + return this->lockable().try_lock_upgrade(); + } + + void unlock_upgrade() const + { + this->lockable().unlock_upgrade(); + } + + template <typename Clock, typename Duration> + bool try_lock_upgrade_until(chrono::time_point<Clock, Duration> const & abs_time) const + { + return this->lockable().try_lock_upgrade_until(abs_time); + } + template <typename Rep, typename Period> + bool try_lock_upgrade_for(chrono::duration<Rep, Period> const & rel_time) const + { + return this->lockable().try_lock_upgrade_for(rel_time); + } + + bool try_unlock_shared_and_lock() const + { + return this->lockable().try_unlock_shared_and_lock(); + } + + template <typename Clock, typename Duration> + bool try_unlock_shared_and_lock_until(chrono::time_point<Clock, Duration> const & abs_time) const + { + return this->lockable().try_unlock_shared_and_lock_until(abs_time); + } + template <typename Rep, typename Period> + bool try_unlock_shared_and_lock_for(chrono::duration<Rep, Period> const & rel_time) const + { + return this->lockable().try_unlock_shared_and_lock_for(rel_time); + } + + void unlock_and_lock_shared() const + { + this->lockable().unlock_and_lock_shared(); + } + + bool try_unlock_shared_and_lock_upgrade() const + { + return this->lockable().try_unlock_shared_and_lock_upgrade(); + } + + template <typename Clock, typename Duration> + bool try_unlock_shared_and_lock_upgrade_until(chrono::time_point<Clock, Duration> const & abs_time) const + { + return this->lockable().try_unlock_shared_and_lock_upgrade_until(abs_time); + } + template <typename Rep, typename Period> + bool try_unlock_shared_and_lock_upgrade_for(chrono::duration<Rep, Period> const & rel_time) const + { + return this->lockable().try_unlock_shared_and_lock_upgrade_for(rel_time); + } + + void unlock_and_lock_upgrade() const + { + this->lockable().unlock_and_lock_upgrade(); + } + + void unlock_upgrade_and_lock() const + { + this->lockable().unlock_upgrade_and_lock(); + } + + bool try_unlock_upgrade_and_lock() const + { + return this->lockable().try_unlock_upgrade_and_lock(); + } + template <typename Clock, typename Duration> + bool try_unlock_upgrade_and_lock_until(chrono::time_point<Clock, Duration> const & abs_time) const + { + return this->lockable().try_unlock_upgrade_and_lock_until(abs_time); + } + template <typename Rep, typename Period> + bool try_unlock_upgrade_and_lock_for(chrono::duration<Rep, Period> const & rel_time) const + { + return this->lockable().try_unlock_upgrade_and_lock_for(rel_time); + } + + void unlock_upgrade_and_lock_shared() const + { + this->lockable().unlock_upgrade_and_lock_shared(); + } + + }; +//] + +} +#endif diff --git a/boost/thread/lockable_concepts.hpp b/boost/thread/lockable_concepts.hpp new file mode 100644 index 0000000000..bedd962e3b --- /dev/null +++ b/boost/thread/lockable_concepts.hpp @@ -0,0 +1,157 @@ +// (C) Copyright 2012 Vicente Botet +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_THREAD_LOCKABLE_CONCEPTS_HPP +#define BOOST_THREAD_LOCKABLE_CONCEPTS_HPP + +#include <boost/chrono/chrono.hpp> +#include <boost/concept_check.hpp> + +namespace boost +{ + + /** + * BasicLockable object supports the basic features + * required to delimit a critical region + * Supports the basic lock and unlock functions. + */ + + //[BasicLockable + template <typename Mutex> + struct BasicLockable + { + + BOOST_CONCEPT_USAGE(BasicLockable) + { + l.lock(); + l.unlock(); + } + BasicLockable() : l(*static_cast<Mutex*>(0)) {} + private: + BasicLockable operator=(BasicLockable const&); + + Mutex& l; + } + ; + //] + /** + * Lockable extends BasicLockable + * with try_lock functions. + */ + + //[Lockable + template <typename Mutex> + struct Lockable + { + BOOST_CONCEPT_ASSERT(( BasicLockable<Mutex> )); + + BOOST_CONCEPT_USAGE(Lockable) + { + if (l.try_lock()) return; + } + Lockable() : l(*static_cast<Mutex*>(0)) {} + private: + Lockable operator=(Lockable const&); + Mutex& l; + }; + //] + + /** + * TimedLockable object extends Lockable + * with timed lock functions: try_lock_until and try_lock_for and the exception based lock_until and lock_for + */ + + //[TimedLockable + template <typename Mutex> + struct TimedLockable + { + BOOST_CONCEPT_ASSERT(( Lockable<Mutex> )); + + BOOST_CONCEPT_USAGE(TimedLockable) + { + if (l.try_lock_until(t)) return; + if (l.try_lock_for(d)) return; + } + TimedLockable() : l(*static_cast<Mutex*>(0)) {} + private: + TimedLockable operator=(TimedLockable const&); + Mutex& l; + chrono::system_clock::time_point t; + chrono::system_clock::duration d; + }; + //] + + /** + * SharedLockable object extends TimedLockable + * with the lock_shared, lock_shared_until, lock_shared_for, try_lock_shared_until, try_lock_shared + * and unlock_shared functions + */ + //[SharedLockable + template <typename Mutex> + struct SharedLockable + { + BOOST_CONCEPT_ASSERT(( TimedLockable<Mutex> )); + + BOOST_CONCEPT_USAGE(SharedLockable) + { + l.lock_shared(); + l.unlock_shared(); + if (l.try_lock_shared()) return; + if (l.try_lock_shared_until(t)) return; + if (l.try_lock_shared_for(d)) return; + } + SharedLockable() : l(*static_cast<Mutex*>(0)) {} + private: + SharedLockable operator=(SharedLockable const&); + Mutex& l; + chrono::system_clock::time_point t; + chrono::system_clock::duration d; + }; + //] + + /** + * UpgradeLockable object extends SharedLockable + * with the lock_upgrade, lock_upgrade_until, unlock_upgrade_and_lock, + * unlock_and_lock_shared and unlock_upgrade_and_lock_shared functions + */ + + //[UpgradeLockable + template <typename Mutex> + struct UpgradeLockable + { + BOOST_CONCEPT_ASSERT(( SharedLockable<Mutex> )); + + BOOST_CONCEPT_USAGE(UpgradeLockable) + { + l.lock_upgrade(); + l.unlock_upgrade(); + if (l.try_lock_upgrade()) return; + if (l.try_lock_upgrade_until(t)) return; + if (l.try_lock_upgrade_for(d)) return; + if (l.try_unlock_shared_and_lock()) return; + if (l.try_unlock_shared_and_lock_until(t)) return; + if (l.try_unlock_shared_and_lock_for(d)) return; + l.unlock_and_lock_shared(); + if (l.try_unlock_shared_and_lock_upgrade()) return; + if (l.try_unlock_shared_and_lock_upgrade_until(t)) return; + if (l.try_unlock_shared_and_lock_upgrade_for(d)) return; + l.unlock_and_lock_upgrade(); + l.unlock_upgrade_and_lock(); + if (l.try_unlock_upgrade_and_lock()) return; + if (l.try_unlock_upgrade_and_lock_until(t)) return; + if (l.try_unlock_upgrade_and_lock_for(d)) return; + l.unlock_upgrade_and_lock_shared(); + } + UpgradeLockable() : l(*static_cast<Mutex*>(0)) {} + private: + UpgradeLockable operator=(UpgradeLockable const&); + Mutex& l; + chrono::system_clock::time_point t; + chrono::system_clock::duration d; + }; + //] + +} +#endif diff --git a/boost/thread/lockable_traits.hpp b/boost/thread/lockable_traits.hpp new file mode 100644 index 0000000000..8a17ae72d3 --- /dev/null +++ b/boost/thread/lockable_traits.hpp @@ -0,0 +1,207 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_LOCKABLE_TRAITS_HPP +#define BOOST_THREAD_LOCKABLE_TRAITS_HPP + +#include <boost/thread/detail/config.hpp> + +#include <boost/assert.hpp> +#include <boost/detail/workaround.hpp> +#include <boost/type_traits/is_class.hpp> + +#include <boost/config/abi_prefix.hpp> + +// todo make use of integral_constant, true_type and false_type + +namespace boost +{ + namespace sync + { + +#if defined(BOOST_NO_SFINAE) || \ + BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600)) || \ + BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) +#if ! defined BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES +#define BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES +#endif +#endif + +#ifndef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES + namespace detail + { +#define BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(member_name) \ + template<typename T, bool=boost::is_class<T>::value> \ + struct has_member_called_##member_name \ + { \ + BOOST_STATIC_CONSTANT(bool, value=false); \ + }; \ + \ + template<typename T> \ + struct has_member_called_##member_name<T,true> \ + { \ + typedef char true_type; \ + struct false_type \ + { \ + true_type dummy[2]; \ + }; \ + \ + struct fallback { int member_name; }; \ + struct derived: \ + T, fallback \ + { \ + derived(); \ + }; \ + \ + template<int fallback::*> struct tester; \ + \ + template<typename U> \ + static false_type has_member(tester<&U::member_name>*); \ + template<typename U> \ + static true_type has_member(...); \ + \ + BOOST_STATIC_CONSTANT( \ + bool, value=sizeof(has_member<derived>(0))==sizeof(true_type)); \ + } + + BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(lock) +; BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(unlock); + BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(try_lock); + + template<typename T,bool=has_member_called_lock<T>::value > + struct has_member_lock + { + BOOST_STATIC_CONSTANT(bool, value=false); + }; + + template<typename T> + struct has_member_lock<T,true> + { + typedef char true_type; + struct false_type + { + true_type dummy[2]; + }; + + template<typename U,typename V> + static true_type has_member(V (U::*)()); + template<typename U> + static false_type has_member(U); + + BOOST_STATIC_CONSTANT( + bool,value=sizeof(has_member_lock<T>::has_member(&T::lock))==sizeof(true_type)); + }; + + template<typename T,bool=has_member_called_unlock<T>::value > + struct has_member_unlock + { + BOOST_STATIC_CONSTANT(bool, value=false); + }; + + template<typename T> + struct has_member_unlock<T,true> + { + typedef char true_type; + struct false_type + { + true_type dummy[2]; + }; + + template<typename U,typename V> + static true_type has_member(V (U::*)()); + template<typename U> + static false_type has_member(U); + + BOOST_STATIC_CONSTANT( + bool,value=sizeof(has_member_unlock<T>::has_member(&T::unlock))==sizeof(true_type)); + }; + + template<typename T,bool=has_member_called_try_lock<T>::value > + struct has_member_try_lock + { + BOOST_STATIC_CONSTANT(bool, value=false); + }; + + template<typename T> + struct has_member_try_lock<T,true> + { + typedef char true_type; + struct false_type + { + true_type dummy[2]; + }; + + template<typename U> + static true_type has_member(bool (U::*)()); + template<typename U> + static false_type has_member(U); + + BOOST_STATIC_CONSTANT( + bool,value=sizeof(has_member_try_lock<T>::has_member(&T::try_lock))==sizeof(true_type)); + }; + + } + + template<typename T> + struct is_basic_lockable + { + BOOST_STATIC_CONSTANT(bool, value = detail::has_member_lock<T>::value && + detail::has_member_unlock<T>::value); + }; + template<typename T> + struct is_lockable + { + BOOST_STATIC_CONSTANT(bool, value = + is_basic_lockable<T>::value && + detail::has_member_try_lock<T>::value); + }; + +#else + template<typename T> + struct is_basic_lockable + { + BOOST_STATIC_CONSTANT(bool, value = false); + }; + template<typename T> + struct is_lockable + { + BOOST_STATIC_CONSTANT(bool, value = false); + }; +#endif + + template<typename T> + struct is_recursive_mutex_sur_parole + { + BOOST_STATIC_CONSTANT(bool, value = false); + }; + template<typename T> + struct is_recursive_mutex_sur_parolle : is_recursive_mutex_sur_parole<T> + { + }; + + template<typename T> + struct is_recursive_basic_lockable + { + BOOST_STATIC_CONSTANT(bool, value = is_basic_lockable<T>::value && + is_recursive_mutex_sur_parolle<T>::value); + }; + template<typename T> + struct is_recursive_lockable + { + BOOST_STATIC_CONSTANT(bool, value = is_lockable<T>::value && + is_recursive_mutex_sur_parolle<T>::value); + }; + } + template<typename T> + struct is_mutex_type + { + BOOST_STATIC_CONSTANT(bool, value = sync::is_lockable<T>::value); + }; + +} +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/locks.hpp b/boost/thread/locks.hpp index 5111d33e68..6749964cf5 100644 --- a/boost/thread/locks.hpp +++ b/boost/thread/locks.hpp @@ -6,1822 +6,11 @@ #ifndef BOOST_THREAD_LOCKS_HPP #define BOOST_THREAD_LOCKS_HPP -#include <boost/thread/detail/config.hpp> -#include <boost/thread/exceptions.hpp> -#include <boost/thread/detail/move.hpp> -#include <algorithm> -#include <iterator> -#include <boost/thread/thread_time.hpp> -#include <boost/detail/workaround.hpp> -#include <boost/type_traits/is_class.hpp> -#ifdef BOOST_THREAD_USES_CHRONO -#include <boost/chrono/time_point.hpp> -#include <boost/chrono/duration.hpp> -#endif - -#include <boost/config/abi_prefix.hpp> - -namespace boost -{ - struct xtime; - -#if defined(BOOST_NO_SFINAE) || \ - BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600)) || \ - BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) -#define BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES -#endif - -#ifndef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES - namespace detail - { -#define BOOST_DEFINE_HAS_MEMBER_CALLED(member_name) \ - template<typename T, bool=boost::is_class<T>::value> \ - struct has_member_called_##member_name \ - { \ - BOOST_STATIC_CONSTANT(bool, value=false); \ - }; \ - \ - template<typename T> \ - struct has_member_called_##member_name<T,true> \ - { \ - typedef char true_type; \ - struct false_type \ - { \ - true_type dummy[2]; \ - }; \ - \ - struct fallback { int member_name; }; \ - struct derived: \ - T, fallback \ - { \ - derived(); \ - }; \ - \ - template<int fallback::*> struct tester; \ - \ - template<typename U> \ - static false_type has_member(tester<&U::member_name>*); \ - template<typename U> \ - static true_type has_member(...); \ - \ - BOOST_STATIC_CONSTANT( \ - bool, value=sizeof(has_member<derived>(0))==sizeof(true_type)); \ - } - - BOOST_DEFINE_HAS_MEMBER_CALLED(lock); - BOOST_DEFINE_HAS_MEMBER_CALLED(unlock); - BOOST_DEFINE_HAS_MEMBER_CALLED(try_lock); - - template<typename T,bool=has_member_called_lock<T>::value > - struct has_member_lock - { - BOOST_STATIC_CONSTANT(bool, value=false); - }; - - template<typename T> - struct has_member_lock<T,true> - { - typedef char true_type; - struct false_type - { - true_type dummy[2]; - }; - - template<typename U,typename V> - static true_type has_member(V (U::*)()); - template<typename U> - static false_type has_member(U); - - BOOST_STATIC_CONSTANT( - bool,value=sizeof(has_member_lock<T>::has_member(&T::lock))==sizeof(true_type)); - }; - - template<typename T,bool=has_member_called_unlock<T>::value > - struct has_member_unlock - { - BOOST_STATIC_CONSTANT(bool, value=false); - }; - - template<typename T> - struct has_member_unlock<T,true> - { - typedef char true_type; - struct false_type - { - true_type dummy[2]; - }; - - template<typename U,typename V> - static true_type has_member(V (U::*)()); - template<typename U> - static false_type has_member(U); - - BOOST_STATIC_CONSTANT( - bool,value=sizeof(has_member_unlock<T>::has_member(&T::unlock))==sizeof(true_type)); - }; - - template<typename T,bool=has_member_called_try_lock<T>::value > - struct has_member_try_lock - { - BOOST_STATIC_CONSTANT(bool, value=false); - }; - - template<typename T> - struct has_member_try_lock<T,true> - { - typedef char true_type; - struct false_type - { - true_type dummy[2]; - }; - - template<typename U> - static true_type has_member(bool (U::*)()); - template<typename U> - static false_type has_member(U); - - BOOST_STATIC_CONSTANT( - bool,value=sizeof(has_member_try_lock<T>::has_member(&T::try_lock))==sizeof(true_type)); - }; - - } - - - template<typename T> - struct is_mutex_type - { - BOOST_STATIC_CONSTANT(bool, value = detail::has_member_lock<T>::value && - detail::has_member_unlock<T>::value && - detail::has_member_try_lock<T>::value); - - }; -#else - template<typename T> - struct is_mutex_type - { - BOOST_STATIC_CONSTANT(bool, value = false); - }; -#endif - - struct defer_lock_t - {}; - struct try_to_lock_t - {}; - struct adopt_lock_t - {}; - - BOOST_CONSTEXPR_OR_CONST defer_lock_t defer_lock={}; - BOOST_CONSTEXPR_OR_CONST try_to_lock_t try_to_lock={}; - BOOST_CONSTEXPR_OR_CONST adopt_lock_t adopt_lock={}; - - template<typename Mutex> - class shared_lock; - - template<typename Mutex> - class upgrade_lock; - - template<typename Mutex> - class unique_lock; - - namespace detail - { - template<typename Mutex> - class try_lock_wrapper; - } - -#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES - template<typename T> - struct is_mutex_type<unique_lock<T> > - { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - - template<typename T> - struct is_mutex_type<shared_lock<T> > - { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - - template<typename T> - struct is_mutex_type<upgrade_lock<T> > - { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - - template<typename T> - struct is_mutex_type<detail::try_lock_wrapper<T> > - { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - - class mutex; - class timed_mutex; - class recursive_mutex; - class recursive_timed_mutex; - class shared_mutex; - - template<> - struct is_mutex_type<mutex> - { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - template<> - struct is_mutex_type<timed_mutex> - { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - template<> - struct is_mutex_type<recursive_mutex> - { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - template<> - struct is_mutex_type<recursive_timed_mutex> - { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - template<> - struct is_mutex_type<shared_mutex> - { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - -#endif - - template<typename Mutex> - class lock_guard - { - private: - Mutex& m; - - public: - typedef Mutex mutex_type; - BOOST_THREAD_NO_COPYABLE(lock_guard) - - explicit lock_guard(Mutex& m_): - m(m_) - { - m.lock(); - } - lock_guard(Mutex& m_,adopt_lock_t): - m(m_) - {} - ~lock_guard() - { - m.unlock(); - } - }; - - template<typename Mutex> - class unique_lock - { - private: - Mutex* m; - bool is_locked; - - private: - explicit unique_lock(upgrade_lock<Mutex>&); - unique_lock& operator=(upgrade_lock<Mutex>& other); - public: - typedef Mutex mutex_type; - BOOST_THREAD_MOVABLE_ONLY(unique_lock) - -#if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF. -#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) - unique_lock(const volatile unique_lock&); -#endif -#endif - unique_lock() BOOST_NOEXCEPT : - m(0),is_locked(false) - {} - - explicit unique_lock(Mutex& m_): - m(&m_),is_locked(false) - { - lock(); - } - unique_lock(Mutex& m_,adopt_lock_t): - m(&m_),is_locked(true) - {} - unique_lock(Mutex& m_,defer_lock_t) BOOST_NOEXCEPT: - m(&m_),is_locked(false) - {} - unique_lock(Mutex& m_,try_to_lock_t): - m(&m_),is_locked(false) - { - try_lock(); - } - template<typename TimeDuration> - unique_lock(Mutex& m_,TimeDuration const& target_time): - m(&m_),is_locked(false) - { - timed_lock(target_time); - } - unique_lock(Mutex& m_,system_time const& target_time): - m(&m_),is_locked(false) - { - timed_lock(target_time); - } - -#ifdef BOOST_THREAD_USES_CHRONO - template <class Clock, class Duration> - unique_lock(Mutex& mtx, const chrono::time_point<Clock, Duration>& t) - : m(&mtx), is_locked(mtx.try_lock_until(t)) - { - } - template <class Rep, class Period> - unique_lock(Mutex& mtx, const chrono::duration<Rep, Period>& d) - : m(&mtx), is_locked(mtx.try_lock_for(d)) - { - } -#endif - - unique_lock(BOOST_THREAD_RV_REF(unique_lock) other) BOOST_NOEXCEPT: - m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) - { - BOOST_THREAD_RV(other).is_locked=false; - BOOST_THREAD_RV(other).m=0; - } - BOOST_THREAD_EXPLICIT_LOCK_CONVERSION unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other); - -#ifndef BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION - unique_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT - { - unique_lock temp(::boost::move(other)); - swap(temp); - return *this; - } -#endif - - unique_lock& operator=(BOOST_THREAD_RV_REF(unique_lock) other) BOOST_NOEXCEPT - { - unique_lock temp(::boost::move(other)); - swap(temp); - return *this; - } -#if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF. -#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) - unique_lock& operator=(unique_lock<Mutex> other) - { - swap(other); - return *this; - } -#endif // BOOST_WORKAROUND -#endif - - // Conversion from upgrade locking - unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock<mutex_type> BOOST_THREAD_RV_REF_END ul, try_to_lock_t) - : m(0),is_locked(false) - { - if (BOOST_THREAD_RV(ul).owns_lock()) { - if (BOOST_THREAD_RV(ul).mutex()->try_unlock_upgrade_and_lock()) - { - m = BOOST_THREAD_RV(ul).release(); - is_locked = true; - } - } - else - { - m = BOOST_THREAD_RV(ul).release(); - } - } - -#ifdef BOOST_THREAD_USES_CHRONO - template <class Clock, class Duration> - unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock<mutex_type> BOOST_THREAD_RV_REF_END ul, - const chrono::time_point<Clock, Duration>& abs_time) - : m(0),is_locked(false) - { - if (BOOST_THREAD_RV(ul).owns_lock()) { - if (BOOST_THREAD_RV(ul).mutex()->try_unlock_upgrade_and_lock_until(abs_time)) - { - m = BOOST_THREAD_RV(ul).release(); - is_locked = true; - } - } - else - { - m = BOOST_THREAD_RV(ul).release(); - } - } - - template <class Rep, class Period> - unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock<mutex_type> BOOST_THREAD_RV_REF_END ul, - const chrono::duration<Rep, Period>& rel_time) - : m(0),is_locked(false) - { - if (BOOST_THREAD_RV(ul).owns_lock()) { - if (BOOST_THREAD_RV(ul).mutex()->try_unlock_upgrade_and_lock_for(rel_time)) - { - m = BOOST_THREAD_RV(ul).release(); - is_locked = true; - } - } - else - { - m = BOOST_THREAD_RV(ul).release(); - } - } -#endif - -#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS - // Conversion from shared locking - unique_lock(BOOST_THREAD_RV_REF_BEG shared_lock<mutex_type> BOOST_THREAD_RV_REF_END sl, try_to_lock_t) - : m(0),is_locked(false) - { - if (BOOST_THREAD_RV(sl).owns_lock()) { - if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock()) - { - m = BOOST_THREAD_RV(sl).release(); - is_locked = true; - } - } - else - { - m = BOOST_THREAD_RV(sl).release(); - } - } - -#ifdef BOOST_THREAD_USES_CHRONO - template <class Clock, class Duration> - unique_lock(BOOST_THREAD_RV_REF_BEG shared_lock<mutex_type> BOOST_THREAD_RV_REF_END sl, - const chrono::time_point<Clock, Duration>& abs_time) - : m(0),is_locked(false) - { - if (BOOST_THREAD_RV(sl).owns_lock()) { - if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_until(abs_time)) - { - m = BOOST_THREAD_RV(sl).release(); - is_locked = true; - } - } - else - { - m = BOOST_THREAD_RV(sl).release(); - } - } - - template <class Rep, class Period> - unique_lock(BOOST_THREAD_RV_REF_BEG shared_lock<mutex_type> BOOST_THREAD_RV_REF_END sl, - const chrono::duration<Rep, Period>& rel_time) - : m(0),is_locked(false) - { - if (BOOST_THREAD_RV(sl).owns_lock()) { - if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_for(rel_time)) - { - m = BOOST_THREAD_RV(sl).release(); - is_locked = true; - } - } - else - { - m = BOOST_THREAD_RV(sl).release(); - } - } -#endif // BOOST_THREAD_USES_CHRONO -#endif // BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS - - - void swap(unique_lock& other) BOOST_NOEXCEPT - { - std::swap(m,other.m); - std::swap(is_locked,other.is_locked); - } - - ~unique_lock() - { - if(owns_lock()) - { - m->unlock(); - } - } - void lock() - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex")); - } - m->lock(); - is_locked=true; - } - bool try_lock() - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex")); - } - is_locked=m->try_lock(); - return is_locked; - } - template<typename TimeDuration> - bool timed_lock(TimeDuration const& relative_time) - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex")); - } - is_locked=m->timed_lock(relative_time); - return is_locked; - } - - bool timed_lock(::boost::system_time const& absolute_time) - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex")); - } - is_locked=m->timed_lock(absolute_time); - return is_locked; - } - bool timed_lock(::boost::xtime const& absolute_time) - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex")); - } - is_locked=m->timed_lock(absolute_time); - return is_locked; - } - -#ifdef BOOST_THREAD_USES_CHRONO - - template <class Rep, class Period> - bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex")); - } - is_locked=m->try_lock_for(rel_time); - return is_locked; - } - template <class Clock, class Duration> - bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time) - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex")); - } - is_locked=m->try_lock_until(abs_time); - return is_locked; - } -#endif - - void unlock() - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex")); - } - if(!owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock doesn't own the mutex")); - } - m->unlock(); - is_locked=false; - } - -#if defined(BOOST_NO_EXPLICIT_CONVERSION_OPERATORS) - typedef void (unique_lock::*bool_type)(); - operator bool_type() const BOOST_NOEXCEPT - { - return is_locked?&unique_lock::lock:0; - } - bool operator!() const BOOST_NOEXCEPT - { - return !owns_lock(); - } -#else - explicit operator bool() const BOOST_NOEXCEPT - { - return owns_lock(); - } -#endif - bool owns_lock() const BOOST_NOEXCEPT - { - return is_locked; - } - - Mutex* mutex() const BOOST_NOEXCEPT - { - return m; - } - - Mutex* release() BOOST_NOEXCEPT - { - Mutex* const res=m; - m=0; - is_locked=false; - return res; - } - - friend class shared_lock<Mutex>; - friend class upgrade_lock<Mutex>; - }; - - template<typename Mutex> - void swap(unique_lock<Mutex>& lhs,unique_lock<Mutex>& rhs) BOOST_NOEXCEPT - { - lhs.swap(rhs); - } - - BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) unique_lock<Mutex> BOOST_THREAD_DCL_MOVABLE_END - - template<typename Mutex> - class shared_lock - { - protected: - Mutex* m; - bool is_locked; - - public: - typedef Mutex mutex_type; - BOOST_THREAD_MOVABLE_ONLY(shared_lock) - - shared_lock() BOOST_NOEXCEPT: - m(0),is_locked(false) - {} - - explicit shared_lock(Mutex& m_): - m(&m_),is_locked(false) - { - lock(); - } - shared_lock(Mutex& m_,adopt_lock_t): - m(&m_),is_locked(true) - {} - shared_lock(Mutex& m_,defer_lock_t) BOOST_NOEXCEPT: - m(&m_),is_locked(false) - {} - shared_lock(Mutex& m_,try_to_lock_t): - m(&m_),is_locked(false) - { - try_lock(); - } - shared_lock(Mutex& m_,system_time const& target_time): - m(&m_),is_locked(false) - { - timed_lock(target_time); - } - -#ifdef BOOST_THREAD_USES_CHRONO - template <class Clock, class Duration> - shared_lock(Mutex& mtx, const chrono::time_point<Clock, Duration>& t) - : m(&mtx), is_locked(mtx.try_lock_shared_until(t)) - { - } - template <class Rep, class Period> - shared_lock(Mutex& mtx, const chrono::duration<Rep, Period>& d) - : m(&mtx), is_locked(mtx.try_lock_shared_for(d)) - { - } -#endif - - shared_lock(BOOST_THREAD_RV_REF_BEG shared_lock<Mutex> BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT: - m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) - { - BOOST_THREAD_RV(other).is_locked=false; - BOOST_THREAD_RV(other).m=0; - } - - BOOST_THREAD_EXPLICIT_LOCK_CONVERSION shared_lock(BOOST_THREAD_RV_REF_BEG unique_lock<Mutex> BOOST_THREAD_RV_REF_END other): - m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) - { - if(is_locked) - { - m->unlock_and_lock_shared(); - } - BOOST_THREAD_RV(other).is_locked=false; - BOOST_THREAD_RV(other).m=0; - } - - BOOST_THREAD_EXPLICIT_LOCK_CONVERSION shared_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other): - m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) - { - if(is_locked) - { - m->unlock_upgrade_and_lock_shared(); - } - BOOST_THREAD_RV(other).is_locked=false; - BOOST_THREAD_RV(other).m=0; - } - - - shared_lock& operator=(BOOST_THREAD_RV_REF_BEG shared_lock<Mutex> BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT - { - shared_lock temp(::boost::move(other)); - swap(temp); - return *this; - } -#ifndef BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION - shared_lock& operator=(BOOST_THREAD_RV_REF_BEG unique_lock<Mutex> BOOST_THREAD_RV_REF_END other) - { - shared_lock temp(::boost::move(other)); - swap(temp); - return *this; - } - - shared_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other) - { - shared_lock temp(::boost::move(other)); - swap(temp); - return *this; - } -#endif - - void swap(shared_lock& other) BOOST_NOEXCEPT - { - std::swap(m,other.m); - std::swap(is_locked,other.is_locked); - } - - Mutex* mutex() const BOOST_NOEXCEPT - { - return m; - } - - Mutex* release() BOOST_NOEXCEPT - { - Mutex* const res=m; - m=0; - is_locked=false; - return res; - } - - ~shared_lock() - { - if(owns_lock()) - { - m->unlock_shared(); - } - } - void lock() - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex")); - } - m->lock_shared(); - is_locked=true; - } - bool try_lock() - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex")); - } - is_locked=m->try_lock_shared(); - return is_locked; - } - bool timed_lock(boost::system_time const& target_time) - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex")); - } - is_locked=m->timed_lock_shared(target_time); - return is_locked; - } - template<typename Duration> - bool timed_lock(Duration const& target_time) - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex")); - } - is_locked=m->timed_lock_shared(target_time); - return is_locked; - } -#ifdef BOOST_THREAD_USES_CHRONO - template <class Rep, class Period> - bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex")); - } - is_locked=m->try_lock_shared_for(rel_time); - return is_locked; - } - template <class Clock, class Duration> - bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time) - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex")); - } - is_locked=m->try_lock_shared_until(abs_time); - return is_locked; - } -#endif - void unlock() - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); - } - if(!owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock doesn't own the mutex")); - } - m->unlock_shared(); - is_locked=false; - } - -#if defined(BOOST_NO_EXPLICIT_CONVERSION_OPERATORS) - typedef void (shared_lock<Mutex>::*bool_type)(); - operator bool_type() const BOOST_NOEXCEPT - { - return is_locked?&shared_lock::lock:0; - } - bool operator!() const BOOST_NOEXCEPT - { - return !owns_lock(); - } -#else - explicit operator bool() const BOOST_NOEXCEPT - { - return owns_lock(); - } -#endif - bool owns_lock() const BOOST_NOEXCEPT - { - return is_locked; - } - - }; - - BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) shared_lock<Mutex> BOOST_THREAD_DCL_MOVABLE_END - - template<typename Mutex> - void swap(shared_lock<Mutex>& lhs,shared_lock<Mutex>& rhs) BOOST_NOEXCEPT - { - lhs.swap(rhs); - } - - template<typename Mutex> - class upgrade_lock - { - protected: - Mutex* m; - bool is_locked; - - public: - typedef Mutex mutex_type; - BOOST_THREAD_MOVABLE_ONLY(upgrade_lock) - - upgrade_lock() BOOST_NOEXCEPT: - m(0),is_locked(false) - {} - - explicit upgrade_lock(Mutex& m_): - m(&m_),is_locked(false) - { - lock(); - } - upgrade_lock(Mutex& m_,adopt_lock_t): - m(&m_),is_locked(true) - {} - upgrade_lock(Mutex& m_,defer_lock_t) BOOST_NOEXCEPT: - m(&m_),is_locked(false) - {} - upgrade_lock(Mutex& m_,try_to_lock_t): - m(&m_),is_locked(false) - { - try_lock(); - } - -#ifdef BOOST_THREAD_USES_CHRONO - template <class Clock, class Duration> - upgrade_lock(Mutex& mtx, const chrono::time_point<Clock, Duration>& t) - : m(&mtx), is_locked(mtx.try_lock_upgrade_until(t)) - { - } - template <class Rep, class Period> - upgrade_lock(Mutex& mtx, const chrono::duration<Rep, Period>& d) - : m(&mtx), is_locked(mtx.try_lock_upgrade_for(d)) - { - } -#endif - - upgrade_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT: - m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) - { - BOOST_THREAD_RV(other).is_locked=false; - BOOST_THREAD_RV(other).m=0; - } - - BOOST_THREAD_EXPLICIT_LOCK_CONVERSION upgrade_lock(BOOST_THREAD_RV_REF_BEG unique_lock<Mutex> BOOST_THREAD_RV_REF_END other): - m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) - { - if(is_locked) - { - m->unlock_and_lock_upgrade(); - } - BOOST_THREAD_RV(other).is_locked=false; - BOOST_THREAD_RV(other).m=0; - } - - upgrade_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT - { - upgrade_lock temp(::boost::move(other)); - swap(temp); - return *this; - } - -#ifndef BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION - upgrade_lock& operator=(BOOST_THREAD_RV_REF_BEG unique_lock<Mutex> BOOST_THREAD_RV_REF_END other) - { - upgrade_lock temp(::boost::move(other)); - swap(temp); - return *this; - } -#endif - -#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS - // Conversion from shared locking - upgrade_lock(BOOST_THREAD_RV_REF_BEG shared_lock<mutex_type> BOOST_THREAD_RV_REF_END sl, try_to_lock_t) - : m(0),is_locked(false) - { - if (BOOST_THREAD_RV(sl).owns_lock()) { - if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_upgrade()) - { - m = BOOST_THREAD_RV(sl).release(); - is_locked = true; - } - } - else - { - m = BOOST_THREAD_RV(sl).release(); - } - } - -#ifdef BOOST_THREAD_USES_CHRONO - template <class Clock, class Duration> - upgrade_lock(BOOST_THREAD_RV_REF_BEG shared_lock<mutex_type> BOOST_THREAD_RV_REF_END sl, - const chrono::time_point<Clock, Duration>& abs_time) - : m(0),is_locked(false) - { - if (BOOST_THREAD_RV(sl).owns_lock()) { - if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_upgrade_until(abs_time)) - { - m = BOOST_THREAD_RV(sl).release(); - is_locked = true; - } - } - else - { - m = BOOST_THREAD_RV(sl).release(); - } - } - - template <class Rep, class Period> - upgrade_lock(BOOST_THREAD_RV_REF_BEG shared_lock<mutex_type> BOOST_THREAD_RV_REF_END sl, - const chrono::duration<Rep, Period>& rel_time) - : m(0),is_locked(false) - { - if (BOOST_THREAD_RV(sl).owns_lock()) { - if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_upgrade_for(rel_time)) - { - m = BOOST_THREAD_RV(sl).release(); - is_locked = true; - } - } - else - { - m = BOOST_THREAD_RV(sl).release(); - } - } -#endif // BOOST_THREAD_USES_CHRONO -#endif // BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS - - void swap(upgrade_lock& other) BOOST_NOEXCEPT - { - std::swap(m,other.m); - std::swap(is_locked,other.is_locked); - } - Mutex* mutex() const BOOST_NOEXCEPT - { - return m; - } - - Mutex* release() BOOST_NOEXCEPT - { - Mutex* const res=m; - m=0; - is_locked=false; - return res; - } - ~upgrade_lock() - { - if(owns_lock()) - { - m->unlock_upgrade(); - } - } - void lock() - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost upgrade_lock owns already the mutex")); - } - m->lock_upgrade(); - is_locked=true; - } - bool try_lock() - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost upgrade_lock owns already the mutex")); - } - is_locked=m->try_lock_upgrade(); - return is_locked; - } - void unlock() - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); - } - if(!owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost upgrade_lock doesn't own the mutex")); - } - m->unlock_upgrade(); - is_locked=false; - } -#ifdef BOOST_THREAD_USES_CHRONO - template <class Rep, class Period> - bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex")); - } - is_locked=m->try_lock_upgrade_for(rel_time); - return is_locked; - } - template <class Clock, class Duration> - bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time) - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex")); - } - is_locked=m->try_lock_upgrade_until(abs_time); - return is_locked; - } -#endif -#if defined(BOOST_NO_EXPLICIT_CONVERSION_OPERATORS) - typedef void (upgrade_lock::*bool_type)(); - operator bool_type() const BOOST_NOEXCEPT - { - return is_locked?&upgrade_lock::lock:0; - } - bool operator!() const BOOST_NOEXCEPT - { - return !owns_lock(); - } -#else - explicit operator bool() const BOOST_NOEXCEPT - { - return owns_lock(); - } -#endif - bool owns_lock() const BOOST_NOEXCEPT - { - return is_locked; - } - friend class shared_lock<Mutex>; - friend class unique_lock<Mutex>; - }; - - template<typename Mutex> - void swap(upgrade_lock<Mutex>& lhs,upgrade_lock<Mutex>& rhs) BOOST_NOEXCEPT - { - lhs.swap(rhs); - } - - BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) upgrade_lock<Mutex> BOOST_THREAD_DCL_MOVABLE_END - - template<typename Mutex> - unique_lock<Mutex>::unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other): - m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) - { - if(is_locked) - { - m->unlock_upgrade_and_lock(); - } - BOOST_THREAD_RV(other).release(); - } - - template <class Mutex> - class upgrade_to_unique_lock - { - private: - upgrade_lock<Mutex>* source; - unique_lock<Mutex> exclusive; - - public: - typedef Mutex mutex_type; - BOOST_THREAD_MOVABLE_ONLY(upgrade_to_unique_lock) - - explicit upgrade_to_unique_lock(upgrade_lock<Mutex>& m_): - source(&m_),exclusive(::boost::move(*source)) - {} - ~upgrade_to_unique_lock() - { - if(source) - { - *source=BOOST_THREAD_MAKE_RV_REF(upgrade_lock<Mutex>(::boost::move(exclusive))); - } - } - - upgrade_to_unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_to_unique_lock<Mutex> BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT: - source(BOOST_THREAD_RV(other).source),exclusive(::boost::move(BOOST_THREAD_RV(other).exclusive)) - { - BOOST_THREAD_RV(other).source=0; - } - - upgrade_to_unique_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_to_unique_lock<Mutex> BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT - { - upgrade_to_unique_lock temp(other); - swap(temp); - return *this; - } - - void swap(upgrade_to_unique_lock& other) BOOST_NOEXCEPT - { - std::swap(source,other.source); - exclusive.swap(other.exclusive); - } - -#if defined(BOOST_NO_EXPLICIT_CONVERSION_OPERATORS) - typedef void (upgrade_to_unique_lock::*bool_type)(upgrade_to_unique_lock&); - operator bool_type() const BOOST_NOEXCEPT - { - return exclusive.owns_lock()?&upgrade_to_unique_lock::swap:0; - } - bool operator!() const BOOST_NOEXCEPT - { - return !owns_lock(); - } -#else - explicit operator bool() const BOOST_NOEXCEPT - { - return owns_lock(); - } -#endif - - bool owns_lock() const BOOST_NOEXCEPT - { - return exclusive.owns_lock(); - } - }; - - BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) upgrade_to_unique_lock<Mutex> BOOST_THREAD_DCL_MOVABLE_END - - namespace detail - { - template<typename Mutex> - class try_lock_wrapper: - private unique_lock<Mutex> - { - typedef unique_lock<Mutex> base; - public: - BOOST_THREAD_MOVABLE_ONLY(try_lock_wrapper) - - try_lock_wrapper() - {} - - explicit try_lock_wrapper(Mutex& m): - base(m,try_to_lock) - {} - - try_lock_wrapper(Mutex& m_,adopt_lock_t): - base(m_,adopt_lock) - {} - try_lock_wrapper(Mutex& m_,defer_lock_t): - base(m_,defer_lock) - {} - try_lock_wrapper(Mutex& m_,try_to_lock_t): - base(m_,try_to_lock) - {} -#ifndef BOOST_NO_RVALUE_REFERENCES - try_lock_wrapper(BOOST_THREAD_RV_REF(try_lock_wrapper) other): - base(::boost::move(other)) - {} - -#elif defined BOOST_THREAD_USES_MOVE - try_lock_wrapper(BOOST_THREAD_RV_REF(try_lock_wrapper) other): - base(::boost::move(static_cast<base&>(other))) - {} - -#else - try_lock_wrapper(BOOST_THREAD_RV_REF(try_lock_wrapper) other): - base(BOOST_THREAD_RV_REF(base)(*other)) - {} -#endif - try_lock_wrapper& operator=(BOOST_THREAD_RV_REF_BEG try_lock_wrapper<Mutex> BOOST_THREAD_RV_REF_END other) - { - try_lock_wrapper temp(other); - swap(temp); - return *this; - } - void swap(try_lock_wrapper& other) - { - base::swap(other); - } - void lock() - { - base::lock(); - } - bool try_lock() - { - return base::try_lock(); - } - void unlock() - { - base::unlock(); - } - bool owns_lock() const - { - return base::owns_lock(); - } - Mutex* mutex() const - { - return base::mutex(); - } - Mutex* release() - { - return base::release(); - } - -#if defined(BOOST_NO_EXPLICIT_CONVERSION_OPERATORS) - typedef typename base::bool_type bool_type; - operator bool_type() const - { - return base::operator bool_type(); - } - bool operator!() const - { - return !this->owns_lock(); - } -#else - explicit operator bool() const - { - return owns_lock(); - } -#endif - }; - - template<typename Mutex> - void swap(try_lock_wrapper<Mutex>& lhs,try_lock_wrapper<Mutex>& rhs) - { - lhs.swap(rhs); - } - - template<typename MutexType1,typename MutexType2> - unsigned try_lock_internal(MutexType1& m1,MutexType2& m2) - { - boost::unique_lock<MutexType1> l1(m1,boost::try_to_lock); - if(!l1) - { - return 1; - } - if(!m2.try_lock()) - { - return 2; - } - l1.release(); - return 0; - } - - template<typename MutexType1,typename MutexType2,typename MutexType3> - unsigned try_lock_internal(MutexType1& m1,MutexType2& m2,MutexType3& m3) - { - boost::unique_lock<MutexType1> l1(m1,boost::try_to_lock); - if(!l1) - { - return 1; - } - if(unsigned const failed_lock=try_lock_internal(m2,m3)) - { - return failed_lock+1; - } - l1.release(); - return 0; - } - - - template<typename MutexType1,typename MutexType2,typename MutexType3, - typename MutexType4> - unsigned try_lock_internal(MutexType1& m1,MutexType2& m2,MutexType3& m3, - MutexType4& m4) - { - boost::unique_lock<MutexType1> l1(m1,boost::try_to_lock); - if(!l1) - { - return 1; - } - if(unsigned const failed_lock=try_lock_internal(m2,m3,m4)) - { - return failed_lock+1; - } - l1.release(); - return 0; - } - - template<typename MutexType1,typename MutexType2,typename MutexType3, - typename MutexType4,typename MutexType5> - unsigned try_lock_internal(MutexType1& m1,MutexType2& m2,MutexType3& m3, - MutexType4& m4,MutexType5& m5) - { - boost::unique_lock<MutexType1> l1(m1,boost::try_to_lock); - if(!l1) - { - return 1; - } - if(unsigned const failed_lock=try_lock_internal(m2,m3,m4,m5)) - { - return failed_lock+1; - } - l1.release(); - return 0; - } - - - template<typename MutexType1,typename MutexType2> - unsigned lock_helper(MutexType1& m1,MutexType2& m2) - { - boost::unique_lock<MutexType1> l1(m1); - if(!m2.try_lock()) - { - return 1; - } - l1.release(); - return 0; - } - - template<typename MutexType1,typename MutexType2,typename MutexType3> - unsigned lock_helper(MutexType1& m1,MutexType2& m2,MutexType3& m3) - { - boost::unique_lock<MutexType1> l1(m1); - if(unsigned const failed_lock=try_lock_internal(m2,m3)) - { - return failed_lock; - } - l1.release(); - return 0; - } - - template<typename MutexType1,typename MutexType2,typename MutexType3, - typename MutexType4> - unsigned lock_helper(MutexType1& m1,MutexType2& m2,MutexType3& m3, - MutexType4& m4) - { - boost::unique_lock<MutexType1> l1(m1); - if(unsigned const failed_lock=try_lock_internal(m2,m3,m4)) - { - return failed_lock; - } - l1.release(); - return 0; - } - - template<typename MutexType1,typename MutexType2,typename MutexType3, - typename MutexType4,typename MutexType5> - unsigned lock_helper(MutexType1& m1,MutexType2& m2,MutexType3& m3, - MutexType4& m4,MutexType5& m5) - { - boost::unique_lock<MutexType1> l1(m1); - if(unsigned const failed_lock=try_lock_internal(m2,m3,m4,m5)) - { - return failed_lock; - } - l1.release(); - return 0; - } - } - - namespace detail - { - template<bool x> - struct is_mutex_type_wrapper - {}; - - template<typename MutexType1,typename MutexType2> - void lock_impl(MutexType1& m1,MutexType2& m2,is_mutex_type_wrapper<true>) - { - unsigned const lock_count=2; - unsigned lock_first=0; - for(;;) - { - switch(lock_first) - { - case 0: - lock_first=detail::lock_helper(m1,m2); - if(!lock_first) - return; - break; - case 1: - lock_first=detail::lock_helper(m2,m1); - if(!lock_first) - return; - lock_first=(lock_first+1)%lock_count; - break; - } - } - } - - template<typename Iterator> - void lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper<false>); - } - - - template<typename MutexType1,typename MutexType2> - void lock(MutexType1& m1,MutexType2& m2) - { - detail::lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); - } - - template<typename MutexType1,typename MutexType2> - void lock(const MutexType1& m1,MutexType2& m2) - { - detail::lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); - } - - template<typename MutexType1,typename MutexType2> - void lock(MutexType1& m1,const MutexType2& m2) - { - detail::lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); - } - - template<typename MutexType1,typename MutexType2> - void lock(const MutexType1& m1,const MutexType2& m2) - { - detail::lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); - } - - template<typename MutexType1,typename MutexType2,typename MutexType3> - void lock(MutexType1& m1,MutexType2& m2,MutexType3& m3) - { - unsigned const lock_count=3; - unsigned lock_first=0; - for(;;) - { - switch(lock_first) - { - case 0: - lock_first=detail::lock_helper(m1,m2,m3); - if(!lock_first) - return; - break; - case 1: - lock_first=detail::lock_helper(m2,m3,m1); - if(!lock_first) - return; - lock_first=(lock_first+1)%lock_count; - break; - case 2: - lock_first=detail::lock_helper(m3,m1,m2); - if(!lock_first) - return; - lock_first=(lock_first+2)%lock_count; - break; - } - } - } - - template<typename MutexType1,typename MutexType2,typename MutexType3, - typename MutexType4> - void lock(MutexType1& m1,MutexType2& m2,MutexType3& m3, - MutexType4& m4) - { - unsigned const lock_count=4; - unsigned lock_first=0; - for(;;) - { - switch(lock_first) - { - case 0: - lock_first=detail::lock_helper(m1,m2,m3,m4); - if(!lock_first) - return; - break; - case 1: - lock_first=detail::lock_helper(m2,m3,m4,m1); - if(!lock_first) - return; - lock_first=(lock_first+1)%lock_count; - break; - case 2: - lock_first=detail::lock_helper(m3,m4,m1,m2); - if(!lock_first) - return; - lock_first=(lock_first+2)%lock_count; - break; - case 3: - lock_first=detail::lock_helper(m4,m1,m2,m3); - if(!lock_first) - return; - lock_first=(lock_first+3)%lock_count; - break; - } - } - } - - template<typename MutexType1,typename MutexType2,typename MutexType3, - typename MutexType4,typename MutexType5> - void lock(MutexType1& m1,MutexType2& m2,MutexType3& m3, - MutexType4& m4,MutexType5& m5) - { - unsigned const lock_count=5; - unsigned lock_first=0; - for(;;) - { - switch(lock_first) - { - case 0: - lock_first=detail::lock_helper(m1,m2,m3,m4,m5); - if(!lock_first) - return; - break; - case 1: - lock_first=detail::lock_helper(m2,m3,m4,m5,m1); - if(!lock_first) - return; - lock_first=(lock_first+1)%lock_count; - break; - case 2: - lock_first=detail::lock_helper(m3,m4,m5,m1,m2); - if(!lock_first) - return; - lock_first=(lock_first+2)%lock_count; - break; - case 3: - lock_first=detail::lock_helper(m4,m5,m1,m2,m3); - if(!lock_first) - return; - lock_first=(lock_first+3)%lock_count; - break; - case 4: - lock_first=detail::lock_helper(m5,m1,m2,m3,m4); - if(!lock_first) - return; - lock_first=(lock_first+4)%lock_count; - break; - } - } - } - - namespace detail - { - template<typename Mutex,bool x=is_mutex_type<Mutex>::value> - struct try_lock_impl_return - { - typedef int type; - }; - - template<typename Iterator> - struct try_lock_impl_return<Iterator,false> - { - typedef Iterator type; - }; - - template<typename MutexType1,typename MutexType2> - int try_lock_impl(MutexType1& m1,MutexType2& m2,is_mutex_type_wrapper<true>) - { - return ((int)detail::try_lock_internal(m1,m2))-1; - } - - template<typename Iterator> - Iterator try_lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper<false>); - } - - template<typename MutexType1,typename MutexType2> - typename detail::try_lock_impl_return<MutexType1>::type try_lock(MutexType1& m1,MutexType2& m2) - { - return detail::try_lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); - } - - template<typename MutexType1,typename MutexType2> - typename detail::try_lock_impl_return<MutexType1>::type try_lock(const MutexType1& m1,MutexType2& m2) - { - return detail::try_lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); - } - - template<typename MutexType1,typename MutexType2> - typename detail::try_lock_impl_return<MutexType1>::type try_lock(MutexType1& m1,const MutexType2& m2) - { - return detail::try_lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); - } - - template<typename MutexType1,typename MutexType2> - typename detail::try_lock_impl_return<MutexType1>::type try_lock(const MutexType1& m1,const MutexType2& m2) - { - return detail::try_lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); - } - - template<typename MutexType1,typename MutexType2,typename MutexType3> - int try_lock(MutexType1& m1,MutexType2& m2,MutexType3& m3) - { - return ((int)detail::try_lock_internal(m1,m2,m3))-1; - } - - template<typename MutexType1,typename MutexType2,typename MutexType3,typename MutexType4> - int try_lock(MutexType1& m1,MutexType2& m2,MutexType3& m3,MutexType4& m4) - { - return ((int)detail::try_lock_internal(m1,m2,m3,m4))-1; - } - - template<typename MutexType1,typename MutexType2,typename MutexType3,typename MutexType4,typename MutexType5> - int try_lock(MutexType1& m1,MutexType2& m2,MutexType3& m3,MutexType4& m4,MutexType5& m5) - { - return ((int)detail::try_lock_internal(m1,m2,m3,m4,m5))-1; - } - - - namespace detail - { - template<typename Iterator> - struct range_lock_guard - { - Iterator begin; - Iterator end; - - range_lock_guard(Iterator begin_,Iterator end_): - begin(begin_),end(end_) - { - boost::lock(begin,end); - } - - void release() - { - begin=end; - } - - ~range_lock_guard() - { - for(;begin!=end;++begin) - { - begin->unlock(); - } - } - }; - - template<typename Iterator> - Iterator try_lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper<false>) - - { - if(begin==end) - { - return end; - } - typedef typename std::iterator_traits<Iterator>::value_type lock_type; - unique_lock<lock_type> guard(*begin,try_to_lock); - - if(!guard.owns_lock()) - { - return begin; - } - Iterator const failed=boost::try_lock(++begin,end); - if(failed==end) - { - guard.release(); - } - - return failed; - } - } - - - namespace detail - { - template<typename Iterator> - void lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper<false>) - { - typedef typename std::iterator_traits<Iterator>::value_type lock_type; - - if(begin==end) - { - return; - } - bool start_with_begin=true; - Iterator second=begin; - ++second; - Iterator next=second; - - for(;;) - { - unique_lock<lock_type> begin_lock(*begin,defer_lock); - if(start_with_begin) - { - begin_lock.lock(); - Iterator const failed_lock=boost::try_lock(next,end); - if(failed_lock==end) - { - begin_lock.release(); - return; - } - start_with_begin=false; - next=failed_lock; - } - else - { - detail::range_lock_guard<Iterator> guard(next,end); - if(begin_lock.try_lock()) - { - Iterator const failed_lock=boost::try_lock(second,next); - if(failed_lock==next) - { - begin_lock.release(); - guard.release(); - return; - } - start_with_begin=false; - next=failed_lock; - } - else - { - start_with_begin=true; - next=second; - } - } - } - } - - } -} -#include <boost/config/abi_suffix.hpp> +#include <boost/thread/lock_algorithms.hpp> +#include <boost/thread/lock_types.hpp> +#include <boost/thread/lock_guard.hpp> +#include <boost/thread/lockable_traits.hpp> +#include <boost/thread/lock_options.hpp> #endif diff --git a/boost/thread/mutex.hpp b/boost/thread/mutex.hpp index 4669886c7f..05c60941c4 100644 --- a/boost/thread/mutex.hpp +++ b/boost/thread/mutex.hpp @@ -3,7 +3,7 @@ // mutex.hpp // -// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2007 Anthony Williams // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -18,4 +18,36 @@ #error "Boost threads unavailable on this platform" #endif +#include <boost/thread/lockable_traits.hpp> + + +namespace boost +{ + namespace sync + { +#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES + template<> + struct is_basic_lockable<mutex> + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_lockable<mutex> + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_basic_lockable<timed_mutex> + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_lockable<timed_mutex> + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; +#endif + } +} + #endif diff --git a/boost/thread/null_mutex.hpp b/boost/thread/null_mutex.hpp new file mode 100644 index 0000000000..f439f9ffb2 --- /dev/null +++ b/boost/thread/null_mutex.hpp @@ -0,0 +1,243 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2008-2009,2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_THREAD_NULL_MUTEX_HPP +#define BOOST_THREAD_NULL_MUTEX_HPP + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/delete.hpp> +#include <boost/chrono/chrono.hpp> + +/// \file +/// Describes null_mutex class + +namespace boost +{ + + /// Implements a mutex that simulates a mutex without doing any operation and + /// simulates a successful operation. + class null_mutex + { + public: + + BOOST_THREAD_NO_COPYABLE( null_mutex) /*< no copyable >*/ + + null_mutex() {} + + /// Simulates a mutex lock() operation. Empty function. + void lock() + { + } + + /// Simulates a mutex try_lock() operation. + /// Equivalent to "return true;" + bool try_lock() + { + return true; + } + + /// Simulates a mutex unlock() operation. + /// Empty function. + void unlock() + { + } + +#ifdef BOOST_THREAD_USES_CHRONO + /// Simulates a mutex try_lock_until() operation. + /// Equivalent to "return true;" + template <typename Clock, typename Duration> + bool try_lock_until(chrono::time_point<Clock, Duration> const &) + { + return true; + } + + /// Simulates a mutex try_lock_for() operation. + /// Equivalent to "return true;" + template <typename Rep, typename Period> + bool try_lock_for(chrono::duration<Rep, Period> const &) + { + return true; + } +#endif + + /// Simulates a mutex lock_shared() operation. + /// Empty function. + void lock_shared() + { + } + + /// Simulates a mutex try_lock_shared() operation. + /// Equivalent to "return true;" + bool try_lock_shared() + { + return true; + } + + /// Simulates a mutex unlock_shared() operation. + /// Empty function. + void unlock_shared() + { + } + + /// Simulates a mutex try_lock_shared_until() operation. + /// Equivalent to "return true;" + template <typename Clock, typename Duration> + bool try_lock_shared_until(chrono::time_point<Clock, Duration> const &) + { + return true; + } + /// Simulates a mutex try_lock_shared_for() operation. + /// Equivalent to "return true;" + template <typename Rep, typename Period> + bool try_lock_shared_for(chrono::duration<Rep, Period> const &) + { + return true; + } + + /// Simulates a mutex lock_upgrade() operation. + /// Empty function. + void lock_upgrade() + { + } + + /// Simulates a mutex try_lock_upgrade() operation. + /// Equivalent to "return true;" + bool try_lock_upgrade() + { + return true; + } + + /// Simulates a mutex unlock_upgrade() operation. + /// Empty function. + void unlock_upgrade() + { + } + + /// Simulates a mutex try_lock_upgrade_until() operation. + /// Equivalent to "return true;" + template <typename Clock, typename Duration> + bool try_lock_upgrade_until(chrono::time_point<Clock, Duration> const &) + { + return true; + } + + /// Simulates a mutex try_lock_upgrade_for() operation. + /// Equivalent to "return true;" + template <typename Rep, typename Period> + bool try_lock_upgrade_for(chrono::duration<Rep, Period> const &) + { + return true; + } + + /// Simulates a mutex try_unlock_shared_and_lock() operation. + /// Equivalent to "return true;" + bool try_unlock_shared_and_lock() + { + return true; + } + +#ifdef BOOST_THREAD_USES_CHRONO + /// Simulates a mutex try_unlock_shared_and_lock_until() operation. + /// Equivalent to "return true;" + template <typename Clock, typename Duration> + bool try_unlock_shared_and_lock_until(chrono::time_point<Clock, Duration> const &) + { + return true; + } + + /// Simulates a mutex try_unlock_shared_and_lock_for() operation. + /// Equivalent to "return true;" + template <typename Rep, typename Period> + bool try_unlock_shared_and_lock_for(chrono::duration<Rep, Period> const &) + { + return true; + } +#endif + + /// Simulates unlock_and_lock_shared(). + /// Empty function. + void unlock_and_lock_shared() + { + } + + /// Simulates a mutex try_unlock_shared_and_lock_upgrade() operation. + /// Equivalent to "return true;" + bool try_unlock_shared_and_lock_upgrade() + { + return true; + } + +#ifdef BOOST_THREAD_USES_CHRONO + /// Simulates a mutex try_unlock_shared_and_lock_upgrade_until() operation. + /// Equivalent to "return true;" + template <typename Clock, typename Duration> + bool try_unlock_shared_and_lock_upgrade_until(chrono::time_point<Clock, Duration> const &) + { + return true; + } + + /// Simulates a mutex try_unlock_shared_and_lock_upgrade_for() operation. + /// Equivalent to "return true;" + template <typename Rep, typename Period> + bool try_unlock_shared_and_lock_upgrade_for(chrono::duration<Rep, Period> const &) + { + return true; + } +#endif + + /// Simulates unlock_and_lock_upgrade(). + /// Empty function. + void unlock_and_lock_upgrade() + { + } + + /// Simulates unlock_upgrade_and_lock(). + /// Empty function. + void unlock_upgrade_and_lock() + { + } + + /// Simulates a mutex try_unlock_upgrade_and_lock() operation. + /// Equivalent to "return true;" + bool try_unlock_upgrade_and_lock() + { + return true; + } + +#ifdef BOOST_THREAD_USES_CHRONO + /// Simulates a mutex try_unlock_upgrade_and_lock_until() operation. + /// Equivalent to "return true;" + template <typename Clock, typename Duration> + bool try_unlock_upgrade_and_lock_until(chrono::time_point<Clock, Duration> const &) + { + return true; + } + + /// Simulates a mutex try_unlock_upgrade_and_lock_for() operation. + /// Equivalent to "return true;" + template <typename Rep, typename Period> + bool try_unlock_upgrade_and_lock_for(chrono::duration<Rep, Period> const &) + { + return true; + } +#endif + + /// Simulates unlock_upgrade_and_lock_shared(). + /// Empty function. + void unlock_upgrade_and_lock_shared() + { + } + + }; + +} //namespace boost { + + +#endif diff --git a/boost/thread/once.hpp b/boost/thread/once.hpp index acd216edd6..9fcfb53339 100644 --- a/boost/thread/once.hpp +++ b/boost/thread/once.hpp @@ -9,11 +9,18 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#include <boost/thread/detail/config.hpp> #include <boost/thread/detail/platform.hpp> #if defined(BOOST_THREAD_PLATFORM_WIN32) #include <boost/thread/win32/once.hpp> #elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +#if defined BOOST_THREAD_ONCE_FAST_EPOCH #include <boost/thread/pthread/once.hpp> +#elif defined BOOST_THREAD_ONCE_ATOMIC +#include <boost/thread/pthread/once_atomic.hpp> +#else +#error "Once Not Implemented" +#endif #else #error "Boost threads unavailable on this platform" #endif @@ -24,7 +31,9 @@ namespace boost { // template<class Callable, class ...Args> void // call_once(once_flag& flag, Callable&& func, Args&&... args); - inline void call_once(void (*func)(),once_flag& flag) +template<typename Function> +inline void call_once(Function func,once_flag& flag) +//inline void call_once(void (*func)(),once_flag& flag) { call_once(flag,func); } diff --git a/boost/thread/ostream_buffer.hpp b/boost/thread/ostream_buffer.hpp new file mode 100644 index 0000000000..cc02a9c0ce --- /dev/null +++ b/boost/thread/ostream_buffer.hpp @@ -0,0 +1,45 @@ +// (C) Copyright 2013 Vicente J. Botet Escriba +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +#ifndef BOOST_THREAD_OSTREAM_BUFFER_HPP +#define BOOST_THREAD_OSTREAM_BUFFER_HPP + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/delete.hpp> +#include <sstream> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + + template <typename OStream> + class ostream_buffer + { + public: + typedef std::basic_ostringstream<typename OStream::char_type, typename OStream::traits_type> stream_type; + ostream_buffer(OStream& os) : + os_(os) + { + } + ~ostream_buffer() + { + os_ << o_str_.str(); + } + stream_type& stream() + { + return o_str_; + } + private: + OStream& os_; + stream_type o_str_; + }; + +} + +#include <boost/config/abi_suffix.hpp> + +#endif // header diff --git a/boost/thread/poly_lockable.hpp b/boost/thread/poly_lockable.hpp new file mode 100644 index 0000000000..7346188116 --- /dev/null +++ b/boost/thread/poly_lockable.hpp @@ -0,0 +1,68 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2008-2009,2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_THREAD_POLY_LOCKABLE_HPP +#define BOOST_THREAD_POLY_LOCKABLE_HPP + +#include <boost/thread/detail/delete.hpp> +#include <boost/chrono/chrono.hpp> + +namespace boost +{ + + //[basic_poly_lockable + class basic_poly_lockable + { + public: + + virtual ~basic_poly_lockable() = 0; + + virtual void lock() = 0; + virtual void unlock() = 0; + + }; + //] + + //[poly_lockable + class poly_lockable : public basic_poly_lockable<Lockable> + { + public: + + virtual ~poly_lockable() = 0; + virtual bool try_lock() = 0; + }; + //] + + //[timed_poly_lockable + class timed_poly_lockable: public poly_lockable<TimedLock> + { + public: + virtual ~timed_poly_lockable()=0; + + virtual bool try_lock_until(chrono::system_clock::time_point const & abs_time)=0; + virtual bool try_lock_until(chrono::steady_clock::time_point const & abs_time)=0; + template <typename Clock, typename Duration> + bool try_lock_until(chrono::time_point<Clock, Duration> const & abs_time) + { + return try_lock_until(time_point_cast<Clock::time_point>(abs_time)); + } + + virtual bool try_lock_for(chrono::nanoseconds const & relative_time)=0; + template <typename Rep, typename Period> + bool try_lock_for(chrono::duration<Rep, Period> const & rel_time) + { + return try_lock_for(duration_cast<Clock::duration>(rel_time)); + } + + }; + //] + +} +#endif diff --git a/boost/thread/poly_lockable_adapter.hpp b/boost/thread/poly_lockable_adapter.hpp new file mode 100644 index 0000000000..448789ecbc --- /dev/null +++ b/boost/thread/poly_lockable_adapter.hpp @@ -0,0 +1,89 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2008-2009,2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_THREAD_POLY_LOCKABLE_ADAPTER_HPP +#define BOOST_THREAD_POLY_LOCKABLE_ADAPTER_HPP + +#include <boost/thread/poly_lockable.hpp> + +namespace boost +{ + + //[poly_basic_lockable_adapter + template <typename Mutex, typename Base=poly_basic_lockable> + class poly_basic_lockable_adapter : public Base + { + public: + typedef Mutex mutex_type; + + protected: + mutex_type& mtx() const + { + return mtx_; + } + mutable mutex_type mtx_; /*< mutable so that it can be modified by const functions >*/ + public: + + BOOST_THREAD_NO_COPYABLE( poly_basic_lockable_adapter) /*< no copyable >*/ + + poly_basic_lockable_adapter() + {} + + void lock() + { + mtx().lock(); + } + void unlock() + { + mtx().unlock(); + } + + }; + //] + + //[poly_lockable_adapter + template <typename Mutex, typename Base=poly_lockable> + class poly_lockable_adapter : public poly_basic_lockable_adapter<Mutex, Base> + { + public: + typedef Mutex mutex_type; + + bool try_lock() + { + return this->mtx().try_lock(); + } + }; + //] + + //[poly_timed_lockable_adapter + template <typename Mutex, typename Base=poly_timed_lockable> + class poly_timed_lockable_adapter: public poly_lockable_adapter<Mutex, Base> + { + public: + typedef Mutex mutex_type; + + bool try_lock_until(chrono::system_clock::time_point const & abs_time) + { + return this->mtx().try_lock_until(abs_time); + } + bool try_lock_until(chrono::steady_clock::time_point const & abs_time) + { + return this->mtx().try_lock_until(abs_time); + } + bool try_lock_for(chrono::nanoseconds const & rel_time) + { + return this->mtx().try_lock_for(rel_time); + } + + }; + //] + +} +#endif diff --git a/boost/thread/poly_shared_lockable.hpp b/boost/thread/poly_shared_lockable.hpp new file mode 100644 index 0000000000..4348ed76c2 --- /dev/null +++ b/boost/thread/poly_shared_lockable.hpp @@ -0,0 +1,135 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2008-2009,2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_THREAD_POLY_SHARED_LOCKABLE_HPP +#define BOOST_THREAD_POLY_SHARED_LOCKABLE_HPP + +#include <boost/thread/poly_lockable.hpp> +#include <boost/chrono/chrono.hpp> + +namespace boost +{ + + + //[shared_poly_lockable + class shared_poly_lockable: public timed_poly_lockable + { + public: + virtual ~shared_poly_lockable() = 0; + + virtual void lock_shared() = 0; + virtual bool try_lock_shared() = 0; + virtual void unlock_shared() = 0; + + virtual bool try_lock_shared_until(chrono::system_clock::time_point const & abs_time)=0; + virtual bool try_lock_shared_until(chrono::steady_clock::time_point const & abs_time)=0; + template <typename Clock, typename Duration> + bool try_lock_shared_until(chrono::time_point<Clock, Duration> const & abs_time) + { + return try_lock_shared_until(time_point_cast<Clock::time_point>(abs_time)); + } + + virtual bool try_lock_shared_for(chrono::nanoseconds const & relative_time)=0; + template <typename Rep, typename Period> + bool try_lock_shared_for(chrono::duration<Rep, Period> const & rel_time) + { + return try_lock_shared_for(duration_cast<Clock::duration>(rel_time)); + } + + }; + + //] + + //[upgrade_poly_lockable + class upgrade_poly_lockable: public shared_poly_lockable + { + public: + virtual ~upgrade_poly_lockable() = 0; + + virtual void lock_upgrade() = 0; + virtual bool try_lock_upgrade() = 0; + virtual void unlock_upgrade() = 0; + + virtual bool try_lock_upgrade_until(chrono::system_clock::time_point const & abs_time)=0; + virtual bool try_lock_upgrade_until(chrono::steady_clock::time_point const & abs_time)=0; + template <typename Clock, typename Duration> + bool try_lock_upgrade_until(chrono::time_point<Clock, Duration> const & abs_time) + { + return try_lock_upgrade_until(time_point_cast<Clock::time_point>(abs_time)); + } + + virtual bool try_lock_upgrade_for(chrono::nanoseconds const & relative_time)=0; + template <typename Rep, typename Period> + bool try_lock_upgrade_for(chrono::duration<Rep, Period> const & rel_time) + { + return try_lock_upgrade_for(duration_cast<Clock::duration>(rel_time)); + } + + virtual bool try_unlock_shared_and_lock() = 0; + + virtual bool try_unlock_shared_and_lock_until(chrono::system_clock::time_point const & abs_time)=0; + virtual bool try_unlock_shared_and_lock_until(chrono::steady_clock::time_point const & abs_time)=0; + template <typename Clock, typename Duration> + bool try_unlock_shared_and_lock_until(chrono::time_point<Clock, Duration> const & abs_time) + { + return try_unlock_shared_and_lock_until(time_point_cast<Clock::time_point>(abs_time)); + } + + virtual bool try_unlock_shared_and_lock_for(chrono::nanoseconds const & relative_time)=0; + template <typename Rep, typename Period> + bool try_unlock_shared_and_lock_for(chrono::duration<Rep, Period> const & rel_time) + { + return try_unlock_shared_and_lock_for(duration_cast<Clock::duration>(rel_time)); + } + + virtual void unlock_and_lock_shared() = 0; + virtual bool try_unlock_shared_and_lock_upgrade() = 0; + + virtual bool try_unlock_shared_and_lock_upgrade_until(chrono::system_clock::time_point const & abs_time)=0; + virtual bool try_unlock_shared_and_lock_upgrade_until(chrono::steady_clock::time_point const & abs_time)=0; + template <typename Clock, typename Duration> + bool try_unlock_shared_and_lock_upgrade_until(chrono::time_point<Clock, Duration> const & abs_time) + { + return try_unlock_shared_and_lock_upgrade_until(time_point_cast<Clock::time_point>(abs_time)); + } + + virtual bool try_unlock_shared_and_lock_upgrade_for(chrono::nanoseconds const & relative_time)=0; + template <typename Rep, typename Period> + bool try_unlock_shared_and_lock_upgrade_for(chrono::duration<Rep, Period> const & rel_time) + { + return try_unlock_shared_and_lock_upgrade_for(duration_cast<Clock::duration>(rel_time)); + } + + virtual void unlock_and_lock_upgrade() = 0; + virtual void unlock_upgrade_and_lock() = 0; + virtual bool try_unlock_upgrade_and_lock() = 0; + + virtual bool try_unlock_upgrade_and_lock_until(chrono::system_clock::time_point const & abs_time)=0; + virtual bool try_unlock_upgrade_and_lock_until(chrono::steady_clock::time_point const & abs_time)=0; + template <typename Clock, typename Duration> + bool try_unlock_upgrade_and_lock_until(chrono::time_point<Clock, Duration> const & abs_time) + { + return try_unlock_upgrade_and_lock_until(time_point_cast<Clock::time_point>(abs_time)); + } + + virtual bool try_unlock_upgrade_and_lock_for(chrono::nanoseconds const & relative_time)=0; + template <typename Rep, typename Period> + bool try_unlock_upgrade_and_lock_for(chrono::duration<Rep, Period> const & rel_time) + { + return try_unlock_upgrade_and_lock_for(duration_cast<Clock::duration>(rel_time)); + } + + virtual void unlock_upgrade_and_lock_shared() = 0; + + }; +//] + +} +#endif diff --git a/boost/thread/poly_shared_lockable_adapter.hpp b/boost/thread/poly_shared_lockable_adapter.hpp new file mode 100644 index 0000000000..f136128907 --- /dev/null +++ b/boost/thread/poly_shared_lockable_adapter.hpp @@ -0,0 +1,170 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2008-2009,2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_THREAD_POLY_SHARED_LOCKABLE_ADAPTER_HPP +#define BOOST_THREAD_POLY_SHARED_LOCKABLE_ADAPTER_HPP + +#include <boost/thread/poly_lockable_adapter.hpp> +#include <boost/thread/poly_shared_lockable.hpp> + +namespace boost +{ + + //[shared_lockable_adapter + template <typename Mutex, typename Base=poly_shared_lockable> + class poly_shared_lockable_adapter: public poly_timed_lockable_adapter<Mutex, Base> + { + public: + typedef Mutex mutex_type; + + void lock_shared() + { + this->mtx().lock_shared(); + } + bool try_lock_shared() + { + return this->mtx().try_lock_shared(); + } + void unlock_shared() + { + this->mtx().unlock_shared(); + } + + bool try_lock_shared_until(chrono::system_clock::time_point const & abs_time) + { + return this->mtx().try_lock_shared_until(abs_time); + } + bool try_lock_shared_until(chrono::steady_clock::time_point const & abs_time) + { + return this->mtx().try_lock_shared_until(abs_time); + } + bool try_lock_shared_for(chrono::nanoseconds const & rel_time) + { + return this->mtx().try_lock_shared_for(rel_time); + } + + }; + + //] + + //[upgrade_lockable_adapter + template <typename Mutex, typename Base=poly_shared_lockable> + class upgrade_lockable_adapter: public shared_lockable_adapter<Mutex, Base> + { + public: + typedef Mutex mutex_type; + + void lock_upgrade() + { + this->mtx().lock_upgrade(); + } + + bool try_lock_upgrade() + { + return this->mtx().try_lock_upgrade(); + } + + void unlock_upgrade() + { + this->mtx().unlock_upgrade(); + } + + bool try_lock_upgrade_until(chrono::system_clock::time_point const & abs_time) + { + return this->mtx().try_lock_upgrade_until(abs_time); + } + bool try_lock_upgrade_until(chrono::steady_clock::time_point const & abs_time) + { + return this->mtx().try_lock_upgrade_until(abs_time); + } + bool try_lock_upgrade_for(chrono::nanoseconds const & rel_time) + { + return this->mtx().try_lock_upgrade_for(rel_time); + } + + bool try_unlock_shared_and_lock() + { + return this->mtx().try_unlock_shared_and_lock(); + } + + bool try_unlock_shared_and_lock_until(chrono::system_clock::time_point const & abs_time) + { + return this->mtx().try_unlock_shared_and_lock_until(abs_time); + } + bool try_unlock_shared_and_lock_until(chrono::steady_clock::time_point const & abs_time) + { + return this->mtx().try_unlock_shared_and_lock_until(abs_time); + } + template <typename Rep, typename Period> + bool try_unlock_shared_and_lock_for(chrono::nanoseconds const & rel_time) + { + return this->mtx().try_unlock_shared_and_lock_for(rel_time); + } + + void unlock_and_lock_shared() + { + this->mtx().unlock_and_lock_shared(); + } + + bool try_unlock_shared_and_lock_upgrade() + { + return this->mtx().try_unlock_shared_and_lock_upgrade(); + } + + bool try_unlock_shared_and_lock_upgrade_until(chrono::system_clock::time_point const & abs_time) + { + return this->mtx().try_unlock_shared_and_lock_upgrade_until(abs_time); + } + bool try_unlock_shared_and_lock_upgrade_until(chrono::steady_clock::time_point const & abs_time) + { + return this->mtx().try_unlock_shared_and_lock_upgrade_until(abs_time); + } + bool try_unlock_shared_and_lock_upgrade_for(chrono::nanoseconds const & rel_time) + { + return this->mtx().try_unlock_shared_and_lock_upgrade_for(rel_time); + } + + void unlock_and_lock_upgrade() + { + this->mtx().unlock_and_lock_upgrade(); + } + + void unlock_upgrade_and_lock() + { + this->mtx().unlock_upgrade_and_lock(); + } + + bool try_unlock_upgrade_and_lock() + { + return this->mtx().try_unlock_upgrade_and_lock(); + } + bool try_unlock_upgrade_and_lock_until(chrono::system_clock::time_point const & abs_time) + { + return this->mtx().try_unlock_upgrade_and_lock_until(abs_time); + } + bool try_unlock_upgrade_and_lock_until(chrono::steady_clock::time_point const & abs_time) + { + return this->mtx().try_unlock_upgrade_and_lock_until(abs_time); + } + bool try_unlock_upgrade_and_lock_for(chrono::nanoseconds const & rel_time) + { + return this->mtx().try_unlock_upgrade_and_lock_for(rel_time); + } + + void unlock_upgrade_and_lock_shared() + { + this->mtx().unlock_upgrade_and_lock_shared(); + } + + }; +//] + +} +#endif diff --git a/boost/thread/pthread/condition_variable.hpp b/boost/thread/pthread/condition_variable.hpp index aa7100766e..b30d37f9b0 100644 --- a/boost/thread/pthread/condition_variable.hpp +++ b/boost/thread/pthread/condition_variable.hpp @@ -4,11 +4,13 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // (C) Copyright 2007-10 Anthony Williams -// (C) Copyright 2011 Vicente J. Botet Escriba +// (C) Copyright 2011-2012 Vicente J. Botet Escriba #include <boost/thread/pthread/timespec.hpp> #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp> +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS #include <boost/thread/pthread/thread_data.hpp> +#endif #include <boost/thread/pthread/condition_variable_fwd.hpp> #ifdef BOOST_THREAD_USES_CHRONO #include <boost/chrono/system_clocks.hpp> @@ -20,10 +22,12 @@ namespace boost { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS namespace this_thread { void BOOST_THREAD_DECL interruption_point(); } +#endif namespace thread_cv_detail { @@ -53,57 +57,88 @@ namespace boost inline void condition_variable::wait(unique_lock<mutex>& m) { +#if defined BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED + if(! m.owns_lock()) + { + boost::throw_exception(condition_error(-1, "boost::condition_variable::wait() failed precondition mutex not owned")); + } +#endif int res=0; { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS thread_cv_detail::lock_on_exit<unique_lock<mutex> > guard; detail::interruption_checker check_for_interruption(&internal_mutex,&cond); guard.activate(m); do { res = pthread_cond_wait(&cond,&internal_mutex); } while (res == EINTR); +#else + //boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex); + pthread_mutex_t* the_mutex = m.mutex()->native_handle(); + do { + res = pthread_cond_wait(&cond,the_mutex); + } while (res == EINTR); +#endif } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS this_thread::interruption_point(); +#endif if(res) { - boost::throw_exception(condition_error(res, "boost:: condition_variable constructor failed in pthread_cond_wait")); + boost::throw_exception(condition_error(res, "boost::condition_variable::wait failed in pthread_cond_wait")); } } - inline bool condition_variable::do_timed_wait( + inline bool condition_variable::do_wait_until( unique_lock<mutex>& m, struct timespec const &timeout) { +#if defined BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED if (!m.owns_lock()) - boost::throw_exception(condition_error(EPERM, "condition_variable do_timed_wait: mutex not locked")); - + { + boost::throw_exception(condition_error(EPERM, "boost::condition_variable::do_wait_until() failed precondition mutex not owned")); + } +#endif thread_cv_detail::lock_on_exit<unique_lock<mutex> > guard; int cond_res; { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS detail::interruption_checker check_for_interruption(&internal_mutex,&cond); guard.activate(m); cond_res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout); +#else + //boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex); + pthread_mutex_t* the_mutex = m.mutex()->native_handle(); + cond_res=pthread_cond_timedwait(&cond,the_mutex,&timeout); +#endif } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS this_thread::interruption_point(); +#endif if(cond_res==ETIMEDOUT) { return false; } if(cond_res) { - boost::throw_exception(condition_error(cond_res, "condition_variable failed in pthread_cond_timedwait")); + boost::throw_exception(condition_error(cond_res, "boost::condition_variable::do_wait_until failed in pthread_cond_timedwait")); } return true; } inline void condition_variable::notify_one() BOOST_NOEXCEPT { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); +#endif BOOST_VERIFY(!pthread_cond_signal(&cond)); } inline void condition_variable::notify_all() BOOST_NOEXCEPT { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); +#endif BOOST_VERIFY(!pthread_cond_broadcast(&cond)); } @@ -119,13 +154,13 @@ namespace boost int const res=pthread_mutex_init(&internal_mutex,NULL); if(res) { - boost::throw_exception(thread_resource_error(res, "condition_variable_any failed in pthread_mutex_init")); + boost::throw_exception(thread_resource_error(res, "boost::condition_variable_any::condition_variable_any() failed in pthread_mutex_init")); } int const res2=pthread_cond_init(&cond,NULL); if(res2) { BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex)); - boost::throw_exception(thread_resource_error(res, "condition_variable_any failed in pthread_cond_init")); + boost::throw_exception(thread_resource_error(res2, "boost::condition_variable_any::condition_variable_any() failed in pthread_cond_init")); } } ~condition_variable_any() @@ -140,14 +175,20 @@ namespace boost int res=0; { thread_cv_detail::lock_on_exit<lock_type> guard; +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS detail::interruption_checker check_for_interruption(&internal_mutex,&cond); +#else + boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex); +#endif guard.activate(m); res=pthread_cond_wait(&cond,&internal_mutex); } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS this_thread::interruption_point(); +#endif if(res) { - boost::throw_exception(condition_error(res, "condition_variable_any failed in pthread_cond_wait")); + boost::throw_exception(condition_error(res, "boost::condition_variable_any::wait() failed in pthread_cond_wait")); } } @@ -157,16 +198,17 @@ namespace boost while(!pred()) wait(m); } +#if defined BOOST_THREAD_USES_DATETIME template<typename lock_type> - bool timed_wait(lock_type& m,boost::system_time const& wait_until) + bool timed_wait(lock_type& m,boost::system_time const& abs_time) { - struct timespec const timeout=detail::get_timespec(wait_until); - return do_timed_wait(m, timeout); + struct timespec const timeout=detail::to_timespec(abs_time); + return do_wait_until(m, timeout); } template<typename lock_type> - bool timed_wait(lock_type& m,xtime const& wait_until) + bool timed_wait(lock_type& m,xtime const& abs_time) { - return timed_wait(m,system_time(wait_until)); + return timed_wait(m,system_time(abs_time)); } template<typename lock_type,typename duration_type> @@ -176,20 +218,20 @@ namespace boost } template<typename lock_type,typename predicate_type> - bool timed_wait(lock_type& m,boost::system_time const& wait_until,predicate_type pred) + bool timed_wait(lock_type& m,boost::system_time const& abs_time, predicate_type pred) { while (!pred()) { - if(!timed_wait(m, wait_until)) + if(!timed_wait(m, abs_time)) return pred(); } return true; } template<typename lock_type,typename predicate_type> - bool timed_wait(lock_type& m,xtime const& wait_until,predicate_type pred) + bool timed_wait(lock_type& m,xtime const& abs_time, predicate_type pred) { - return timed_wait(m,system_time(wait_until),pred); + return timed_wait(m,system_time(abs_time),pred); } template<typename lock_type,typename duration_type,typename predicate_type> @@ -197,7 +239,7 @@ namespace boost { return timed_wait(m,get_system_time()+wait_duration,pred); } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template <class lock_type,class Duration> cv_status @@ -265,26 +307,26 @@ namespace boost const chrono::duration<Rep, Period>& d, Predicate pred) { - while (!pred()) - { - if (wait_for(lock, d) == cv_status::timeout) - return pred(); - } - return true; + return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred)); + +// while (!pred()) +// { +// if (wait_for(lock, d) == cv_status::timeout) +// return pred(); +// } +// return true; } template <class lock_type> - inline void wait_until( + cv_status wait_until( lock_type& lk, chrono::time_point<chrono::system_clock, chrono::nanoseconds> tp) { using namespace chrono; nanoseconds d = tp.time_since_epoch(); - timespec ts; - seconds s = duration_cast<seconds>(d); - ts.tv_sec = static_cast<long>(s.count()); - ts.tv_nsec = static_cast<long>((d - s).count()); - do_timed_wait(lk, ts); + timespec ts = boost::detail::to_timespec(d); + if (do_wait_until(lk, ts)) return cv_status::no_timeout; + else return cv_status::timeout; } #endif @@ -302,25 +344,31 @@ namespace boost private: // used by boost::thread::try_join_until template <class lock_type> - inline bool do_timed_wait( + inline bool do_wait_until( lock_type& m, struct timespec const &timeout) { int res=0; { thread_cv_detail::lock_on_exit<lock_type> guard; +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS detail::interruption_checker check_for_interruption(&internal_mutex,&cond); +#else + boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex); +#endif guard.activate(m); res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout); } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS this_thread::interruption_point(); +#endif if(res==ETIMEDOUT) { return false; } if(res) { - boost::throw_exception(condition_error(res, "condition_variable_any failed in pthread_cond_timedwait")); + boost::throw_exception(condition_error(res, "boost::condition_variable_any::do_wait_until() failed in pthread_cond_timedwait")); } return true; } diff --git a/boost/thread/pthread/condition_variable_fwd.hpp b/boost/thread/pthread/condition_variable_fwd.hpp index 4f4bd881d9..e18030fd5f 100644 --- a/boost/thread/pthread/condition_variable_fwd.hpp +++ b/boost/thread/pthread/condition_variable_fwd.hpp @@ -4,22 +4,26 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // (C) Copyright 2007-8 Anthony Williams -// (C) Copyright 2011 Vicente J. Botet Escriba +// (C) Copyright 2011-2012 Vicente J. Botet Escriba #include <boost/assert.hpp> #include <boost/throw_exception.hpp> #include <pthread.h> #include <boost/thread/cv_status.hpp> #include <boost/thread/mutex.hpp> -#include <boost/thread/locks.hpp> +#include <boost/thread/lock_types.hpp> #include <boost/thread/thread_time.hpp> +#include <boost/thread/pthread/timespec.hpp> +#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> #endif #include <boost/thread/detail/delete.hpp> #include <boost/date_time/posix_time/posix_time_duration.hpp> + #include <boost/config/abi_prefix.hpp> namespace boost @@ -28,33 +32,58 @@ namespace boost class condition_variable { private: +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS pthread_mutex_t internal_mutex; +#endif pthread_cond_t cond; public: + //private: // used by boost::thread::try_join_until + + inline bool do_wait_until( + unique_lock<mutex>& lock, + struct timespec const &timeout); + + bool do_wait_for( + unique_lock<mutex>& lock, + struct timespec const &timeout) + { + return do_wait_until(lock, boost::detail::timespec_plus(timeout, boost::detail::timespec_now())); + } + + public: BOOST_THREAD_NO_COPYABLE(condition_variable) condition_variable() { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS int const res=pthread_mutex_init(&internal_mutex,NULL); if(res) { - boost::throw_exception(thread_resource_error(res, "boost:: condition_variable constructor failed in pthread_mutex_init")); + boost::throw_exception(thread_resource_error(res, "boost::condition_variable::condition_variable() constructor failed in pthread_mutex_init")); } +#endif int const res2=pthread_cond_init(&cond,NULL); if(res2) { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex)); - boost::throw_exception(thread_resource_error(res2, "boost:: condition_variable constructor failed in pthread_cond_init")); +#endif + boost::throw_exception(thread_resource_error(res2, "boost::condition_variable::condition_variable() constructor failed in pthread_cond_init")); } } ~condition_variable() { - BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex)); int ret; +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + do { + ret = pthread_mutex_destroy(&internal_mutex); + } while (ret == EINTR); + BOOST_ASSERT(!ret); +#endif do { ret = pthread_cond_destroy(&cond); } while (ret == EINTR); - BOOST_VERIFY(!ret); + BOOST_ASSERT(!ret); } void wait(unique_lock<mutex>& m); @@ -66,23 +95,24 @@ namespace boost } +#if defined BOOST_THREAD_USES_DATETIME inline bool timed_wait( unique_lock<mutex>& m, - boost::system_time const& wait_until) + boost::system_time const& abs_time) { #if defined BOOST_THREAD_WAIT_BUG - struct timespec const timeout=detail::get_timespec(wait_until + BOOST_THREAD_WAIT_BUG); - return do_timed_wait(m, timeout); + struct timespec const timeout=detail::to_timespec(abs_time + BOOST_THREAD_WAIT_BUG); + return do_wait_until(m, timeout); #else - struct timespec const timeout=detail::get_timespec(wait_until); - return do_timed_wait(m, timeout); + struct timespec const timeout=detail::to_timespec(abs_time); + return do_wait_until(m, timeout); #endif } bool timed_wait( unique_lock<mutex>& m, - xtime const& wait_until) + xtime const& abs_time) { - return timed_wait(m,system_time(wait_until)); + return timed_wait(m,system_time(abs_time)); } template<typename duration_type> @@ -96,11 +126,11 @@ namespace boost template<typename predicate_type> bool timed_wait( unique_lock<mutex>& m, - boost::system_time const& wait_until,predicate_type pred) + boost::system_time const& abs_time,predicate_type pred) { while (!pred()) { - if(!timed_wait(m, wait_until)) + if(!timed_wait(m, abs_time)) return pred(); } return true; @@ -109,9 +139,9 @@ namespace boost template<typename predicate_type> bool timed_wait( unique_lock<mutex>& m, - xtime const& wait_until,predicate_type pred) + xtime const& abs_time,predicate_type pred) { - return timed_wait(m,system_time(wait_until),pred); + return timed_wait(m,system_time(abs_time),pred); } template<typename duration_type,typename predicate_type> @@ -121,6 +151,7 @@ namespace boost { return timed_wait(m,get_system_time()+wait_duration,pred); } +#endif #ifdef BOOST_THREAD_USES_CHRONO @@ -190,12 +221,14 @@ namespace boost const chrono::duration<Rep, Period>& d, Predicate pred) { - while (!pred()) - { - if (wait_for(lock, d) == cv_status::timeout) - return pred(); - } - return true; + return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred)); + +// while (!pred()) +// { +// if (wait_for(lock, d) == cv_status::timeout) +// return pred(); +// } +// return true; } #endif @@ -210,27 +243,24 @@ namespace boost void notify_all() BOOST_NOEXCEPT; #ifdef BOOST_THREAD_USES_CHRONO - inline void wait_until( + inline cv_status wait_until( unique_lock<mutex>& lk, chrono::time_point<chrono::system_clock, chrono::nanoseconds> tp) { using namespace chrono; nanoseconds d = tp.time_since_epoch(); - timespec ts; - seconds s = duration_cast<seconds>(d); - ts.tv_sec = static_cast<long>(s.count()); - ts.tv_nsec = static_cast<long>((d - s).count()); - do_timed_wait(lk, ts); + timespec ts = boost::detail::to_timespec(d); + if (do_wait_until(lk, ts)) return cv_status::no_timeout; + else return cv_status::timeout; } #endif - //private: // used by boost::thread::try_join_until - - inline bool do_timed_wait( - unique_lock<mutex>& lock, - struct timespec const &timeout); }; + + BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk); + } + #include <boost/config/abi_suffix.hpp> #endif diff --git a/boost/thread/pthread/mutex.hpp b/boost/thread/pthread/mutex.hpp index 2c5af92b8a..3e9af2a833 100644 --- a/boost/thread/pthread/mutex.hpp +++ b/boost/thread/pthread/mutex.hpp @@ -6,10 +6,14 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#include <boost/thread/detail/config.hpp> #include <pthread.h> #include <boost/throw_exception.hpp> +#include <boost/core/ignore_unused.hpp> #include <boost/thread/exceptions.hpp> -#include <boost/thread/locks.hpp> +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS +#include <boost/thread/lock_types.hpp> +#endif #include <boost/thread/thread_time.hpp> #include <boost/thread/xtime.hpp> #include <boost/assert.hpp> @@ -23,15 +27,68 @@ #include <boost/thread/detail/delete.hpp> #ifdef _POSIX_TIMEOUTS -#if _POSIX_TIMEOUTS >= 0 && _POSIX_C_SOURCE>=200112L +#if _POSIX_TIMEOUTS >= 0 && _POSIX_TIMEOUTS>=200112L +#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK #define BOOST_PTHREAD_HAS_TIMEDLOCK #endif #endif +#endif + #include <boost/config/abi_prefix.hpp> +#ifndef BOOST_THREAD_HAS_NO_EINTR_BUG +#define BOOST_THREAD_HAS_EINTR_BUG +#endif + namespace boost { + namespace posix { +#ifdef BOOST_THREAD_HAS_EINTR_BUG + BOOST_FORCEINLINE int pthread_mutex_destroy(pthread_mutex_t* m) + { + int ret; + do + { + ret = ::pthread_mutex_destroy(m); + } while (ret == EINTR); + return ret; + } + BOOST_FORCEINLINE int pthread_mutex_lock(pthread_mutex_t* m) + { + int ret; + do + { + ret = ::pthread_mutex_lock(m); + } while (ret == EINTR); + return ret; + } + BOOST_FORCEINLINE int pthread_mutex_unlock(pthread_mutex_t* m) + { + int ret; + do + { + ret = ::pthread_mutex_unlock(m); + } while (ret == EINTR); + return ret; + } +#else + BOOST_FORCEINLINE int pthread_mutex_destroy(pthread_mutex_t* m) + { + return ::pthread_mutex_destroy(m); + } + BOOST_FORCEINLINE int pthread_mutex_lock(pthread_mutex_t* m) + { + return ::pthread_mutex_lock(m); + } + BOOST_FORCEINLINE int pthread_mutex_unlock(pthread_mutex_t* m) + { + return ::pthread_mutex_unlock(m); + } + +#endif + + } class mutex { private: @@ -49,20 +106,14 @@ namespace boost } ~mutex() { - int ret; - do - { - ret = pthread_mutex_destroy(&m); - } while (ret == EINTR); + int const res = posix::pthread_mutex_destroy(&m); + boost::ignore_unused(res); + BOOST_ASSERT(!res); } void lock() { - int res; - do - { - res = pthread_mutex_lock(&m); - } while (res == EINTR); + int res = posix::pthread_mutex_lock(&m); if (res) { boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock")); @@ -71,12 +122,11 @@ namespace boost void unlock() { - int ret; - do + int res = posix::pthread_mutex_unlock(&m); + if (res) { - ret = pthread_mutex_unlock(&m); - } while (ret == EINTR); - BOOST_VERIFY(!ret); + boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock")); + } } bool try_lock() @@ -86,12 +136,8 @@ namespace boost { res = pthread_mutex_trylock(&m); } while (res == EINTR); - if(res && (res!=EBUSY)) + if (res==EBUSY) { - // The following throw_exception has been replaced by an assertion and just return false, - // as this is an internal error and the user can do nothing with the exception. - //boost::throw_exception(lock_error(res,"boost: mutex try_lock failed in pthread_mutex_trylock")); - BOOST_ASSERT_MSG(false ,"boost: mutex try_lock failed in pthread_mutex_trylock"); return false; } @@ -105,8 +151,10 @@ namespace boost return &m; } +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS typedef unique_lock<mutex> scoped_lock; typedef detail::try_lock_wrapper<mutex> scoped_try_lock; +#endif }; typedef mutex try_mutex; @@ -132,7 +180,8 @@ namespace boost int const res2=pthread_cond_init(&cond,NULL); if(res2) { - BOOST_VERIFY(!pthread_mutex_destroy(&m)); + BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); + //BOOST_VERIFY(!pthread_mutex_destroy(&m)); boost::throw_exception(thread_resource_error(res2, "boost:: timed_mutex constructor failed in pthread_cond_init")); } is_locked=false; @@ -140,12 +189,13 @@ namespace boost } ~timed_mutex() { - BOOST_VERIFY(!pthread_mutex_destroy(&m)); + BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK BOOST_VERIFY(!pthread_cond_destroy(&cond)); #endif } +#if defined BOOST_THREAD_USES_DATETIME template<typename TimeDuration> bool timed_lock(TimeDuration const & relative_time) { @@ -155,23 +205,39 @@ namespace boost { return timed_lock(system_time(absolute_time)); } - +#endif #ifdef BOOST_PTHREAD_HAS_TIMEDLOCK void lock() { - BOOST_VERIFY(!pthread_mutex_lock(&m)); + int res = posix::pthread_mutex_lock(&m); + if (res) + { + boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock")); + } } void unlock() { - BOOST_VERIFY(!pthread_mutex_unlock(&m)); + int res = posix::pthread_mutex_unlock(&m); + if (res) + { + boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock")); + } } bool try_lock() { - int const res=pthread_mutex_trylock(&m); - BOOST_ASSERT(!res || res==EBUSY); - return !res; + int res; + do + { + res = pthread_mutex_trylock(&m); + } while (res == EINTR); + if (res==EBUSY) + { + return false; + } + + return !res; } @@ -232,12 +298,13 @@ namespace boost public: #endif +#if defined BOOST_THREAD_USES_DATETIME bool timed_lock(system_time const & abs_time) { - struct timespec const ts=detail::get_timespec(abs_time); + struct timespec const ts=boost::detail::to_timespec(abs_time); return do_try_lock_until(ts); } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template <class Rep, class Period> bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) @@ -261,12 +328,9 @@ namespace boost } bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp) { - using namespace chrono; - nanoseconds d = tp.time_since_epoch(); - timespec ts; - seconds s = duration_cast<seconds>(d); - ts.tv_sec = static_cast<long>(s.count()); - ts.tv_nsec = static_cast<long>((d - s).count()); + //using namespace chrono; + chrono::nanoseconds d = tp.time_since_epoch(); + timespec ts = boost::detail::to_timespec(d); return do_try_lock_until(ts); } #endif @@ -278,9 +342,11 @@ namespace boost return &m; } +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS typedef unique_lock<timed_mutex> scoped_timed_lock; typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock; typedef scoped_timed_lock scoped_lock; +#endif }; } diff --git a/boost/thread/pthread/once.hpp b/boost/thread/pthread/once.hpp index 80aa09ee12..0bef0387de 100644 --- a/boost/thread/pthread/once.hpp +++ b/boost/thread/pthread/once.hpp @@ -11,21 +11,50 @@ // http://www.boost.org/LICENSE_1_0.txt) #include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/detail/invoke.hpp> -#include <pthread.h> -#include <boost/assert.hpp> #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp> -#include <boost/cstdint.hpp> #include <boost/thread/detail/delete.hpp> +#include <boost/core/no_exceptions_support.hpp> +#include <boost/bind.hpp> +#include <boost/assert.hpp> #include <boost/config/abi_prefix.hpp> +#include <boost/cstdint.hpp> +#include <pthread.h> +#include <csignal> + namespace boost { -#define BOOST_ONCE_INITIAL_FLAG_VALUE 0 + struct once_flag; + + #define BOOST_ONCE_INITIAL_FLAG_VALUE 0 + + namespace thread_detail + { + typedef boost::uint32_t uintmax_atomic_t; + #define BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_C2(value) value##u + #define BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_MAX_C BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_C2(~0) + + } #ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11 +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template<typename Function, class ...ArgTypes> + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args); +#else + template<typename Function> + inline void call_once(once_flag& flag, Function f); + template<typename Function, typename T1> + inline void call_once(once_flag& flag, Function f, T1 p1); + template<typename Function, typename T1, typename T2> + inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2); + template<typename Function, typename T1, typename T2, typename T3> + inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2, T3 p3); +#endif struct once_flag { @@ -34,78 +63,476 @@ namespace boost : epoch(BOOST_ONCE_INITIAL_FLAG_VALUE) {} private: - boost::uintmax_t epoch; + volatile thread_detail::uintmax_atomic_t epoch; + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template<typename Function, class ...ArgTypes> + friend void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args); +#else template<typename Function> - friend - void call_once(once_flag& flag,Function f); + friend void call_once(once_flag& flag, Function f); + template<typename Function, typename T1> + friend void call_once(once_flag& flag, Function f, T1 p1); + template<typename Function, typename T1, typename T2> + friend void call_once(once_flag& flag, Function f, T1 p1, T2 p2); + template<typename Function, typename T1, typename T2, typename T3> + friend void call_once(once_flag& flag, Function f, T1 p1, T2 p2, T3 p3); + +#endif + }; +#define BOOST_ONCE_INIT once_flag() + #else // BOOST_THREAD_PROVIDES_ONCE_CXX11 struct once_flag { - boost::uintmax_t epoch; + volatile thread_detail::uintmax_atomic_t epoch; }; #define BOOST_ONCE_INIT {BOOST_ONCE_INITIAL_FLAG_VALUE} #endif // BOOST_THREAD_PROVIDES_ONCE_CXX11 - namespace detail + +#if defined BOOST_THREAD_PROVIDES_INVOKE +#define BOOST_THREAD_INVOKE_RET_VOID detail::invoke +#define BOOST_THREAD_INVOKE_RET_VOID_CALL +#elif defined BOOST_THREAD_PROVIDES_INVOKE_RET +#define BOOST_THREAD_INVOKE_RET_VOID detail::invoke<void> +#define BOOST_THREAD_INVOKE_RET_VOID_CALL +#else +#define BOOST_THREAD_INVOKE_RET_VOID boost::bind +#define BOOST_THREAD_INVOKE_RET_VOID_CALL () +#endif + + namespace thread_detail { - BOOST_THREAD_DECL boost::uintmax_t& get_once_per_thread_epoch(); - BOOST_THREAD_DECL extern boost::uintmax_t once_global_epoch; + BOOST_THREAD_DECL uintmax_atomic_t& get_once_per_thread_epoch(); + BOOST_THREAD_DECL extern uintmax_atomic_t once_global_epoch; BOOST_THREAD_DECL extern pthread_mutex_t once_epoch_mutex; BOOST_THREAD_DECL extern pthread_cond_t once_epoch_cv; } // Based on Mike Burrows fast_pthread_once algorithm as described in // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2444.html - template<typename Function> - void call_once(once_flag& flag,Function f) + + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + + + template<typename Function, class ...ArgTypes> + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args) + { + static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE; + static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1; + thread_detail::uintmax_atomic_t const epoch=flag.epoch; + thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch(); + + if(epoch<this_thread_epoch) { - static boost::uintmax_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE; - static boost::uintmax_t const being_initialized=uninitialized_flag+1; - boost::uintmax_t const epoch=flag.epoch; - boost::uintmax_t& this_thread_epoch=detail::get_once_per_thread_epoch(); + pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex); - if(epoch<this_thread_epoch) + while(flag.epoch<=being_initialized) { - pthread::pthread_mutex_scoped_lock lk(&detail::once_epoch_mutex); + if(flag.epoch==uninitialized_flag) + { + flag.epoch=being_initialized; + BOOST_TRY + { + pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex); + BOOST_THREAD_INVOKE_RET_VOID( + thread_detail::decay_copy(boost::forward<Function>(f)), + thread_detail::decay_copy(boost::forward<ArgTypes>(args))... + ) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH (...) + { + flag.epoch=uninitialized_flag; + BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + BOOST_RETHROW + } + BOOST_CATCH_END + flag.epoch=--thread_detail::once_global_epoch; + BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + } + else + { + while(flag.epoch==being_initialized) + { + BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex)); + } + } + } + this_thread_epoch=thread_detail::once_global_epoch; - while(flag.epoch<=being_initialized) + } + } +#else + template<typename Function> + inline void call_once(once_flag& flag, Function f) + { + static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE; + static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1; + thread_detail::uintmax_atomic_t const epoch=flag.epoch; + thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch(); + + if(epoch<this_thread_epoch) + { + pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex); + + while(flag.epoch<=being_initialized) + { + if(flag.epoch==uninitialized_flag) { - if(flag.epoch==uninitialized_flag) + flag.epoch=being_initialized; + BOOST_TRY { - flag.epoch=being_initialized; -#ifndef BOOST_NO_EXCEPTIONS - try // BOOST_NO_EXCEPTIONS protected - { -#endif - pthread::pthread_mutex_scoped_unlock relocker(&detail::once_epoch_mutex); - f(); -#ifndef BOOST_NO_EXCEPTIONS - } - catch(...) // BOOST_NO_EXCEPTIONS protected - { - flag.epoch=uninitialized_flag; - BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv)); - throw; // BOOST_NO_EXCEPTIONS protected - } -#endif - flag.epoch=--detail::once_global_epoch; - BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv)); + pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex); + f(); + } + BOOST_CATCH (...) + { + flag.epoch=uninitialized_flag; + BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + BOOST_RETHROW + } + BOOST_CATCH_END + flag.epoch=--thread_detail::once_global_epoch; + BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + } + else + { + while(flag.epoch==being_initialized) + { + BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex)); + } + } + } + this_thread_epoch=thread_detail::once_global_epoch; + } + } + + template<typename Function, typename T1> + inline void call_once(once_flag& flag, Function f, T1 p1) + { + static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE; + static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1; + thread_detail::uintmax_atomic_t const epoch=flag.epoch; + thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch(); + + if(epoch<this_thread_epoch) + { + pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex); + + while(flag.epoch<=being_initialized) + { + if(flag.epoch==uninitialized_flag) + { + flag.epoch=being_initialized; + BOOST_TRY + { + pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex); + BOOST_THREAD_INVOKE_RET_VOID(f,p1) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH (...) + { + flag.epoch=uninitialized_flag; + BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + BOOST_RETHROW + } + BOOST_CATCH_END + flag.epoch=--thread_detail::once_global_epoch; + BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + } + else + { + while(flag.epoch==being_initialized) + { + BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex)); + } + } + } + this_thread_epoch=thread_detail::once_global_epoch; + } + } + template<typename Function, typename T1, typename T2> + inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2) + { + static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE; + static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1; + thread_detail::uintmax_atomic_t const epoch=flag.epoch; + thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch(); + + if(epoch<this_thread_epoch) + { + pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex); + + while(flag.epoch<=being_initialized) + { + if(flag.epoch==uninitialized_flag) + { + flag.epoch=being_initialized; + BOOST_TRY + { + pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex); + BOOST_THREAD_INVOKE_RET_VOID(f,p1, p2) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH (...) + { + flag.epoch=uninitialized_flag; + BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + BOOST_RETHROW + } + BOOST_CATCH_END + flag.epoch=--thread_detail::once_global_epoch; + BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + } + else + { + while(flag.epoch==being_initialized) + { + BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex)); + } + } + } + this_thread_epoch=thread_detail::once_global_epoch; + } + } + + template<typename Function, typename T1, typename T2, typename T3> + inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2, T3 p3) + { + static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE; + static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1; + thread_detail::uintmax_atomic_t const epoch=flag.epoch; + thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch(); + + if(epoch<this_thread_epoch) + { + pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex); + + while(flag.epoch<=being_initialized) + { + if(flag.epoch==uninitialized_flag) + { + flag.epoch=being_initialized; + BOOST_TRY + { + pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex); + BOOST_THREAD_INVOKE_RET_VOID(f,p1, p2, p3) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH (...) + { + flag.epoch=uninitialized_flag; + BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + BOOST_RETHROW } - else + BOOST_CATCH_END + flag.epoch=--thread_detail::once_global_epoch; + BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + } + else + { + while(flag.epoch==being_initialized) { - while(flag.epoch==being_initialized) - { - BOOST_VERIFY(!pthread_cond_wait(&detail::once_epoch_cv,&detail::once_epoch_mutex)); - } + BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex)); } } - this_thread_epoch=detail::once_global_epoch; } + this_thread_epoch=thread_detail::once_global_epoch; } + } + + template<typename Function> + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f) + { + static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE; + static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1; + thread_detail::uintmax_atomic_t const epoch=flag.epoch; + thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch(); + + if(epoch<this_thread_epoch) + { + pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex); + + while(flag.epoch<=being_initialized) + { + if(flag.epoch==uninitialized_flag) + { + flag.epoch=being_initialized; + BOOST_TRY + { + pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex); + f(); + } + BOOST_CATCH (...) + { + flag.epoch=uninitialized_flag; + BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + BOOST_RETHROW + } + BOOST_CATCH_END + flag.epoch=--thread_detail::once_global_epoch; + BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + } + else + { + while(flag.epoch==being_initialized) + { + BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex)); + } + } + } + this_thread_epoch=thread_detail::once_global_epoch; + } + } + + template<typename Function, typename T1> + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1) + { + static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE; + static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1; + thread_detail::uintmax_atomic_t const epoch=flag.epoch; + thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch(); + + if(epoch<this_thread_epoch) + { + pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex); + + while(flag.epoch<=being_initialized) + { + if(flag.epoch==uninitialized_flag) + { + flag.epoch=being_initialized; + BOOST_TRY + { + pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex); + BOOST_THREAD_INVOKE_RET_VOID( + thread_detail::decay_copy(boost::forward<Function>(f)), + thread_detail::decay_copy(boost::forward<T1>(p1)) + ) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH (...) + { + flag.epoch=uninitialized_flag; + BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + BOOST_RETHROW + } + BOOST_CATCH_END + flag.epoch=--thread_detail::once_global_epoch; + BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + } + else + { + while(flag.epoch==being_initialized) + { + BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex)); + } + } + } + this_thread_epoch=thread_detail::once_global_epoch; + } + } + template<typename Function, typename T1, typename T2> + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2) + { + static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE; + static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1; + thread_detail::uintmax_atomic_t const epoch=flag.epoch; + thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch(); + + if(epoch<this_thread_epoch) + { + pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex); + + while(flag.epoch<=being_initialized) + { + if(flag.epoch==uninitialized_flag) + { + flag.epoch=being_initialized; + BOOST_TRY + { + pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex); + BOOST_THREAD_INVOKE_RET_VOID( + thread_detail::decay_copy(boost::forward<Function>(f)), + thread_detail::decay_copy(boost::forward<T1>(p1)), + thread_detail::decay_copy(boost::forward<T1>(p2)) + ) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH (...) + { + flag.epoch=uninitialized_flag; + BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + BOOST_RETHROW + } + BOOST_CATCH_END + flag.epoch=--thread_detail::once_global_epoch; + BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + } + else + { + while(flag.epoch==being_initialized) + { + BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex)); + } + } + } + this_thread_epoch=thread_detail::once_global_epoch; + } + } + + template<typename Function, typename T1, typename T2, typename T3> + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2, BOOST_THREAD_RV_REF(T3) p3) + { + static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE; + static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1; + thread_detail::uintmax_atomic_t const epoch=flag.epoch; + thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch(); + + if(epoch<this_thread_epoch) + { + pthread::pthread_mutex_scoped_lock lk(&thread_detail::once_epoch_mutex); + + while(flag.epoch<=being_initialized) + { + if(flag.epoch==uninitialized_flag) + { + flag.epoch=being_initialized; + BOOST_TRY + { + pthread::pthread_mutex_scoped_unlock relocker(&thread_detail::once_epoch_mutex); + BOOST_THREAD_INVOKE_RET_VOID( + thread_detail::decay_copy(boost::forward<Function>(f)), + thread_detail::decay_copy(boost::forward<T1>(p1)), + thread_detail::decay_copy(boost::forward<T1>(p2)), + thread_detail::decay_copy(boost::forward<T1>(p3)) + ) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH (...) + { + flag.epoch=uninitialized_flag; + BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + BOOST_RETHROW + } + BOOST_CATCH_END + flag.epoch=--thread_detail::once_global_epoch; + BOOST_VERIFY(!pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + } + else + { + while(flag.epoch==being_initialized) + { + BOOST_VERIFY(!pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex)); + } + } + } + this_thread_epoch=thread_detail::once_global_epoch; + } + } + +#endif + } #include <boost/config/abi_suffix.hpp> diff --git a/boost/thread/pthread/once_atomic.hpp b/boost/thread/pthread/once_atomic.hpp new file mode 100644 index 0000000000..923f07bd90 --- /dev/null +++ b/boost/thread/pthread/once_atomic.hpp @@ -0,0 +1,313 @@ +#ifndef BOOST_THREAD_PTHREAD_ONCE_ATOMIC_HPP +#define BOOST_THREAD_PTHREAD_ONCE_ATOMIC_HPP + +// once.hpp +// +// (C) Copyright 2013 Andrey Semashev +// (C) Copyright 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/thread/detail/config.hpp> + +#include <boost/cstdint.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/detail/invoke.hpp> +#include <boost/core/no_exceptions_support.hpp> +#include <boost/bind.hpp> +#include <boost/atomic.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + + struct once_flag; + + namespace thread_detail + { + +#if BOOST_ATOMIC_INT_LOCK_FREE == 2 + typedef unsigned int atomic_int_type; +#elif BOOST_ATOMIC_SHORT_LOCK_FREE == 2 + typedef unsigned short atomic_int_type; +#elif BOOST_ATOMIC_CHAR_LOCK_FREE == 2 + typedef unsigned char atomic_int_type; +#elif BOOST_ATOMIC_LONG_LOCK_FREE == 2 + typedef unsigned long atomic_int_type; +#elif defined(BOOST_HAS_LONG_LONG) && BOOST_ATOMIC_LLONG_LOCK_FREE == 2 + typedef ulong_long_type atomic_int_type; +#else + // All tested integer types are not atomic, the spinlock pool will be used + typedef unsigned int atomic_int_type; +#endif + + typedef boost::atomic<atomic_int_type> atomic_type; + + BOOST_THREAD_DECL bool enter_once_region(once_flag& flag) BOOST_NOEXCEPT; + BOOST_THREAD_DECL void commit_once_region(once_flag& flag) BOOST_NOEXCEPT; + BOOST_THREAD_DECL void rollback_once_region(once_flag& flag) BOOST_NOEXCEPT; + inline atomic_type& get_atomic_storage(once_flag& flag) BOOST_NOEXCEPT; + } + +#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11 + + struct once_flag + { + BOOST_THREAD_NO_COPYABLE(once_flag) + BOOST_CONSTEXPR once_flag() BOOST_NOEXCEPT : storage(0) + { + } + + private: + thread_detail::atomic_type storage; + + friend BOOST_THREAD_DECL bool thread_detail::enter_once_region(once_flag& flag) BOOST_NOEXCEPT; + friend BOOST_THREAD_DECL void thread_detail::commit_once_region(once_flag& flag) BOOST_NOEXCEPT; + friend BOOST_THREAD_DECL void thread_detail::rollback_once_region(once_flag& flag) BOOST_NOEXCEPT; + friend thread_detail::atomic_type& thread_detail::get_atomic_storage(once_flag& flag) BOOST_NOEXCEPT; + }; + +#define BOOST_ONCE_INIT boost::once_flag() + + namespace thread_detail + { + inline atomic_type& get_atomic_storage(once_flag& flag) BOOST_NOEXCEPT + { + //return reinterpret_cast< atomic_type& >(flag.storage); + return flag.storage; + } + } + +#else // BOOST_THREAD_PROVIDES_ONCE_CXX11 + struct once_flag + { + // The thread_detail::atomic_int_type storage is marked + // with this attribute in order to let the compiler know that it will alias this member + // and silence compilation warnings. + BOOST_THREAD_ATTRIBUTE_MAY_ALIAS thread_detail::atomic_int_type storage; + }; + + #define BOOST_ONCE_INIT {0} + + namespace thread_detail + { + inline atomic_type& get_atomic_storage(once_flag& flag) BOOST_NOEXCEPT + { + return reinterpret_cast< atomic_type& >(flag.storage); + } + + } + +#endif // BOOST_THREAD_PROVIDES_ONCE_CXX11 + +#if defined BOOST_THREAD_PROVIDES_INVOKE +#define BOOST_THREAD_INVOKE_RET_VOID detail::invoke +#define BOOST_THREAD_INVOKE_RET_VOID_CALL +#elif defined BOOST_THREAD_PROVIDES_INVOKE_RET +#define BOOST_THREAD_INVOKE_RET_VOID detail::invoke<void> +#define BOOST_THREAD_INVOKE_RET_VOID_CALL +#else +#define BOOST_THREAD_INVOKE_RET_VOID boost::bind +#define BOOST_THREAD_INVOKE_RET_VOID_CALL () +#endif + + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + + template<typename Function, class ...ArgTypes> + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args) + { + if (thread_detail::enter_once_region(flag)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID( + thread_detail::decay_copy(boost::forward<Function>(f)), + thread_detail::decay_copy(boost::forward<ArgTypes>(args))... + ) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH (...) + { + thread_detail::rollback_once_region(flag); + BOOST_RETHROW + } + BOOST_CATCH_END + thread_detail::commit_once_region(flag); + } + } +#else + template<typename Function> + inline void call_once(once_flag& flag, Function f) + { + if (thread_detail::enter_once_region(flag)) + { + BOOST_TRY + { + f(); + } + BOOST_CATCH (...) + { + thread_detail::rollback_once_region(flag); + BOOST_RETHROW + } + BOOST_CATCH_END + thread_detail::commit_once_region(flag); + } + } + + template<typename Function, typename T1> + inline void call_once(once_flag& flag, Function f, T1 p1) + { + if (thread_detail::enter_once_region(flag)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID(f, p1) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH (...) + { + thread_detail::rollback_once_region(flag); + BOOST_RETHROW + } + BOOST_CATCH_END + thread_detail::commit_once_region(flag); + } + } + + template<typename Function, typename T1, typename T2> + inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2) + { + if (thread_detail::enter_once_region(flag)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID(f, p1, p2) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH (...) + { + thread_detail::rollback_once_region(flag); + BOOST_RETHROW + } + BOOST_CATCH_END + thread_detail::commit_once_region(flag); + } + } + + template<typename Function, typename T1, typename T2, typename T3> + inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2, T3 p3) + { + if (thread_detail::enter_once_region(flag)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID(f, p1, p2, p3) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH (...) + { + thread_detail::rollback_once_region(flag); + BOOST_RETHROW + } + BOOST_CATCH_END + thread_detail::commit_once_region(flag); + } + } + + template<typename Function> + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f) + { + if (thread_detail::enter_once_region(flag)) + { + BOOST_TRY + { + f(); + } + BOOST_CATCH (...) + { + thread_detail::rollback_once_region(flag); + BOOST_RETHROW + } + BOOST_CATCH_END + thread_detail::commit_once_region(flag); + } + } + + template<typename Function, typename T1> + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1) + { + if (thread_detail::enter_once_region(flag)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID( + thread_detail::decay_copy(boost::forward<Function>(f)), + thread_detail::decay_copy(boost::forward<T1>(p1)) + ) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH (...) + { + thread_detail::rollback_once_region(flag); + BOOST_RETHROW + } + BOOST_CATCH_END + thread_detail::commit_once_region(flag); + } + } + template<typename Function, typename T1, typename T2> + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2) + { + if (thread_detail::enter_once_region(flag)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID( + thread_detail::decay_copy(boost::forward<Function>(f)), + thread_detail::decay_copy(boost::forward<T1>(p1)), + thread_detail::decay_copy(boost::forward<T1>(p2)) + ) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH (...) + { + thread_detail::rollback_once_region(flag); + BOOST_RETHROW + } + BOOST_CATCH_END + thread_detail::commit_once_region(flag); + } + } + template<typename Function, typename T1, typename T2, typename T3> + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2, BOOST_THREAD_RV_REF(T3) p3) + { + if (thread_detail::enter_once_region(flag)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID( + thread_detail::decay_copy(boost::forward<Function>(f)), + thread_detail::decay_copy(boost::forward<T1>(p1)), + thread_detail::decay_copy(boost::forward<T1>(p2)), + thread_detail::decay_copy(boost::forward<T1>(p3)) + ) BOOST_THREAD_INVOKE_RET_VOID_CALL; + + } + BOOST_CATCH (...) + { + thread_detail::rollback_once_region(flag); + BOOST_RETHROW + } + BOOST_CATCH_END + thread_detail::commit_once_region(flag); + } + } + + + +#endif +} + +#include <boost/config/abi_suffix.hpp> + +#endif + diff --git a/boost/thread/pthread/recursive_mutex.hpp b/boost/thread/pthread/recursive_mutex.hpp index 22acf41fa2..9330d77de9 100644 --- a/boost/thread/pthread/recursive_mutex.hpp +++ b/boost/thread/pthread/recursive_mutex.hpp @@ -9,7 +9,9 @@ #include <pthread.h> #include <boost/throw_exception.hpp> #include <boost/thread/exceptions.hpp> -#include <boost/thread/locks.hpp> +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS +#include <boost/thread/lock_types.hpp> +#endif #include <boost/thread/thread_time.hpp> #include <boost/assert.hpp> #ifndef _WIN32 @@ -26,10 +28,13 @@ #include <boost/thread/detail/delete.hpp> #ifdef _POSIX_TIMEOUTS -#if _POSIX_TIMEOUTS >= 0 +#if _POSIX_TIMEOUTS >= 0 && _POSIX_TIMEOUTS>=200112L +#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK #define BOOST_PTHREAD_HAS_TIMEDLOCK #endif #endif +#endif + #if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) && defined(BOOST_PTHREAD_HAS_TIMEDLOCK) #define BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK @@ -110,7 +115,7 @@ namespace boost BOOST_VERIFY(!pthread_mutex_unlock(&m)); } - bool try_lock() + bool try_lock() BOOST_NOEXCEPT { int const res=pthread_mutex_trylock(&m); BOOST_ASSERT(!res || res==EBUSY); @@ -167,8 +172,10 @@ namespace boost #endif +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS typedef unique_lock<recursive_mutex> scoped_lock; typedef detail::try_lock_wrapper<recursive_mutex> scoped_try_lock; +#endif }; typedef recursive_mutex recursive_try_mutex; @@ -232,11 +239,13 @@ namespace boost #endif } +#if defined BOOST_THREAD_USES_DATETIME template<typename TimeDuration> bool timed_lock(TimeDuration const & relative_time) { return timed_lock(get_system_time()+relative_time); } +#endif #ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK void lock() @@ -294,7 +303,7 @@ namespace boost BOOST_VERIFY(!pthread_cond_signal(&cond)); } - bool try_lock() + bool try_lock() BOOST_NOEXCEPT { boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); if(is_locked && !pthread_equal(owner,pthread_self())) @@ -334,12 +343,13 @@ namespace boost #endif +#if defined BOOST_THREAD_USES_DATETIME bool timed_lock(system_time const & abs_time) { - struct timespec const ts=detail::get_timespec(abs_time); + struct timespec const ts=detail::to_timespec(abs_time); return do_try_lock_until(ts); } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template <class Rep, class Period> bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) @@ -363,12 +373,9 @@ namespace boost } bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp) { - using namespace chrono; - nanoseconds d = tp.time_since_epoch(); - timespec ts; - seconds s = duration_cast<seconds>(d); - ts.tv_sec = static_cast<long>(s.count()); - ts.tv_nsec = static_cast<long>((d - s).count()); + //using namespace chrono; + chrono::nanoseconds d = tp.time_since_epoch(); + timespec ts = boost::detail::to_timespec(d); return do_try_lock_until(ts); } #endif @@ -380,9 +387,11 @@ namespace boost return &m; } +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS typedef unique_lock<recursive_timed_mutex> scoped_timed_lock; typedef detail::try_lock_wrapper<recursive_timed_mutex> scoped_try_lock; typedef scoped_timed_lock scoped_lock; +#endif }; } diff --git a/boost/thread/pthread/shared_mutex.hpp b/boost/thread/pthread/shared_mutex.hpp index cf45188606..458d6c8361 100644 --- a/boost/thread/pthread/shared_mutex.hpp +++ b/boost/thread/pthread/shared_mutex.hpp @@ -12,12 +12,15 @@ #include <boost/static_assert.hpp> #include <boost/thread/mutex.hpp> #include <boost/thread/condition_variable.hpp> +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS #include <boost/thread/detail/thread_interruption.hpp> +#endif #ifdef BOOST_THREAD_USES_CHRONO #include <boost/chrono/system_clocks.hpp> #include <boost/chrono/ceil.hpp> #endif #include <boost/thread/detail/delete.hpp> +#include <boost/assert.hpp> #include <boost/config/abi_prefix.hpp> @@ -26,8 +29,125 @@ namespace boost class shared_mutex { private: - struct state_data + class state_data { + public: + state_data () : + shared_count(0), + exclusive(false), + upgrade(false), + exclusive_waiting_blocked(false) + {} + + void assert_free() const + { + BOOST_ASSERT( ! exclusive ); + BOOST_ASSERT( ! upgrade ); + BOOST_ASSERT( shared_count==0 ); + } + + void assert_locked() const + { + BOOST_ASSERT( exclusive ); + BOOST_ASSERT( shared_count==0 ); + BOOST_ASSERT( ! upgrade ); + } + + void assert_lock_shared () const + { + BOOST_ASSERT( ! exclusive ); + BOOST_ASSERT( shared_count>0 ); + //BOOST_ASSERT( (! upgrade) || (shared_count>1)); + // if upgraded there are at least 2 threads sharing the mutex, + // except when unlock_upgrade_and_lock has decreased the number of readers but has not taken yet exclusive ownership. + } + + void assert_lock_upgraded () const + { + BOOST_ASSERT( ! exclusive ); + BOOST_ASSERT( upgrade ); + BOOST_ASSERT( shared_count>0 ); + } + + void assert_lock_not_upgraded () const + { + BOOST_ASSERT( ! upgrade ); + } + + bool can_lock () const + { + return ! (shared_count || exclusive); + } + + void exclusive_blocked (bool blocked) + { + exclusive_waiting_blocked = blocked; + } + + void lock () + { + exclusive = true; + } + + void unlock () + { + exclusive = false; + exclusive_waiting_blocked = false; + } + + bool can_lock_shared () const + { + return ! (exclusive || exclusive_waiting_blocked); + } + + bool more_shared () const + { + return shared_count > 0 ; + } + unsigned get_shared_count () const + { + return shared_count ; + } + unsigned lock_shared () + { + return ++shared_count; + } + + + void unlock_shared () + { + --shared_count; + } + + bool unlock_shared_downgrades() + { + if (upgrade) { + upgrade=false; + exclusive=true; + return true; + } else { + exclusive_waiting_blocked=false; + return false; + } + } + + void lock_upgrade () + { + ++shared_count; + upgrade=true; + } + bool can_lock_upgrade () const + { + return ! (exclusive || exclusive_waiting_blocked || upgrade); + } + + void unlock_upgrade () + { + upgrade=false; + --shared_count; + } + + //private: unsigned shared_count; bool exclusive; bool upgrade; @@ -49,12 +169,11 @@ namespace boost } public: + BOOST_THREAD_NO_COPYABLE(shared_mutex) shared_mutex() { - state_data state_={0,0,0,0}; - state=state_; } ~shared_mutex() @@ -63,44 +182,45 @@ namespace boost void lock_shared() { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); - - while(state.exclusive || state.exclusive_waiting_blocked) +#endif + boost::unique_lock<boost::mutex> lk(state_change); + while(!state.can_lock_shared()) { shared_cond.wait(lk); } - ++state.shared_count; + state.lock_shared(); } bool try_lock_shared() { - boost::mutex::scoped_lock lk(state_change); + boost::unique_lock<boost::mutex> lk(state_change); - if(state.exclusive || state.exclusive_waiting_blocked) + if(!state.can_lock_shared()) { return false; } - else - { - ++state.shared_count; - return true; - } + state.lock_shared(); + return true; } +#if defined BOOST_THREAD_USES_DATETIME bool timed_lock_shared(system_time const& timeout) { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); +#endif + boost::unique_lock<boost::mutex> lk(state_change); - while(state.exclusive || state.exclusive_waiting_blocked) + while(!state.can_lock_shared()) { if(!shared_cond.timed_wait(lk,timeout)) { return false; } } - ++state.shared_count; + state.lock_shared(); return true; } @@ -109,6 +229,7 @@ namespace boost { return timed_lock_shared(get_system_time()+relative_time); } +#endif #ifdef BOOST_THREAD_USES_CHRONO template <class Rep, class Period> bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time) @@ -118,36 +239,43 @@ namespace boost template <class Clock, class Duration> bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time) { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); +#endif + boost::unique_lock<boost::mutex> lk(state_change); - while(state.exclusive || state.exclusive_waiting_blocked) + while(!state.can_lock_shared()) + //while(state.exclusive || state.exclusive_waiting_blocked) { if(cv_status::timeout==shared_cond.wait_until(lk,abs_time)) { return false; } } - ++state.shared_count; + state.lock_shared(); return true; } #endif void unlock_shared() { - boost::mutex::scoped_lock lk(state_change); - bool const last_reader=!--state.shared_count; - - if(last_reader) + boost::unique_lock<boost::mutex> lk(state_change); + state.assert_lock_shared(); + state.unlock_shared(); + if (! state.more_shared()) { - if(state.upgrade) + if (state.upgrade) { + // As there is a thread doing a unlock_upgrade_and_lock that is waiting for ! state.more_shared() + // avoid other threads to lock, lock_upgrade or lock_shared, so only this thread is notified. state.upgrade=false; state.exclusive=true; + lk.unlock(); upgrade_cond.notify_one(); } else { state.exclusive_waiting_blocked=false; + lk.unlock(); } release_waiters(); } @@ -155,10 +283,12 @@ namespace boost void lock() { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); +#endif + boost::unique_lock<boost::mutex> lk(state_change); - while(state.shared_count || state.exclusive) + while (state.shared_count || state.exclusive) { state.exclusive_waiting_blocked=true; exclusive_cond.wait(lk); @@ -166,10 +296,13 @@ namespace boost state.exclusive=true; } +#if defined BOOST_THREAD_USES_DATETIME bool timed_lock(system_time const& timeout) { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); +#endif + boost::unique_lock<boost::mutex> lk(state_change); while(state.shared_count || state.exclusive) { @@ -194,7 +327,7 @@ namespace boost { return timed_lock(get_system_time()+relative_time); } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template <class Rep, class Period> bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) @@ -204,8 +337,10 @@ namespace boost template <class Clock, class Duration> bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time) { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); +#endif + boost::unique_lock<boost::mutex> lk(state_change); while(state.shared_count || state.exclusive) { @@ -228,7 +363,7 @@ namespace boost bool try_lock() { - boost::mutex::scoped_lock lk(state_change); + boost::unique_lock<boost::mutex> lk(state_change); if(state.shared_count || state.exclusive) { @@ -244,28 +379,35 @@ namespace boost void unlock() { - boost::mutex::scoped_lock lk(state_change); + boost::unique_lock<boost::mutex> lk(state_change); + state.assert_locked(); state.exclusive=false; state.exclusive_waiting_blocked=false; + state.assert_free(); release_waiters(); } void lock_upgrade() { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); +#endif + boost::unique_lock<boost::mutex> lk(state_change); while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) { shared_cond.wait(lk); } - ++state.shared_count; + state.lock_shared(); state.upgrade=true; } +#if defined BOOST_THREAD_USES_DATETIME bool timed_lock_upgrade(system_time const& timeout) { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); +#endif + boost::unique_lock<boost::mutex> lk(state_change); while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) { if(!shared_cond.timed_wait(lk,timeout)) @@ -277,7 +419,7 @@ namespace boost break; } } - ++state.shared_count; + state.lock_shared(); state.upgrade=true; return true; } @@ -287,7 +429,7 @@ namespace boost { return timed_lock_upgrade(get_system_time()+relative_time); } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template <class Rep, class Period> bool try_lock_upgrade_for(const chrono::duration<Rep, Period>& rel_time) @@ -297,8 +439,10 @@ namespace boost template <class Clock, class Duration> bool try_lock_upgrade_until(const chrono::time_point<Clock, Duration>& abs_time) { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); +#endif + boost::unique_lock<boost::mutex> lk(state_change); while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) { if(cv_status::timeout == shared_cond.wait_until(lk,abs_time)) @@ -310,68 +454,75 @@ namespace boost break; } } - ++state.shared_count; + state.lock_shared(); state.upgrade=true; return true; } #endif bool try_lock_upgrade() { - boost::mutex::scoped_lock lk(state_change); + boost::unique_lock<boost::mutex> lk(state_change); if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) { return false; } else { - ++state.shared_count; + state.lock_shared(); state.upgrade=true; + state.assert_lock_upgraded(); return true; } } void unlock_upgrade() { - boost::mutex::scoped_lock lk(state_change); - state.upgrade=false; - bool const last_reader=!--state.shared_count; - - if(last_reader) + boost::unique_lock<boost::mutex> lk(state_change); + //state.upgrade=false; + state.unlock_upgrade(); + if(! state.more_shared() ) { state.exclusive_waiting_blocked=false; release_waiters(); } else { - shared_cond.notify_all(); + shared_cond.notify_all(); } } // Upgrade <-> Exclusive void unlock_upgrade_and_lock() { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); - --state.shared_count; - while(state.shared_count) +#endif + boost::unique_lock<boost::mutex> lk(state_change); + state.assert_lock_upgraded(); + state.unlock_shared(); + while (state.more_shared()) { upgrade_cond.wait(lk); } state.upgrade=false; state.exclusive=true; + state.assert_locked(); } void unlock_and_lock_upgrade() { - boost::mutex::scoped_lock lk(state_change); + boost::unique_lock<boost::mutex> lk(state_change); + state.assert_locked(); state.exclusive=false; state.upgrade=true; - ++state.shared_count; + state.lock_shared(); state.exclusive_waiting_blocked=false; + state.assert_lock_upgraded(); release_waiters(); } bool try_unlock_upgrade_and_lock() { - boost::mutex::scoped_lock lk(state_change); + boost::unique_lock<boost::mutex> lk(state_change); + state.assert_lock_upgraded(); if( !state.exclusive && !state.exclusive_waiting_blocked && state.upgrade @@ -380,6 +531,7 @@ namespace boost state.shared_count=0; state.exclusive=true; state.upgrade=false; + state.assert_locked(); return true; } return false; @@ -398,8 +550,11 @@ namespace boost try_unlock_upgrade_and_lock_until( const chrono::time_point<Clock, Duration>& abs_time) { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); +#endif + boost::unique_lock<boost::mutex> lk(state_change); + state.assert_lock_upgraded(); if (state.shared_count != 1) { for (;;) @@ -422,9 +577,10 @@ namespace boost // Shared <-> Exclusive void unlock_and_lock_shared() { - boost::mutex::scoped_lock lk(state_change); + boost::unique_lock<boost::mutex> lk(state_change); + state.assert_locked(); state.exclusive=false; - ++state.shared_count; + state.lock_shared(); state.exclusive_waiting_blocked=false; release_waiters(); } @@ -432,7 +588,8 @@ namespace boost #ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS bool try_unlock_shared_and_lock() { - boost::mutex::scoped_lock lk(state_change); + boost::unique_lock<boost::mutex> lk(state_change); + state.assert_lock_shared(); if( !state.exclusive && !state.exclusive_waiting_blocked && !state.upgrade @@ -458,8 +615,11 @@ namespace boost try_unlock_shared_and_lock_until( const chrono::time_point<Clock, Duration>& abs_time) { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); +#endif + boost::unique_lock<boost::mutex> lk(state_change); + state.assert_lock_shared(); if (state.shared_count != 1) { for (;;) @@ -483,7 +643,8 @@ namespace boost // Shared <-> Upgrade void unlock_upgrade_and_lock_shared() { - boost::mutex::scoped_lock lk(state_change); + boost::unique_lock<boost::mutex> lk(state_change); + state.assert_lock_upgraded(); state.upgrade=false; state.exclusive_waiting_blocked=false; release_waiters(); @@ -492,7 +653,8 @@ namespace boost #ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS bool try_unlock_shared_and_lock_upgrade() { - boost::mutex::scoped_lock lk(state_change); + boost::unique_lock<boost::mutex> lk(state_change); + state.assert_lock_shared(); if( !state.exclusive && !state.exclusive_waiting_blocked && !state.upgrade @@ -517,8 +679,11 @@ namespace boost try_unlock_shared_and_lock_upgrade_until( const chrono::time_point<Clock, Duration>& abs_time) { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); +#endif + boost::unique_lock<boost::mutex> lk(state_change); + state.assert_lock_shared(); if( state.exclusive || state.exclusive_waiting_blocked || state.upgrade diff --git a/boost/thread/pthread/shared_mutex_assert.hpp b/boost/thread/pthread/shared_mutex_assert.hpp new file mode 100644 index 0000000000..186ab7984b --- /dev/null +++ b/boost/thread/pthread/shared_mutex_assert.hpp @@ -0,0 +1,724 @@ +#ifndef BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP +#define BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP + +// (C) Copyright 2006-8 Anthony Williams +// (C) Copyright 2012 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/assert.hpp> +#include <boost/static_assert.hpp> +#include <boost/thread/mutex.hpp> +#include <boost/thread/condition_variable.hpp> +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS +#include <boost/thread/detail/thread_interruption.hpp> +#endif +#ifdef BOOST_THREAD_USES_CHRONO +#include <boost/chrono/system_clocks.hpp> +#include <boost/chrono/ceil.hpp> +#endif +#include <boost/thread/detail/delete.hpp> +#include <boost/assert.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + class shared_mutex + { + private: + class state_data + { + public: + state_data () : + shared_count(0), + exclusive(false), + upgrade(false), + exclusive_waiting_blocked(false) + {} + + void assert_free() const + { + BOOST_ASSERT( ! exclusive ); + BOOST_ASSERT( ! upgrade ); + BOOST_ASSERT( shared_count==0 ); + } + + void assert_locked() const + { + BOOST_ASSERT( exclusive ); + BOOST_ASSERT( shared_count==0 ); + BOOST_ASSERT( ! upgrade ); + } + + void assert_lock_shared () const + { + BOOST_ASSERT( ! exclusive ); + BOOST_ASSERT( shared_count>0 ); + //BOOST_ASSERT( (! upgrade) || (shared_count>1)); + // if upgraded there are at least 2 threads sharing the mutex, + // except when unlock_upgrade_and_lock has decreased the number of readers but has not taken yet exclusive ownership. + } + + void assert_lock_upgraded () const + { + BOOST_ASSERT( ! exclusive ); + BOOST_ASSERT( upgrade ); + BOOST_ASSERT( shared_count>0 ); + } + + void assert_lock_not_upgraded () const + { + BOOST_ASSERT( ! upgrade ); + } + + bool can_lock () const + { + return ! (shared_count || exclusive); + } + + void exclusive_blocked (bool blocked) + { + exclusive_waiting_blocked = blocked; + } + + void lock () + { + exclusive = true; + } + + void unlock () + { + exclusive = false; + exclusive_waiting_blocked = false; + } + + bool can_lock_shared () const + { + return ! (exclusive || exclusive_waiting_blocked); + } + + bool is_last_shared () const + { + return !shared_count ; + } + unsigned get_shared_count () const + { + return shared_count ; + } + unsigned lock_shared () + { + return ++shared_count; + } + + + void unlock_shared () + { + --shared_count; + } + + bool unlock_shared_downgrades() + { + if (upgrade) { + upgrade=false; + exclusive=true; + return true; + } else { + exclusive_waiting_blocked=false; + return false; + } + } + + void lock_upgrade () + { + lock_shared (); + upgrade=true; + } + bool can_lock_upgrade () const + { + return ! (exclusive || exclusive_waiting_blocked || upgrade); + } + + void unlock_upgrade () + { + upgrade=false; + unlock_shared(); + } + + //private: + unsigned shared_count; + bool exclusive; + bool upgrade; + bool exclusive_waiting_blocked; + }; + + + + state_data state; + boost::mutex state_change; + boost::condition_variable shared_cond; + boost::condition_variable exclusive_cond; + boost::condition_variable upgrade_cond; + + void release_waiters() + { + exclusive_cond.notify_one(); + shared_cond.notify_all(); + } + + public: + BOOST_THREAD_NO_COPYABLE(shared_mutex) + + shared_mutex() + { + } + + ~shared_mutex() + { + } + + void lock_shared() + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock<boost::mutex> lk(state_change); + + while(!state.can_lock_shared()) + { + shared_cond.wait(lk); + } + state.lock_shared(); + } + + bool try_lock_shared() + { + boost::unique_lock<boost::mutex> lk(state_change); + if(!state.can_lock_shared()) + { + return false; + } + else + { + state.lock_shared(); + return true; + } + } + +#if defined BOOST_THREAD_USES_DATETIME + bool timed_lock_shared(system_time const& timeout) + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock<boost::mutex> lk(state_change); + + while(!state.can_lock_shared()) + { + if(!shared_cond.timed_wait(lk,timeout)) + { + return false; + } + } + state.lock_shared(); + return true; + } + + template<typename TimeDuration> + bool timed_lock_shared(TimeDuration const & relative_time) + { + return timed_lock_shared(get_system_time()+relative_time); + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + template <class Rep, class Period> + bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time) + { + return try_lock_shared_until(chrono::steady_clock::now() + rel_time); + } + template <class Clock, class Duration> + bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time) + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock<boost::mutex> lk(state_change); + + while(!state.can_lock_shared()) + { + if(cv_status::timeout==shared_cond.wait_until(lk,abs_time)) + { + return false; + } + } + state.lock_shared(); + return true; + } +#endif + void unlock_shared() + { + boost::unique_lock<boost::mutex> lk(state_change); + state.assert_lock_shared(); + state.unlock_shared(); + if (state.get_shared_count () == 0) + { + if (state.unlock_shared_downgrades()) + { + lk.unlock(); + upgrade_cond.notify_one(); + } else { + lk.unlock(); + } + release_waiters(); + } + } + + void lock() + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock<boost::mutex> lk(state_change); + + while(!state.can_lock()) + { + state.exclusive_blocked(true); + exclusive_cond.wait(lk); + } + state.lock(); + } + +#if defined BOOST_THREAD_USES_DATETIME + bool timed_lock(system_time const& timeout) + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock<boost::mutex> lk(state_change); + + while(!state.can_lock()) + { + state.exclusive_blocked(true); + if(!exclusive_cond.timed_wait(lk,timeout)) + { + if(!state.can_lock()) + { + state.exclusive_blocked(false); + release_waiters(); + return false; + } + break; + } + } + state.exclusive=true; + //state.lock(); + return true; + } + + template<typename TimeDuration> + bool timed_lock(TimeDuration const & relative_time) + { + return timed_lock(get_system_time()+relative_time); + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + template <class Rep, class Period> + bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) + { + return try_lock_until(chrono::steady_clock::now() + rel_time); + } + template <class Clock, class Duration> + bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time) + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock<boost::mutex> lk(state_change); + + while(!state.can_lock()) + { + state.exclusive_blocked(true); + if(cv_status::timeout == exclusive_cond.wait_until(lk,abs_time)) + { + if(!state.can_lock()) + { + state.exclusive_blocked(false); + release_waiters(); + return false; + } + break; + } + } + state.exclusive=true; + //state.lock(); + return true; + } +#endif + + bool try_lock() + { + boost::unique_lock<boost::mutex> lk(state_change); + + if(!state.can_lock()) + { + return false; + } + else + { + state.lock(); + return true; + } + + } + + void unlock() + { + boost::unique_lock<boost::mutex> lk(state_change); + state.assert_locked(); + state.unlock(); + state.assert_free(); + release_waiters(); + } + + void lock_upgrade() + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock<boost::mutex> lk(state_change); + while(!state.can_lock_upgrade()) + { + shared_cond.wait(lk); + } + state.lock_upgrade(); + } + +#if defined BOOST_THREAD_USES_DATETIME + bool timed_lock_upgrade(system_time const& timeout) + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock<boost::mutex> lk(state_change); + while(!state.can_lock_upgrade()) + { + if(!shared_cond.timed_wait(lk,timeout)) + { + if(!state.can_lock_upgrade()) + { + return false; + } + break; + } + } + state.lock_upgrade(); + return true; + } + + template<typename TimeDuration> + bool timed_lock_upgrade(TimeDuration const & relative_time) + { + return timed_lock_upgrade(get_system_time()+relative_time); + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + template <class Rep, class Period> + bool try_lock_upgrade_for(const chrono::duration<Rep, Period>& rel_time) + { + return try_lock_upgrade_until(chrono::steady_clock::now() + rel_time); + } + template <class Clock, class Duration> + bool try_lock_upgrade_until(const chrono::time_point<Clock, Duration>& abs_time) + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock<boost::mutex> lk(state_change); + while(!state.can_lock_upgrade()) + { + if(cv_status::timeout == shared_cond.wait_until(lk,abs_time)) + { + if(!state.can_lock_upgrade()) + { + return false; + } + break; + } + } + state.lock_upgrade(); + return true; + } +#endif + bool try_lock_upgrade() + { + boost::unique_lock<boost::mutex> lk(state_change); + if(!state.can_lock_upgrade()) + { + return false; + } + else + { + state.lock_upgrade(); + state.assert_lock_upgraded(); + return true; + } + } + + void unlock_upgrade() + { + boost::unique_lock<boost::mutex> lk(state_change); + state.assert_lock_upgraded(); + state.unlock_upgrade(); + state.assert_lock_not_upgraded (); + if(state.get_shared_count () == 0) + { + state.exclusive_blocked(false); + lk.unlock(); + release_waiters(); + } else { + lk.unlock(); + shared_cond.notify_all(); + } + } + + // Upgrade <-> Exclusive + void unlock_upgrade_and_lock() + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock<boost::mutex> lk(state_change); + state.assert_lock_upgraded(); + // assert state.get_shared_count() >=1 + while( + //! state.exclusive_waiting_blocked // Fixme: is this needed? + //&& + state.get_shared_count()!=1) + { + upgrade_cond.wait(lk); + } + state.unlock_upgrade(); + state.lock(); + state.assert_locked(); + } + + void unlock_and_lock_upgrade() + { + boost::unique_lock<boost::mutex> lk(state_change); + state.assert_locked(); + state.unlock(); + state.lock_upgrade(); + state.assert_lock_upgraded(); + release_waiters(); + } + + bool try_unlock_upgrade_and_lock() + { + boost::unique_lock<boost::mutex> lk(state_change); + state.assert_lock_upgraded(); + if( //!state.exclusive // this should be removed once the assertion work + ! state.exclusive_waiting_blocked // Fixme: why this is needed? + //&& state.upgrade // this should be removed once the assertion work + && state.get_shared_count()==1) + { + state.unlock_upgrade(); + state.lock(); + state.assert_locked(); + return true; + } + return false; + } +#ifdef BOOST_THREAD_USES_CHRONO + template <class Rep, class Period> + bool + try_unlock_upgrade_and_lock_for( + const chrono::duration<Rep, Period>& rel_time) + { + return try_unlock_upgrade_and_lock_until( + chrono::steady_clock::now() + rel_time); + } + template <class Clock, class Duration> + bool + try_unlock_upgrade_and_lock_until( + const chrono::time_point<Clock, Duration>& abs_time) + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock<boost::mutex> lk(state_change); + state.assert_lock_upgraded(); + if (//state.exclusive // this should be removed once the assertion work + state.exclusive_waiting_blocked // Fixme: is this needed? + //|| ! state.upgrade // this should be removed once the assertion work + || state.get_shared_count() != 1) + { + for (;;) + { + //cv_status status = shared_cond.wait_until(lk,abs_time); + cv_status status = upgrade_cond.wait_until(lk,abs_time); + if (//!state.exclusive // this should be removed once the assertion work + ! state.exclusive_waiting_blocked // Fixme: is this needed? + //&& ! state.upgrade // this should be removed once the assertion work + && state.get_shared_count() == 1) + break; + if(status == cv_status::timeout) + return false; + } + } + state.unlock_upgrade(); + state.lock(); + return true; + } +#endif + + // Shared <-> Exclusive + void unlock_and_lock_shared() + { + boost::unique_lock<boost::mutex> lk(state_change); + state.assert_locked(); + state.unlock(); + state.lock_shared(); + release_waiters(); + } + +#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS + bool try_unlock_shared_and_lock() + { + boost::unique_lock<boost::mutex> lk(state_change); + state.assert_lock_shared(); + if( //!state.exclusive // this should be removed once the assertion work + ! state.exclusive_waiting_blocked // Fixme: why this is needed? + //&& ! state.upgrade // Fixme: why this is needed if state.get_shared_count()==1? + && state.get_shared_count()==1) + { + state.unlock_shared(); + state.lock(); + return true; + } + return false; + } +#ifdef BOOST_THREAD_USES_CHRONO + template <class Rep, class Period> + bool + try_unlock_shared_and_lock_for( + const chrono::duration<Rep, Period>& rel_time) + { + return try_unlock_shared_and_lock_until( + chrono::steady_clock::now() + rel_time); + } + template <class Clock, class Duration> + bool + try_unlock_shared_and_lock_until( + const chrono::time_point<Clock, Duration>& abs_time) + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock<boost::mutex> lk(state_change); + state.assert_lock_shared(); + if ( // !state.exclusive // this should be removed once the assertion work + state.exclusive_waiting_blocked // Fixme: is this needed? + //|| state.upgrade // Fixme: why this is needed if state.get_shared_count()==1? + || state.get_shared_count() != 1) + { + for (;;) + { + cv_status status = shared_cond.wait_until(lk,abs_time); + if ( //! state.exclusive // this should be removed once the assertion work + ! state.exclusive_waiting_blocked // Fixme: is this needed? + //&& ! state.upgrade + && state.get_shared_count() == 1) + break; + if(status == cv_status::timeout) + return false; + } + } + state.unlock_shared(); + state.lock(); + state.upgrade=false; // Is this absolutely needed? + state.exclusive_waiting_blocked=false; // Is this absolutely needed? + return true; + } +#endif +#endif + + // Shared <-> Upgrade + void unlock_upgrade_and_lock_shared() + { + boost::unique_lock<boost::mutex> lk(state_change); + state.assert_lock_upgraded(); + //state.unlock_upgrade(); + //state.lock_shared(); // less efficient + state.upgrade=false; + state.exclusive_waiting_blocked=false; // Is this absolutely needed? + release_waiters(); + } + +#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS + bool try_unlock_shared_and_lock_upgrade() + { + boost::unique_lock<boost::mutex> lk(state_change); + state.assert_lock_shared(); + if( //! state.exclusive // this should be removed once the assertion work + ! state.exclusive_waiting_blocked // Fixme: is this needed? + && ! state.upgrade + ) + { + state.upgrade=true; + return true; + } + return false; + } +#ifdef BOOST_THREAD_USES_CHRONO + template <class Rep, class Period> + bool + try_unlock_shared_and_lock_upgrade_for( + const chrono::duration<Rep, Period>& rel_time) + { + return try_unlock_shared_and_lock_upgrade_until( + chrono::steady_clock::now() + rel_time); + } + template <class Clock, class Duration> + bool + try_unlock_shared_and_lock_upgrade_until( + const chrono::time_point<Clock, Duration>& abs_time) + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock<boost::mutex> lk(state_change); + state.assert_lock_shared(); + if( //state.exclusive // this should be removed once the assertion work + state.exclusive_waiting_blocked // Fixme: is this needed? + || state.upgrade + ) + { + for (;;) + { + cv_status status = exclusive_cond.wait_until(lk,abs_time); + if( //! state.exclusive // this should be removed once the assertion work + ! state.exclusive_waiting_blocked // Fixme: is this needed? + && ! state.upgrade + ) + break; + if(status == cv_status::timeout) + return false; + } + } + //state.unlock_shared(); + //state.lock_upgrade(); // less efficient + state.upgrade=true; + return true; + } +#endif +#endif + }; + + typedef shared_mutex upgrade_mutex; +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/pthread/thread_data.hpp b/boost/thread/pthread/thread_data.hpp index 5f84799f85..801f470b46 100644 --- a/boost/thread/pthread/thread_data.hpp +++ b/boost/thread/pthread/thread_data.hpp @@ -8,18 +8,29 @@ #include <boost/thread/detail/config.hpp> #include <boost/thread/exceptions.hpp> +#include <boost/thread/lock_guard.hpp> +#include <boost/thread/lock_types.hpp> +#include <boost/thread/mutex.hpp> +#include <boost/thread/pthread/condition_variable_fwd.hpp> + #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> -#include <boost/thread/mutex.hpp> -#include <boost/optional.hpp> -#include <pthread.h> #include <boost/assert.hpp> -#include <boost/thread/pthread/condition_variable_fwd.hpp> -#include <map> -#include <unistd.h> #ifdef BOOST_THREAD_USES_CHRONO #include <boost/chrono/system_clocks.hpp> #endif + +#include <map> +#include <vector> +#include <utility> + +#if defined(__ANDROID__) +#include <asm/page.h> // http://code.google.com/p/android/issues/detail?id=39983 +#endif + +#include <pthread.h> +#include <unistd.h> + #include <boost/config/abi_prefix.hpp> namespace boost @@ -70,6 +81,7 @@ namespace boost namespace detail { + struct shared_state_base; struct tss_cleanup_function; struct thread_exit_callback_node; struct tss_data_node @@ -100,27 +112,57 @@ namespace boost bool joined; boost::detail::thread_exit_callback_node* thread_exit_callbacks; std::map<void const*,boost::detail::tss_data_node> tss_data; - bool interrupt_enabled; - bool interrupt_requested; + pthread_mutex_t* cond_mutex; pthread_cond_t* current_cond; + typedef std::vector<std::pair<condition_variable*, mutex*> + //, hidden_allocator<std::pair<condition_variable*, mutex*> > + > notify_list_t; + notify_list_t notify; + typedef std::vector<shared_ptr<shared_state_base> > async_states_t; + async_states_t async_states_; + +//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + // These data must be at the end so that the access to the other fields doesn't change + // when BOOST_THREAD_PROVIDES_INTERRUPTIONS is defined. + // Another option is to have them always + bool interrupt_enabled; + bool interrupt_requested; +//#endif thread_data_base(): + thread_handle(0), done(false),join_started(false),joined(false), thread_exit_callbacks(0), - interrupt_enabled(true), - interrupt_requested(false), - current_cond(0) + cond_mutex(0), + current_cond(0), + notify(), + async_states_() +//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + , interrupt_enabled(true) + , interrupt_requested(false) +//#endif {} virtual ~thread_data_base(); typedef pthread_t native_handle_type; virtual void run()=0; + virtual void notify_all_at_thread_exit(condition_variable* cv, mutex* m) + { + notify.push_back(std::pair<condition_variable*, mutex*>(cv, m)); + } + + void make_ready_at_thread_exit(shared_ptr<shared_state_base> as) + { + async_states_.push_back(as); + } + }; BOOST_THREAD_DECL thread_data_base* get_current_thread_data(); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS class interruption_checker { thread_data_base* const thread_info; @@ -172,35 +214,68 @@ namespace boost } } }; +#endif } namespace this_thread { + namespace hiden + { + void BOOST_THREAD_DECL sleep_for(const timespec& ts); + void BOOST_THREAD_DECL sleep_until(const timespec& ts); + } + #ifdef BOOST_THREAD_USES_CHRONO - void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns); +#ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY + + inline + void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns) + { + return boost::this_thread::hiden::sleep_for(boost::detail::to_timespec(ns)); + } #endif +#endif // BOOST_THREAD_USES_CHRONO + + namespace no_interruption_point + { + namespace hiden + { + void BOOST_THREAD_DECL sleep_for(const timespec& ts); + void BOOST_THREAD_DECL sleep_until(const timespec& ts); + } + + #ifdef BOOST_THREAD_USES_CHRONO + #ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY + + inline + void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns) + { + return boost::this_thread::hiden::sleep_for(boost::detail::to_timespec(ns)); + } + #endif + #endif // BOOST_THREAD_USES_CHRONO + + } // no_interruption_point + void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT; +#if defined BOOST_THREAD_USES_DATETIME #ifdef __DECXXX /// Workaround of DECCXX issue of incorrect template substitution - template<typename TimeDuration> - inline void sleep(TimeDuration const& rel_time) + template<> +#endif + inline void sleep(system_time const& abs_time) { - this_thread::sleep(get_system_time()+rel_time); + return boost::this_thread::hiden::sleep_until(boost::detail::to_timespec(abs_time)); } - template<> - void BOOST_THREAD_DECL sleep(system_time const& abs_time); -#else - void BOOST_THREAD_DECL sleep(system_time const& abs_time); - template<typename TimeDuration> inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time) { this_thread::sleep(get_system_time()+rel_time); } -#endif - } +#endif // BOOST_THREAD_USES_DATETIME + } // this_thread } #include <boost/config/abi_suffix.hpp> diff --git a/boost/thread/pthread/thread_heap_alloc.hpp b/boost/thread/pthread/thread_heap_alloc.hpp index 737c29858b..7828318f05 100644 --- a/boost/thread/pthread/thread_heap_alloc.hpp +++ b/boost/thread/pthread/thread_heap_alloc.hpp @@ -17,7 +17,7 @@ namespace boost return new T(); } -#ifndef BOOST_NO_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template<typename T,typename A1> inline T* heap_new(A1&& a1) { @@ -72,7 +72,7 @@ namespace boost { return heap_new_impl<T,A1&>(a1); } - + template<typename T,typename A1,typename A2> inline T* heap_new(A1 const& a1,A2 const& a2) { @@ -218,8 +218,8 @@ namespace boost { return heap_new_impl<T,A1&,A2&,A3&,A4&>(a1,a2,a3,a4); } - -#endif + +#endif template<typename T> inline void heap_delete(T* data) { diff --git a/boost/thread/pthread/timespec.hpp b/boost/thread/pthread/timespec.hpp index d7465c1ac3..82f50f6ca7 100644 --- a/boost/thread/pthread/timespec.hpp +++ b/boost/thread/pthread/timespec.hpp @@ -1,34 +1,118 @@ #ifndef BOOST_THREAD_PTHREAD_TIMESPEC_HPP #define BOOST_THREAD_PTHREAD_TIMESPEC_HPP -// (C) Copyright 2007-8 Anthony Williams +// (C) Copyright 2007-8 Anthony Williams +// (C) Copyright 2012 Vicente J. Botet Escriba // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#include <boost/thread/detail/config.hpp> #include <boost/thread/thread_time.hpp> +#if defined BOOST_THREAD_USES_DATETIME #include <boost/date_time/posix_time/conversion.hpp> +#endif #include <pthread.h> #ifndef _WIN32 #include <unistd.h> #endif +#ifdef BOOST_THREAD_USES_CHRONO +#include <boost/chrono/duration.hpp> +#endif + +#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) +# define BOOST_THREAD_TIMESPEC_MAC_API +#include <sys/time.h> //for gettimeofday and timeval +#else +#include <time.h> // for clock_gettime +#endif #include <boost/config/abi_prefix.hpp> namespace boost { - namespace detail - { - inline struct timespec get_timespec(boost::system_time const& abs_time) - { - struct timespec timeout={0,0}; - boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0); - - timeout.tv_sec=time_since_epoch.total_seconds(); - timeout.tv_nsec=(long)(time_since_epoch.fractional_seconds()*(1000000000l/time_since_epoch.ticks_per_second())); - return timeout; - } + namespace detail + { +#if defined BOOST_THREAD_USES_DATETIME + inline struct timespec to_timespec(boost::system_time const& abs_time) + { + struct timespec timeout = { 0,0}; + boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0); + + timeout.tv_sec=time_since_epoch.total_seconds(); + timeout.tv_nsec=(long)(time_since_epoch.fractional_seconds()*(1000000000l/time_since_epoch.ticks_per_second())); + return timeout; + } +#endif +#if defined BOOST_THREAD_USES_CHRONO + inline timespec to_timespec(chrono::nanoseconds const& ns) + { + struct timespec ts; + 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 ts; } + +#endif + + inline timespec to_timespec(boost::intmax_t const& ns) + { + boost::intmax_t s = ns / 1000000000l; + struct timespec ts; + ts.tv_sec = static_cast<long> (s); + ts.tv_nsec = static_cast<long> (ns - s * 1000000000l); + return ts; + } + inline boost::intmax_t to_nanoseconds_int_max(timespec const& ts) + { + return static_cast<boost::intmax_t>(ts.tv_sec) * 1000000000l + ts.tv_nsec; + } + inline bool timespec_ge_zero(timespec const& ts) + { + return (ts.tv_sec >= 0) || (ts.tv_nsec >= 0); + } + inline timespec timespec_now() + { + timespec ts; + +#if 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 ) ) + { + BOOST_ASSERT(0 && "Boost::Thread - Internal Error"); + } +#endif + return ts; + } + inline timespec timespec_zero() + { + timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = 0; + return ts; + } + inline timespec timespec_plus(timespec const& lhs, timespec const& rhs) + { + return to_timespec(to_nanoseconds_int_max(lhs) + to_nanoseconds_int_max(rhs)); + } + inline timespec timespec_minus(timespec const& lhs, timespec const& rhs) + { + return to_timespec(to_nanoseconds_int_max(lhs) - to_nanoseconds_int_max(rhs)); + } + inline bool timespec_gt(timespec const& lhs, timespec const& rhs) + { + return to_nanoseconds_int_max(lhs) > to_nanoseconds_int_max(rhs); + } + inline bool timespec_ge(timespec const& lhs, timespec const& rhs) + { + return to_nanoseconds_int_max(lhs) >= to_nanoseconds_int_max(rhs); + } + + } } #include <boost/config/abi_suffix.hpp> diff --git a/boost/thread/recursive_mutex.hpp b/boost/thread/recursive_mutex.hpp index d5f6116e72..e716a190ff 100644 --- a/boost/thread/recursive_mutex.hpp +++ b/boost/thread/recursive_mutex.hpp @@ -3,7 +3,7 @@ // recursive_mutex.hpp // -// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2007 Anthony Williams // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -18,4 +18,47 @@ #error "Boost threads unavailable on this platform" #endif +#include <boost/thread/lockable_traits.hpp> + +namespace boost +{ + namespace sync + { + +#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES + template<> + struct is_basic_lockable<recursive_mutex> + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_lockable<recursive_mutex> + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_basic_lockable<recursive_timed_mutex> + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_lockable<recursive_timed_mutex> + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; +#endif + + template<> + struct is_recursive_mutex_sur_parolle<recursive_mutex> + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_recursive_mutex_sur_parolle<recursive_timed_mutex> + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + } +} #endif diff --git a/boost/thread/reverse_lock.hpp b/boost/thread/reverse_lock.hpp index c196cde072..479c314bdb 100644 --- a/boost/thread/reverse_lock.hpp +++ b/boost/thread/reverse_lock.hpp @@ -6,7 +6,9 @@ #ifndef BOOST_THREAD_REVERSE_LOCK_HPP #define BOOST_THREAD_REVERSE_LOCK_HPP #include <boost/thread/detail/config.hpp> -#include <boost/thread/locks.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/lockable_traits.hpp> +#include <boost/thread/lock_options.hpp> #include <boost/thread/detail/delete.hpp> namespace boost @@ -15,7 +17,6 @@ namespace boost template<typename Lock> class reverse_lock { - public: typedef typename Lock::mutex_type mutex_type; BOOST_THREAD_NO_COPYABLE(reverse_lock) diff --git a/boost/thread/scoped_thread.hpp b/boost/thread/scoped_thread.hpp new file mode 100644 index 0000000000..ae0d1efc53 --- /dev/null +++ b/boost/thread/scoped_thread.hpp @@ -0,0 +1,289 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2009-2012 Anthony Williams +// (C) Copyright 2012 Vicente J. Botet Escriba + +// Based on the Anthony's idea of scoped_thread in CCiA + +#ifndef BOOST_THREAD_SCOPED_THREAD_HPP +#define BOOST_THREAD_SCOPED_THREAD_HPP + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/delete.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/thread_functors.hpp> +#include <boost/thread/thread_only.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + + /** + * RAI @c thread wrapper adding a specific destroyer allowing to master what can be done at destruction time. + * + * CallableThread: A callable void(thread&) . + * The default is a join_if_joinable. + * + * thread std/boost::thread destructor terminates the program if the thread is not joinable. + * Having a wrapper that can join the thread before destroying it seems a natural need. + * + * Example: + * + * boost::strict_scoped_thread<> t((boost::thread(F))); + * + */ + template <class CallableThread = join_if_joinable> + class strict_scoped_thread + { + thread t_; + struct dummy; + public: + + BOOST_THREAD_NO_COPYABLE( strict_scoped_thread) /// non copyable + + /* + * + */ +#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> + 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) : + 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) : + t_(boost::forward<F>(f), boost::forward<A1>(a1)) {} + template <class F, class A1, class A2> + strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1, BOOST_THREAD_FWD_REF(A2) a2) : + t_(boost::forward<F>(f), boost::forward<A1>(a1), boost::forward<A2>(a2)) {} + template <class F, class A1, class A2, class A3> + strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1, BOOST_THREAD_FWD_REF(A2) a2, BOOST_THREAD_FWD_REF(A3) a3) : + t_(boost::forward<F>(f), boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)) {} +#endif + + /** + * Constructor from the thread to own. + * + * @param t: the thread to own. + * + * Effects: move the thread to own @c t. + */ + explicit strict_scoped_thread(BOOST_THREAD_RV_REF(thread) t) BOOST_NOEXCEPT : + t_(boost::move(t)) + { + } + + /** + * Destructor + * Effects: Call the CallableThread functor before destroying the owned thread. + * Remark: The CallableThread should not throw when joining the thread as the scoped variable is on a scope outside the thread function. + */ + ~strict_scoped_thread() + { + CallableThread on_destructor; + + on_destructor(t_); + } + + }; + + /** + * RAI @c thread wrapper adding a specific destroyer allowing to master what can be done at destruction time. + * + * CallableThread: A callable void(thread&) . + * The default is join_if_joinable. + * + * thread std::thread destructor terminates the program if the thread is not joinable. + * Having a wrapper that can join the thread before destroying it seems a natural need. + * + * Remark: @c scoped_thread is not a @c thread as @c thread is not designed to be derived from as a polymorphic type. + * Anyway @c scoped_thread can be used in most of the contexts a @c thread could be used as it has the + * same non-deprecated interface with the exception of the construction. + * + * Example: + * + * boost::scoped_thread<> t((boost::thread(F))); + * t.interrupt(); + * + */ + template <class CallableThread = join_if_joinable> + class scoped_thread + { + thread t_; + struct dummy; + public: + + typedef thread::id id; + + BOOST_THREAD_MOVABLE_ONLY( scoped_thread) /// Movable only + + /** + * Default Constructor. + * + * Effects: wraps a not-a-thread. + */ + scoped_thread() BOOST_NOEXCEPT: + t_() + { + } + + /** + * + */ + +#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> + 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) : + t_(boost::forward<F>(f)) {} + template <class F, class A1> + scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1) : + t_(boost::forward<F>(f), boost::forward<A1>(a1)) {} + template <class F, class A1, class A2> + scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1, BOOST_THREAD_FWD_REF(A2) a2) : + t_(boost::forward<F>(f), boost::forward<A1>(a1), boost::forward<A2>(a2)) {} + template <class F, class A1, class A2, class A3> + scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1, BOOST_THREAD_FWD_REF(A2) a2, BOOST_THREAD_FWD_REF(A3) a3) : + t_(boost::forward<F>(f), boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)) {} + +#endif + /** + * Constructor from the thread to own. + * + * @param t: the thread to own. + * + * Effects: move the thread to own @c t. + */ + explicit scoped_thread(BOOST_THREAD_RV_REF(thread) t) BOOST_NOEXCEPT : + t_(boost::move(t)) + { + } + +// explicit operator thread() +// { +// return boost::move(t_); +// } + + /** + * Move constructor. + */ + scoped_thread(BOOST_RV_REF(scoped_thread) x) BOOST_NOEXCEPT : + t_(boost::move(BOOST_THREAD_RV(x).t_)) + {} + + /** + * Destructor + * + * Effects: Call the CallableThread functor before destroying the owned thread. + */ + ~scoped_thread() + { + CallableThread on_destructor; + + on_destructor(t_); + } + + /** + * Move assignment. + */ + scoped_thread& operator=(BOOST_RV_REF(scoped_thread) x) + { + t_ = boost::move(BOOST_THREAD_RV(x).t_); + return *this; + } + + /** + * + */ + void swap(scoped_thread& x) BOOST_NOEXCEPT + { + t_.swap(x.t_); + } + + // forwarded thread functions + inline thread::id get_id() const BOOST_NOEXCEPT + { + return t_.get_id(); + } + + void detach() + { + t_.detach(); + } + + void join() + { + t_.join(); + } + +#ifdef BOOST_THREAD_USES_CHRONO + template <class Rep, class Period> + bool try_join_for(const chrono::duration<Rep, Period>& rel_time) + { + return t_.try_join_for(rel_time); + } + + template <class Clock, class Duration> + bool try_join_until(const chrono::time_point<Clock, Duration>& abs_time) + { + return t_.try_join_until(abs_time); + } +#endif + + thread::native_handle_type native_handle()BOOST_NOEXCEPT + { + return t_.native_handle(); + } + + bool joinable() const BOOST_NOEXCEPT + { + return t_.joinable(); + } + +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + void interrupt() + { + t_.interrupt(); + } + + bool interruption_requested() const BOOST_NOEXCEPT + { + return t_.interruption_requested(); + } +#endif + + static unsigned hardware_concurrency() BOOST_NOEXCEPT + { + return thread::hardware_concurrency(); + } + +#ifdef BOOST_THREAD_PROVIDES_PHYSICAL_CONCURRENCY + static unsigned physical_concurrency() BOOST_NOEXCEPT + { + return thread::physical_concurrency(); + } +#endif + }; + + /** + * Effects: swaps the contents of two scoped threads. + */ + template <class Destroyer> + void swap(scoped_thread<Destroyer>& lhs, scoped_thread<Destroyer>& rhs) +BOOST_NOEXCEPT { + return lhs.swap(rhs); +} + +} +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/shared_lock_guard.hpp b/boost/thread/shared_lock_guard.hpp index 8a2f2c54d1..97a6397c1e 100644 --- a/boost/thread/shared_lock_guard.hpp +++ b/boost/thread/shared_lock_guard.hpp @@ -6,7 +6,8 @@ #ifndef BOOST_THREAD_SHARED_LOCK_GUARD_HPP #define BOOST_THREAD_SHARED_LOCK_GUARD_HPP #include <boost/thread/detail/config.hpp> -#include <boost/thread/locks.hpp> +//#include <boost/thread/locks.hpp> +#include <boost/thread/lock_options.hpp> #include <boost/thread/detail/delete.hpp> namespace boost diff --git a/boost/thread/shared_mutex.hpp b/boost/thread/shared_mutex.hpp index e85e269d44..b968f2ac10 100644 --- a/boost/thread/shared_mutex.hpp +++ b/boost/thread/shared_mutex.hpp @@ -18,9 +18,32 @@ #include <boost/thread/win32/shared_mutex.hpp> #endif #elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +//#include <boost/thread/v2/shared_mutex.hpp> #include <boost/thread/pthread/shared_mutex.hpp> #else #error "Boost threads unavailable on this platform" #endif +#include <boost/thread/lockable_traits.hpp> + +namespace boost +{ + namespace sync + { +#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES + template<> + struct is_basic_lockable<shared_mutex> + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_lockable<shared_mutex> + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; +#endif + + } +} + #endif diff --git a/boost/thread/strict_lock.hpp b/boost/thread/strict_lock.hpp new file mode 100644 index 0000000000..93b7b1e71c --- /dev/null +++ b/boost/thread/strict_lock.hpp @@ -0,0 +1,235 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2008-2009,2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_STRICT_LOCK_HPP +#define BOOST_THREAD_STRICT_LOCK_HPP + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/delete.hpp> +#include <boost/thread/detail/lockable_wrapper.hpp> +#include <boost/thread/lock_options.hpp> +#include <boost/thread/lock_traits.hpp> +#include <boost/thread/lockable_traits.hpp> +#include <boost/thread/lockable_concepts.hpp> +#include <boost/thread/lock_concepts.hpp> +#include <boost/thread/exceptions.hpp> +#include <boost/throw_exception.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + + + //[strict_lock + template <typename Lockable> + class strict_lock + { + + BOOST_CONCEPT_ASSERT(( BasicLockable<Lockable> )); + public: + typedef Lockable mutex_type; + + // construct/copy/destroy: + + BOOST_THREAD_NO_COPYABLE( strict_lock) + + /** + * Constructor from a mutex reference. + * + * @param mtx the mutex to lock. + * + * __Effects: Stores a reference to the mutex to lock and locks it. + * __Throws: Any exception BasicMutex::lock() can throw. + */ + explicit strict_lock(mutex_type& mtx) : + mtx_(mtx) + { + mtx.lock(); + } /*< locks on construction >*/ + + +#if ! defined BOOST_THREAD_NO_CXX11_HDR_INITIALIZER_LIST + strict_lock(std::initializer_list<thread_detail::lockable_wrapper<Lockable> > l_) : + mtx_(*(const_cast<thread_detail::lockable_wrapper<Lockable>*>(l_.begin())->m)) + { + mtx_.lock(); + } +#endif + + /** + * Destructor + * + * __Effects: unlocks the stored mutex. + * + * __Throws + */ + ~strict_lock() + { + mtx_.unlock(); + } /*< unlocks on destruction >*/ + + + // observers + + /** + * @return the owned mutex. + */ + mutex_type* mutex() const BOOST_NOEXCEPT + { + return &mtx_; + } + + /** + * @return whether this lock is locking a mutex. + */ + bool owns_lock() const BOOST_NOEXCEPT + { + return true; + } + + /** + * @return whether this lock is locking that mutex. + */ + bool owns_lock(const mutex_type* l) const BOOST_NOEXCEPT + { + return l == mutex(); + } /*< strict locks specific function >*/ + + //BOOST_ADRESS_OF_DELETE(strict_lock) /*< disable aliasing >*/ + //BOOST_HEAP_ALLOCATION_DELETE(strict_lock) /*< disable heap allocation >*/ + + /*< no possibility to unlock >*/ + + private: + mutex_type& mtx_; + }; + //] + template <typename Lockable> + struct is_strict_lock_sur_parole<strict_lock<Lockable> > : true_type + { + }; + + /** + * A nested strict lock is a scoped lock guard ensuring the mutex is locked on its + * scope, by taking ownership of an nesting lock, locking the mutex on construction if not already locked + * and restoring the ownership to the nesting lock on destruction. + */ + //[nested_strict_lock + template <typename Lock> + class nested_strict_lock + { + BOOST_CONCEPT_ASSERT(( BasicLock<Lock> )); /*< The Lock must be a movable lock >*/ + public: + typedef typename Lock::mutex_type mutex_type; /*< Name the lockable type locked by Lock >*/ + + BOOST_THREAD_NO_COPYABLE( nested_strict_lock) + + /** + * Constructor from a nesting @c Lock. + * + * @param lk the nesting lock + * + * __Requires: <c>lk.mutex() != null_ptr</c> + * __Effects: Stores the reference to the lock parameter and takes ownership on it. + * If the lock doesn't owns the mutex @c mtx lock it. + * __Postconditions: @c owns_lock(lk.mutex()) + * __StrongException + * __Throws: + * + * - lock_error when BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is defined and lk.mutex() == null_ptr + * + * - Any exception that @c lk.lock() can throw. + * + */ + explicit nested_strict_lock(Lock& lk) : + lk_(lk) /*< Store reference to lk >*/ + { + /*< Define BOOST_THREAD_DONT_CHECK_PRECONDITIONS if you don't want to check lk ownership >*/ + BOOST_THREAD_ASSERT_PRECONDITION( lk.mutex() != 0, + lock_error() + ); + if (!lk.owns_lock()) lk.lock(); /*< ensures it is locked >*/ + tmp_lk_ = move(lk); /*< Move ownership to temporary lk >*/ + } + +#if ! defined BOOST_THREAD_NO_CXX11_HDR_INITIALIZER_LIST + nested_strict_lock(std::initializer_list<thread_detail::lockable_wrapper<Lock> > l_) : + lk_(*(const_cast<thread_detail::lockable_wrapper<Lock>*>(l_.begin())->m)) + { + /*< Define BOOST_THREAD_DONT_CHECK_PRECONDITIONS if you don't want to check lk ownership >*/ + BOOST_THREAD_ASSERT_PRECONDITION( lk_.mutex() != 0, + lock_error() + ); + if (!lk_.owns_lock()) lk_.lock(); /*< ensures it is locked >*/ + tmp_lk_ = move(lk_); /*< Move ownership to temporary lk >*/ + } +#endif + + /** + * Destructor + * + * __Effects: Restores ownership to the nesting lock. + */ + ~nested_strict_lock()BOOST_NOEXCEPT + { + lk_ = move(tmp_lk_); /*< Move ownership to nesting lock >*/ + } + + // observers + /** + * return @c the owned mutex. + */ + mutex_type* mutex() const BOOST_NOEXCEPT + { + return tmp_lk_.mutex(); + } + + /** + * @return whether this lock is locking a mutex. + */ + bool owns_lock() const BOOST_NOEXCEPT + { + return true; + } + + /** + * @return whether if this lock is locking that mutex. + */ + bool owns_lock(mutex_type const* l) const BOOST_NOEXCEPT + { + return l == mutex(); + } + + //BOOST_ADRESS_OF_DELETE(nested_strict_lock) + //BOOST_HEAP_ALLOCATEION_DELETE(nested_strict_lock) + + private: + Lock& lk_; + Lock tmp_lk_; + }; + //] + + template <typename Lock> + struct is_strict_lock_sur_parole<nested_strict_lock<Lock> > : true_type + { + }; + +#if ! defined BOOST_THREAD_NO_MAKE_STRICT_LOCK + template <typename Lockable> + strict_lock<Lockable> make_strict_lock(Lockable& mtx) + { + return { thread_detail::lockable_wrapper<Lockable>(mtx) }; + } + template <typename Lock> + nested_strict_lock<Lock> make_nested_strict_lock(Lock& lk) + { + return { thread_detail::lockable_wrapper<Lock>(lk) }; + } +#endif +} +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/sync_bounded_queue.hpp b/boost/thread/sync_bounded_queue.hpp new file mode 100644 index 0000000000..63afb614ee --- /dev/null +++ b/boost/thread/sync_bounded_queue.hpp @@ -0,0 +1,722 @@ +#ifndef BOOST_THREAD_SYNC_BOUNDED_QUEUE_HPP +#define BOOST_THREAD_SYNC_BOUNDED_QUEUE_HPP + +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2013-2014. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/condition_variable.hpp> +#include <boost/thread/mutex.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/throw_exception.hpp> +#include <boost/thread/concurrent_queues/queue_op_status.hpp> + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD +#include <boost/smart_ptr/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#endif +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + + template <typename ValueType> + class sync_bounded_queue + { + public: + typedef ValueType value_type; + typedef std::size_t size_type; + + // Constructors/Assignment/Destructors + BOOST_THREAD_NO_COPYABLE(sync_bounded_queue) + explicit sync_bounded_queue(size_type max_elems); + template <typename Range> + sync_bounded_queue(size_type max_elems, Range range); + ~sync_bounded_queue(); + + // Observers + inline bool empty() const; + inline bool full() const; + inline size_type capacity() const; + inline size_type size() const; + inline bool closed() const; + + // Modifiers + inline void close(); + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + inline void push(const value_type& x); + inline void push(BOOST_THREAD_RV_REF(value_type) x); + inline bool try_push(const value_type& x); + inline bool try_push(BOOST_THREAD_RV_REF(value_type) x); + inline bool try_push(no_block_tag, const value_type& x); + inline bool try_push(no_block_tag, BOOST_THREAD_RV_REF(value_type) x); +#endif + inline void push_back(const value_type& x); + inline void push_back(BOOST_THREAD_RV_REF(value_type) x); + inline queue_op_status try_push_back(const value_type& x); + inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x); + inline queue_op_status nonblocking_push_back(const value_type& x); + inline queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x); + inline queue_op_status wait_push_back(const value_type& x); + inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x); + + // Observers/Modifiers +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + inline void pull(value_type&); + // enable_if is_nothrow_copy_movable<value_type> + inline value_type pull(); + inline shared_ptr<ValueType> ptr_pull(); + inline bool try_pull(value_type&); + inline bool try_pull(no_block_tag,value_type&); + inline shared_ptr<ValueType> try_pull(); +#endif + inline void pull_front(value_type&); + // enable_if is_nothrow_copy_movable<value_type> + inline value_type pull_front(); + inline queue_op_status try_pull_front(value_type&); + inline queue_op_status nonblocking_pull_front(value_type&); + + inline queue_op_status wait_pull_front(ValueType& elem); + + private: + mutable mutex mtx_; + condition_variable not_empty_; + condition_variable not_full_; + size_type waiting_full_; + size_type waiting_empty_; + value_type* data_; + size_type in_; + size_type out_; + size_type capacity_; + bool closed_; + + inline size_type inc(size_type idx) const BOOST_NOEXCEPT + { + return (idx + 1) % capacity_; + } + + inline bool empty(unique_lock<mutex>& ) const BOOST_NOEXCEPT + { + return in_ == out_; + } + inline bool empty(lock_guard<mutex>& ) const BOOST_NOEXCEPT + { + return in_ == out_; + } + inline bool full(unique_lock<mutex>& ) const BOOST_NOEXCEPT + { + return (inc(in_) == out_); + } + inline bool full(lock_guard<mutex>& ) const BOOST_NOEXCEPT + { + return (inc(in_) == out_); + } + inline size_type capacity(lock_guard<mutex>& ) const BOOST_NOEXCEPT + { + return capacity_-1; + } + inline size_type size(lock_guard<mutex>& lk) const BOOST_NOEXCEPT + { + if (full(lk)) return capacity(lk); + return ((out_+capacity(lk)-in_) % capacity(lk)); + } + + inline void throw_if_closed(unique_lock<mutex>&); + inline bool closed(unique_lock<mutex>&) const; + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + inline bool try_pull(value_type& x, unique_lock<mutex>& lk); + inline shared_ptr<value_type> try_pull(unique_lock<mutex>& lk); + inline bool try_push(const value_type& x, unique_lock<mutex>& lk); + inline bool try_push(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk); +#endif + inline queue_op_status try_pull_front(value_type& x, unique_lock<mutex>& lk); + inline queue_op_status try_push_back(const value_type& x, unique_lock<mutex>& lk); + inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk); + + inline queue_op_status wait_pull_front(value_type& x, unique_lock<mutex>& lk); + inline queue_op_status wait_push_back(const value_type& x, unique_lock<mutex>& lk); + inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk); + + inline void wait_until_not_empty(unique_lock<mutex>& lk); + inline void wait_until_not_empty(unique_lock<mutex>& lk, bool&); + inline size_type wait_until_not_full(unique_lock<mutex>& lk); + inline size_type wait_until_not_full(unique_lock<mutex>& lk, bool&); + + + inline void notify_not_empty_if_needed(unique_lock<mutex>& lk) + { + if (waiting_empty_ > 0) + { + --waiting_empty_; + lk.unlock(); + not_empty_.notify_one(); + } + } + inline void notify_not_full_if_needed(unique_lock<mutex>& lk) + { + if (waiting_full_ > 0) + { + --waiting_full_; + lk.unlock(); + not_full_.notify_one(); + } + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + inline void pull(value_type& elem, unique_lock<mutex>& lk) + { + elem = boost::move(data_[out_]); + out_ = inc(out_); + notify_not_full_if_needed(lk); + } + inline value_type pull(unique_lock<mutex>& lk) + { + value_type elem = boost::move(data_[out_]); + out_ = inc(out_); + notify_not_full_if_needed(lk); + return boost::move(elem); + } + inline boost::shared_ptr<value_type> ptr_pull(unique_lock<mutex>& lk) + { + shared_ptr<value_type> res = make_shared<value_type>(boost::move(data_[out_])); + out_ = inc(out_); + notify_not_full_if_needed(lk); + return res; + } +#endif + inline void pull_front(value_type& elem, unique_lock<mutex>& lk) + { + elem = boost::move(data_[out_]); + out_ = inc(out_); + notify_not_full_if_needed(lk); + } + inline value_type pull_front(unique_lock<mutex>& lk) + { + value_type elem = boost::move(data_[out_]); + out_ = inc(out_); + notify_not_full_if_needed(lk); + return boost::move(elem); + } + + inline void set_in(size_type in, unique_lock<mutex>& lk) + { + in_ = in; + notify_not_empty_if_needed(lk); + } + + inline void push_at(const value_type& elem, size_type in_p_1, unique_lock<mutex>& lk) + { + data_[in_] = elem; + set_in(in_p_1, lk); + } + + inline void push_at(BOOST_THREAD_RV_REF(value_type) elem, size_type in_p_1, unique_lock<mutex>& lk) + { + data_[in_] = boost::move(elem); + set_in(in_p_1, lk); + } + }; + + template <typename ValueType> + sync_bounded_queue<ValueType>::sync_bounded_queue(typename sync_bounded_queue<ValueType>::size_type max_elems) : + waiting_full_(0), waiting_empty_(0), data_(new value_type[max_elems + 1]), in_(0), out_(0), capacity_(max_elems + 1), + closed_(false) + { + BOOST_ASSERT_MSG(max_elems >= 1, "number of elements must be > 1"); + } + +// template <typename ValueType> +// template <typename Range> +// sync_bounded_queue<ValueType>::sync_bounded_queue(size_type max_elems, Range range) : +// waiting_full_(0), waiting_empty_(0), data_(new value_type[max_elems + 1]), in_(0), out_(0), capacity_(max_elems + 1), +// closed_(false) +// { +// BOOST_ASSERT_MSG(max_elems >= 1, "number of elements must be > 1"); +// BOOST_ASSERT_MSG(max_elems == size(range), "number of elements must match range's size"); +// try +// { +// typedef typename Range::iterator iterator_t; +// iterator_t first = boost::begin(range); +// iterator_t end = boost::end(range); +// size_type in = 0; +// for (iterator_t cur = first; cur != end; ++cur, ++in) +// { +// data_[in] = *cur; +// } +// set_in(in); +// } +// catch (...) +// { +// delete[] data_; +// } +// } + + template <typename ValueType> + sync_bounded_queue<ValueType>::~sync_bounded_queue() + { + delete[] data_; + } + + template <typename ValueType> + void sync_bounded_queue<ValueType>::close() + { + { + lock_guard<mutex> lk(mtx_); + closed_ = true; + } + not_empty_.notify_all(); + not_full_.notify_all(); + } + + template <typename ValueType> + bool sync_bounded_queue<ValueType>::closed() const + { + lock_guard<mutex> lk(mtx_); + return closed_; + } + template <typename ValueType> + bool sync_bounded_queue<ValueType>::closed(unique_lock<mutex>& ) const + { + return closed_; + } + + template <typename ValueType> + bool sync_bounded_queue<ValueType>::empty() const + { + lock_guard<mutex> lk(mtx_); + return empty(lk); + } + template <typename ValueType> + bool sync_bounded_queue<ValueType>::full() const + { + lock_guard<mutex> lk(mtx_); + return full(lk); + } + + template <typename ValueType> + typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::capacity() const + { + lock_guard<mutex> lk(mtx_); + return capacity(lk); + } + + template <typename ValueType> + typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::size() const + { + lock_guard<mutex> lk(mtx_); + return size(lk); + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + bool sync_bounded_queue<ValueType>::try_pull(ValueType& elem, unique_lock<mutex>& lk) + { + if (empty(lk)) + { + throw_if_closed(lk); + return false; + } + pull(elem, lk); + return true; + } + template <typename ValueType> + shared_ptr<ValueType> sync_bounded_queue<ValueType>::try_pull(unique_lock<mutex>& lk) + { + if (empty(lk)) + { + throw_if_closed(lk); + return shared_ptr<ValueType>(); + } + return ptr_pull(lk); + } + template <typename ValueType> + bool sync_bounded_queue<ValueType>::try_pull(ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + return try_pull(elem, lk); + } +#endif + + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::try_pull_front(ValueType& elem, unique_lock<mutex>& lk) + { + if (empty(lk)) + { + if (closed(lk)) return queue_op_status::closed; + return queue_op_status::empty; + } + pull_front(elem, lk); + return queue_op_status::success; + } + + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::try_pull_front(ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + return try_pull_front(elem, lk); + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + bool sync_bounded_queue<ValueType>::try_pull(no_block_tag,ValueType& elem) + { + unique_lock<mutex> lk(mtx_, try_to_lock); + if (!lk.owns_lock()) + { + return false; + } + return try_pull(elem, lk); + } + template <typename ValueType> + boost::shared_ptr<ValueType> sync_bounded_queue<ValueType>::try_pull() + { + unique_lock<mutex> lk(mtx_); + return try_pull(lk); + } +#endif + + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::nonblocking_pull_front(ValueType& elem) + { + unique_lock<mutex> lk(mtx_, try_to_lock); + if (!lk.owns_lock()) + { + return queue_op_status::busy; + } + return try_pull_front(elem, lk); + } + + template <typename ValueType> + void sync_bounded_queue<ValueType>::throw_if_closed(unique_lock<mutex>&) + { + if (closed_) + { + BOOST_THROW_EXCEPTION( sync_queue_is_closed() ); + } + } + + template <typename ValueType> + void sync_bounded_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk) + { + for (;;) + { + if (out_ != in_) break; + throw_if_closed(lk); + ++waiting_empty_; + not_empty_.wait(lk); + } + } + template <typename ValueType> + void sync_bounded_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk, bool & closed) + { + for (;;) + { + if (out_ != in_) break; + if (closed_) {closed=true; return;} + ++waiting_empty_; + not_empty_.wait(lk); + } + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + void sync_bounded_queue<ValueType>::pull(ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + wait_until_not_empty(lk); + pull(elem, lk); + } +// template <typename ValueType> +// void sync_bounded_queue<ValueType>::pull(ValueType& elem, bool & closed) +// { +// unique_lock<mutex> lk(mtx_); +// wait_until_not_empty(lk, closed); +// if (closed) {return;} +// pull(elem, lk); +// } + + // enable if ValueType is nothrow movable + template <typename ValueType> + ValueType sync_bounded_queue<ValueType>::pull() + { + unique_lock<mutex> lk(mtx_); + wait_until_not_empty(lk); + return pull(lk); + } + template <typename ValueType> + boost::shared_ptr<ValueType> sync_bounded_queue<ValueType>::ptr_pull() + { + unique_lock<mutex> lk(mtx_); + wait_until_not_empty(lk); + return ptr_pull(lk); + } + +#endif + + template <typename ValueType> + void sync_bounded_queue<ValueType>::pull_front(ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + wait_until_not_empty(lk); + pull_front(elem, lk); + } + + // enable if ValueType is nothrow movable + template <typename ValueType> + ValueType sync_bounded_queue<ValueType>::pull_front() + { + unique_lock<mutex> lk(mtx_); + wait_until_not_empty(lk); + return pull_front(lk); + } + + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::wait_pull_front(ValueType& elem, unique_lock<mutex>& lk) + { + if (empty(lk) && closed(lk)) {return queue_op_status::closed;} + wait_until_not_empty(lk); + pull_front(elem, lk); + return queue_op_status::success; + } + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::wait_pull_front(ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + return wait_pull_front(elem, lk); + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + bool sync_bounded_queue<ValueType>::try_push(const ValueType& elem, unique_lock<mutex>& lk) + { + throw_if_closed(lk); + size_type in_p_1 = inc(in_); + if (in_p_1 == out_) // full() + { + return false; + } + push_at(elem, in_p_1, lk); + return true; + } + template <typename ValueType> + bool sync_bounded_queue<ValueType>::try_push(const ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + return try_push(elem, lk); + } + +#endif + + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::try_push_back(const ValueType& elem, unique_lock<mutex>& lk) + { + if (closed(lk)) return queue_op_status::closed; + size_type in_p_1 = inc(in_); + if (in_p_1 == out_) // full() + { + return queue_op_status::full; + } + push_at(elem, in_p_1, lk); + return queue_op_status::success; + } + + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::try_push_back(const ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + return try_push_back(elem, lk); + } + + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::wait_push_back(const ValueType& elem, unique_lock<mutex>& lk) + { + if (closed(lk)) return queue_op_status::closed; + push_at(elem, wait_until_not_full(lk), lk); + return queue_op_status::success; + } + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::wait_push_back(const ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + return wait_push_back(elem, lk); + } + + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + bool sync_bounded_queue<ValueType>::try_push(no_block_tag, const ValueType& elem) + { + unique_lock<mutex> lk(mtx_, try_to_lock); + if (!lk.owns_lock()) return false; + return try_push(elem, lk); + } +#endif + + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::nonblocking_push_back(const ValueType& elem) + { + unique_lock<mutex> lk(mtx_, try_to_lock); + if (!lk.owns_lock()) return queue_op_status::busy; + return try_push_back(elem, lk); + } + + template <typename ValueType> + typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::wait_until_not_full(unique_lock<mutex>& lk) + { + for (;;) + { + throw_if_closed(lk); + size_type in_p_1 = inc(in_); + if (in_p_1 != out_) // ! full() + { + return in_p_1; + } + ++waiting_full_; + not_full_.wait(lk); + } + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + void sync_bounded_queue<ValueType>::push(const ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + push_at(elem, wait_until_not_full(lk), lk); + } +#endif + template <typename ValueType> + void sync_bounded_queue<ValueType>::push_back(const ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + push_at(elem, wait_until_not_full(lk), lk); + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + bool sync_bounded_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk) + { + throw_if_closed(lk); + size_type in_p_1 = inc(in_); + if (in_p_1 == out_) // full() + { + return false; + } + push_at(boost::move(elem), in_p_1, lk); + return true; + } + + template <typename ValueType> + bool sync_bounded_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(mtx_); + return try_push(boost::move(elem), lk); + } +#endif + + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk) + { + if (closed(lk)) return queue_op_status::closed; + size_type in_p_1 = inc(in_); + if (in_p_1 == out_) // full() + { + return queue_op_status::full; + } + push_at(boost::move(elem), in_p_1, lk); + return queue_op_status::success; + } + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(mtx_); + return try_push_back(boost::move(elem), lk); + } + + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk) + { + if (closed(lk)) return queue_op_status::closed; + push_at(boost::move(elem), wait_until_not_full(lk), lk); + return queue_op_status::success; + } + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(mtx_); + return try_push_back(boost::move(elem), lk); + } + + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + bool sync_bounded_queue<ValueType>::try_push(no_block_tag, BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(mtx_, try_to_lock); + if (!lk.owns_lock()) + { + return false; + } + return try_push(boost::move(elem), lk); + } +#endif + template <typename ValueType> + queue_op_status sync_bounded_queue<ValueType>::nonblocking_push_back(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(mtx_, try_to_lock); + if (!lk.owns_lock()) + { + return queue_op_status::busy; + } + return try_push_back(boost::move(elem), lk); + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + void sync_bounded_queue<ValueType>::push(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(mtx_); + push_at(boost::move(elem), wait_until_not_full(lk), lk); + } +#endif + template <typename ValueType> + void sync_bounded_queue<ValueType>::push_back(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(mtx_); + push_at(boost::move(elem), wait_until_not_full(lk), lk); + } + + template <typename ValueType> + sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, BOOST_THREAD_RV_REF(ValueType) elem) + { + sbq.push_back(boost::move(elem)); + return sbq; + } + + template <typename ValueType> + sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, ValueType const&elem) + { + sbq.push_back(elem); + return sbq; + } + + template <typename ValueType> + sync_bounded_queue<ValueType>& operator>>(sync_bounded_queue<ValueType>& sbq, ValueType &elem) + { + sbq.pull_front(elem); + return sbq; + } + +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/sync_queue.hpp b/boost/thread/sync_queue.hpp new file mode 100644 index 0000000000..5037e909ed --- /dev/null +++ b/boost/thread/sync_queue.hpp @@ -0,0 +1,663 @@ +#ifndef BOOST_THREAD_SYNC_QUEUE_HPP +#define BOOST_THREAD_SYNC_QUEUE_HPP + +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2013-2014. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/condition_variable.hpp> +#include <boost/thread/mutex.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/concurrent_queues/queue_op_status.hpp> + +#include <boost/throw_exception.hpp> +#include <boost/smart_ptr/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <boost/thread/csbl/deque.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + + template <typename ValueType> + class sync_queue + { + public: + typedef ValueType value_type; + typedef csbl::deque<ValueType> underlying_queue_type; + typedef std::size_t size_type; + typedef queue_op_status op_status; + + // Constructors/Assignment/Destructors + BOOST_THREAD_NO_COPYABLE(sync_queue) + inline sync_queue(); + //template <typename Range> + //inline explicit sync_queue(Range range); + inline ~sync_queue(); + + // Observers + inline bool empty() const; + inline bool full() const; + inline size_type size() const; + inline bool closed() const; + + // Modifiers + inline void close(); + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + inline void push(const value_type& x); + inline bool try_push(const value_type& x); + inline bool try_push(no_block_tag, const value_type& x); + inline void push(BOOST_THREAD_RV_REF(value_type) x); + inline bool try_push(BOOST_THREAD_RV_REF(value_type) x); + inline bool try_push(no_block_tag, BOOST_THREAD_RV_REF(value_type) x); +#endif + inline void push_back(const value_type& x); + inline queue_op_status try_push_back(const value_type& x); + inline queue_op_status nonblocking_push_back(const value_type& x); + inline queue_op_status wait_push_back(const value_type& x); + inline void push_back(BOOST_THREAD_RV_REF(value_type) x); + inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x); + inline queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x); + inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x); + + + // Observers/Modifiers +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + inline void pull(value_type&); + inline void pull(ValueType& elem, bool & closed); + // enable_if is_nothrow_copy_movable<value_type> + inline value_type pull(); + inline shared_ptr<ValueType> ptr_pull(); +#endif + inline void pull_front(value_type&); + // enable_if is_nothrow_copy_movable<value_type> + inline value_type pull_front(); + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + inline bool try_pull(value_type&); + inline bool try_pull(no_block_tag,value_type&); + inline shared_ptr<ValueType> try_pull(); +#endif + inline queue_op_status try_pull_front(value_type&); + inline queue_op_status nonblocking_pull_front(value_type&); + inline queue_op_status wait_pull_front(ValueType& elem); + + inline underlying_queue_type underlying_queue() { + lock_guard<mutex> lk(mtx_); + waiting_empty_ = 0; + return boost::move(data_); + } + + private: + mutable mutex mtx_; + condition_variable not_empty_; + size_type waiting_empty_; + underlying_queue_type data_; + bool closed_; + + inline bool empty(unique_lock<mutex>& ) const BOOST_NOEXCEPT + { + return data_.empty(); + } + inline bool empty(lock_guard<mutex>& ) const BOOST_NOEXCEPT + { + return data_.empty(); + } + + inline size_type size(lock_guard<mutex>& ) const BOOST_NOEXCEPT + { + return data_.size(); + } + + inline void throw_if_closed(unique_lock<mutex>&); + inline bool closed(unique_lock<mutex>& lk) const; + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + inline bool try_pull(value_type& x, unique_lock<mutex>& lk); + inline bool try_push(const value_type& x, unique_lock<mutex>& lk); + inline bool try_push(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk); + inline shared_ptr<value_type> try_pull(unique_lock<mutex>& lk); +#endif + inline queue_op_status try_pull_front(value_type& x, unique_lock<mutex>& lk); + inline queue_op_status wait_pull_front(value_type& x, unique_lock<mutex>& lk); + inline queue_op_status try_push_back(const value_type& x, unique_lock<mutex>& lk); + inline queue_op_status wait_push_back(const value_type& x, unique_lock<mutex>& lk); + inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk); + inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk); + + inline void wait_until_not_empty(unique_lock<mutex>& lk); + inline void wait_until_not_empty(unique_lock<mutex>& lk, bool&); + + inline void notify_not_empty_if_needed(unique_lock<mutex>& lk) + { + if (waiting_empty_ > 0) + { + --waiting_empty_; + lk.unlock(); + not_empty_.notify_one(); + } + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + inline void pull(value_type& elem, unique_lock<mutex>& ) + { + elem = boost::move(data_.front()); + data_.pop_front(); + } + inline value_type pull(unique_lock<mutex>& ) + { + value_type e = boost::move(data_.front()); + data_.pop_front(); + return boost::move(e); + } + inline boost::shared_ptr<value_type> ptr_pull(unique_lock<mutex>& ) + { + shared_ptr<value_type> res = make_shared<value_type>(boost::move(data_.front())); + data_.pop_front(); + return res; + } +#endif + inline void pull_front(value_type& elem, unique_lock<mutex>& ) + { + elem = boost::move(data_.front()); + data_.pop_front(); + } + inline value_type pull_front(unique_lock<mutex>& ) + { + value_type e = boost::move(data_.front()); + data_.pop_front(); + return boost::move(e); + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + inline void push(const value_type& elem, unique_lock<mutex>& lk) + { + data_.push_back(elem); + notify_not_empty_if_needed(lk); + } + + inline void push(BOOST_THREAD_RV_REF(value_type) elem, unique_lock<mutex>& lk) + { + data_.push_back(boost::move(elem)); + notify_not_empty_if_needed(lk); + } +#endif + inline void push_back(const value_type& elem, unique_lock<mutex>& lk) + { + data_.push_back(elem); + notify_not_empty_if_needed(lk); + } + + inline void push_back(BOOST_THREAD_RV_REF(value_type) elem, unique_lock<mutex>& lk) + { + data_.push_back(boost::move(elem)); + notify_not_empty_if_needed(lk); + } + }; + + template <typename ValueType> + sync_queue<ValueType>::sync_queue() : + waiting_empty_(0), data_(), closed_(false) + { + BOOST_ASSERT(data_.empty()); + } + +// template <typename ValueType> +// template <typename Range> +// explicit sync_queue<ValueType>::sync_queue(Range range) : +// waiting_empty_(0), data_(), closed_(false) +// { +// try +// { +// typedef typename Range::iterator iterator_t; +// iterator_t first = boost::begin(range); +// iterator_t end = boost::end(range); +// for (iterator_t cur = first; cur != end; ++cur) +// { +// data_.push(boost::move(*cur));; +// } +// notify_not_empty_if_needed(lk); +// } +// catch (...) +// { +// delete[] data_; +// } +// } + + template <typename ValueType> + sync_queue<ValueType>::~sync_queue() + { + } + + template <typename ValueType> + void sync_queue<ValueType>::close() + { + { + lock_guard<mutex> lk(mtx_); + closed_ = true; + } + not_empty_.notify_all(); + } + + template <typename ValueType> + bool sync_queue<ValueType>::closed() const + { + lock_guard<mutex> lk(mtx_); + return closed_; + } + template <typename ValueType> + bool sync_queue<ValueType>::closed(unique_lock<mutex>&) const + { + return closed_; + } + + template <typename ValueType> + bool sync_queue<ValueType>::empty() const + { + lock_guard<mutex> lk(mtx_); + return empty(lk); + } + template <typename ValueType> + bool sync_queue<ValueType>::full() const + { + return false; + } + + template <typename ValueType> + typename sync_queue<ValueType>::size_type sync_queue<ValueType>::size() const + { + lock_guard<mutex> lk(mtx_); + return size(lk); + } + + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + bool sync_queue<ValueType>::try_pull(ValueType& elem, unique_lock<mutex>& lk) + { + if (empty(lk)) + { + throw_if_closed(lk); + return false; + } + pull(elem, lk); + return true; + } + template <typename ValueType> + shared_ptr<ValueType> sync_queue<ValueType>::try_pull(unique_lock<mutex>& lk) + { + if (empty(lk)) + { + throw_if_closed(lk); + return shared_ptr<ValueType>(); + } + return ptr_pull(lk); + } +#endif + template <typename ValueType> + queue_op_status sync_queue<ValueType>::try_pull_front(ValueType& elem, unique_lock<mutex>& lk) + { + if (empty(lk)) + { + if (closed(lk)) return queue_op_status::closed; + return queue_op_status::empty; + } + pull_front(elem, lk); + return queue_op_status::success; + } + template <typename ValueType> + queue_op_status sync_queue<ValueType>::wait_pull_front(ValueType& elem, unique_lock<mutex>& lk) + { + if (empty(lk)) + { + if (closed(lk)) return queue_op_status::closed; + } + bool has_been_closed = false; + wait_until_not_empty(lk, has_been_closed); + if (has_been_closed) return queue_op_status::closed; + pull_front(elem, lk); + return queue_op_status::success; + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + bool sync_queue<ValueType>::try_pull(ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + return try_pull(elem, lk); + } +#endif + template <typename ValueType> + queue_op_status sync_queue<ValueType>::try_pull_front(ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + return try_pull_front(elem, lk); + } + + template <typename ValueType> + queue_op_status sync_queue<ValueType>::wait_pull_front(ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + return wait_pull_front(elem, lk); + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + bool sync_queue<ValueType>::try_pull(no_block_tag,ValueType& elem) + { + unique_lock<mutex> lk(mtx_, try_to_lock); + if (!lk.owns_lock()) + { + return false; + } + return try_pull(elem, lk); + } + template <typename ValueType> + boost::shared_ptr<ValueType> sync_queue<ValueType>::try_pull() + { + unique_lock<mutex> lk(mtx_); + return try_pull(lk); + } +#endif + template <typename ValueType> + queue_op_status sync_queue<ValueType>::nonblocking_pull_front(ValueType& elem) + { + unique_lock<mutex> lk(mtx_, try_to_lock); + if (!lk.owns_lock()) + { + return queue_op_status::busy; + } + return try_pull_front(elem, lk); + } + + template <typename ValueType> + void sync_queue<ValueType>::throw_if_closed(unique_lock<mutex>&) + { + if (closed_) + { + BOOST_THROW_EXCEPTION( sync_queue_is_closed() ); + } + } + + template <typename ValueType> + void sync_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk) + { + for (;;) + { + if (! empty(lk)) break; + throw_if_closed(lk); + ++waiting_empty_; + not_empty_.wait(lk); + } + } + template <typename ValueType> + void sync_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk, bool & closed) + { + for (;;) + { + if (! empty(lk)) break; + if (closed_) {closed=true; return;} + ++waiting_empty_; + not_empty_.wait(lk); + } + closed=false; + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + void sync_queue<ValueType>::pull(ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + wait_until_not_empty(lk); + pull(elem, lk); + } + template <typename ValueType> + void sync_queue<ValueType>::pull(ValueType& elem, bool & closed) + { + unique_lock<mutex> lk(mtx_); + wait_until_not_empty(lk, closed); + if (closed) {return;} + pull(elem, lk); + } + + // enable if ValueType is nothrow movable + template <typename ValueType> + ValueType sync_queue<ValueType>::pull() + { + unique_lock<mutex> lk(mtx_); + wait_until_not_empty(lk); + return pull(lk); + } + template <typename ValueType> + boost::shared_ptr<ValueType> sync_queue<ValueType>::ptr_pull() + { + unique_lock<mutex> lk(mtx_); + wait_until_not_empty(lk); + return ptr_pull(lk); + } +#endif + + template <typename ValueType> + void sync_queue<ValueType>::pull_front(ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + wait_until_not_empty(lk); + pull_front(elem, lk); + } + + // enable if ValueType is nothrow movable + template <typename ValueType> + ValueType sync_queue<ValueType>::pull_front() + { + unique_lock<mutex> lk(mtx_); + wait_until_not_empty(lk); + return pull_front(lk); + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + bool sync_queue<ValueType>::try_push(const ValueType& elem, unique_lock<mutex>& lk) + { + throw_if_closed(lk); + push(elem, lk); + return true; + } + + template <typename ValueType> + bool sync_queue<ValueType>::try_push(const ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + return try_push(elem, lk); + } +#endif + + template <typename ValueType> + queue_op_status sync_queue<ValueType>::try_push_back(const ValueType& elem, unique_lock<mutex>& lk) + { + if (closed(lk)) return queue_op_status::closed; + push_back(elem, lk); + return queue_op_status::success; + } + + template <typename ValueType> + queue_op_status sync_queue<ValueType>::try_push_back(const ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + return try_push_back(elem, lk); + } + + template <typename ValueType> + queue_op_status sync_queue<ValueType>::wait_push_back(const ValueType& elem, unique_lock<mutex>& lk) + { + if (closed(lk)) return queue_op_status::closed; + push_back(elem, lk); + return queue_op_status::success; + } + + template <typename ValueType> + queue_op_status sync_queue<ValueType>::wait_push_back(const ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + return wait_push_back(elem, lk); + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + bool sync_queue<ValueType>::try_push(no_block_tag, const ValueType& elem) + { + unique_lock<mutex> lk(mtx_, try_to_lock); + if (!lk.owns_lock()) return false; + return try_push(elem, lk); + } +#endif + template <typename ValueType> + queue_op_status sync_queue<ValueType>::nonblocking_push_back(const ValueType& elem) + { + unique_lock<mutex> lk(mtx_, try_to_lock); + if (!lk.owns_lock()) return queue_op_status::busy; + return try_push_back(elem, lk); + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + void sync_queue<ValueType>::push(const ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + throw_if_closed(lk); + push(elem, lk); + } +#endif + + template <typename ValueType> + void sync_queue<ValueType>::push_back(const ValueType& elem) + { + unique_lock<mutex> lk(mtx_); + throw_if_closed(lk); + push_back(elem, lk); + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + bool sync_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk) + { + throw_if_closed(lk); + push(boost::move(elem), lk); + return true; + } + + template <typename ValueType> + bool sync_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(mtx_); + return try_push(boost::move(elem), lk); + } +#endif + + template <typename ValueType> + queue_op_status sync_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk) + { + if (closed(lk)) return queue_op_status::closed; + push_back(boost::move(elem), lk); + return queue_op_status::success; + } + + template <typename ValueType> + queue_op_status sync_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(mtx_); + return try_push_back(boost::move(elem), lk); + } + + template <typename ValueType> + queue_op_status sync_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk) + { + if (closed(lk)) return queue_op_status::closed; + push_back(boost::move(elem), lk); + return queue_op_status::success; + } + + template <typename ValueType> + queue_op_status sync_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(mtx_); + return wait_push_back(boost::move(elem), lk); + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + bool sync_queue<ValueType>::try_push(no_block_tag, BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(mtx_, try_to_lock); + if (!lk.owns_lock()) + { + return false; + } + return try_push(boost::move(elem), lk); + } +#endif + + template <typename ValueType> + queue_op_status sync_queue<ValueType>::nonblocking_push_back(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(mtx_, try_to_lock); + if (!lk.owns_lock()) + { + return queue_op_status::busy; + } + return try_push_back(boost::move(elem), lk); + } + +#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD + template <typename ValueType> + void sync_queue<ValueType>::push(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(mtx_); + throw_if_closed(lk); + push(boost::move(elem), lk); + } +#endif + + template <typename ValueType> + void sync_queue<ValueType>::push_back(BOOST_THREAD_RV_REF(ValueType) elem) + { + unique_lock<mutex> lk(mtx_); + throw_if_closed(lk); + push_back(boost::move(elem), lk); + } + + template <typename ValueType> + sync_queue<ValueType>& operator<<(sync_queue<ValueType>& sbq, BOOST_THREAD_RV_REF(ValueType) elem) + { + sbq.push_back(boost::move(elem)); + return sbq; + } + + template <typename ValueType> + sync_queue<ValueType>& operator<<(sync_queue<ValueType>& sbq, ValueType const&elem) + { + sbq.push_back(elem); + return sbq; + } + + template <typename ValueType> + sync_queue<ValueType>& operator>>(sync_queue<ValueType>& sbq, ValueType &elem) + { + sbq.pull_front(elem); + return sbq; + } + +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/synchronized_value.hpp b/boost/thread/synchronized_value.hpp new file mode 100644 index 0000000000..e161063040 --- /dev/null +++ b/boost/thread/synchronized_value.hpp @@ -0,0 +1,1068 @@ +// (C) Copyright 2010 Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk +// (C) Copyright 2012 Vicente J. Botet Escriba +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +#ifndef BOOST_THREAD_SYNCHRONIZED_VALUE_HPP +#define BOOST_THREAD_SYNCHRONIZED_VALUE_HPP + +#include <boost/thread/detail/config.hpp> + +#include <boost/thread/detail/move.hpp> +#include <boost/thread/mutex.hpp> +#include <boost/thread/lock_types.hpp> +#include <boost/thread/lock_guard.hpp> +#include <boost/thread/lock_algorithms.hpp> +#include <boost/thread/lock_factories.hpp> +#include <boost/thread/strict_lock.hpp> +#include <boost/core/swap.hpp> +#include <boost/utility/declval.hpp> +//#include <boost/type_traits.hpp> +//#include <boost/thread/detail/is_nothrow_default_constructible.hpp> +//#if ! defined BOOST_NO_CXX11_HDR_TYPE_TRAITS +//#include <type_traits> +//#endif + +#if ! defined(BOOST_THREAD_NO_SYNCHRONIZE) +#include <tuple> // todo change to <boost/tuple.hpp> once Boost.Tuple or Boost.Fusion provides Move semantics on C++98 compilers. +#include <functional> +#endif + +#include <boost/utility/result_of.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + + /** + * strict lock providing a const pointer access to the synchronized value type. + * + * @param T the value type. + * @param Lockable the mutex type protecting the value type. + */ + template <typename T, typename Lockable = mutex> + class const_strict_lock_ptr + { + public: + typedef T value_type; + typedef Lockable mutex_type; + protected: + + // this should be a strict_lock, but unique_lock is needed to be able to return it. + boost::unique_lock<mutex_type> lk_; + T const& value_; + + public: + BOOST_THREAD_MOVABLE_ONLY( const_strict_lock_ptr ) + + /** + * @param value constant reference of the value to protect. + * @param mtx reference to the mutex used to protect the value. + * @effects locks the mutex @c mtx, stores a reference to it and to the value type @c value. + */ + const_strict_lock_ptr(T const& val, Lockable & mtx) : + lk_(mtx), value_(val) + { + } + const_strict_lock_ptr(T const& val, Lockable & mtx, adopt_lock_t tag) BOOST_NOEXCEPT : + lk_(mtx, tag), value_(val) + { + } + /** + * Move constructor. + * @effects takes ownership of the mutex owned by @c other, stores a reference to the mutex and the value type of @c other. + */ + const_strict_lock_ptr(BOOST_THREAD_RV_REF(const_strict_lock_ptr) other) BOOST_NOEXCEPT + : lk_(boost::move(BOOST_THREAD_RV(other).lk_)),value_(BOOST_THREAD_RV(other).value_) + { + } + + ~const_strict_lock_ptr() + { + } + + /** + * @return a constant pointer to the protected value + */ + const T* operator->() const + { + return &value_; + } + + /** + * @return a constant reference to the protected value + */ + const T& operator*() const + { + return value_; + } + + }; + + /** + * strict lock providing a pointer access to the synchronized value type. + * + * @param T the value type. + * @param Lockable the mutex type protecting the value type. + */ + template <typename T, typename Lockable = mutex> + class strict_lock_ptr : public const_strict_lock_ptr<T,Lockable> + { + typedef const_strict_lock_ptr<T,Lockable> base_type; + public: + BOOST_THREAD_MOVABLE_ONLY( strict_lock_ptr ) + + /** + * @param value reference of the value to protect. + * @param mtx reference to the mutex used to protect the value. + * @effects locks the mutex @c mtx, stores a reference to it and to the value type @c value. + */ + strict_lock_ptr(T & val, Lockable & mtx) : + base_type(val, mtx) + { + } + strict_lock_ptr(T & val, Lockable & mtx, adopt_lock_t tag) : + base_type(val, mtx, tag) + { + } + + /** + * Move constructor. + * @effects takes ownership of the mutex owned by @c other, stores a reference to the mutex and the value type of @c other. + */ + strict_lock_ptr(BOOST_THREAD_RV_REF(strict_lock_ptr) other) + : base_type(boost::move(static_cast<base_type&>(other))) + { + } + + ~strict_lock_ptr() + { + } + + /** + * @return a pointer to the protected value + */ + T* operator->() + { + return const_cast<T*>(&this->value_); + } + + /** + * @return a reference to the protected value + */ + T& operator*() + { + return const_cast<T&>(this->value_); + } + + }; + + template <typename SV> + struct synchronized_value_strict_lock_ptr + { + typedef strict_lock_ptr<typename SV::value_type, typename SV::mutex_type> type; + }; + + template <typename SV> + struct synchronized_value_strict_lock_ptr<const SV> + { + typedef const_strict_lock_ptr<typename SV::value_type, typename SV::mutex_type> type; + }; + /** + * unique_lock providing a const pointer access to the synchronized value type. + * + * An object of type const_unique_lock_ptr is a unique_lock that provides a const pointer access to the synchronized value type. + * As unique_lock controls the ownership of a lockable object within a scope. + * Ownership of the lockable object may be acquired at construction or after construction, + * and may be transferred, after acquisition, to another const_unique_lock_ptr object. + * Objects of type const_unique_lock_ptr are not copyable but are movable. + * The behavior of a program is undefined if the mutex and the value type + * pointed do not exist for the entire remaining lifetime of the const_unique_lock_ptr object. + * The supplied Mutex type shall meet the BasicLockable requirements. + * + * @note const_unique_lock_ptr<T, Lockable> meets the Lockable requirements. + * If Lockable meets the TimedLockable requirements, const_unique_lock_ptr<T,Lockable> + * also meets the TimedLockable requirements. + * + * @param T the value type. + * @param Lockable the mutex type protecting the value type. + */ + template <typename T, typename Lockable = mutex> + class const_unique_lock_ptr : public unique_lock<Lockable> + { + typedef unique_lock<Lockable> base_type; + public: + typedef T value_type; + typedef Lockable mutex_type; + protected: + T const& value_; + + public: + BOOST_THREAD_MOVABLE_ONLY(const_unique_lock_ptr) + + /** + * @param value reference of the value to protect. + * @param mtx reference to the mutex used to protect the value. + * + * @requires If mutex_type is not a recursive mutex the calling thread does not own the mutex. + * + * @effects locks the mutex @c mtx, stores a reference to it and to the value type @c value. + */ + const_unique_lock_ptr(T const& val, Lockable & mtx) + : base_type(mtx), value_(val) + { + } + /** + * @param value reference of the value to protect. + * @param mtx reference to the mutex used to protect the value. + * @param tag of type adopt_lock_t used to differentiate the constructor. + * @requires The calling thread own the mutex. + * @effects stores a reference to it and to the value type @c value taking ownership. + */ + const_unique_lock_ptr(T const& val, Lockable & mtx, adopt_lock_t) BOOST_NOEXCEPT + : base_type(mtx, adopt_lock), value_(val) + { + } + /** + * @param value reference of the value to protect. + * @param mtx reference to the mutex used to protect the value. + * @param tag of type defer_lock_t used to differentiate the constructor. + * @effects stores a reference to it and to the value type @c value c. + */ + const_unique_lock_ptr(T const& val, Lockable & mtx, defer_lock_t) BOOST_NOEXCEPT + : base_type(mtx, defer_lock), value_(val) + { + } + /** + * @param value reference of the value to protect. + * @param mtx reference to the mutex used to protect the value. + * @param tag of type try_to_lock_t used to differentiate the constructor. + * @requires If mutex_type is not a recursive mutex the calling thread does not own the mutex. + * @effects try to lock the mutex @c mtx, stores a reference to it and to the value type @c value. + */ + const_unique_lock_ptr(T const& val, Lockable & mtx, try_to_lock_t) BOOST_NOEXCEPT + : base_type(mtx, try_to_lock), value_(val) + { + } + /** + * Move constructor. + * @effects takes ownership of the mutex owned by @c other, stores a reference to the mutex and the value type of @c other. + */ + const_unique_lock_ptr(BOOST_THREAD_RV_REF(const_unique_lock_ptr) other) BOOST_NOEXCEPT + : base_type(boost::move(static_cast<base_type&>(other))), value_(BOOST_THREAD_RV(other).value_) + { + } + + /** + * @effects If owns calls unlock() on the owned mutex. + */ + ~const_unique_lock_ptr() + { + } + + /** + * @return a constant pointer to the protected value + */ + const T* operator->() const + { + BOOST_ASSERT (this->owns_lock()); + return &value_; + } + + /** + * @return a constant reference to the protected value + */ + const T& operator*() const + { + BOOST_ASSERT (this->owns_lock()); + return value_; + } + + }; + + /** + * unique lock providing a pointer access to the synchronized value type. + * + * @param T the value type. + * @param Lockable the mutex type protecting the value type. + */ + template <typename T, typename Lockable = mutex> + class unique_lock_ptr : public const_unique_lock_ptr<T, Lockable> + { + typedef const_unique_lock_ptr<T, Lockable> base_type; + public: + typedef T value_type; + typedef Lockable mutex_type; + + BOOST_THREAD_MOVABLE_ONLY(unique_lock_ptr) + + /** + * @param value reference of the value to protect. + * @param mtx reference to the mutex used to protect the value. + * @effects locks the mutex @c mtx, stores a reference to it and to the value type @c value. + */ + unique_lock_ptr(T & val, Lockable & mtx) + : base_type(val, mtx) + { + } + /** + * @param value reference of the value to protect. + * @param mtx reference to the mutex used to protect the value. + * @param tag of type adopt_lock_t used to differentiate the constructor. + * @effects stores a reference to it and to the value type @c value taking ownership. + */ + unique_lock_ptr(T & value, Lockable & mtx, adopt_lock_t) BOOST_NOEXCEPT + : base_type(value, mtx, adopt_lock) + { + } + /** + * @param value reference of the value to protect. + * @param mtx reference to the mutex used to protect the value. + * @param tag of type defer_lock_t used to differentiate the constructor. + * @effects stores a reference to it and to the value type @c value c. + */ + unique_lock_ptr(T & value, Lockable & mtx, defer_lock_t) BOOST_NOEXCEPT + : base_type(value, mtx, defer_lock) + { + } + /** + * @param value reference of the value to protect. + * @param mtx reference to the mutex used to protect the value. + * @param tag of type try_to_lock_t used to differentiate the constructor. + * @effects try to lock the mutex @c mtx, stores a reference to it and to the value type @c value. + */ + unique_lock_ptr(T & value, Lockable & mtx, try_to_lock_t) BOOST_NOEXCEPT + : base_type(value, mtx, try_to_lock) + { + } + /** + * Move constructor. + * @effects takes ownership of the mutex owned by @c other, stores a reference to the mutex and the value type of @c other. + */ + unique_lock_ptr(BOOST_THREAD_RV_REF(unique_lock_ptr) other) BOOST_NOEXCEPT + : base_type(boost::move(static_cast<base_type&>(other))) + { + } + + ~unique_lock_ptr() + { + } + + /** + * @return a pointer to the protected value + */ + T* operator->() + { + BOOST_ASSERT (this->owns_lock()); + return const_cast<T*>(&this->value_); + } + + /** + * @return a reference to the protected value + */ + T& operator*() + { + BOOST_ASSERT (this->owns_lock()); + return const_cast<T&>(this->value_); + } + + + }; + + template <typename SV> + struct synchronized_value_unique_lock_ptr + { + typedef unique_lock_ptr<typename SV::value_type, typename SV::mutex_type> type; + }; + + template <typename SV> + struct synchronized_value_unique_lock_ptr<const SV> + { + typedef const_unique_lock_ptr<typename SV::value_type, typename SV::mutex_type> type; + }; + /** + * cloaks a value type and the mutex used to protect it together. + * @param T the value type. + * @param Lockable the mutex type protecting the value type. + */ + template <typename T, typename Lockable = mutex> + class synchronized_value + { + +#if ! defined(BOOST_THREAD_NO_MAKE_UNIQUE_LOCKS) +#if ! defined BOOST_NO_CXX11_VARIADIC_TEMPLATES + template <typename ...SV> + friend std::tuple<typename synchronized_value_strict_lock_ptr<SV>::type ...> synchronize(SV& ...sv); +#else + template <typename SV1, typename SV2> + friend std::tuple< + typename synchronized_value_strict_lock_ptr<SV1>::type, + typename synchronized_value_strict_lock_ptr<SV2>::type + > + synchronize(SV1& sv1, SV2& sv2); + template <typename SV1, typename SV2, typename SV3> + friend std::tuple< + typename synchronized_value_strict_lock_ptr<SV1>::type, + typename synchronized_value_strict_lock_ptr<SV2>::type, + typename synchronized_value_strict_lock_ptr<SV3>::type + > + synchronize(SV1& sv1, SV2& sv2, SV3& sv3); +#endif +#endif + + public: + typedef T value_type; + typedef Lockable mutex_type; + private: + T value_; + mutable mutex_type mtx_; + public: + // construction/destruction + /** + * Default constructor. + * + * @Requires: T is DefaultConstructible + */ + synchronized_value() + //BOOST_NOEXCEPT_IF(is_nothrow_default_constructible<T>::value) + : value_() + { + } + + /** + * Constructor from copy constructible value. + * + * Requires: T is CopyConstructible + */ + synchronized_value(T const& other) + //BOOST_NOEXCEPT_IF(is_nothrow_copy_constructible<T>::value) + : value_(other) + { + } + + /** + * Move Constructor. + * + * Requires: T is CopyMovable + */ + synchronized_value(BOOST_THREAD_RV_REF(T) other) + //BOOST_NOEXCEPT_IF(is_nothrow_move_constructible<T>::value) + : value_(boost::move(other)) + { + } + + /** + * Constructor from value type. + * + * Requires: T is DefaultConstructible and Assignable + * Effects: Assigns the value on a scope protected by the mutex of the rhs. The mutex is not copied. + */ + synchronized_value(synchronized_value const& rhs) + { + strict_lock<mutex_type> lk(rhs.mtx_); + value_ = rhs.value_; + } + + /** + * Move Constructor from movable value type + * + */ + synchronized_value(BOOST_THREAD_RV_REF(synchronized_value) other) + { + strict_lock<mutex_type> lk(BOOST_THREAD_RV(other).mtx_); + value_= boost::move(BOOST_THREAD_RV(other).value_); + } + + // mutation + /** + * Assignment operator. + * + * Effects: Copies the underlying value on a scope protected by the two mutexes. + * The mutex is not copied. The locks are acquired using lock, so deadlock is avoided. + * For example, there is no problem if one thread assigns a = b and the other assigns b = a. + * + * Return: *this + */ + + synchronized_value& operator=(synchronized_value const& rhs) + { + if(&rhs != this) + { + // auto _ = make_unique_locks(mtx_, rhs.mtx_); + unique_lock<mutex_type> lk1(mtx_, defer_lock); + unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock); + lock(lk1,lk2); + + value_ = rhs.value_; + } + return *this; + } + /** + * Assignment operator from a T const&. + * Effects: The operator copies the value on a scope protected by the mutex. + * Return: *this + */ + synchronized_value& operator=(value_type const& val) + { + { + strict_lock<mutex_type> lk(mtx_); + value_ = val; + } + return *this; + } + + //observers + /** + * Explicit conversion to value type. + * + * Requires: T is CopyConstructible + * Return: A copy of the protected value obtained on a scope protected by the mutex. + * + */ + T get() const + { + strict_lock<mutex_type> lk(mtx_); + return value_; + } + /** + * Explicit conversion to value type. + * + * Requires: T is CopyConstructible + * Return: A copy of the protected value obtained on a scope protected by the mutex. + * + */ +#if ! defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) + explicit operator T() const + { + return get(); + } +#endif + + /** + * value type getter. + * + * Return: A constant reference to the protected value. + * + * Note: Not thread safe + * + */ + T const& value() const + { + return value_; + } + /** + * mutex getter. + * + * Return: A constant reference to the protecting mutex. + * + * Note: Not thread safe + * + */ + mutex_type const& mutex() const + { + return mtx_; + } + /** + * Swap + * + * Effects: Swaps the data. Again, locks are acquired using lock(). The mutexes are not swapped. + * A swap method accepts a T& and swaps the data inside a critical section. + * This is by far the preferred method of changing the guarded datum wholesale because it keeps the lock only + * for a short time, thus lowering the pressure on the mutex. + */ + void swap(synchronized_value & rhs) + { + if (this == &rhs) { + return; + } + // auto _ = make_unique_locks(mtx_, rhs.mtx_); + unique_lock<mutex_type> lk1(mtx_, defer_lock); + unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock); + lock(lk1,lk2); + boost::swap(value_, rhs.value_); + } + /** + * Swap with the underlying value type + * + * Effects: Swaps the data on a scope protected by the mutex. + */ + void swap(value_type & rhs) + { + strict_lock<mutex_type> lk(mtx_); + boost::swap(value_, rhs); + } + + /** + * Essentially calling a method obj->foo(x, y, z) calls the method foo(x, y, z) inside a critical section as + * long-lived as the call itself. + */ + strict_lock_ptr<T,Lockable> operator->() + { + return BOOST_THREAD_MAKE_RV_REF((strict_lock_ptr<T,Lockable>(value_, mtx_))); + } + /** + * If the synchronized_value object involved is const-qualified, then you'll only be able to call const methods + * through operator->. So, for example, vec->push_back("xyz") won't work if vec were const-qualified. + * The locking mechanism capitalizes on the assumption that const methods don't modify their underlying data. + */ + const_strict_lock_ptr<T,Lockable> operator->() const + { + return BOOST_THREAD_MAKE_RV_REF((const_strict_lock_ptr<T,Lockable>(value_, mtx_))); + } + + /** + * Call function on a locked block. + * + * @requires fct(value_) is well formed. + * + * Example + * void fun(synchronized_value<vector<int>> & v) { + * v ( [](vector<int>> & vec) + * { + * vec.push_back(42); + * assert(vec.back() == 42); + * } ); + * } + */ + template <typename F> + inline + typename boost::result_of<F(value_type&)>::type + operator()(BOOST_THREAD_RV_REF(F) fct) + { + strict_lock<mutex_type> lk(mtx_); + return fct(value_); + } + template <typename F> + inline + typename boost::result_of<F(value_type const&)>::type + operator()(BOOST_THREAD_RV_REF(F) fct) const + { + strict_lock<mutex_type> lk(mtx_); + return fct(value_); + } + + +#if defined BOOST_NO_CXX11_RVALUE_REFERENCES + template <typename F> + inline + typename boost::result_of<F(value_type&)>::type + operator()(F const & fct) + { + strict_lock<mutex_type> lk(mtx_); + return fct(value_); + } + template <typename F> + inline + typename boost::result_of<F(value_type const&)>::type + operator()(F const & fct) const + { + strict_lock<mutex_type> lk(mtx_); + return fct(value_); + } + + template <typename R> + inline + R operator()(R(*fct)(value_type&)) + { + strict_lock<mutex_type> lk(mtx_); + return fct(value_); + } + template <typename R> + inline + R operator()(R(*fct)(value_type const&)) const + { + strict_lock<mutex_type> lk(mtx_); + return fct(value_); + } +#endif + + + /** + * The synchronize() factory make easier to lock on a scope. + * As discussed, operator-> can only lock over the duration of a call, so it is insufficient for complex operations. + * With synchronize() you get to lock the object in a scoped and to directly access the object inside that scope. + * + * Example + * void fun(synchronized_value<vector<int>> & v) { + * auto&& vec=v.synchronize(); + * vec.push_back(42); + * assert(vec.back() == 42); + * } + */ + strict_lock_ptr<T,Lockable> synchronize() + { + return BOOST_THREAD_MAKE_RV_REF((strict_lock_ptr<T,Lockable>(value_, mtx_))); + } + const_strict_lock_ptr<T,Lockable> synchronize() const + { + return BOOST_THREAD_MAKE_RV_REF((const_strict_lock_ptr<T,Lockable>(value_, mtx_))); + } + + unique_lock_ptr<T,Lockable> unique_synchronize() + { + return BOOST_THREAD_MAKE_RV_REF((unique_lock_ptr<T,Lockable>(value_, mtx_))); + } + const_unique_lock_ptr<T,Lockable> unique_synchronize() const + { + return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr<T,Lockable>(value_, mtx_))); + } + unique_lock_ptr<T,Lockable> unique_synchronize(defer_lock_t tag) + { + return BOOST_THREAD_MAKE_RV_REF((unique_lock_ptr<T,Lockable>(value_, mtx_, tag))); + } + const_unique_lock_ptr<T,Lockable> unique_synchronize(defer_lock_t tag) const + { + return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr<T,Lockable>(value_, mtx_, tag))); + } + unique_lock_ptr<T,Lockable> defer_synchronize() BOOST_NOEXCEPT + { + return BOOST_THREAD_MAKE_RV_REF((unique_lock_ptr<T,Lockable>(value_, mtx_, defer_lock))); + } + const_unique_lock_ptr<T,Lockable> defer_synchronize() const BOOST_NOEXCEPT + { + return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr<T,Lockable>(value_, mtx_, defer_lock))); + } + unique_lock_ptr<T,Lockable> try_to_synchronize() BOOST_NOEXCEPT + { + return BOOST_THREAD_MAKE_RV_REF((unique_lock_ptr<T,Lockable>(value_, mtx_, try_to_lock))); + } + const_unique_lock_ptr<T,Lockable> try_to_synchronize() const BOOST_NOEXCEPT + { + return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr<T,Lockable>(value_, mtx_, try_to_lock))); + } + unique_lock_ptr<T,Lockable> adopt_synchronize() BOOST_NOEXCEPT + { + return BOOST_THREAD_MAKE_RV_REF((unique_lock_ptr<T,Lockable>(value_, mtx_, adopt_lock))); + } + const_unique_lock_ptr<T,Lockable> adopt_synchronize() const BOOST_NOEXCEPT + { + return BOOST_THREAD_MAKE_RV_REF((const_unique_lock_ptr<T,Lockable>(value_, mtx_, adopt_lock))); + } + + +#if ! defined __IBMCPP__ + private: +#endif + class deref_value + { + private: + friend class synchronized_value; + + boost::unique_lock<mutex_type> lk_; + T& value_; + + explicit deref_value(synchronized_value& outer): + lk_(outer.mtx_),value_(outer.value_) + {} + + public: + BOOST_THREAD_MOVABLE_ONLY(deref_value) + + deref_value(BOOST_THREAD_RV_REF(deref_value) other): + lk_(boost::move(BOOST_THREAD_RV(other).lk_)),value_(BOOST_THREAD_RV(other).value_) + {} + operator T&() + { + return value_; + } + + deref_value& operator=(T const& newVal) + { + value_=newVal; + return *this; + } + }; + class const_deref_value + { + private: + friend class synchronized_value; + + boost::unique_lock<mutex_type> lk_; + const T& value_; + + explicit const_deref_value(synchronized_value const& outer): + lk_(outer.mtx_), value_(outer.value_) + {} + + public: + BOOST_THREAD_MOVABLE_ONLY(const_deref_value) + + const_deref_value(BOOST_THREAD_RV_REF(const_deref_value) other): + lk_(boost::move(BOOST_THREAD_RV(other).lk_)), value_(BOOST_THREAD_RV(other).value_) + {} + + operator const T&() + { + return value_; + } + }; + + public: + deref_value operator*() + { + return BOOST_THREAD_MAKE_RV_REF(deref_value(*this)); + } + + const_deref_value operator*() const + { + return BOOST_THREAD_MAKE_RV_REF(const_deref_value(*this)); + } + + // io functions + /** + * @requires T is OutputStreamable + * @effects saves the value type on the output stream @c os. + */ + template <typename OStream> + void save(OStream& os) const + { + strict_lock<mutex_type> lk(mtx_); + os << value_; + } + /** + * @requires T is InputStreamable + * @effects loads the value type from the input stream @c is. + */ + template <typename IStream> + void load(IStream& is) const + { + strict_lock<mutex_type> lk(mtx_); + is >> value_; + } + + // relational operators + /** + * @requires T is EqualityComparable + * + */ + bool operator==(synchronized_value const& rhs) const + { + unique_lock<mutex_type> lk1(mtx_, defer_lock); + unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock); + lock(lk1,lk2); + + return value_ == rhs.value_; + } + /** + * @requires T is LessThanComparable + * + */ + bool operator<(synchronized_value const& rhs) const + { + unique_lock<mutex_type> lk1(mtx_, defer_lock); + unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock); + lock(lk1,lk2); + + return value_ < rhs.value_; + } + /** + * @requires T is GreaterThanComparable + * + */ + bool operator>(synchronized_value const& rhs) const + { + unique_lock<mutex_type> lk1(mtx_, defer_lock); + unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock); + lock(lk1,lk2); + + return value_ > rhs.value_; + } + bool operator<=(synchronized_value const& rhs) const + { + unique_lock<mutex_type> lk1(mtx_, defer_lock); + unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock); + lock(lk1,lk2); + + return value_ <= rhs.value_; + } + bool operator>=(synchronized_value const& rhs) const + { + unique_lock<mutex_type> lk1(mtx_, defer_lock); + unique_lock<mutex_type> lk2(rhs.mtx_, defer_lock); + lock(lk1,lk2); + + return value_ >= rhs.value_; + } + bool operator==(value_type const& rhs) const + { + unique_lock<mutex_type> lk1(mtx_); + + return value_ == rhs; + } + bool operator!=(value_type const& rhs) const + { + unique_lock<mutex_type> lk1(mtx_); + + return value_ != rhs; + } + bool operator<(value_type const& rhs) const + { + unique_lock<mutex_type> lk1(mtx_); + + return value_ < rhs; + } + bool operator<=(value_type const& rhs) const + { + unique_lock<mutex_type> lk1(mtx_); + + return value_ <= rhs; + } + bool operator>(value_type const& rhs) const + { + unique_lock<mutex_type> lk1(mtx_); + + return value_ > rhs; + } + bool operator>=(value_type const& rhs) const + { + unique_lock<mutex_type> lk1(mtx_); + + return value_ >= rhs; + } + + }; + + // Specialized algorithms + /** + * + */ + template <typename T, typename L> + inline void swap(synchronized_value<T,L> & lhs, synchronized_value<T,L> & rhs) + { + lhs.swap(rhs); + } + template <typename T, typename L> + inline void swap(synchronized_value<T,L> & lhs, T & rhs) + { + lhs.swap(rhs); + } + template <typename T, typename L> + inline void swap(T & lhs, synchronized_value<T,L> & rhs) + { + rhs.swap(lhs); + } + + //Hash support + +// template <class T> struct hash; +// template <typename T, typename L> +// struct hash<synchronized_value<T,L> >; + + // Comparison with T + template <typename T, typename L> + bool operator!=(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs) + { + return ! (lhs==rhs); + } + + template <typename T, typename L> + bool operator==(T const& lhs, synchronized_value<T,L> const&rhs) + { + return rhs==lhs; + } + template <typename T, typename L> + bool operator!=(T const& lhs, synchronized_value<T,L> const&rhs) + { + return rhs!=lhs; + } + template <typename T, typename L> + bool operator<(T const& lhs, synchronized_value<T,L> const&rhs) + { + return rhs>=lhs; + } + template <typename T, typename L> + bool operator<=(T const& lhs, synchronized_value<T,L> const&rhs) + { + return rhs>lhs; + } + template <typename T, typename L> + bool operator>(T const& lhs, synchronized_value<T,L> const&rhs) + { + return rhs<=lhs; + } + template <typename T, typename L> + bool operator>=(T const& lhs, synchronized_value<T,L> const&rhs) + { + return rhs<lhs; + } + + /** + * + */ + template <typename OStream, typename T, typename L> + inline OStream& operator<<(OStream& os, synchronized_value<T,L> const& rhs) + { + rhs.save(os); + return os; + } + template <typename IStream, typename T, typename L> + inline IStream& operator>>(IStream& is, synchronized_value<T,L> const& rhs) + { + rhs.load(is); + return is; + } + +#if ! defined(BOOST_THREAD_NO_SYNCHRONIZE) +#if ! defined BOOST_NO_CXX11_VARIADIC_TEMPLATES + + template <typename ...SV> + std::tuple<typename synchronized_value_strict_lock_ptr<SV>::type ...> synchronize(SV& ...sv) + { + boost::lock(sv.mtx_ ...); + typedef std::tuple<typename synchronized_value_strict_lock_ptr<SV>::type ...> t_type; + + return t_type(typename synchronized_value_strict_lock_ptr<SV>::type(sv.value_, sv.mtx_, adopt_lock) ...); + } +#else + + template <typename SV1, typename SV2> + std::tuple< + typename synchronized_value_strict_lock_ptr<SV1>::type, + typename synchronized_value_strict_lock_ptr<SV2>::type + > + synchronize(SV1& sv1, SV2& sv2) + { + boost::lock(sv1.mtx_, sv2.mtx_); + typedef std::tuple< + typename synchronized_value_strict_lock_ptr<SV1>::type, + typename synchronized_value_strict_lock_ptr<SV2>::type + > t_type; + + return t_type( + typename synchronized_value_strict_lock_ptr<SV1>::type(sv1.value_, sv1.mtx_, adopt_lock), + typename synchronized_value_strict_lock_ptr<SV2>::type(sv2.value_, sv2.mtx_, adopt_lock) + ); + + } + template <typename SV1, typename SV2, typename SV3> + std::tuple< + typename synchronized_value_strict_lock_ptr<SV1>::type, + typename synchronized_value_strict_lock_ptr<SV2>::type, + typename synchronized_value_strict_lock_ptr<SV3>::type + > + synchronize(SV1& sv1, SV2& sv2, SV3& sv3) + { + boost::lock(sv1.mtx_, sv2.mtx_); + typedef std::tuple< + typename synchronized_value_strict_lock_ptr<SV1>::type, + typename synchronized_value_strict_lock_ptr<SV2>::type, + typename synchronized_value_strict_lock_ptr<SV3>::type + > t_type; + + return t_type( + typename synchronized_value_strict_lock_ptr<SV1>::type(sv1.value_, sv1.mtx_, adopt_lock), + typename synchronized_value_strict_lock_ptr<SV2>::type(sv2.value_, sv2.mtx_, adopt_lock), + typename synchronized_value_strict_lock_ptr<SV3>::type(sv3.value_, sv3.mtx_, adopt_lock) + ); + + } +#endif +#endif +} + +#include <boost/config/abi_suffix.hpp> + +#endif // header diff --git a/boost/thread/testable_mutex.hpp b/boost/thread/testable_mutex.hpp new file mode 100644 index 0000000000..3c87f9349a --- /dev/null +++ b/boost/thread/testable_mutex.hpp @@ -0,0 +1,152 @@ +// (C) Copyright 2012 Vicente J. Botet Escriba +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +#ifndef BOOST_THREAD_TESTABLE_LOCKABLE_HPP +#define BOOST_THREAD_TESTABLE_LOCKABLE_HPP + +#include <boost/thread/detail/config.hpp> + +#include <boost/thread/thread_only.hpp> + +#include <boost/atomic.hpp> +#include <boost/assert.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + /** + * Based on Associate Mutexes with Data to Prevent Races, By Herb Sutter, May 13, 2010 + * http://www.drdobbs.com/windows/associate-mutexes-with-data-to-prevent-r/224701827?pgno=3 + * + * Make our mutex testable if it isn't already. + * + * Many mutex services (including boost::mutex) don't provide a way to ask, + * "Do I already hold a lock on this mutex?" + * Sometimes it is needed to know if a method like is_locked to be available. + * This wrapper associates an arbitrary lockable type with a thread id that stores the ID of the thread that + * currently holds the lockable. The thread id initially holds an invalid value that means no threads own the mutex. + * When we acquire a lock, we set the thread id; and when we release a lock, we reset it back to its default no id state. + * + */ + template <typename Lockable> + class testable_mutex + { + Lockable mtx_; + atomic<thread::id> id_; + public: + /// the type of the wrapped lockable + typedef Lockable lockable_type; + + /// Non copyable + BOOST_THREAD_NO_COPYABLE(testable_mutex) + + testable_mutex() : id_(thread::id()) {} + + void lock() + { + BOOST_ASSERT(! is_locked_by_this_thread()); + mtx_.lock(); + id_ = this_thread::get_id(); + } + + void unlock() + { + BOOST_ASSERT(is_locked_by_this_thread()); + id_ = thread::id(); + mtx_.unlock(); + } + + bool try_lock() + { + BOOST_ASSERT(! is_locked_by_this_thread()); + if (mtx_.try_lock()) + { + id_ = this_thread::get_id(); + return true; + } + else + { + return false; + } + } +#ifdef BOOST_THREAD_USES_CHRONO + template <class Rep, class Period> + bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) + { + BOOST_ASSERT(! is_locked_by_this_thread()); + if (mtx_.try_lock_for(rel_time)) + { + id_ = this_thread::get_id(); + return true; + } + else + { + return false; + } + } + template <class Clock, class Duration> + bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time) + { + BOOST_ASSERT(! is_locked_by_this_thread()); + if (mtx_.try_lock_until(abs_time)) + { + id_ = this_thread::get_id(); + return true; + } + else + { + return false; + } + } +#endif + + bool is_locked_by_this_thread() const + { + return this_thread::get_id() == id_; + } + bool is_locked() const + { + return ! (thread::id() == id_); + } + + thread::id get_id() const + { + return id_; + } + + // todo add the shared and upgrade mutex functions + }; + + template <typename Lockable> + struct is_testable_lockable : false_type + {}; + + template <typename Lockable> + struct is_testable_lockable<testable_mutex<Lockable> > : true_type + {}; + +// /** +// * Overloaded function used to check if the mutex is locked when it is testable and do nothing otherwise. +// * +// * This function is used usually to assert the pre-condition when the function can only be called when the mutex +// * must be locked by the current thread. +// */ +// template <typename Lockable> +// bool is_locked_by_this_thread(testable_mutex<Lockable> const& mtx) +// { +// return mtx.is_locked(); +// } +// template <typename Lockable> +// bool is_locked_by_this_thread(Lockable const&) +// { +// return true; +// } +} + +#include <boost/config/abi_suffix.hpp> + +#endif // header diff --git a/boost/thread/thread.hpp b/boost/thread/thread.hpp index ee15c6e365..3e63b42aaa 100644 --- a/boost/thread/thread.hpp +++ b/boost/thread/thread.hpp @@ -9,20 +9,8 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#include <boost/thread/detail/platform.hpp> - -#if defined(BOOST_THREAD_PLATFORM_WIN32) -#include <boost/thread/win32/thread_data.hpp> -#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) -#include <boost/thread/pthread/thread_data.hpp> -#else -#error "Boost threads unavailable on this platform" -#endif - -#include <boost/thread/detail/thread.hpp> -#include <boost/thread/detail/thread_interruption.hpp> +#include <boost/thread/thread_only.hpp> #include <boost/thread/detail/thread_group.hpp> -#include <boost/thread/v2/thread.hpp> #endif diff --git a/boost/thread/thread_functors.hpp b/boost/thread/thread_functors.hpp new file mode 100644 index 0000000000..f7bd816b17 --- /dev/null +++ b/boost/thread/thread_functors.hpp @@ -0,0 +1,57 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2009-2012 Anthony Williams +// (C) Copyright 2012 Vicente J. Botet Escriba + +// Based on the Anthony's idea of scoped_thread in CCiA + +#ifndef BOOST_THREAD_THREAD_FUNCTORS_HPP +#define BOOST_THREAD_THREAD_FUNCTORS_HPP + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/delete.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/thread_only.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + + struct detach + { + void operator()(thread& t) + { + t.detach(); + } + }; + + struct join_if_joinable + { + void operator()(thread& t) + { + if (t.joinable()) + { + t.join(); + } + } + }; + +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + struct interrupt_and_join_if_joinable + { + void operator()(thread& t) + { + t.interrupt(); + if (t.joinable()) + { + t.join(); + } + } + }; +#endif +} +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/thread_guard.hpp b/boost/thread/thread_guard.hpp new file mode 100644 index 0000000000..85157f101e --- /dev/null +++ b/boost/thread/thread_guard.hpp @@ -0,0 +1,46 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2009-2012 Anthony Williams +// (C) Copyright 2012 Vicente J. Botet Escriba + +// Based on the Anthony's idea of thread_joiner in CCiA + +#ifndef BOOST_THREAD_THREAD_GUARD_HPP +#define BOOST_THREAD_THREAD_GUARD_HPP + +#include <boost/thread/detail/delete.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/thread_functors.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + + /** + * Non-copyable RAII scoped thread guard joiner which join the thread if joinable when destroyed. + */ + template <class CallableThread = join_if_joinable> + class thread_guard + { + thread& t_; + public: + BOOST_THREAD_NO_COPYABLE( thread_guard) + + explicit thread_guard(thread& t) : + t_(t) + { + } + ~thread_guard() + { + CallableThread on_destructor; + + on_destructor(t_); + } + }; + +} +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/thread_only.hpp b/boost/thread/thread_only.hpp new file mode 100644 index 0000000000..0d0c07061f --- /dev/null +++ b/boost/thread/thread_only.hpp @@ -0,0 +1,29 @@ +#ifndef BOOST_THREAD_THREAD_ONLY_HPP +#define BOOST_THREAD_THREAD_ONLY_HPP + +// thread.hpp +// +// (C) Copyright 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/thread/detail/platform.hpp> + +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#include <boost/thread/win32/thread_data.hpp> +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +#include <boost/thread/pthread/thread_data.hpp> +#else +#error "Boost threads unavailable on this platform" +#endif + +#include <boost/thread/detail/thread.hpp> +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS +#include <boost/thread/detail/thread_interruption.hpp> +#endif +#include <boost/thread/v2/thread.hpp> + + +#endif diff --git a/boost/thread/thread_pool.hpp b/boost/thread/thread_pool.hpp new file mode 100644 index 0000000000..4d2dcbea3a --- /dev/null +++ b/boost/thread/thread_pool.hpp @@ -0,0 +1,15 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2013/09 Vicente J. Botet Escriba +// Adapt to boost from CCIA C++11 implementation +// first implementation of a simple pool thread using a vector of threads and a sync_queue. + +#ifndef BOOST_THREAD_THREAD_POOL_HPP +#define BOOST_THREAD_THREAD_POOL_HPP + +#include <boost/thread/executors/basic_thread_pool.hpp> + +#endif diff --git a/boost/thread/tss.hpp b/boost/thread/tss.hpp index c920024b0f..d798bef558 100644 --- a/boost/thread/tss.hpp +++ b/boost/thread/tss.hpp @@ -19,10 +19,10 @@ namespace boost { virtual ~tss_cleanup_function() {} - + virtual void operator()(void* data)=0; }; - + BOOST_THREAD_DECL void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing); BOOST_THREAD_DECL void* get_tss_data(void const* key); } @@ -42,16 +42,16 @@ namespace boost delete static_cast<T*>(data); } }; - + struct run_custom_cleanup_function: detail::tss_cleanup_function { void (*cleanup_function)(T*); - + explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)): cleanup_function(cleanup_function_) {} - + void operator()(void* data) { cleanup_function(static_cast<T*>(data)); @@ -60,10 +60,10 @@ namespace boost boost::shared_ptr<detail::tss_cleanup_function> cleanup; - + public: typedef T element_type; - + thread_specific_ptr(): cleanup(detail::heap_new<delete_data>(),detail::do_heap_delete<delete_data>()) {} @@ -87,7 +87,7 @@ namespace boost { return get(); } - T& operator*() const + typename boost::detail::sp_dereference< T >::type operator*() const { return *get(); } diff --git a/boost/thread/user_scheduler.hpp b/boost/thread/user_scheduler.hpp new file mode 100644 index 0000000000..6305b9e26c --- /dev/null +++ b/boost/thread/user_scheduler.hpp @@ -0,0 +1,202 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// 2013/11 Vicente J. Botet Escriba +// first implementation of a simple serial scheduler. + +#ifndef BOOST_THREAD_USER_SCHEDULER_HPP +#define BOOST_THREAD_USER_SCHEDULER_HPP + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/delete.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/sync_queue.hpp> +#include <boost/thread/detail/work.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + + class user_scheduler + { + /// type-erasure to store the works to do + typedef thread_detail::work work; + + /// the thread safe work queue + sync_queue<work > work_queue; + + public: + /** + * Effects: try to execute one task. + * Returns: whether a task has been executed. + * Throws: whatever the current task constructor throws or the task() throws. + */ + bool try_executing_one() + { + work task; + try + { + if (work_queue.try_pull_front(task) == queue_op_status::success) + { + task(); + return true; + } + return false; + } + catch (std::exception& ) + { + return false; + } + catch (...) + { + 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(); + } + } + + + /** + * The main loop of the worker thread + */ + void worker_thread() + { + while (!closed()) + { + schedule_one_or_yield(); + } + while (try_executing_one()) + { + } + } + + public: + /// user_scheduler is not copyable. + BOOST_THREAD_NO_COPYABLE(user_scheduler) + + /** + * \b Effects: creates a thread pool that runs closures using one of its closure-executing methods. + * + * \b Throws: Whatever exception is thrown while initializing the needed resources. + */ + user_scheduler() + { + } + /** + * \b Effects: Destroys the thread pool. + * + * \b Synchronization: The completion of all the closures happen before the completion of the \c user_scheduler destructor. + */ + ~user_scheduler() + { + // signal to all the worker thread that there will be no more submissions. + close(); + } + + /** + * loop + */ + void loop() { worker_thread(); } + /** + * \b Effects: close the \c user_scheduler for submissions. + * The loop will work until there is no more closures to run. + */ + void close() + { + work_queue.close(); + } + + /** + * \b Returns: whether the pool is closed for submissions. + */ + bool closed() + { + return work_queue.closed(); + } + + /** + * \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible. + * + * \b Effects: The specified \c closure will be scheduled for execution at some point in the future. + * If invoked closure throws an exception the \c user_scheduler will call \c std::terminate, as is the case with threads. + * + * \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables. + * + * \b Throws: \c sync_queue_is_closed if the thread pool is closed. + * Whatever exception that can be throw while storing the closure. + */ + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template <typename Closure> + void submit(Closure & closure) + { + work w ((closure)); + work_queue.push_back(boost::move(w)); + //work_queue.push(work(closure)); // todo check why this doesn't work + } +#endif + void submit(void (*closure)()) + { + work w ((closure)); + work_queue.push_back(boost::move(w)); + //work_queue.push_back(work(closure)); // todo check why this doesn't work + } + + template <typename Closure> + void submit(BOOST_THREAD_RV_REF(Closure) closure) + { + work w =boost::move(closure); + work_queue.push_back(boost::move(w)); + //work_queue.push_back(work(boost::move(closure))); // todo check why this doesn't work + } + + /** + * \b Requires: This must be called from an scheduled task. + * + * \b Effects: reschedule functions until pred() + */ + template <typename Pred> + bool reschedule_until(Pred const& pred) + { + do { + if ( ! try_executing_one()) + { + return false; + } + } while (! pred()); + return true; + } + /** + * run queued closures + */ + void run_queued_closures() + { + sync_queue<work>::underlying_queue_type q = work_queue.underlying_queue(); + while (q.empty()) + { + work task = q.front(); + q.pop_front(); + task(); + } + } + + }; + +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/v2/shared_mutex.hpp b/boost/thread/v2/shared_mutex.hpp new file mode 100755 index 0000000000..5acab4d8cd --- /dev/null +++ b/boost/thread/v2/shared_mutex.hpp @@ -0,0 +1,1062 @@ +#ifndef BOOST_THREAD_V2_SHARED_MUTEX_HPP +#define BOOST_THREAD_V2_SHARED_MUTEX_HPP + +// shared_mutex.hpp +// +// Copyright Howard Hinnant 2007-2010. +// Copyright Vicente J. Botet Escriba 2012. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +/* +<shared_mutex> synopsis + +namespace boost +{ +namespace thread_v2 +{ + +class shared_mutex +{ +public: + + shared_mutex(); + ~shared_mutex(); + + shared_mutex(const shared_mutex&) = delete; + shared_mutex& operator=(const shared_mutex&) = delete; + + // Exclusive ownership + + void lock(); + bool try_lock(); + template <class Rep, class Period> + bool try_lock_for(const boost::chrono::duration<Rep, Period>& rel_time); + template <class Clock, class Duration> + bool + try_lock_until( + const boost::chrono::time_point<Clock, Duration>& abs_time); + void unlock(); + + // Shared ownership + + void lock_shared(); + bool try_lock_shared(); + template <class Rep, class Period> + bool + try_lock_shared_for(const boost::chrono::duration<Rep, Period>& rel_time); + template <class Clock, class Duration> + bool + try_lock_shared_until( + const boost::chrono::time_point<Clock, Duration>& abs_time); + void unlock_shared(); +}; + +class upgrade_mutex +{ +public: + + upgrade_mutex(); + ~upgrade_mutex(); + + upgrade_mutex(const upgrade_mutex&) = delete; + upgrade_mutex& operator=(const upgrade_mutex&) = delete; + + // Exclusive ownership + + void lock(); + bool try_lock(); + template <class Rep, class Period> + bool try_lock_for(const boost::chrono::duration<Rep, Period>& rel_time); + template <class Clock, class Duration> + bool + try_lock_until( + const boost::chrono::time_point<Clock, Duration>& abs_time); + void unlock(); + + // Shared ownership + + void lock_shared(); + bool try_lock_shared(); + template <class Rep, class Period> + bool + try_lock_shared_for(const boost::chrono::duration<Rep, Period>& rel_time); + template <class Clock, class Duration> + bool + try_lock_shared_until( + const boost::chrono::time_point<Clock, Duration>& abs_time); + void unlock_shared(); + + // Upgrade ownership + + void lock_upgrade(); + bool try_lock_upgrade(); + template <class Rep, class Period> + bool + try_lock_upgrade_for( + const boost::chrono::duration<Rep, Period>& rel_time); + template <class Clock, class Duration> + bool + try_lock_upgrade_until( + const boost::chrono::time_point<Clock, Duration>& abs_time); + void unlock_upgrade(); + + // Shared <-> Exclusive + + bool try_unlock_shared_and_lock(); + template <class Rep, class Period> + bool + try_unlock_shared_and_lock_for( + const boost::chrono::duration<Rep, Period>& rel_time); + template <class Clock, class Duration> + bool + try_unlock_shared_and_lock_until( + const boost::chrono::time_point<Clock, Duration>& abs_time); + void unlock_and_lock_shared(); + + // Shared <-> Upgrade + + bool try_unlock_shared_and_lock_upgrade(); + template <class Rep, class Period> + bool + try_unlock_shared_and_lock_upgrade_for( + const boost::chrono::duration<Rep, Period>& rel_time); + template <class Clock, class Duration> + bool + try_unlock_shared_and_lock_upgrade_until( + const boost::chrono::time_point<Clock, Duration>& abs_time); + void unlock_upgrade_and_lock_shared(); + + // Upgrade <-> Exclusive + + void unlock_upgrade_and_lock(); + bool try_unlock_upgrade_and_lock(); + template <class Rep, class Period> + bool + try_unlock_upgrade_and_lock_for( + const boost::chrono::duration<Rep, Period>& rel_time); + template <class Clock, class Duration> + bool + try_unlock_upgrade_and_lock_until( + const boost::chrono::time_point<Clock, Duration>& abs_time); + void unlock_and_lock_upgrade(); +}; + +} // thread_v2 +} // boost + + */ + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/mutex.hpp> +#include <boost/thread/condition_variable.hpp> +#include <boost/thread/mutex.hpp> +#include <boost/chrono.hpp> +#include <climits> +#include <boost/system/system_error.hpp> +#define BOOST_THREAD_INLINE inline + +namespace boost { + namespace thread_v2 { + + class shared_mutex + { + typedef ::boost::mutex mutex_t; + typedef ::boost::condition_variable cond_t; + typedef unsigned count_t; + + mutex_t mut_; + cond_t gate1_; + cond_t gate2_; + count_t state_; + + static const count_t write_entered_ = 1U << (sizeof(count_t)*CHAR_BIT - 1); + static const count_t n_readers_ = ~write_entered_; + + public: + BOOST_THREAD_INLINE shared_mutex(); + BOOST_THREAD_INLINE ~shared_mutex(); + +#ifndef BOOST_NO_CXX11_DELETED_FUNCTIONS + shared_mutex(shared_mutex const&) = delete; + shared_mutex& operator=(shared_mutex const&) = delete; +#else // BOOST_NO_CXX11_DELETED_FUNCTIONS + private: + shared_mutex(shared_mutex const&); + shared_mutex& operator=(shared_mutex const&); + public: +#endif // BOOST_NO_CXX11_DELETED_FUNCTIONS + + // Exclusive ownership + + BOOST_THREAD_INLINE void lock(); + BOOST_THREAD_INLINE bool try_lock(); + template <class Rep, class Period> + bool try_lock_for(const boost::chrono::duration<Rep, Period>& rel_time) + { + return try_lock_until(boost::chrono::steady_clock::now() + rel_time); + } + template <class Clock, class Duration> + bool + try_lock_until( + const boost::chrono::time_point<Clock, Duration>& abs_time); + BOOST_THREAD_INLINE void unlock(); + + + // Shared ownership + + BOOST_THREAD_INLINE void lock_shared(); + BOOST_THREAD_INLINE bool try_lock_shared(); + template <class Rep, class Period> + bool + try_lock_shared_for(const boost::chrono::duration<Rep, Period>& rel_time) + { + return try_lock_shared_until(boost::chrono::steady_clock::now() + + rel_time); + } + template <class Clock, class Duration> + bool + try_lock_shared_until( + const boost::chrono::time_point<Clock, Duration>& abs_time); + BOOST_THREAD_INLINE void unlock_shared(); + +#if defined BOOST_THREAD_USES_DATETIME + bool timed_lock(system_time const& timeout); + template<typename TimeDuration> + bool timed_lock(TimeDuration const & relative_time) + { + return timed_lock(get_system_time()+relative_time); + } + bool timed_lock_shared(system_time const& timeout); + template<typename TimeDuration> + bool timed_lock_shared(TimeDuration const & relative_time) + { + return timed_lock_shared(get_system_time()+relative_time); + } +#endif + }; + + template <class Clock, class Duration> + bool + shared_mutex::try_lock_until( + const boost::chrono::time_point<Clock, Duration>& abs_time) + { + boost::unique_lock<mutex_t> lk(mut_); + if (state_ & write_entered_) + { + while (true) + { + boost::cv_status status = gate1_.wait_until(lk, abs_time); + if ((state_ & write_entered_) == 0) + break; + if (status == boost::cv_status::timeout) + return false; + } + } + state_ |= write_entered_; + if (state_ & n_readers_) + { + while (true) + { + boost::cv_status status = gate2_.wait_until(lk, abs_time); + if ((state_ & n_readers_) == 0) + break; + if (status == boost::cv_status::timeout) + { + state_ &= ~write_entered_; + return false; + } + } + } + return true; + } + + template <class Clock, class Duration> + bool + shared_mutex::try_lock_shared_until( + const boost::chrono::time_point<Clock, Duration>& abs_time) + { + boost::unique_lock<mutex_t> lk(mut_); + if ((state_ & write_entered_) || (state_ & n_readers_) == n_readers_) + { + while (true) + { + boost::cv_status status = gate1_.wait_until(lk, abs_time); + if ((state_ & write_entered_) == 0 && + (state_ & n_readers_) < n_readers_) + break; + if (status == boost::cv_status::timeout) + return false; + } + } + count_t num_readers = (state_ & n_readers_) + 1; + state_ &= ~n_readers_; + state_ |= num_readers; + return true; + } + +#if defined BOOST_THREAD_USES_DATETIME + bool shared_mutex::timed_lock(system_time const& abs_time) + { + boost::unique_lock<mutex_t> lk(mut_); + if (state_ & write_entered_) + { + while (true) + { + bool status = gate1_.timed_wait(lk, abs_time); + if ((state_ & write_entered_) == 0) + break; + if (!status) + return false; + } + } + state_ |= write_entered_; + if (state_ & n_readers_) + { + while (true) + { + bool status = gate2_.timed_wait(lk, abs_time); + if ((state_ & n_readers_) == 0) + break; + if (!status) + { + state_ &= ~write_entered_; + return false; + } + } + } + return true; + } + bool shared_mutex::timed_lock_shared(system_time const& abs_time) + { + boost::unique_lock<mutex_t> lk(mut_); + if (state_ & write_entered_) + { + while (true) + { + bool status = gate1_.timed_wait(lk, abs_time); + if ((state_ & write_entered_) == 0) + break; + if (!status ) + return false; + } + } + state_ |= write_entered_; + if (state_ & n_readers_) + { + while (true) + { + bool status = gate2_.timed_wait(lk, abs_time); + if ((state_ & n_readers_) == 0) + break; + if (!status) + { + state_ &= ~write_entered_; + return false; + } + } + } + return true; + } +#endif + class upgrade_mutex + { + typedef boost::mutex mutex_t; + typedef boost::condition_variable cond_t; + typedef unsigned count_t; + + mutex_t mut_; + cond_t gate1_; + cond_t gate2_; + count_t state_; + + static const unsigned write_entered_ = 1U << (sizeof(count_t)*CHAR_BIT - 1); + static const unsigned upgradable_entered_ = write_entered_ >> 1; + static const unsigned n_readers_ = ~(write_entered_ | upgradable_entered_); + + public: + + BOOST_THREAD_INLINE upgrade_mutex(); + BOOST_THREAD_INLINE ~upgrade_mutex(); + +#ifndef BOOST_CXX11_NO_DELETED_FUNCTIONS + upgrade_mutex(const upgrade_mutex&) = delete; + upgrade_mutex& operator=(const upgrade_mutex&) = delete; +#else // BOOST_CXX11_NO_DELETED_FUNCTIONS + private: + upgrade_mutex(const upgrade_mutex&); + upgrade_mutex& operator=(const upgrade_mutex&); + public: +#endif // BOOST_CXX11_NO_DELETED_FUNCTIONS + + // Exclusive ownership + + BOOST_THREAD_INLINE void lock(); + BOOST_THREAD_INLINE bool try_lock(); + template <class Rep, class Period> + bool try_lock_for(const boost::chrono::duration<Rep, Period>& rel_time) + { + return try_lock_until(boost::chrono::steady_clock::now() + rel_time); + } + template <class Clock, class Duration> + bool + try_lock_until( + const boost::chrono::time_point<Clock, Duration>& abs_time); + BOOST_THREAD_INLINE void unlock(); + + // Shared ownership + + BOOST_THREAD_INLINE void lock_shared(); + BOOST_THREAD_INLINE bool try_lock_shared(); + template <class Rep, class Period> + bool + try_lock_shared_for(const boost::chrono::duration<Rep, Period>& rel_time) + { + return try_lock_shared_until(boost::chrono::steady_clock::now() + + rel_time); + } + template <class Clock, class Duration> + bool + try_lock_shared_until( + const boost::chrono::time_point<Clock, Duration>& abs_time); + BOOST_THREAD_INLINE void unlock_shared(); + + // Upgrade ownership + + BOOST_THREAD_INLINE void lock_upgrade(); + BOOST_THREAD_INLINE bool try_lock_upgrade(); + template <class Rep, class Period> + bool + try_lock_upgrade_for( + const boost::chrono::duration<Rep, Period>& rel_time) + { + return try_lock_upgrade_until(boost::chrono::steady_clock::now() + + rel_time); + } + template <class Clock, class Duration> + bool + try_lock_upgrade_until( + const boost::chrono::time_point<Clock, Duration>& abs_time); + BOOST_THREAD_INLINE void unlock_upgrade(); + + // Shared <-> Exclusive + + BOOST_THREAD_INLINE bool try_unlock_shared_and_lock(); + template <class Rep, class Period> + bool + try_unlock_shared_and_lock_for( + const boost::chrono::duration<Rep, Period>& rel_time) + { + return try_unlock_shared_and_lock_until( + boost::chrono::steady_clock::now() + rel_time); + } + template <class Clock, class Duration> + bool + try_unlock_shared_and_lock_until( + const boost::chrono::time_point<Clock, Duration>& abs_time); + BOOST_THREAD_INLINE void unlock_and_lock_shared(); + + // Shared <-> Upgrade + + BOOST_THREAD_INLINE bool try_unlock_shared_and_lock_upgrade(); + template <class Rep, class Period> + bool + try_unlock_shared_and_lock_upgrade_for( + const boost::chrono::duration<Rep, Period>& rel_time) + { + return try_unlock_shared_and_lock_upgrade_until( + boost::chrono::steady_clock::now() + rel_time); + } + template <class Clock, class Duration> + bool + try_unlock_shared_and_lock_upgrade_until( + const boost::chrono::time_point<Clock, Duration>& abs_time); + BOOST_THREAD_INLINE void unlock_upgrade_and_lock_shared(); + + // Upgrade <-> Exclusive + + BOOST_THREAD_INLINE void unlock_upgrade_and_lock(); + BOOST_THREAD_INLINE bool try_unlock_upgrade_and_lock(); + template <class Rep, class Period> + bool + try_unlock_upgrade_and_lock_for( + const boost::chrono::duration<Rep, Period>& rel_time) + { + return try_unlock_upgrade_and_lock_until( + boost::chrono::steady_clock::now() + rel_time); + } + template <class Clock, class Duration> + bool + try_unlock_upgrade_and_lock_until( + const boost::chrono::time_point<Clock, Duration>& abs_time); + BOOST_THREAD_INLINE void unlock_and_lock_upgrade(); + +#if defined BOOST_THREAD_USES_DATETIME + inline bool timed_lock(system_time const& abs_time); + template<typename TimeDuration> + bool timed_lock(TimeDuration const & relative_time) + { + return timed_lock(get_system_time()+relative_time); + } + inline bool timed_lock_shared(system_time const& abs_time); + template<typename TimeDuration> + bool timed_lock_shared(TimeDuration const & relative_time) + { + return timed_lock_shared(get_system_time()+relative_time); + } + inline bool timed_lock_upgrade(system_time const& abs_time); + template<typename TimeDuration> + bool timed_lock_upgrade(TimeDuration const & relative_time) + { + return timed_lock_upgrade(get_system_time()+relative_time); + } +#endif + + }; + + template <class Clock, class Duration> + bool + upgrade_mutex::try_lock_until( + const boost::chrono::time_point<Clock, Duration>& abs_time) + { + boost::unique_lock<mutex_t> lk(mut_); + if (state_ & (write_entered_ | upgradable_entered_)) + { + while (true) + { + boost::cv_status status = gate1_.wait_until(lk, abs_time); + if ((state_ & (write_entered_ | upgradable_entered_)) == 0) + break; + if (status == boost::cv_status::timeout) + return false; + } + } + state_ |= write_entered_; + if (state_ & n_readers_) + { + while (true) + { + boost::cv_status status = gate2_.wait_until(lk, abs_time); + if ((state_ & n_readers_) == 0) + break; + if (status == boost::cv_status::timeout) + { + state_ &= ~write_entered_; + return false; + } + } + } + return true; + } + + template <class Clock, class Duration> + bool + upgrade_mutex::try_lock_shared_until( + const boost::chrono::time_point<Clock, Duration>& abs_time) + { + boost::unique_lock<mutex_t> lk(mut_); + if ((state_ & write_entered_) || (state_ & n_readers_) == n_readers_) + { + while (true) + { + boost::cv_status status = gate1_.wait_until(lk, abs_time); + if ((state_ & write_entered_) == 0 && + (state_ & n_readers_) < n_readers_) + break; + if (status == boost::cv_status::timeout) + return false; + } + } + count_t num_readers = (state_ & n_readers_) + 1; + state_ &= ~n_readers_; + state_ |= num_readers; + return true; + } + + template <class Clock, class Duration> + bool + upgrade_mutex::try_lock_upgrade_until( + const boost::chrono::time_point<Clock, Duration>& abs_time) + { + boost::unique_lock<mutex_t> lk(mut_); + if ((state_ & (write_entered_ | upgradable_entered_)) || + (state_ & n_readers_) == n_readers_) + { + while (true) + { + boost::cv_status status = gate1_.wait_until(lk, abs_time); + if ((state_ & (write_entered_ | upgradable_entered_)) == 0 && + (state_ & n_readers_) < n_readers_) + break; + if (status == boost::cv_status::timeout) + return false; + } + } + count_t num_readers = (state_ & n_readers_) + 1; + state_ &= ~n_readers_; + state_ |= upgradable_entered_ | num_readers; + return true; + } + +#if defined BOOST_THREAD_USES_DATETIME + bool upgrade_mutex::timed_lock(system_time const& abs_time) + { + boost::unique_lock<mutex_t> lk(mut_); + if (state_ & (write_entered_ | upgradable_entered_)) + { + while (true) + { + bool status = gate1_.timed_wait(lk, abs_time); + if ((state_ & (write_entered_ | upgradable_entered_)) == 0) + break; + if (!status) + return false; + } + } + state_ |= write_entered_; + if (state_ & n_readers_) + { + while (true) + { + bool status = gate2_.timed_wait(lk, abs_time); + if ((state_ & n_readers_) == 0) + break; + if (!status) + { + state_ &= ~write_entered_; + return false; + } + } + } + return true; + } + bool upgrade_mutex::timed_lock_shared(system_time const& abs_time) + { + boost::unique_lock<mutex_t> lk(mut_); + if ((state_ & write_entered_) || (state_ & n_readers_) == n_readers_) + { + while (true) + { + bool status = gate1_.timed_wait(lk, abs_time); + if ((state_ & write_entered_) == 0 && + (state_ & n_readers_) < n_readers_) + break; + if (!status) + return false; + } + } + count_t num_readers = (state_ & n_readers_) + 1; + state_ &= ~n_readers_; + state_ |= num_readers; + return true; + } + bool upgrade_mutex::timed_lock_upgrade(system_time const& abs_time) + { + boost::unique_lock<mutex_t> lk(mut_); + if ((state_ & (write_entered_ | upgradable_entered_)) || + (state_ & n_readers_) == n_readers_) + { + while (true) + { + bool status = gate1_.timed_wait(lk, abs_time); + if ((state_ & (write_entered_ | upgradable_entered_)) == 0 && + (state_ & n_readers_) < n_readers_) + break; + if (!status) + return false; + } + } + count_t num_readers = (state_ & n_readers_) + 1; + state_ &= ~n_readers_; + state_ |= upgradable_entered_ | num_readers; + return true; + } + +#endif + template <class Clock, class Duration> + bool + upgrade_mutex::try_unlock_shared_and_lock_until( + const boost::chrono::time_point<Clock, Duration>& abs_time) + { + boost::unique_lock<mutex_t> lk(mut_); + if (state_ != 1) + { + while (true) + { + boost::cv_status status = gate2_.wait_until(lk, abs_time); + if (state_ == 1) + break; + if (status == boost::cv_status::timeout) + return false; + } + } + state_ = write_entered_; + return true; + } + + template <class Clock, class Duration> + bool + upgrade_mutex::try_unlock_shared_and_lock_upgrade_until( + const boost::chrono::time_point<Clock, Duration>& abs_time) + { + boost::unique_lock<mutex_t> lk(mut_); + if ((state_ & (write_entered_ | upgradable_entered_)) != 0) + { + while (true) + { + boost::cv_status status = gate2_.wait_until(lk, abs_time); + if ((state_ & (write_entered_ | upgradable_entered_)) == 0) + break; + if (status == boost::cv_status::timeout) + return false; + } + } + state_ |= upgradable_entered_; + return true; + } + + template <class Clock, class Duration> + bool + upgrade_mutex::try_unlock_upgrade_and_lock_until( + const boost::chrono::time_point<Clock, Duration>& abs_time) + { + boost::unique_lock<mutex_t> lk(mut_); + if ((state_ & n_readers_) != 1) + { + while (true) + { + boost::cv_status status = gate2_.wait_until(lk, abs_time); + if ((state_ & n_readers_) == 1) + break; + if (status == boost::cv_status::timeout) + return false; + } + } + state_ = write_entered_; + return true; + } + + ////// + // shared_mutex + + shared_mutex::shared_mutex() + : state_(0) + { + } + + shared_mutex::~shared_mutex() + { + boost::lock_guard<mutex_t> _(mut_); + } + + // Exclusive ownership + + void + shared_mutex::lock() + { + boost::unique_lock<mutex_t> lk(mut_); + while (state_ & write_entered_) + gate1_.wait(lk); + state_ |= write_entered_; + while (state_ & n_readers_) + gate2_.wait(lk); + } + + bool + shared_mutex::try_lock() + { + boost::unique_lock<mutex_t> lk(mut_); + if (state_ == 0) + { + state_ = write_entered_; + return true; + } + return false; + } + + void + shared_mutex::unlock() + { + boost::lock_guard<mutex_t> _(mut_); + state_ = 0; + gate1_.notify_all(); + } + + // Shared ownership + + void + shared_mutex::lock_shared() + { + boost::unique_lock<mutex_t> lk(mut_); + while ((state_ & write_entered_) || (state_ & n_readers_) == n_readers_) + gate1_.wait(lk); + count_t num_readers = (state_ & n_readers_) + 1; + state_ &= ~n_readers_; + state_ |= num_readers; + } + + bool + shared_mutex::try_lock_shared() + { + boost::unique_lock<mutex_t> lk(mut_); + count_t num_readers = state_ & n_readers_; + if (!(state_ & write_entered_) && num_readers != n_readers_) + { + ++num_readers; + state_ &= ~n_readers_; + state_ |= num_readers; + return true; + } + return false; + } + + void + shared_mutex::unlock_shared() + { + boost::lock_guard<mutex_t> _(mut_); + count_t num_readers = (state_ & n_readers_) - 1; + state_ &= ~n_readers_; + state_ |= num_readers; + if (state_ & write_entered_) + { + if (num_readers == 0) + gate2_.notify_one(); + } + else + { + if (num_readers == n_readers_ - 1) + gate1_.notify_one(); + } + } + + // upgrade_mutex + + upgrade_mutex::upgrade_mutex() + : gate1_(), + gate2_(), + state_(0) + { + } + + upgrade_mutex::~upgrade_mutex() + { + boost::lock_guard<mutex_t> _(mut_); + } + + // Exclusive ownership + + void + upgrade_mutex::lock() + { + boost::unique_lock<mutex_t> lk(mut_); + while (state_ & (write_entered_ | upgradable_entered_)) + gate1_.wait(lk); + state_ |= write_entered_; + while (state_ & n_readers_) + gate2_.wait(lk); + } + + bool + upgrade_mutex::try_lock() + { + boost::unique_lock<mutex_t> lk(mut_); + if (state_ == 0) + { + state_ = write_entered_; + return true; + } + return false; + } + + void + upgrade_mutex::unlock() + { + boost::lock_guard<mutex_t> _(mut_); + state_ = 0; + gate1_.notify_all(); + } + + // Shared ownership + + void + upgrade_mutex::lock_shared() + { + boost::unique_lock<mutex_t> lk(mut_); + while ((state_ & write_entered_) || (state_ & n_readers_) == n_readers_) + gate1_.wait(lk); + count_t num_readers = (state_ & n_readers_) + 1; + state_ &= ~n_readers_; + state_ |= num_readers; + } + + bool + upgrade_mutex::try_lock_shared() + { + boost::unique_lock<mutex_t> lk(mut_); + count_t num_readers = state_ & n_readers_; + if (!(state_ & write_entered_) && num_readers != n_readers_) + { + ++num_readers; + state_ &= ~n_readers_; + state_ |= num_readers; + return true; + } + return false; + } + + void + upgrade_mutex::unlock_shared() + { + boost::lock_guard<mutex_t> _(mut_); + count_t num_readers = (state_ & n_readers_) - 1; + state_ &= ~n_readers_; + state_ |= num_readers; + if (state_ & write_entered_) + { + if (num_readers == 0) + gate2_.notify_one(); + } + else + { + if (num_readers == n_readers_ - 1) + gate1_.notify_one(); + } + } + + // Upgrade ownership + + void + upgrade_mutex::lock_upgrade() + { + boost::unique_lock<mutex_t> lk(mut_); + while ((state_ & (write_entered_ | upgradable_entered_)) || + (state_ & n_readers_) == n_readers_) + gate1_.wait(lk); + count_t num_readers = (state_ & n_readers_) + 1; + state_ &= ~n_readers_; + state_ |= upgradable_entered_ | num_readers; + } + + bool + upgrade_mutex::try_lock_upgrade() + { + boost::unique_lock<mutex_t> lk(mut_); + count_t num_readers = state_ & n_readers_; + if (!(state_ & (write_entered_ | upgradable_entered_)) + && num_readers != n_readers_) + { + ++num_readers; + state_ &= ~n_readers_; + state_ |= upgradable_entered_ | num_readers; + return true; + } + return false; + } + + void + upgrade_mutex::unlock_upgrade() + { + { + boost::lock_guard<mutex_t> _(mut_); + count_t num_readers = (state_ & n_readers_) - 1; + state_ &= ~(upgradable_entered_ | n_readers_); + state_ |= num_readers; + } + gate1_.notify_all(); + } + + // Shared <-> Exclusive + + bool + upgrade_mutex::try_unlock_shared_and_lock() + { + boost::unique_lock<mutex_t> lk(mut_); + if (state_ == 1) + { + state_ = write_entered_; + return true; + } + return false; + } + + void + upgrade_mutex::unlock_and_lock_shared() + { + { + boost::lock_guard<mutex_t> _(mut_); + state_ = 1; + } + gate1_.notify_all(); + } + + // Shared <-> Upgrade + + bool + upgrade_mutex::try_unlock_shared_and_lock_upgrade() + { + boost::unique_lock<mutex_t> lk(mut_); + if (!(state_ & (write_entered_ | upgradable_entered_))) + { + state_ |= upgradable_entered_; + return true; + } + return false; + } + + void + upgrade_mutex::unlock_upgrade_and_lock_shared() + { + { + boost::lock_guard<mutex_t> _(mut_); + state_ &= ~upgradable_entered_; + } + gate1_.notify_all(); + } + + // Upgrade <-> Exclusive + + void + upgrade_mutex::unlock_upgrade_and_lock() + { + boost::unique_lock<mutex_t> lk(mut_); + count_t num_readers = (state_ & n_readers_) - 1; + state_ &= ~(upgradable_entered_ | n_readers_); + state_ |= write_entered_ | num_readers; + while (state_ & n_readers_) + gate2_.wait(lk); + } + + bool + upgrade_mutex::try_unlock_upgrade_and_lock() + { + boost::unique_lock<mutex_t> lk(mut_); + if (state_ == (upgradable_entered_ | 1)) + { + state_ = write_entered_; + return true; + } + return false; + } + + void + upgrade_mutex::unlock_and_lock_upgrade() + { + { + boost::lock_guard<mutex_t> _(mut_); + state_ = upgradable_entered_ | 1; + } + gate1_.notify_all(); + } + + } // thread_v2 +} // boost + +namespace boost { + //using thread_v2::shared_mutex; + using thread_v2::upgrade_mutex; + typedef thread_v2::upgrade_mutex shared_mutex; +} + +#endif diff --git a/boost/thread/v2/thread.hpp b/boost/thread/v2/thread.hpp index d686c5fe9b..181661a34e 100644 --- a/boost/thread/v2/thread.hpp +++ b/boost/thread/v2/thread.hpp @@ -9,26 +9,77 @@ #include <boost/thread/detail/config.hpp> #ifdef BOOST_THREAD_USES_CHRONO #include <boost/chrono/system_clocks.hpp> +#include <boost/chrono/ceil.hpp> #endif #include <boost/thread/condition_variable.hpp> -#include <boost/thread/locks.hpp> +#include <boost/thread/lock_types.hpp> namespace boost { namespace this_thread { - + namespace no_interruption_point + { #ifdef BOOST_THREAD_USES_CHRONO + template <class Clock, class Duration> + void sleep_until(const chrono::time_point<Clock, Duration>& t) + { + using namespace chrono; + mutex mut; + condition_variable cv; + unique_lock<mutex> lk(mut); + while (Clock::now() < t) + cv.wait_until(lk, t); + } + +#ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY + template <class Rep, class Period> void sleep_for(const chrono::duration<Rep, Period>& d) { using namespace chrono; - nanoseconds ns = duration_cast<nanoseconds> (d); - if (ns < d) ++ns; - sleep_for(ns); + if (d > duration<Rep, Period>::zero()) + { + duration<long double> Max = nanoseconds::max BOOST_PREVENT_MACRO_SUBSTITUTION (); + nanoseconds ns; + if (d < Max) + { + ns = duration_cast<nanoseconds>(d); + if (ns < d) + ++ns; + } + else + ns = nanoseconds:: max BOOST_PREVENT_MACRO_SUBSTITUTION (); + sleep_for(ns); + } } + template <class Duration> + inline BOOST_SYMBOL_VISIBLE + void sleep_until(const chrono::time_point<chrono::steady_clock, Duration>& t) + { + using namespace chrono; + sleep_for(t - steady_clock::now()); + } +#else + template <class Rep, class Period> + void sleep_for(const chrono::duration<Rep, Period>& d) + { + using namespace chrono; + if (d > duration<Rep, Period>::zero()) + { + steady_clock::time_point c_timeout = steady_clock::now() + ceil<nanoseconds>(d); + sleep_until(c_timeout); + } + } + +#endif + +#endif + } +#ifdef BOOST_THREAD_USES_CHRONO + template <class Clock, class Duration> void sleep_until(const chrono::time_point<Clock, Duration>& t) { @@ -40,6 +91,28 @@ namespace boost cv.wait_until(lk, t); } +#ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY + + template <class Rep, class Period> + void sleep_for(const chrono::duration<Rep, Period>& d) + { + using namespace chrono; + if (d > duration<Rep, Period>::zero()) + { + duration<long double> Max = nanoseconds::max BOOST_PREVENT_MACRO_SUBSTITUTION (); + nanoseconds ns; + if (d < Max) + { + ns = duration_cast<nanoseconds>(d); + if (ns < d) + ++ns; + } + else + ns = nanoseconds:: max BOOST_PREVENT_MACRO_SUBSTITUTION (); + sleep_for(ns); + } + } + template <class Duration> inline BOOST_SYMBOL_VISIBLE void sleep_until(const chrono::time_point<chrono::steady_clock, Duration>& t) @@ -47,6 +120,19 @@ namespace boost using namespace chrono; sleep_for(t - steady_clock::now()); } +#else + template <class Rep, class Period> + void sleep_for(const chrono::duration<Rep, Period>& d) + { + using namespace chrono; + if (d > duration<Rep, Period>::zero()) + { + steady_clock::time_point c_timeout = steady_clock::now() + ceil<nanoseconds>(d); + sleep_until(c_timeout); + } + } + +#endif #endif } diff --git a/boost/thread/win32/basic_recursive_mutex.hpp b/boost/thread/win32/basic_recursive_mutex.hpp index eb5ec8489d..cfdfa043a3 100644 --- a/boost/thread/win32/basic_recursive_mutex.hpp +++ b/boost/thread/win32/basic_recursive_mutex.hpp @@ -42,7 +42,7 @@ namespace boost mutex.destroy(); } - bool try_lock() + bool try_lock() BOOST_NOEXCEPT { long const current_thread_id=win32::GetCurrentThreadId(); return try_recursive_lock(current_thread_id) || try_basic_lock(current_thread_id); @@ -58,6 +58,7 @@ namespace boost recursion_count=1; } } +#if defined BOOST_THREAD_USES_DATETIME bool timed_lock(::boost::system_time const& target) { long const current_thread_id=win32::GetCurrentThreadId(); @@ -68,6 +69,7 @@ namespace boost { return timed_lock(get_system_time()+timeout); } +#endif #ifdef BOOST_THREAD_USES_CHRONO template <class Rep, class Period> @@ -93,7 +95,7 @@ namespace boost } private: - bool try_recursive_lock(long current_thread_id) + bool try_recursive_lock(long current_thread_id) BOOST_NOEXCEPT { if(::boost::detail::interlocked_read_acquire(&locking_thread_id)==current_thread_id) { @@ -103,7 +105,7 @@ namespace boost return false; } - bool try_basic_lock(long current_thread_id) + bool try_basic_lock(long current_thread_id) BOOST_NOEXCEPT { if(mutex.try_lock()) { @@ -114,6 +116,7 @@ namespace boost return false; } +#if defined BOOST_THREAD_USES_DATETIME bool try_timed_lock(long current_thread_id,::boost::system_time const& target) { if(mutex.timed_lock(target)) @@ -124,6 +127,7 @@ namespace boost } return false; } +#endif template <typename TP> bool try_timed_lock_until(long current_thread_id,TP const& target) { diff --git a/boost/thread/win32/basic_timed_mutex.hpp b/boost/thread/win32/basic_timed_mutex.hpp index 30580e7c17..d20c6589e6 100644 --- a/boost/thread/win32/basic_timed_mutex.hpp +++ b/boost/thread/win32/basic_timed_mutex.hpp @@ -14,7 +14,9 @@ #include <boost/thread/win32/thread_primitives.hpp> #include <boost/thread/win32/interlocked_read.hpp> #include <boost/thread/thread_time.hpp> +#if defined BOOST_THREAD_USES_DATETIME #include <boost/thread/xtime.hpp> +#endif #include <boost/detail/interlocked.hpp> #ifdef BOOST_THREAD_USES_CHRONO #include <boost/chrono/system_clocks.hpp> @@ -58,7 +60,7 @@ namespace boost } - bool try_lock() + bool try_lock() BOOST_NOEXCEPT { return !win32::interlocked_bit_test_and_set(&active_count,lock_flag_bit); } @@ -79,8 +81,10 @@ namespace boost do { - BOOST_VERIFY(win32::WaitForSingleObject( - sem,::boost::detail::win32::infinite)==0); + unsigned const retval(win32::WaitForSingleObjectEx(sem, ::boost::detail::win32::infinite,0)); + BOOST_VERIFY(0 == retval || ::boost::detail::win32::wait_abandoned == retval); +// BOOST_VERIFY(win32::WaitForSingleObject( +// sem,::boost::detail::win32::infinite)==0); clear_waiting_and_try_lock(old_count); lock_acquired=!(old_count&lock_flag_value); } @@ -91,10 +95,13 @@ namespace boost { for(;;) { - long const new_count=(old_count&lock_flag_value)?(old_count+1):(old_count|lock_flag_value); + bool const was_locked=(old_count&lock_flag_value) ? true : false; + long const new_count=was_locked?(old_count+1):(old_count|lock_flag_value); long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count); if(current==old_count) { + if(was_locked) + old_count=new_count; break; } old_count=current; @@ -118,6 +125,7 @@ namespace boost } +#if defined BOOST_THREAD_USES_DATETIME bool timed_lock(::boost::system_time const& wait_until) { if(try_lock()) @@ -134,7 +142,7 @@ namespace boost do { - if(win32::WaitForSingleObject(sem,::boost::detail::get_milliseconds_until(wait_until))!=0) + if(win32::WaitForSingleObjectEx(sem,::boost::detail::get_milliseconds_until(wait_until),0)!=0) { BOOST_INTERLOCKED_DECREMENT(&active_count); return false; @@ -147,7 +155,6 @@ namespace boost return true; } - template<typename Duration> bool timed_lock(Duration const& timeout) { @@ -158,7 +165,7 @@ namespace boost { return timed_lock(system_time(timeout)); } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template <class Rep, class Period> bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) @@ -196,9 +203,14 @@ namespace boost do { - chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now()); + chrono::time_point<chrono::system_clock, chrono::system_clock::duration> now = chrono::system_clock::now(); + if (tp<=now) { + BOOST_INTERLOCKED_DECREMENT(&active_count); + return false; + } + chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-now); - if(win32::WaitForSingleObject(sem,static_cast<unsigned long>(rel_time.count()))!=0) + if(win32::WaitForSingleObjectEx(sem,static_cast<unsigned long>(rel_time.count()),0)!=0) { BOOST_INTERLOCKED_DECREMENT(&active_count); return false; diff --git a/boost/thread/win32/condition_variable.hpp b/boost/thread/win32/condition_variable.hpp index 63f830b186..14c23ce0e2 100644 --- a/boost/thread/win32/condition_variable.hpp +++ b/boost/thread/win32/condition_variable.hpp @@ -6,23 +6,31 @@ // (C) Copyright 2007-8 Anthony Williams // (C) Copyright 2011-2012 Vicente J. Botet Escriba -#include <boost/thread/mutex.hpp> #include <boost/thread/win32/thread_primitives.hpp> -#include <limits.h> -#include <boost/assert.hpp> -#include <algorithm> -#include <boost/thread/cv_status.hpp> #include <boost/thread/win32/thread_data.hpp> -#include <boost/thread/thread_time.hpp> +#include <boost/thread/win32/thread_data.hpp> #include <boost/thread/win32/interlocked_read.hpp> +#include <boost/thread/cv_status.hpp> +#if defined BOOST_THREAD_USES_DATETIME #include <boost/thread/xtime.hpp> -#include <vector> +#endif +#include <boost/thread/mutex.hpp> +#include <boost/thread/thread_time.hpp> +#include <boost/thread/lock_guard.hpp> +#include <boost/thread/lock_types.hpp> + +#include <boost/assert.hpp> #include <boost/intrusive_ptr.hpp> + #ifdef BOOST_THREAD_USES_CHRONO #include <boost/chrono/system_clocks.hpp> #include <boost/chrono/ceil.hpp> #endif +#include <limits.h> +#include <algorithm> +#include <vector> + #include <boost/config/abi_prefix.hpp> namespace boost @@ -88,7 +96,7 @@ namespace boost bool woken() { - unsigned long const woken_result=detail::win32::WaitForSingleObject(wake_sem,0); + unsigned long const woken_result=detail::win32::WaitForSingleObjectEx(wake_sem,0,0); BOOST_ASSERT((woken_result==detail::win32::timeout) || (woken_result==0)); return woken_result==0; } @@ -183,14 +191,16 @@ namespace boost struct entry_manager { entry_ptr const entry; + boost::mutex& internal_mutex; BOOST_THREAD_NO_COPYABLE(entry_manager) - entry_manager(entry_ptr const& entry_): - entry(entry_) + entry_manager(entry_ptr const& entry_, boost::mutex& mutex_): + entry(entry_), internal_mutex(mutex_) {} ~entry_manager() { + boost::lock_guard<boost::mutex> internal_lock(internal_mutex); entry->remove_waiter(); } @@ -207,7 +217,7 @@ namespace boost { relocker<lock_type> locker(lock); - entry_manager entry(get_wait_entry()); + entry_manager entry(get_wait_entry(), internal_mutex); locker.unlock(); @@ -314,6 +324,7 @@ namespace boost } +#if defined BOOST_THREAD_USES_DATETIME bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time) { return do_wait(m,abs_time); @@ -326,7 +337,16 @@ namespace boost template<typename duration_type> bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration) { - return do_wait(m,wait_duration.total_milliseconds()); + if (wait_duration.is_pos_infinity()) + { + wait(m); // or do_wait(m,detail::timeout::sentinel()); + return true; + } + if (wait_duration.is_special()) + { + return true; + } + return do_wait(m,wait_duration.total_milliseconds()); } template<typename predicate_type> @@ -344,7 +364,7 @@ namespace boost { return do_wait(m,wait_duration.total_milliseconds(),pred); } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template <class Clock, class Duration> @@ -354,7 +374,11 @@ namespace boost const chrono::time_point<Clock, Duration>& t) { using namespace chrono; - do_wait(lock, ceil<milliseconds>(t-Clock::now()).count()); + chrono::time_point<Clock, Duration> now = Clock::now(); + if (t<=now) { + return cv_status::timeout; + } + do_wait(lock, ceil<milliseconds>(t-now).count()); return Clock::now() < t ? cv_status::no_timeout : cv_status::timeout; } @@ -366,6 +390,10 @@ namespace boost const chrono::duration<Rep, Period>& d) { using namespace chrono; + if (d<=chrono::duration<Rep, Period>::zero()) { + return cv_status::timeout; + } + steady_clock::time_point c_now = steady_clock::now(); do_wait(lock, ceil<milliseconds>(d).count()); return steady_clock::now() - c_now < d ? cv_status::no_timeout : @@ -393,7 +421,7 @@ namespace boost const chrono::duration<Rep, Period>& d, Predicate pred) { - return wait_until(lock, chrono::steady_clock::now() + d, pred); + return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred)); } #endif }; @@ -421,6 +449,7 @@ namespace boost while(!pred()) wait(m); } +#if defined BOOST_THREAD_USES_DATETIME template<typename lock_type> bool timed_wait(lock_type& m,boost::system_time const& abs_time) { @@ -456,6 +485,7 @@ namespace boost { return do_wait(m,wait_duration.total_milliseconds(),pred); } +#endif #ifdef BOOST_THREAD_USES_CHRONO template <class lock_type, class Clock, class Duration> @@ -465,7 +495,11 @@ namespace boost const chrono::time_point<Clock, Duration>& t) { using namespace chrono; - do_wait(lock, ceil<milliseconds>(t-Clock::now()).count()); + chrono::time_point<Clock, Duration> now = Clock::now(); + if (t<=now) { + return cv_status::timeout; + } + do_wait(lock, ceil<milliseconds>(t-now).count()); return Clock::now() < t ? cv_status::no_timeout : cv_status::timeout; } @@ -477,6 +511,9 @@ namespace boost const chrono::duration<Rep, Period>& d) { using namespace chrono; + if (d<=chrono::duration<Rep, Period>::zero()) { + return cv_status::timeout; + } steady_clock::time_point c_now = steady_clock::now(); do_wait(lock, ceil<milliseconds>(d).count()); return steady_clock::now() - c_now < d ? cv_status::no_timeout : @@ -505,11 +542,12 @@ namespace boost const chrono::duration<Rep, Period>& d, Predicate pred) { - return wait_until(lock, chrono::steady_clock::now() + d, pred); + return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred)); } #endif }; + BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk); } #include <boost/config/abi_suffix.hpp> diff --git a/boost/thread/win32/interlocked_read.hpp b/boost/thread/win32/interlocked_read.hpp index 133fb6f975..2ad3fe9017 100644 --- a/boost/thread/win32/interlocked_read.hpp +++ b/boost/thread/win32/interlocked_read.hpp @@ -3,46 +3,43 @@ // interlocked_read_win32.hpp // -// (C) Copyright 2005-8 Anthony Williams +// (C) Copyright 2005-8 Anthony Williams +// (C) Copyright 2012 Vicente J. Botet Escriba // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include <boost/detail/interlocked.hpp> +#include <boost/thread/detail/config.hpp> #include <boost/config/abi_prefix.hpp> #ifdef BOOST_MSVC -extern "C" void _ReadWriteBarrier(void); -#pragma intrinsic(_ReadWriteBarrier) - namespace boost { namespace detail { - inline long interlocked_read_acquire(long volatile* x) + // Since VS2005 volatile reads always acquire + inline long interlocked_read_acquire(long volatile* x) BOOST_NOEXCEPT { long const res=*x; - _ReadWriteBarrier(); return res; } - inline void* interlocked_read_acquire(void* volatile* x) + inline void* interlocked_read_acquire(void* volatile* x) BOOST_NOEXCEPT { void* const res=*x; - _ReadWriteBarrier(); return res; } - inline void interlocked_write_release(long volatile* x,long value) + // Since VS2005 volatile writes always release + inline void interlocked_write_release(long volatile* x,long value) BOOST_NOEXCEPT { - _ReadWriteBarrier(); *x=value; } - inline void interlocked_write_release(void* volatile* x,void* value) + inline void interlocked_write_release(void* volatile* x,void* value) BOOST_NOEXCEPT { - _ReadWriteBarrier(); *x=value; } } @@ -54,19 +51,19 @@ namespace boost { namespace detail { - inline long interlocked_read_acquire(long volatile* x) + inline long interlocked_read_acquire(long volatile* x) BOOST_NOEXCEPT { return BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,0,0); } - inline void* interlocked_read_acquire(void* volatile* x) + inline void* interlocked_read_acquire(void* volatile* x) BOOST_NOEXCEPT { return BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(x,0,0); } - inline void interlocked_write_release(long volatile* x,long value) + inline void interlocked_write_release(long volatile* x,long value) BOOST_NOEXCEPT { BOOST_INTERLOCKED_EXCHANGE(x,value); } - inline void interlocked_write_release(void* volatile* x,void* value) + inline void interlocked_write_release(void* volatile* x,void* value) BOOST_NOEXCEPT { BOOST_INTERLOCKED_EXCHANGE_POINTER(x,value); } diff --git a/boost/thread/win32/mfc_thread_init.hpp b/boost/thread/win32/mfc_thread_init.hpp new file mode 100644 index 0000000000..e866f8949f --- /dev/null +++ b/boost/thread/win32/mfc_thread_init.hpp @@ -0,0 +1,40 @@ +#ifndef BOOST_THREAD_WIN32_MFC_THREAD_INIT_HPP +#define BOOST_THREAD_WIN32_MFC_THREAD_INIT_HPP +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2008 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba + + +// check if we use MFC +#ifdef _AFXDLL +# if defined(_AFXEXT) + +// can't use ExtRawDllMain from afxdllx.h as it also defines the symbol _pRawDllMain +extern "C" +inline BOOL WINAPI ExtRawDllMain(HINSTANCE, DWORD dwReason, LPVOID) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + // save critical data pointers before running the constructors + AFX_MODULE_STATE* pModuleState = AfxGetModuleState(); + pModuleState->m_pClassInit = pModuleState->m_classList; + pModuleState->m_pFactoryInit = pModuleState->m_factoryList; + pModuleState->m_classList.m_pHead = NULL; + pModuleState->m_factoryList.m_pHead = NULL; + } + return TRUE; // ok +} + +extern "C" __declspec(selectany) BOOL (WINAPI * const _pRawDllMainOrig)(HANDLE, DWORD, LPVOID) = &ExtRawDllMain; + +# elif defined(_USRDLL) + +extern "C" BOOL WINAPI RawDllMain(HANDLE, DWORD dwReason, LPVOID); +extern "C" __declspec(selectany) BOOL (WINAPI * const _pRawDllMainOrig)(HANDLE, DWORD, LPVOID) = &RawDllMain; + +# endif +#endif + +#endif diff --git a/boost/thread/win32/mutex.hpp b/boost/thread/win32/mutex.hpp index 85a00e29f9..01544784b5 100644 --- a/boost/thread/win32/mutex.hpp +++ b/boost/thread/win32/mutex.hpp @@ -8,7 +8,10 @@ #include <boost/thread/win32/basic_timed_mutex.hpp> #include <boost/thread/exceptions.hpp> -#include <boost/thread/locks.hpp> +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS +#include <boost/thread/lock_types.hpp> +#endif +#include <boost/thread/detail/delete.hpp> #include <boost/config/abi_prefix.hpp> @@ -33,8 +36,10 @@ namespace boost destroy(); } +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS typedef unique_lock<mutex> scoped_lock; typedef detail::try_lock_wrapper<mutex> scoped_try_lock; +#endif }; typedef mutex try_mutex; @@ -54,9 +59,11 @@ namespace boost destroy(); } +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS typedef unique_lock<timed_mutex> scoped_timed_lock; typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock; typedef scoped_timed_lock scoped_lock; +#endif }; } diff --git a/boost/thread/win32/once.hpp b/boost/thread/win32/once.hpp index 3066b50bc3..24eb0f29d0 100644 --- a/boost/thread/win32/once.hpp +++ b/boost/thread/win32/once.hpp @@ -5,7 +5,7 @@ // // (C) Copyright 2005-7 Anthony Williams // (C) Copyright 2005 John Maddock -// (C) Copyright 2011-2012 Vicente J. Botet Escriba +// (C) Copyright 2011-2013 Vicente J. Botet Escriba // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -18,6 +18,11 @@ #include <boost/detail/interlocked.hpp> #include <boost/thread/win32/thread_primitives.hpp> #include <boost/thread/win32/interlocked_read.hpp> +#include <boost/core/no_exceptions_support.hpp> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/detail/invoke.hpp> + +#include <boost/bind.hpp> #include <boost/config/abi_prefix.hpp> @@ -31,6 +36,16 @@ namespace std namespace boost { + struct once_flag; + namespace detail + { + struct once_context; + + inline bool enter_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT; + inline void commit_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT; + inline void rollback_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT; + } + #ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11 struct once_flag @@ -39,12 +54,12 @@ namespace boost BOOST_CONSTEXPR once_flag() BOOST_NOEXCEPT : status(0), count(0) {} - private: long status; long count; - template<typename Function> - friend - void call_once(once_flag& flag,Function f); + private: + friend inline bool enter_once_region(once_flag& flag, detail::once_context& ctx) BOOST_NOEXCEPT; + friend inline void commit_once_region(once_flag& flag, detail::once_context& ctx) BOOST_NOEXCEPT; + friend inline void rollback_once_region(once_flag& flag, detail::once_context& ctx) BOOST_NOEXCEPT; }; #define BOOST_ONCE_INIT once_flag() @@ -59,6 +74,17 @@ namespace boost #define BOOST_ONCE_INIT {0,0} #endif // BOOST_THREAD_PROVIDES_ONCE_CXX11 +#if defined BOOST_THREAD_PROVIDES_INVOKE +#define BOOST_THREAD_INVOKE_RET_VOID detail::invoke +#define BOOST_THREAD_INVOKE_RET_VOID_CALL +#elif defined BOOST_THREAD_PROVIDES_INVOKE_RET +#define BOOST_THREAD_INVOKE_RET_VOID detail::invoke<void> +#define BOOST_THREAD_INVOKE_RET_VOID_CALL +#else +#define BOOST_THREAD_INVOKE_RET_VOID boost::bind +#define BOOST_THREAD_INVOKE_RET_VOID_CALL () +#endif + namespace detail { #ifdef BOOST_NO_ANSI_APIS @@ -126,103 +152,934 @@ namespace boost { name_once_mutex(mutex_name,flag_address); } -#ifdef BOOST_NO_ANSI_APIS - return ::boost::detail::win32::CreateEventW( -#else - return ::boost::detail::win32::CreateEventA( -#endif - 0,::boost::detail::win32::manual_reset_event, - ::boost::detail::win32::event_initially_reset, - mutex_name); + + return ::boost::detail::win32::create_event( + mutex_name, + ::boost::detail::win32::manual_reset_event, + ::boost::detail::win32::event_initially_reset); } - } + struct once_context { + long const function_complete_flag_value; + long const running_value; + bool counted; + detail::win32::handle_manager event_handle; + detail::once_char_type mutex_name[once_mutex_name_length]; + once_context() : + function_complete_flag_value(0xc15730e2), + running_value(0x7f0725e3), + counted(false) + { + mutex_name[0]=0; + } + }; + enum once_action {try_, break_, continue_}; + inline bool enter_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT + { + long status=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&flag.status,ctx.running_value,0); + if(!status) + { + if(!ctx.event_handle) + { + ctx.event_handle=detail::open_once_event(ctx.mutex_name,&flag); + } + if(ctx.event_handle) + { + ::boost::detail::win32::ResetEvent(ctx.event_handle); + } + return true; + } + return false; + } + inline void commit_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT + { + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + } + BOOST_INTERLOCKED_EXCHANGE(&flag.status,ctx.function_complete_flag_value); + if(!ctx.event_handle && + (::boost::detail::interlocked_read_acquire(&flag.count)>1)) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + } + if(ctx.event_handle) + { + ::boost::detail::win32::SetEvent(ctx.event_handle); + } + } + inline void rollback_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT + { + BOOST_INTERLOCKED_EXCHANGE(&flag.status,0); + if(!ctx.event_handle) + { + ctx.event_handle=detail::open_once_event(ctx.mutex_name,&flag); + } + if(ctx.event_handle) + { + ::boost::detail::win32::SetEvent(ctx.event_handle); + } + } + } + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +//#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR) + inline void call_once(once_flag& flag, void (*f)()) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + f(); + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite, 0)); + } + } +//#endif + template<typename Function> + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + f(); + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + template<typename Function, class A, class ...ArgTypes> + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(A) a, BOOST_THREAD_RV_REF(ArgTypes)... args) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID( + thread_detail::decay_copy(boost::forward<Function>(f)), + thread_detail::decay_copy(boost::forward<A>(a)), + thread_detail::decay_copy(boost::forward<ArgTypes>(args))... + ) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } +#else +#if ! defined(BOOST_MSVC) && ! defined(BOOST_INTEL) template<typename Function> void call_once(once_flag& flag,Function f) { // Try for a quick win: if the procedure has already been called // just skip through: - long const function_complete_flag_value=0xc15730e2; - long const running_value=0x7f0725e3; - long status; - bool counted=false; - detail::win32::handle_manager event_handle; - detail::once_char_type mutex_name[detail::once_mutex_name_length]; - mutex_name[0]=0; + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + f(); + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + template<typename Function, typename T1> + void call_once(once_flag& flag,Function f, T1 p1) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID(f,p1) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + template<typename Function, typename T1, typename T2> + void call_once(once_flag& flag,Function f, T1 p1, T2 p2) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID(f,p1,p2) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + template<typename Function, typename T1, typename T2, typename T3> + void call_once(once_flag& flag,Function f, T1 p1, T2 p2, T3 p3) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID(f,p1,p2,p3) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } +#elif defined BOOST_NO_CXX11_RVALUE_REFERENCES - while((status=::boost::detail::interlocked_read_acquire(&flag.status)) - !=function_complete_flag_value) + template<typename Function> + void call_once(once_flag& flag,Function const&f) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) { - status=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&flag.status,running_value,0); - if(!status) + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + f(); + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) { -#ifndef BOOST_NO_EXCEPTIONS - try // BOOST_NO_EXCEPTIONS protected + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + template<typename Function, typename T1> + void call_once(once_flag& flag,Function const&f, T1 const&p1) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID(f,p1) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + template<typename Function, typename T1, typename T2> + void call_once(once_flag& flag,Function const&f, T1 const&p1, T2 const&p2) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID(f,p1,p2) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + template<typename Function, typename T1, typename T2, typename T3> + void call_once(once_flag& flag,Function const&f, T1 const&p1, T2 const&p2, T3 const&p3) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID(f,p1,p2,p3) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } #endif +#if 1 +#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR) + inline void call_once(once_flag& flag, void (*f)()) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) { - if(!event_handle) + BOOST_TRY { - event_handle=detail::open_once_event(mutex_name,&flag); + f(); } - if(event_handle) + BOOST_CATCH(...) { - ::boost::detail::win32::ResetEvent(event_handle); + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW } - f(); - if(!counted) + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) { - BOOST_INTERLOCKED_INCREMENT(&flag.count); - counted=true; + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; } - BOOST_INTERLOCKED_EXCHANGE(&flag.status,function_complete_flag_value); - if(!event_handle && - (::boost::detail::interlocked_read_acquire(&flag.count)>1)) + } + BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + template<typename T1> + void call_once(once_flag& flag,void (*f)(BOOST_THREAD_RV_REF(T1)), BOOST_THREAD_RV_REF(T1) p1) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + f( + thread_detail::decay_copy(boost::forward<T1>(p1)) + ); + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + template<typename Function, typename T1, typename T2> + void call_once(once_flag& flag,void (*f)(BOOST_THREAD_RV_REF(T1),BOOST_THREAD_RV_REF(T2)), BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY { - event_handle=detail::create_once_event(mutex_name,&flag); + f( + thread_detail::decay_copy(boost::forward<T1>(p1)), + thread_detail::decay_copy(boost::forward<T2>(p2)) + ); } - if(event_handle) + BOOST_CATCH(...) { - ::boost::detail::win32::SetEvent(event_handle); + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); break; } -#ifndef BOOST_NO_EXCEPTIONS - catch(...) // BOOST_NO_EXCEPTIONS protected + if(!ctx.counted) { - BOOST_INTERLOCKED_EXCHANGE(&flag.status,0); - if(!event_handle) + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) { - event_handle=detail::open_once_event(mutex_name,&flag); + break; } - if(event_handle) + if(!ctx.event_handle) { - ::boost::detail::win32::SetEvent(event_handle); + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; } - throw; // BOOST_NO_EXCEPTIONS protected } + BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + template<typename Function, typename T1, typename T2, typename T3> + void call_once(once_flag& flag,void (*f)(BOOST_THREAD_RV_REF(T1),BOOST_THREAD_RV_REF(T2)), BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2, BOOST_THREAD_RV_REF(T3) p3) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + f( + thread_detail::decay_copy(boost::forward<T1>(p1)), + thread_detail::decay_copy(boost::forward<T2>(p2)), + thread_detail::decay_copy(boost::forward<T3>(p3)) + ); + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } #endif + template<typename Function> + void call_once(once_flag& flag,BOOST_THREAD_RV_REF(Function) f) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + f(); + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + + template<typename Function, typename T1> + void call_once(once_flag& flag,BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID( + thread_detail::decay_copy(boost::forward<Function>(f)), + thread_detail::decay_copy(boost::forward<T1>(p1)) + ) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + template<typename Function, typename T1, typename T2> + void call_once(once_flag& flag,BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID( + thread_detail::decay_copy(boost::forward<Function>(f)), + thread_detail::decay_copy(boost::forward<T1>(p1)), + thread_detail::decay_copy(boost::forward<T2>(p2)) + ) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + template<typename Function, typename T1, typename T2, typename T3> + void call_once(once_flag& flag,BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2, BOOST_THREAD_RV_REF(T3) p3) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID( + thread_detail::decay_copy(boost::forward<Function>(f)), + thread_detail::decay_copy(boost::forward<T1>(p1)), + thread_detail::decay_copy(boost::forward<T2>(p2)), + thread_detail::decay_copy(boost::forward<T3>(p3)) + ) BOOST_THREAD_INVOKE_RET_VOID_CALL; - if(!counted) + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) { BOOST_INTERLOCKED_INCREMENT(&flag.count); - counted=true; - status=::boost::detail::interlocked_read_acquire(&flag.status); - if(status==function_complete_flag_value) + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) { break; } - if(!event_handle) + if(!ctx.event_handle) { - event_handle=detail::create_once_event(mutex_name,&flag); + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); continue; } } - BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject( - event_handle,::boost::detail::win32::infinite)); + BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); } } + +#endif +#endif } #include <boost/config/abi_suffix.hpp> diff --git a/boost/thread/win32/recursive_mutex.hpp b/boost/thread/win32/recursive_mutex.hpp index 5144e77aa7..1f0f7f5e5f 100644 --- a/boost/thread/win32/recursive_mutex.hpp +++ b/boost/thread/win32/recursive_mutex.hpp @@ -12,7 +12,10 @@ #include <boost/thread/win32/basic_recursive_mutex.hpp> #include <boost/thread/exceptions.hpp> -#include <boost/thread/locks.hpp> +#include <boost/thread/detail/delete.hpp> +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS +#include <boost/thread/lock_types.hpp> +#endif #include <boost/config/abi_prefix.hpp> @@ -32,8 +35,10 @@ namespace boost ::boost::detail::basic_recursive_mutex::destroy(); } +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS typedef unique_lock<recursive_mutex> scoped_lock; typedef detail::try_lock_wrapper<recursive_mutex> scoped_try_lock; +#endif }; typedef recursive_mutex recursive_try_mutex; @@ -52,9 +57,11 @@ namespace boost ::boost::detail::basic_recursive_timed_mutex::destroy(); } +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS typedef unique_lock<recursive_timed_mutex> scoped_timed_lock; typedef detail::try_lock_wrapper<recursive_timed_mutex> scoped_try_lock; typedef scoped_timed_lock scoped_lock; +#endif }; } diff --git a/boost/thread/win32/shared_mutex.hpp b/boost/thread/win32/shared_mutex.hpp index fef2d5badd..fff97b7355 100644 --- a/boost/thread/win32/shared_mutex.hpp +++ b/boost/thread/win32/shared_mutex.hpp @@ -75,7 +75,13 @@ namespace boost BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0); } } - + void release_shared_waiters(state_data old_state) + { + if(old_state.shared_waiting || old_state.exclusive_waiting) + { + BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0); + } + } public: BOOST_THREAD_NO_COPYABLE(shared_mutex) @@ -95,7 +101,7 @@ namespace boost detail::win32::release_semaphore(semaphores[exclusive_sem],LONG_MAX); boost::throw_exception(thread_resource_error()); } - state_data state_={0}; + state_data state_={0,0,0,0,0,0}; state=state_; } @@ -133,15 +139,19 @@ namespace boost void lock_shared() { +#if defined BOOST_THREAD_USES_DATETIME BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel())); +#else + BOOST_VERIFY(try_lock_shared_until(chrono::steady_clock::now())); +#endif } +#if defined BOOST_THREAD_USES_DATETIME template<typename TimeDuration> bool timed_lock_shared(TimeDuration const & relative_time) { return timed_lock_shared(get_system_time()+relative_time); } - bool timed_lock_shared(boost::system_time const& wait_until) { for(;;) @@ -180,7 +190,7 @@ namespace boost return true; } - unsigned long const res=detail::win32::WaitForSingleObject(semaphores[unlock_sem],::boost::detail::get_milliseconds_until(wait_until)); + unsigned long const res=detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem],::boost::detail::get_milliseconds_until(wait_until), 0); if(res==detail::win32::timeout) { for(;;) @@ -220,6 +230,7 @@ namespace boost BOOST_ASSERT(res==0); } } +#endif #ifdef BOOST_THREAD_USES_CHRONO template <class Rep, class Period> @@ -284,8 +295,8 @@ namespace boost unsigned long res; if (tp>n) { chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-n); - res=detail::win32::WaitForSingleObject(semaphores[unlock_sem], - static_cast<unsigned long>(rel_time.count())); + res=detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem], + static_cast<unsigned long>(rel_time.count()), 0); } else { res=detail::win32::timeout; } @@ -378,14 +389,20 @@ namespace boost void lock() { +#if defined BOOST_THREAD_USES_DATETIME BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel())); +#else + BOOST_VERIFY(try_lock_until(chrono::steady_clock::now())); +#endif } +#if defined BOOST_THREAD_USES_DATETIME template<typename TimeDuration> bool timed_lock(TimeDuration const & relative_time) { return timed_lock(get_system_time()+relative_time); } +#endif bool try_lock() { @@ -413,6 +430,7 @@ namespace boost } +#if defined BOOST_THREAD_USES_DATETIME bool timed_lock(boost::system_time const& wait_until) { for(;;) @@ -454,11 +472,12 @@ namespace boost #else const bool wait_all = false; #endif - unsigned long const wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,wait_all,::boost::detail::get_milliseconds_until(wait_until)); + unsigned long const wait_res=detail::win32::WaitForMultipleObjectsEx(2,semaphores,wait_all,::boost::detail::get_milliseconds_until(wait_until), 0); if(wait_res==detail::win32::timeout) { for(;;) { + bool must_notify = false; state_data new_state=old_state; if(new_state.shared_count || new_state.exclusive) { @@ -467,6 +486,7 @@ namespace boost if(!--new_state.exclusive_waiting) { new_state.exclusive_waiting_blocked=false; + must_notify = true; } } } @@ -476,6 +496,11 @@ namespace boost } state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if (must_notify) + { + BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0); + } + if(current_state==old_state) { break; @@ -491,7 +516,7 @@ namespace boost BOOST_ASSERT(wait_res<2); } } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template <class Rep, class Period> bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) @@ -559,8 +584,8 @@ namespace boost unsigned long wait_res; if (tp>n) { chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now()); - wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,wait_all, - static_cast<unsigned long>(rel_time.count())); + wait_res=detail::win32::WaitForMultipleObjectsEx(2,semaphores,wait_all, + static_cast<unsigned long>(rel_time.count()), 0); } else { wait_res=detail::win32::timeout; } @@ -568,6 +593,7 @@ namespace boost { for(;;) { + bool must_notify = false; state_data new_state=old_state; if(new_state.shared_count || new_state.exclusive) { @@ -576,6 +602,7 @@ namespace boost if(!--new_state.exclusive_waiting) { new_state.exclusive_waiting_blocked=false; + must_notify = true; } } } @@ -585,6 +612,10 @@ namespace boost } state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if (must_notify) + { + BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0); + } if(current_state==old_state) { break; @@ -665,7 +696,7 @@ namespace boost return; } - BOOST_VERIFY(!detail::win32::WaitForSingleObject(semaphores[unlock_sem],detail::win32::infinite)); + BOOST_VERIFY(!detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem],detail::win32::infinite, 0)); } } @@ -724,9 +755,14 @@ namespace boost if(last_reader) { release_waiters(old_state); - } else { - release_waiters(old_state); } + else { + release_shared_waiters(old_state); + } + // #7720 + //else { + // release_waiters(old_state); + //} break; } old_state=current_state; @@ -752,7 +788,7 @@ namespace boost { if(!last_reader) { - BOOST_VERIFY(!detail::win32::WaitForSingleObject(upgrade_sem,detail::win32::infinite)); + BOOST_VERIFY(!detail::win32::WaitForSingleObjectEx(upgrade_sem,detail::win32::infinite, 0)); } break; } diff --git a/boost/thread/win32/thread_data.hpp b/boost/thread/win32/thread_data.hpp index 5af4fd3ed3..51f6273f43 100644 --- a/boost/thread/win32/thread_data.hpp +++ b/boost/thread/win32/thread_data.hpp @@ -7,17 +7,33 @@ // (C) Copyright 2011-2012 Vicente J. Botet Escriba #include <boost/thread/detail/config.hpp> -#include <boost/intrusive_ptr.hpp> #include <boost/thread/thread_time.hpp> #include <boost/thread/win32/thread_primitives.hpp> #include <boost/thread/win32/thread_heap_alloc.hpp> + +#include <boost/predef/platform.h> + +#include <boost/intrusive_ptr.hpp> #ifdef BOOST_THREAD_USES_CHRONO #include <boost/chrono/system_clocks.hpp> #endif + +#include <map> +#include <vector> +#include <utility> + #include <boost/config/abi_prefix.hpp> +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4251) +#endif + namespace boost { + class condition_variable; + class mutex; + class thread_attributes { public: thread_attributes() BOOST_NOEXCEPT { @@ -58,32 +74,68 @@ namespace boost namespace detail { + struct shared_state_base; + struct tss_cleanup_function; struct thread_exit_callback_node; - struct tss_data_node; + struct tss_data_node + { + boost::shared_ptr<boost::detail::tss_cleanup_function> func; + void* value; + + tss_data_node(boost::shared_ptr<boost::detail::tss_cleanup_function> func_, + void* value_): + func(func_),value(value_) + {} + }; struct thread_data_base; void intrusive_ptr_add_ref(thread_data_base * p); void intrusive_ptr_release(thread_data_base * p); - struct BOOST_SYMBOL_VISIBLE thread_data_base + struct BOOST_THREAD_DECL thread_data_base { long count; + + // Win32 threading APIs are not available in store apps so + // use abstraction on top of Windows::System::Threading. +#if BOOST_PLAT_WINDOWS_RUNTIME + detail::win32::scoped_winrt_thread thread_handle; +#else detail::win32::handle_manager thread_handle; - detail::win32::handle_manager interruption_handle; +#endif + boost::detail::thread_exit_callback_node* thread_exit_callbacks; - boost::detail::tss_data_node* tss_data; - bool interruption_enabled; unsigned id; + std::map<void const*,boost::detail::tss_data_node> tss_data; + typedef std::vector<std::pair<condition_variable*, mutex*> + //, hidden_allocator<std::pair<condition_variable*, mutex*> > + > notify_list_t; + notify_list_t notify; + + typedef std::vector<shared_ptr<shared_state_base> > async_states_t; + async_states_t async_states_; +//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + // These data must be at the end so that the access to the other fields doesn't change + // when BOOST_THREAD_PROVIDES_INTERRUPTIONS is defined + // Another option is to have them always + detail::win32::handle_manager interruption_handle; + bool interruption_enabled; +//#endif thread_data_base(): - count(0),thread_handle(detail::win32::invalid_handle_value), - interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset)), - thread_exit_callbacks(0),tss_data(0), - interruption_enabled(true), - id(0) - {} - virtual ~thread_data_base() + count(0), + thread_handle(), + thread_exit_callbacks(0), + id(0), + tss_data(), + notify(), + async_states_() +//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + , interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset)) + , interruption_enabled(true) +//#endif {} + virtual ~thread_data_base(); friend void intrusive_ptr_add_ref(thread_data_base * p) { @@ -98,21 +150,34 @@ namespace boost } } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS void interrupt() { BOOST_VERIFY(detail::win32::SetEvent(interruption_handle)!=0); } - +#endif typedef detail::win32::handle native_handle_type; virtual void run()=0; + + virtual void notify_all_at_thread_exit(condition_variable* cv, mutex* m) + { + notify.push_back(std::pair<condition_variable*, mutex*>(cv, m)); + } + + void make_ready_at_thread_exit(shared_ptr<shared_state_base> as) + { + async_states_.push_back(as); + } + }; + BOOST_THREAD_DECL thread_data_base* get_current_thread_data(); typedef boost::intrusive_ptr<detail::thread_data_base> thread_data_ptr; struct BOOST_SYMBOL_VISIBLE timeout { - unsigned long start; + win32::ticks_type start; uintmax_t milliseconds; bool relative; boost::system_time abs_time; @@ -120,14 +185,15 @@ namespace boost static unsigned long const max_non_infinite_wait=0xfffffffe; timeout(uintmax_t milliseconds_): - start(win32::GetTickCount()), + start(win32::GetTickCount64_()()), milliseconds(milliseconds_), - relative(true), - abs_time(boost::get_system_time()) + relative(true) + //, + // abs_time(boost::get_system_time()) {} timeout(boost::system_time const& abs_time_): - start(win32::GetTickCount()), + start(win32::GetTickCount64_()()), milliseconds(0), relative(false), abs_time(abs_time_) @@ -152,8 +218,8 @@ namespace boost } else if(relative) { - unsigned long const now=win32::GetTickCount(); - unsigned long const elapsed=now-start; + win32::ticks_type const now=win32::GetTickCount64_()(); + win32::ticks_type const elapsed=now-start; return remaining_time((elapsed<milliseconds)?(milliseconds-elapsed):0); } else @@ -205,7 +271,6 @@ namespace boost { interruptible_wait(detail::win32::invalid_handle_value,abs_time); } - template<typename TimeDuration> inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time) { @@ -221,10 +286,41 @@ namespace boost interruptible_wait(chrono::duration_cast<chrono::milliseconds>(ns).count()); } #endif + namespace no_interruption_point + { + bool BOOST_THREAD_DECL non_interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time); + inline void non_interruptible_wait(uintmax_t milliseconds) + { + non_interruptible_wait(detail::win32::invalid_handle_value,milliseconds); + } + inline BOOST_SYMBOL_VISIBLE void non_interruptible_wait(system_time const& abs_time) + { + non_interruptible_wait(detail::win32::invalid_handle_value,abs_time); + } + template<typename TimeDuration> + inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time) + { + non_interruptible_wait(detail::pin_to_zero(rel_time.total_milliseconds())); + } + inline BOOST_SYMBOL_VISIBLE void sleep(system_time const& abs_time) + { + non_interruptible_wait(abs_time); + } +#ifdef BOOST_THREAD_USES_CHRONO + inline void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns) + { + non_interruptible_wait(chrono::duration_cast<chrono::milliseconds>(ns).count()); + } +#endif + } } } +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + #include <boost/config/abi_suffix.hpp> #endif diff --git a/boost/thread/win32/thread_heap_alloc.hpp b/boost/thread/win32/thread_heap_alloc.hpp index 843e46b532..610fe3263e 100644 --- a/boost/thread/win32/thread_heap_alloc.hpp +++ b/boost/thread/win32/thread_heap_alloc.hpp @@ -5,10 +5,12 @@ #ifndef THREAD_HEAP_ALLOC_HPP #define THREAD_HEAP_ALLOC_HPP #include <new> +#include <boost/thread/detail/config.hpp> #include <boost/thread/win32/thread_primitives.hpp> #include <stdexcept> #include <boost/assert.hpp> #include <boost/throw_exception.hpp> +#include <boost/core/no_exceptions_support.hpp> #if defined( BOOST_USE_WINDOWS_H ) # include <windows.h> @@ -75,180 +77,153 @@ namespace boost inline T* heap_new() { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); -#ifndef BOOST_NO_EXCEPTIONS - try // BOOST_NO_EXCEPTIONS protected -#endif + BOOST_TRY { T* const data=new (heap_memory) T(); return data; } -#ifndef BOOST_NO_EXCEPTIONS - catch(...) // BOOST_NO_EXCEPTIONS protected + BOOST_CATCH(...) { free_raw_heap_memory(heap_memory); - throw; // BOOST_NO_EXCEPTIONS protected + BOOST_RETHROW } -#endif + BOOST_CATCH_END } -#ifndef BOOST_NO_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template<typename T,typename A1> inline T* heap_new(A1&& a1) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); -#ifndef BOOST_NO_EXCEPTIONS - try // BOOST_NO_EXCEPTIONS protected -#endif + BOOST_TRY { T* const data=new (heap_memory) T(static_cast<A1&&>(a1)); return data; } -#ifndef BOOST_NO_EXCEPTIONS - catch(...) // BOOST_NO_EXCEPTIONS protected + BOOST_CATCH(...) { free_raw_heap_memory(heap_memory); - throw; // BOOST_NO_EXCEPTIONS protected + BOOST_RETHROW } -#endif + BOOST_CATCH_END } template<typename T,typename A1,typename A2> inline T* heap_new(A1&& a1,A2&& a2) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); -#ifndef BOOST_NO_EXCEPTIONS - try // BOOST_NO_EXCEPTIONS protected -#endif + BOOST_TRY { T* const data=new (heap_memory) T(static_cast<A1&&>(a1),static_cast<A2&&>(a2)); return data; } -#ifndef BOOST_NO_EXCEPTIONS - catch(...) // BOOST_NO_EXCEPTIONS protected + BOOST_CATCH(...) { free_raw_heap_memory(heap_memory); - throw; // BOOST_NO_EXCEPTIONS protected + BOOST_RETHROW } -#endif + BOOST_CATCH_END } template<typename T,typename A1,typename A2,typename A3> inline T* heap_new(A1&& a1,A2&& a2,A3&& a3) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); -#ifndef BOOST_NO_EXCEPTIONS - try // BOOST_NO_EXCEPTIONS protected -#endif + BOOST_TRY { T* const data=new (heap_memory) T(static_cast<A1&&>(a1),static_cast<A2&&>(a2), static_cast<A3&&>(a3)); return data; } -#ifndef BOOST_NO_EXCEPTIONS - catch(...) // BOOST_NO_EXCEPTIONS protected + BOOST_CATCH(...) { free_raw_heap_memory(heap_memory); - throw; // BOOST_NO_EXCEPTIONS protected + BOOST_RETHROW } -#endif + BOOST_CATCH_END } template<typename T,typename A1,typename A2,typename A3,typename A4> inline T* heap_new(A1&& a1,A2&& a2,A3&& a3,A4&& a4) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); -#ifndef BOOST_NO_EXCEPTIONS - try // BOOST_NO_EXCEPTIONS protected -#endif + BOOST_TRY { T* const data=new (heap_memory) T(static_cast<A1&&>(a1),static_cast<A2&&>(a2), static_cast<A3&&>(a3),static_cast<A4&&>(a4)); return data; } -#ifndef BOOST_NO_EXCEPTIONS - catch(...) // BOOST_NO_EXCEPTIONS protected + BOOST_CATCH(...) { free_raw_heap_memory(heap_memory); - throw; // BOOST_NO_EXCEPTIONS protected + BOOST_RETHROW } -#endif + BOOST_CATCH_END } #else template<typename T,typename A1> inline T* heap_new_impl(A1 a1) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); -#ifndef BOOST_NO_EXCEPTIONS - try // BOOST_NO_EXCEPTIONS protected -#endif + BOOST_TRY { T* const data=new (heap_memory) T(a1); return data; } -#ifndef BOOST_NO_EXCEPTIONS - catch(...) // BOOST_NO_EXCEPTIONS protected + BOOST_CATCH(...) { free_raw_heap_memory(heap_memory); - throw; // BOOST_NO_EXCEPTIONS protected + BOOST_RETHROW } -#endif + BOOST_CATCH_END } template<typename T,typename A1,typename A2> inline T* heap_new_impl(A1 a1,A2 a2) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); -#ifndef BOOST_NO_EXCEPTIONS - try // BOOST_NO_EXCEPTIONS protected -#endif + BOOST_TRY { T* const data=new (heap_memory) T(a1,a2); return data; } -#ifndef BOOST_NO_EXCEPTIONS - catch(...) // BOOST_NO_EXCEPTIONS protected + BOOST_CATCH(...) { free_raw_heap_memory(heap_memory); - throw; // BOOST_NO_EXCEPTIONS protected + BOOST_RETHROW } -#endif + BOOST_CATCH_END } template<typename T,typename A1,typename A2,typename A3> inline T* heap_new_impl(A1 a1,A2 a2,A3 a3) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); -#ifndef BOOST_NO_EXCEPTIONS - try // BOOST_NO_EXCEPTIONS protected -#endif + BOOST_TRY { T* const data=new (heap_memory) T(a1,a2,a3); return data; } -#ifndef BOOST_NO_EXCEPTIONS - catch(...) // BOOST_NO_EXCEPTIONS protected + BOOST_CATCH(...) { free_raw_heap_memory(heap_memory); - throw; // BOOST_NO_EXCEPTIONS protected + BOOST_RETHROW } -#endif + BOOST_CATCH_END } template<typename T,typename A1,typename A2,typename A3,typename A4> inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); -#ifndef BOOST_NO_EXCEPTIONS - try // BOOST_NO_EXCEPTIONS protected -#endif + BOOST_TRY { T* const data=new (heap_memory) T(a1,a2,a3,a4); return data; } -#ifndef BOOST_NO_EXCEPTIONS - catch(...) // BOOST_NO_EXCEPTIONS protected + BOOST_CATCH(...) { free_raw_heap_memory(heap_memory); - throw; // BOOST_NO_EXCEPTIONS protected + BOOST_RETHROW } -#endif + BOOST_CATCH_END } diff --git a/boost/thread/win32/thread_primitives.hpp b/boost/thread/win32/thread_primitives.hpp index 294e42ee9b..2960822f65 100644 --- a/boost/thread/win32/thread_primitives.hpp +++ b/boost/thread/win32/thread_primitives.hpp @@ -10,13 +10,19 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#include <boost/config.hpp> +#include <boost/thread/detail/config.hpp> +#include <boost/predef/platform.h> #include <boost/throw_exception.hpp> #include <boost/assert.hpp> #include <boost/thread/exceptions.hpp> #include <boost/detail/interlocked.hpp> +//#include <boost/detail/winapi/synchronization.hpp> #include <algorithm> +#if BOOST_PLAT_WINDOWS_RUNTIME +#include <thread> +#endif + #if defined( BOOST_USE_WINDOWS_H ) # include <windows.h> @@ -26,41 +32,61 @@ namespace boost { namespace win32 { - typedef ULONG_PTR ulong_ptr; typedef HANDLE handle; + typedef SYSTEM_INFO system_info; + typedef unsigned __int64 ticks_type; unsigned const infinite=INFINITE; unsigned const timeout=WAIT_TIMEOUT; handle const invalid_handle_value=INVALID_HANDLE_VALUE; unsigned const event_modify_state=EVENT_MODIFY_STATE; unsigned const synchronize=SYNCHRONIZE; + unsigned const wait_abandoned=WAIT_ABANDONED; + unsigned const create_event_initial_set = 0x00000002; + unsigned const create_event_manual_reset = 0x00000001; + unsigned const event_all_access = EVENT_ALL_ACCESS; + unsigned const semaphore_all_access = SEMAPHORE_ALL_ACCESS; + # ifdef BOOST_NO_ANSI_APIS +# if BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA using ::CreateMutexW; using ::CreateEventW; - using ::OpenEventW; using ::CreateSemaphoreW; # else + using ::CreateMutexExW; + using ::CreateEventExW; + using ::CreateSemaphoreExW; +# endif + using ::OpenEventW; +# else using ::CreateMutexA; using ::CreateEventA; using ::OpenEventA; using ::CreateSemaphoreA; # endif +#if BOOST_PLAT_WINDOWS_RUNTIME + using ::GetNativeSystemInfo; + using ::GetTickCount64; +#else + using ::GetSystemInfo; +#endif using ::CloseHandle; using ::ReleaseMutex; using ::ReleaseSemaphore; using ::SetEvent; using ::ResetEvent; - using ::WaitForMultipleObjects; - using ::WaitForSingleObject; + using ::WaitForMultipleObjectsEx; + using ::WaitForSingleObjectEx; using ::GetCurrentProcessId; using ::GetCurrentThreadId; using ::GetCurrentThread; using ::GetCurrentProcess; using ::DuplicateHandle; +#if !BOOST_PLAT_WINDOWS_RUNTIME using ::SleepEx; using ::Sleep; using ::QueueUserAPC; - using ::GetTickCount; +#endif } } } @@ -81,39 +107,58 @@ extern "C" { typedef int BOOL; typedef unsigned long DWORD; typedef void* HANDLE; - # include <kfuncs.h> # ifdef __cplusplus } # endif # endif +# ifdef __cplusplus +extern "C" { +# endif +struct _SYSTEM_INFO; +# ifdef __cplusplus +} +#endif + namespace boost { namespace detail { namespace win32 { - # ifdef _WIN64 typedef unsigned __int64 ulong_ptr; # else typedef unsigned long ulong_ptr; # endif typedef void* handle; + typedef _SYSTEM_INFO system_info; + typedef unsigned __int64 ticks_type; unsigned const infinite=~0U; unsigned const timeout=258U; handle const invalid_handle_value=(handle)(-1); unsigned const event_modify_state=2; unsigned const synchronize=0x100000u; + unsigned const wait_abandoned=0x00000080u; + unsigned const create_event_initial_set = 0x00000002; + unsigned const create_event_manual_reset = 0x00000001; + unsigned const event_all_access = 0x1F0003; + unsigned const semaphore_all_access = 0x1F0003; extern "C" { struct _SECURITY_ATTRIBUTES; # ifdef BOOST_NO_ANSI_APIS +# if BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA __declspec(dllimport) void* __stdcall CreateMutexW(_SECURITY_ATTRIBUTES*,int,wchar_t const*); __declspec(dllimport) void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES*,long,long,wchar_t const*); __declspec(dllimport) void* __stdcall CreateEventW(_SECURITY_ATTRIBUTES*,int,int,wchar_t const*); +# else + __declspec(dllimport) void* __stdcall CreateMutexExW(_SECURITY_ATTRIBUTES*,wchar_t const*,unsigned long,unsigned long); + __declspec(dllimport) void* __stdcall CreateEventExW(_SECURITY_ATTRIBUTES*,wchar_t const*,unsigned long,unsigned long); + __declspec(dllimport) void* __stdcall CreateSemaphoreExW(_SECURITY_ATTRIBUTES*,long,long,wchar_t const*,unsigned long,unsigned long); +# endif __declspec(dllimport) void* __stdcall OpenEventW(unsigned long,int,wchar_t const*); # else __declspec(dllimport) void* __stdcall CreateMutexA(_SECURITY_ATTRIBUTES*,int,char const*); @@ -121,18 +166,24 @@ namespace boost __declspec(dllimport) void* __stdcall CreateEventA(_SECURITY_ATTRIBUTES*,int,int,char const*); __declspec(dllimport) void* __stdcall OpenEventA(unsigned long,int,char const*); # endif +#if BOOST_PLAT_WINDOWS_RUNTIME + __declspec(dllimport) void __stdcall GetNativeSystemInfo(_SYSTEM_INFO*); + __declspec(dllimport) ticks_type __stdcall GetTickCount64(); +#else + __declspec(dllimport) void __stdcall GetSystemInfo(_SYSTEM_INFO*); +#endif __declspec(dllimport) int __stdcall CloseHandle(void*); __declspec(dllimport) int __stdcall ReleaseMutex(void*); - __declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void*,unsigned long); - __declspec(dllimport) unsigned long __stdcall WaitForMultipleObjects(unsigned long nCount,void* const * lpHandles,int bWaitAll,unsigned long dwMilliseconds); + __declspec(dllimport) unsigned long __stdcall WaitForSingleObjectEx(void*,unsigned long,int); + __declspec(dllimport) unsigned long __stdcall WaitForMultipleObjectsEx(unsigned long nCount,void* const * lpHandles,int bWaitAll,unsigned long dwMilliseconds,int bAlertable); __declspec(dllimport) int __stdcall ReleaseSemaphore(void*,long,long*); __declspec(dllimport) int __stdcall DuplicateHandle(void*,void*,void*,void**,unsigned long,int,unsigned long); +#if !BOOST_PLAT_WINDOWS_RUNTIME __declspec(dllimport) unsigned long __stdcall SleepEx(unsigned long,int); __declspec(dllimport) void __stdcall Sleep(unsigned long); typedef void (__stdcall *queue_user_apc_callback_function)(ulong_ptr); __declspec(dllimport) unsigned long __stdcall QueueUserAPC(queue_user_apc_callback_function,void*,ulong_ptr); - - __declspec(dllimport) unsigned long __stdcall GetTickCount(); +#endif # ifndef UNDER_CE __declspec(dllimport) unsigned long __stdcall GetCurrentProcessId(); @@ -165,6 +216,103 @@ namespace boost { namespace win32 { + namespace detail { typedef int (__stdcall *farproc_t)(); typedef ticks_type (__stdcall *gettickcount64_t)(); } +#if !BOOST_PLAT_WINDOWS_RUNTIME + extern "C" + { + __declspec(dllimport) detail::farproc_t __stdcall GetProcAddress(void *, const char *); +#if !defined(BOOST_NO_ANSI_APIS) + __declspec(dllimport) void * __stdcall GetModuleHandleA(const char *); +#else + __declspec(dllimport) void * __stdcall GetModuleHandleW(const wchar_t *); +#endif + __declspec(dllimport) unsigned long __stdcall GetTickCount(); +#ifdef _MSC_VER + long _InterlockedCompareExchange(long volatile *, long, long); +#pragma intrinsic(_InterlockedCompareExchange) +#elif defined(__MINGW64_VERSION_MAJOR) + long _InterlockedCompareExchange(long volatile *, long, long); +#else + // Mingw doesn't provide intrinsics +#define _InterlockedCompareExchange InterlockedCompareExchange +#endif + } + // 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; + unsigned long previous_count, current_tick32, previous_count_zone, current_tick32_zone; + ticks_type current_tick64; + + previous_count = (unsigned long) _InterlockedCompareExchange(&count, 0, 0); + current_tick32 = GetTickCount(); + + if(previous_count == 0xFFFFFFFF) + { + // count has never been written + unsigned long initial_count; + initial_count = current_tick32 >> 28; + previous_count = (unsigned long) _InterlockedCompareExchange(&count, initial_count, 0xFFFFFFFF); + + current_tick64 = initial_count; + current_tick64 <<= 28; + current_tick64 += current_tick32 & 0x0FFFFFFF; + return current_tick64; + } + + previous_count_zone = previous_count & 15; + current_tick32_zone = current_tick32 >> 28; + + if(current_tick32_zone == previous_count_zone) + { + // The top four bits of the 32-bit tick count haven't changed since count was last written. + current_tick64 = previous_count; + current_tick64 <<= 28; + current_tick64 += current_tick32 & 0x0FFFFFFF; + return current_tick64; + } + + 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; + current_tick64 <<= 28; + current_tick64 += current_tick32 & 0x0FFFFFFF; + return current_tick64; + } + + // Oops, we weren't called often enough, we're stuck + return 0xFFFFFFFF; + } +#else +#endif + inline detail::gettickcount64_t GetTickCount64_() + { + static detail::gettickcount64_t gettickcount64impl; + if(gettickcount64impl) + return gettickcount64impl; + + // GetTickCount and GetModuleHandle are not allowed in the Windows Runtime, + // and kernel32 isn't used in Windows Phone. +#if BOOST_PLAT_WINDOWS_RUNTIME + gettickcount64impl = &GetTickCount64; +#else + detail::farproc_t addr=GetProcAddress( +#if !defined(BOOST_NO_ANSI_APIS) + GetModuleHandleA("KERNEL32.DLL"), +#else + GetModuleHandleW(L"KERNEL32.DLL"), +#endif + "GetTickCount64"); + if(addr) + gettickcount64impl=(detail::gettickcount64_t) addr; + else + gettickcount64impl=&GetTickCount64emulation; +#endif + return gettickcount64impl; + } + enum event_type { auto_reset_event=false, @@ -177,13 +325,32 @@ namespace boost event_initially_set=true }; - inline handle create_anonymous_event(event_type type,initial_event_state state) + inline handle create_event( +#if !defined(BOOST_NO_ANSI_APIS) + const char *mutex_name, +#else + const wchar_t *mutex_name, +#endif + event_type type, + initial_event_state state) { #if !defined(BOOST_NO_ANSI_APIS) - handle const res=win32::CreateEventA(0,type,state,0); + handle const res = win32::CreateEventA(0, type, state, mutex_name); +#elif BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA + handle const res = win32::CreateEventW(0, type, state, mutex_name); #else - handle const res=win32::CreateEventW(0,type,state,0); + handle const res = win32::CreateEventExW( + 0, + mutex_name, + type ? create_event_manual_reset : 0 | state ? create_event_initial_set : 0, + event_all_access); #endif + return res; + } + + inline handle create_anonymous_event(event_type type,initial_event_state state) + { + handle const res = create_event(0, type, state); if(!res) { boost::throw_exception(thread_resource_error()); @@ -191,28 +358,29 @@ namespace boost return res; } - inline handle create_anonymous_semaphore(long initial_count,long max_count) + inline handle create_anonymous_semaphore_nothrow(long initial_count,long max_count) { #if !defined(BOOST_NO_ANSI_APIS) - handle const res=CreateSemaphoreA(0,initial_count,max_count,0); + handle const res=win32::CreateSemaphoreA(0,initial_count,max_count,0); #else - handle const res=CreateSemaphoreW(0,initial_count,max_count,0); +#if BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA + handle const res=win32::CreateSemaphoreEx(0,initial_count,max_count,0,0); +#else + handle const res=win32::CreateSemaphoreExW(0,initial_count,max_count,0,0,semaphore_all_access); +#endif #endif + return res; + } + + inline handle create_anonymous_semaphore(long initial_count,long max_count) + { + handle const res=create_anonymous_semaphore_nothrow(initial_count,max_count); if(!res) { boost::throw_exception(thread_resource_error()); } return res; } - inline handle create_anonymous_semaphore_nothrow(long initial_count,long max_count) - { -#if !defined(BOOST_NO_ANSI_APIS) - handle const res=CreateSemaphoreA(0,initial_count,max_count,0); -#else - handle const res=CreateSemaphoreW(0,initial_count,max_count,0); -#endif - return res; - } inline handle duplicate_handle(handle source) { @@ -231,8 +399,65 @@ namespace boost { BOOST_VERIFY(ReleaseSemaphore(semaphore,count,0)!=0); } + + inline void get_system_info(system_info *info) + { +#if BOOST_PLAT_WINDOWS_RUNTIME + win32::GetNativeSystemInfo(info); +#else + win32::GetSystemInfo(info); +#endif + } + + inline void sleep(unsigned long milliseconds) + { + if(milliseconds == 0) + { +#if BOOST_PLAT_WINDOWS_RUNTIME + std::this_thread::yield(); +#else + ::boost::detail::win32::Sleep(0); +#endif + } + else + { +#if BOOST_PLAT_WINDOWS_RUNTIME + ::boost::detail::win32::WaitForSingleObjectEx(::boost::detail::win32::GetCurrentThread(), milliseconds, 0); +#else + ::boost::detail::win32::Sleep(milliseconds); +#endif + } + } + +#if BOOST_PLAT_WINDOWS_RUNTIME + class BOOST_THREAD_DECL scoped_winrt_thread + { + public: + scoped_winrt_thread() : m_completionHandle(invalid_handle_value) + {} + + ~scoped_winrt_thread() + { + if (m_completionHandle != ::boost::detail::win32::invalid_handle_value) + { + CloseHandle(m_completionHandle); + } + } + + typedef unsigned(__stdcall * thread_func)(void *); + bool start(thread_func address, void *parameter, unsigned int *thrdId); + + handle waitable_handle() const + { + BOOST_ASSERT(m_completionHandle != ::boost::detail::win32::invalid_handle_value); + return m_completionHandle; + } - class handle_manager + private: + handle m_completionHandle; + }; +#endif + class BOOST_THREAD_DECL handle_manager { private: handle handle_to_manage; @@ -294,7 +519,6 @@ namespace boost cleanup(); } }; - } } } @@ -341,7 +565,7 @@ namespace boost { inline bool interlocked_bit_test_and_set(long* x,long bit) { -#if 0 +#ifndef BOOST_INTEL_CXX_VERSION __asm { mov eax,bit; mov edx,x; @@ -351,7 +575,11 @@ namespace boost #else bool ret; __asm { - mov eax,bit; mov edx,x; lock bts [edx],eax; setc al; mov ret, al + mov eax,bit + mov edx,x + lock bts [edx],eax + setc al + mov ret, al }; return ret; @@ -360,7 +588,7 @@ namespace boost inline bool interlocked_bit_test_and_reset(long* x,long bit) { -#if 0 +#ifndef BOOST_INTEL_CXX_VERSION __asm { mov eax,bit; mov edx,x; @@ -368,11 +596,13 @@ namespace boost setc al; }; #else - - bool ret; __asm { - mov eax,bit; mov edx,x; lock btr [edx],eax; setc al; mov ret, al + mov eax,bit + mov edx,x + lock btr [edx],eax + setc al + mov ret, al }; return ret; diff --git a/boost/thread/with_lock_guard.hpp b/boost/thread/with_lock_guard.hpp new file mode 100644 index 0000000000..5d99b36f2e --- /dev/null +++ b/boost/thread/with_lock_guard.hpp @@ -0,0 +1,234 @@ +// (C) Copyright 2013 Ruslan Baratov +// Copyright (C) 2014 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See www.boost.org/libs/thread for documentation. + +#ifndef BOOST_THREAD_WITH_LOCK_GUARD_HPP +#define BOOST_THREAD_WITH_LOCK_GUARD_HPP + +#include <boost/thread/lock_guard.hpp> +#include <boost/utility/result_of.hpp> +//#include <boost/thread/detail/invoke.hpp> + +namespace boost { + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ + !defined(BOOST_NO_CXX11_DECLTYPE) && \ + !defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) + +/** + * Utility to run functions in scope protected by mutex. + * + * Examples: + * + * int func(int, int&); + * boost::mutex m; + * int a; + * int result = boost::with_lock_guard(m, func, 1, boost::ref(a)); + * + * // using boost::bind + * int result = boost::with_lock_guard( + * m, boost::bind(func, 2, boost::ref(a)) + * ); + * + * // using lambda + * int a; + * int result = boost::with_lock_guard( + * m, + * [&a](int x) { + * a = 3; + * return x + 4; + * }, + * 5 + * ); + */ +template <class Lockable, class Function, class... Args> +typename boost::result_of<Function(Args...)>::type with_lock_guard( + Lockable& m, + BOOST_FWD_REF(Function) func, + BOOST_FWD_REF(Args)... args +) //-> decltype(func(boost::forward<Args>(args)...)) +{ + boost::lock_guard<Lockable> lock(m); + return func(boost::forward<Args>(args)...); +} + +#else + +// Workaround versions for compilers without c++11 variadic templates support. +// (function arguments limit: 4) +// (for lambda support define BOOST_RESULT_OF_USE_DECLTYPE may be needed) + +template <class Lockable, class Func> +typename boost::result_of<Func()>::type with_lock_guard( + Lockable& m, + BOOST_FWD_REF(Func) func +) { + boost::lock_guard<Lockable> lock(m); + return func(); +} + +template <class Lockable, class Func, class Arg> +typename boost::result_of<Func(Arg)>::type with_lock_guard( + Lockable& m, + BOOST_FWD_REF(Func) func, + BOOST_FWD_REF(Arg) arg +) { + boost::lock_guard<Lockable> lock(m); + return func( + boost::forward<Arg>(arg) + ); +} + +template <class Lockable, class Func, class Arg1, class Arg2> +typename boost::result_of<Func(Arg1, Arg2)>::type with_lock_guard( + Lockable& m, + BOOST_FWD_REF(Func) func, + BOOST_FWD_REF(Arg1) arg1, + BOOST_FWD_REF(Arg2) arg2 +) { + boost::lock_guard<Lockable> lock(m); + return func( + boost::forward<Arg1>(arg1), + boost::forward<Arg2>(arg2) + ); +} + +template <class Lockable, class Func, class Arg1, class Arg2, class Arg3> +typename boost::result_of<Func(Arg1, Arg2, Arg3)>::type with_lock_guard( + Lockable& m, + BOOST_FWD_REF(Func) func, + BOOST_FWD_REF(Arg1) arg1, + BOOST_FWD_REF(Arg2) arg2, + BOOST_FWD_REF(Arg3) arg3 +) { + boost::lock_guard<Lockable> lock(m); + return func( + boost::forward<Arg1>(arg1), + boost::forward<Arg2>(arg2), + boost::forward<Arg3>(arg3) + ); +} + +template < + class Lockable, class Func, class Arg1, class Arg2, class Arg3, class Arg4 +> +typename boost::result_of<Func(Arg1, Arg2, Arg3, Arg4)>::type with_lock_guard( + Lockable& m, + BOOST_FWD_REF(Func) func, + BOOST_FWD_REF(Arg1) arg1, + BOOST_FWD_REF(Arg2) arg2, + BOOST_FWD_REF(Arg3) arg3, + BOOST_FWD_REF(Arg4) arg4 +) { + boost::lock_guard<Lockable> lock(m); + return func( + boost::forward<Arg1>(arg1), + boost::forward<Arg2>(arg2), + boost::forward<Arg3>(arg3), + boost::forward<Arg4>(arg4) + ); +} + +// overloads for function pointer +// (if argument is not function pointer, static assert will trigger) +template <class Lockable, class Func> +typename boost::result_of< + typename boost::add_pointer<Func>::type() +>::type with_lock_guard( + Lockable& m, + Func* func +) { + BOOST_STATIC_ASSERT(boost::is_function<Func>::value); + + boost::lock_guard<Lockable> lock(m); + return func(); +} + +template <class Lockable, class Func, class Arg> +typename boost::result_of< + typename boost::add_pointer<Func>::type(Arg) +>::type with_lock_guard( + Lockable& m, + Func* func, + BOOST_FWD_REF(Arg) arg +) { + BOOST_STATIC_ASSERT(boost::is_function<Func>::value); + + boost::lock_guard<Lockable> lock(m); + return func( + boost::forward<Arg>(arg) + ); +} + +template <class Lockable, class Func, class Arg1, class Arg2> +typename boost::result_of< + typename boost::add_pointer<Func>::type(Arg1, Arg2) +>::type with_lock_guard( + Lockable& m, + Func* func, + BOOST_FWD_REF(Arg1) arg1, + BOOST_FWD_REF(Arg2) arg2 +) { + BOOST_STATIC_ASSERT(boost::is_function<Func>::value); + + boost::lock_guard<Lockable> lock(m); + return func( + boost::forward<Arg1>(arg1), + boost::forward<Arg2>(arg2) + ); +} + +template <class Lockable, class Func, class Arg1, class Arg2, class Arg3> +typename boost::result_of< + typename boost::add_pointer<Func>::type(Arg1, Arg2, Arg3) +>::type with_lock_guard( + Lockable& m, + Func* func, + BOOST_FWD_REF(Arg1) arg1, + BOOST_FWD_REF(Arg2) arg2, + BOOST_FWD_REF(Arg3) arg3 +) { + BOOST_STATIC_ASSERT(boost::is_function<Func>::value); + + boost::lock_guard<Lockable> lock(m); + return func( + boost::forward<Arg1>(arg1), + boost::forward<Arg2>(arg2), + boost::forward<Arg3>(arg3) + ); +} + +template < + class Lockable, class Func, class Arg1, class Arg2, class Arg3, class Arg4 +> +typename boost::result_of< + typename boost::add_pointer<Func>::type(Arg1, Arg2, Arg3, Arg4) +>::type with_lock_guard( + Lockable& m, + Func* func, + BOOST_FWD_REF(Arg1) arg1, + BOOST_FWD_REF(Arg2) arg2, + BOOST_FWD_REF(Arg3) arg3, + BOOST_FWD_REF(Arg4) arg4 +) { + BOOST_STATIC_ASSERT(boost::is_function<Func>::value); + + boost::lock_guard<Lockable> lock(m); + return func( + boost::forward<Arg1>(arg1), + boost::forward<Arg2>(arg2), + boost::forward<Arg3>(arg3), + boost::forward<Arg4>(arg4) + ); +} + +#endif + +} // namespace boost + +#endif // BOOST_THREAD_WITH_LOCK_GUARD_HPP + diff --git a/boost/thread/xtime.hpp b/boost/thread/xtime.hpp index 1ca996fa0c..9c6a359640 100644 --- a/boost/thread/xtime.hpp +++ b/boost/thread/xtime.hpp @@ -9,6 +9,7 @@ #define BOOST_XTIME_WEK070601_HPP #include <boost/thread/detail/config.hpp> +#if defined BOOST_THREAD_USES_DATETIME #include <boost/cstdint.hpp> #include <boost/thread/thread_time.hpp> @@ -88,5 +89,5 @@ inline int xtime_cmp(const xtime& xt1, const xtime& xt2) } // namespace boost #include <boost/config/abi_suffix.hpp> - +#endif #endif //BOOST_XTIME_WEK070601_HPP |