diff options
Diffstat (limited to 'boost/thread')
36 files changed, 3553 insertions, 1157 deletions
diff --git a/boost/thread/barrier.hpp b/boost/thread/barrier.hpp index 4ca30cb4df..4fd89883b8 100644 --- a/boost/thread/barrier.hpp +++ b/boost/thread/barrier.hpp @@ -2,7 +2,7 @@ // David Moore, William E. Kempf // Copyright (C) 2007-8 Anthony Williams // -// Distributed under the Boost Software License, Version 1.0. (See accompanying +// 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_BARRIER_JDM030602_HPP @@ -28,14 +28,14 @@ namespace boost : m_threshold(count), m_count(count), m_generation(0) { if (count == 0) - boost::throw_exception(std::invalid_argument("count cannot be zero.")); + 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++; diff --git a/boost/thread/cv_status.hpp b/boost/thread/cv_status.hpp new file mode 100644 index 0000000000..99b3c0c218 --- /dev/null +++ b/boost/thread/cv_status.hpp @@ -0,0 +1,26 @@ +// cv_status.hpp +// +// Copyright (C) 2011 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_CV_STATUS_HPP +#define BOOST_THREAD_CV_STATUS_HPP + +#include <boost/detail/scoped_enum_emulation.hpp> + +namespace boost +{ + + // enum class cv_status; + BOOST_SCOPED_ENUM_DECLARE_BEGIN(cv_status) + { + no_timeout, + timeout + } + BOOST_SCOPED_ENUM_DECLARE_END(cv_status) +} + +#endif // header diff --git a/boost/thread/detail/config.hpp b/boost/thread/detail/config.hpp index b59550669c..d9270df8af 100644 --- a/boost/thread/detail/config.hpp +++ b/boost/thread/detail/config.hpp @@ -1,5 +1,6 @@ // Copyright (C) 2001-2003 // William E. Kempf +// Copyright (C) 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) @@ -10,13 +11,117 @@ #include <boost/config.hpp> #include <boost/detail/workaround.hpp> +// This compiler doesn't support Boost.Chrono +#if defined __IBMCPP__ && (__IBMCPP__ < 1100) +#define BOOST_THREAD_DONT_USE_CHRONO +#endif + +// This compiler doesn't support Boost.Move +#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) +#define BOOST_THREAD_DONT_USE_MOVE +#endif +// This compiler doesn't support Boost.Container Allocators files +#if defined __SUNPRO_CC +#define BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS +#endif + +#if defined _WIN32_WCE && _WIN32_WCE==0x501 +#define BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS +#endif + +#if ! defined BOOST_THREAD_DONT_PROVIDE_BASIC_THREAD_ID +#define BOOST_THREAD_PROVIDES_BASIC_THREAD_ID +#endif + +// Default version is 2 #if !defined BOOST_THREAD_VERSION -#define BOOST_THREAD_VERSION 1 +#define BOOST_THREAD_VERSION 2 #else -#if BOOST_THREAD_VERSION!=1 && BOOST_THREAD_VERSION!=2 -#error "BOOST_THREAD_VERSION must be 1 or 2" +#if BOOST_THREAD_VERSION!=2 && BOOST_THREAD_VERSION!=3 +#error "BOOST_THREAD_VERSION must be 2 or 3" +#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 +#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 +#endif + +// Don't provided by default in version 1. +#if defined BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION +#define BOOST_THREAD_EXPLICIT_LOCK_CONVERSION explicit +#else +#define BOOST_THREAD_EXPLICIT_LOCK_CONVERSION +#endif + + +// 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 #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 +#endif +#endif + +#if BOOST_THREAD_VERSION==3 +#if ! defined BOOST_THREAD_DONT_PROVIDE_ONCE_CXX11 +#define BOOST_THREAD_PROVIDES_ONCE_CXX11 +#endif +#if ! defined BOOST_THREAD_DONT_PROVIDE_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 +#define BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE +#endif +#if ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE +#define BOOST_THREAD_PROVIDES_FUTURE +#endif +#if ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS +#define BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS +#endif +#if ! defined BOOST_THREAD_DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSIONS +#define BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS +#endif +#if ! defined BOOST_THREAD_DONT_PROVIDE_EXPLICIT_LOCK_CONVERSION +#define BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION +#endif +#if ! defined BOOST_THREAD_DONT_PROVIDE_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 +#define BOOST_THREAD_USES_MOVE +#endif +#endif + +#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 +#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 +// 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 #endif #if BOOST_WORKAROUND(__BORLANDC__, < 0x600) @@ -26,7 +131,7 @@ # pragma warn -8066 // Unreachable code #endif -#include "platform.hpp" +#include <boost/thread/detail/platform.hpp> // provided for backwards compatibility, since this // macro was used for several releases by mistake. diff --git a/boost/thread/detail/delete.hpp b/boost/thread/detail/delete.hpp new file mode 100644 index 0000000000..9e56d4429e --- /dev/null +++ b/boost/thread/detail/delete.hpp @@ -0,0 +1,45 @@ +// 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_DELETE_HPP +#define BOOST_THREAD_DETAIL_DELETE_HPP + +#include <boost/config.hpp> + +/** + * BOOST_THREAD_DELETE_COPY_CTOR deletes the copy constructor when the compiler supports it or + * makes it private. + * + * BOOST_THREAD_DELETE_COPY_ASSIGN deletes the copy assignment when the compiler supports it or + * makes it private. + */ +#ifndef BOOST_NO_DELETED_FUNCTIONS +#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 +#define BOOST_THREAD_DELETE_COPY_CTOR(CLASS) \ + private: \ + CLASS(CLASS&); \ + public: + +#define BOOST_THREAD_DELETE_COPY_ASSIGN(CLASS) \ + private: \ + CLASS& operator=(CLASS&); \ + public: +#endif // BOOST_NO_DELETED_FUNCTIONS + +/** + * BOOST_THREAD_NO_COPYABLE deletes the copy constructor and assignment when the compiler supports it or + * makes them private. + */ +#define BOOST_THREAD_NO_COPYABLE(CLASS) \ + BOOST_THREAD_DELETE_COPY_CTOR(CLASS) \ + BOOST_THREAD_DELETE_COPY_ASSIGN(CLASS) + +#endif // BOOST_THREAD_DETAIL_DELETE_HPP diff --git a/boost/thread/detail/memory.hpp b/boost/thread/detail/memory.hpp new file mode 100644 index 0000000000..7d47efc781 --- /dev/null +++ b/boost/thread/detail/memory.hpp @@ -0,0 +1,54 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (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) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#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> + +namespace boost +{ + namespace thread_detail + { + template <class _Alloc> + class allocator_destructor + { + typedef container::allocator_traits<_Alloc> alloc_traits; + public: + typedef typename alloc_traits::pointer pointer; + typedef typename alloc_traits::size_type size_type; + private: + _Alloc& alloc_; + size_type s_; + public: + allocator_destructor(_Alloc& a, size_type s)BOOST_NOEXCEPT + : alloc_(a), s_(s) + {} + void operator()(pointer p)BOOST_NOEXCEPT + { + 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 665a0b5978..748b8dc241 100644 --- a/boost/thread/detail/move.hpp +++ b/boost/thread/detail/move.hpp @@ -2,6 +2,7 @@ // 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-2012 Vicente J. Botet Escriba #ifndef BOOST_THREAD_MOVE_HPP #define BOOST_THREAD_MOVE_HPP @@ -11,10 +12,12 @@ #include <boost/utility/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> #endif +#include <boost/thread/detail/delete.hpp> #include <boost/move/move.hpp> - #include <boost/config/abi_prefix.hpp> namespace boost @@ -22,6 +25,8 @@ namespace boost namespace detail { + template <typename T> + struct has_move_emulation_enabled_aux_dummy_specialization; template<typename T> struct thread_move_t { @@ -44,6 +49,7 @@ namespace boost }; } + #ifndef BOOST_NO_SFINAE template<typename T> typename enable_if<boost::is_convertible<T&,boost::detail::thread_move_t<T> >, boost::detail::thread_move_t<T> >::type move(T& t) @@ -57,9 +63,183 @@ namespace boost { return t; } +} + +#if ! defined BOOST_NO_RVALUE_REFERENCES + +#define BOOST_THREAD_RV_REF(TYPE) BOOST_RV_REF(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 +#define BOOST_THREAD_MAKE_RV_REF(RVALUE) RVALUE +#define BOOST_THREAD_FWD_REF(TYPE) BOOST_FWD_REF(TYPE) +#define BOOST_THREAD_DCL_MOVABLE(TYPE) +#define BOOST_THREAD_DCL_MOVABLE_BEG(T) \ + namespace detail { \ + template <typename T> \ + struct has_move_emulation_enabled_aux_dummy_specialization< + +#define BOOST_THREAD_DCL_MOVABLE_END > \ + : integral_constant<bool, true> \ + {}; \ + } + +#elif ! defined BOOST_NO_RVALUE_REFERENCES && defined BOOST_MSVC + +#define BOOST_THREAD_RV_REF(TYPE) BOOST_RV_REF(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 +#define BOOST_THREAD_MAKE_RV_REF(RVALUE) RVALUE +#define BOOST_THREAD_FWD_REF(TYPE) BOOST_FWD_REF(TYPE) +#define BOOST_THREAD_DCL_MOVABLE(TYPE) +#define BOOST_THREAD_DCL_MOVABLE_BEG(T) \ + namespace detail { \ + template <typename T> \ + struct has_move_emulation_enabled_aux_dummy_specialization< + +#define BOOST_THREAD_DCL_MOVABLE_END > \ + : integral_constant<bool, true> \ + {}; \ + } + +#else + +#if defined BOOST_THREAD_USES_MOVE +#define BOOST_THREAD_RV_REF(TYPE) BOOST_RV_REF(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 +#define BOOST_THREAD_FWD_REF(TYPE) BOOST_FWD_REF(TYPE) +#define BOOST_THREAD_DCL_MOVABLE(TYPE) +#define BOOST_THREAD_DCL_MOVABLE_BEG(T) \ + namespace detail { \ + template <typename T> \ + struct has_move_emulation_enabled_aux_dummy_specialization< + +#define BOOST_THREAD_DCL_MOVABLE_END > \ + : integral_constant<bool, true> \ + {}; \ + } + +#else + +#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 > +#define BOOST_THREAD_RV(V) (*V) +#define BOOST_THREAD_FWD_REF(TYPE) BOOST_FWD_REF(TYPE) + +#define BOOST_THREAD_DCL_MOVABLE(TYPE) \ +template <> \ +struct has_move_emulation_enabled_aux< TYPE > \ + : BOOST_MOVE_BOOST_NS::integral_constant<bool, true> \ +{}; + +#define BOOST_THREAD_DCL_MOVABLE_BEG(T) \ +template <typename T> \ +struct has_move_emulation_enabled_aux< + +#define BOOST_THREAD_DCL_MOVABLE_END > \ + : BOOST_MOVE_BOOST_NS::integral_constant<bool, true> \ +{}; + +#endif + +namespace boost +{ +namespace detail +{ + template <typename T> + BOOST_THREAD_RV_REF(typename ::boost::remove_cv<typename ::boost::remove_reference<T>::type>::type) + make_rv_ref(T v) BOOST_NOEXCEPT + { + return (BOOST_THREAD_RV_REF(typename ::boost::remove_cv<typename ::boost::remove_reference<T>::type>::type))(v); + } +// template <typename T> +// BOOST_THREAD_RV_REF(typename ::boost::remove_cv<typename ::boost::remove_reference<T>::type>::type) +// make_rv_ref(T &v) BOOST_NOEXCEPT +// { +// return (BOOST_THREAD_RV_REF(typename ::boost::remove_cv<typename ::boost::remove_reference<T>::type>::type))(v); +// } +// template <typename T> +// const BOOST_THREAD_RV_REF(typename ::boost::remove_cv<typename ::boost::remove_reference<T>::type>::type) +// make_rv_ref(T const&v) BOOST_NOEXCEPT +// { +// return (const BOOST_THREAD_RV_REF(typename ::boost::remove_cv<typename ::boost::remove_reference<T>::type>::type))(v); +// } +} +} + +#define BOOST_THREAD_MAKE_RV_REF(RVALUE) RVALUE.move() +//#define BOOST_THREAD_MAKE_RV_REF(RVALUE) boost::detail::make_rv_ref(RVALUE) +#endif + + +#if ! defined BOOST_NO_RVALUE_REFERENCES + +#define BOOST_THREAD_MOVABLE(TYPE) + +#else + +#if defined BOOST_THREAD_USES_MOVE +#define BOOST_THREAD_MOVABLE(TYPE) \ + ::boost::rv<TYPE>& move() BOOST_NOEXCEPT \ + { \ + return *static_cast< ::boost::rv<TYPE>* >(this); \ + } \ + const ::boost::rv<TYPE>& move() const BOOST_NOEXCEPT \ + { \ + return *static_cast<const ::boost::rv<TYPE>* >(this); \ + } \ + operator ::boost::rv<TYPE>&() \ + { \ + return *static_cast< ::boost::rv<TYPE>* >(this); \ + } \ + operator const ::boost::rv<TYPE>&() const \ + { \ + return *static_cast<const ::boost::rv<TYPE>* >(this); \ + }\ +#else + +#define BOOST_THREAD_MOVABLE(TYPE) \ + operator ::boost::detail::thread_move_t<TYPE>() BOOST_NOEXCEPT \ + { \ + return move(); \ + } \ + ::boost::detail::thread_move_t<TYPE> move() BOOST_NOEXCEPT \ + { \ + ::boost::detail::thread_move_t<TYPE> x(*this); \ + return x; \ + } \ + +#endif +#endif + +#define BOOST_THREAD_MOVABLE_ONLY(TYPE) \ + BOOST_THREAD_NO_COPYABLE(TYPE) \ + BOOST_THREAD_MOVABLE(TYPE) \ + +#define BOOST_THREAD_COPYABLE_AND_MOVABLE(TYPE) \ + BOOST_THREAD_MOVABLE(TYPE) \ + + + +#ifndef BOOST_NO_RVALUE_REFERENCES +namespace boost +{ namespace thread_detail + { + template <class T> + typename decay<T>::type + decay_copy(T&& t) + { + return boost::forward<T>(t); + } + } } +#endif #include <boost/config/abi_suffix.hpp> diff --git a/boost/thread/detail/platform.hpp b/boost/thread/detail/platform.hpp index 58601b04b2..1f33b1a67a 100644 --- a/boost/thread/detail/platform.hpp +++ b/boost/thread/detail/platform.hpp @@ -19,6 +19,7 @@ // choose platform #if defined(linux) || defined(__linux) || defined(__linux__) # define BOOST_THREAD_LINUX +//# define BOOST_THREAD_WAIT_BUG boost::posix_time::microseconds(100000) #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) # define BOOST_THREAD_BSD #elif defined(sun) || defined(__sun) @@ -35,6 +36,7 @@ # define BOOST_THREAD_BEOS #elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) # define BOOST_THREAD_MACOS +//# define BOOST_THREAD_WAIT_BUG boost::posix_time::microseconds(1000) #elif defined(__IBMCPP__) || defined(_AIX) # define BOOST_THREAD_AIX #elif defined(__amigaos__) @@ -55,7 +57,7 @@ // dispatcher table. If there is no entry for a platform but pthreads is // available on the platform, pthread is choosen as default. If nothing is // available the preprocessor will fail with a diagnostic message. - + #if defined(BOOST_THREAD_POSIX) # define BOOST_THREAD_PLATFORM_PTHREAD #else diff --git a/boost/thread/detail/thread.hpp b/boost/thread/detail/thread.hpp index 7ac342bfc6..3c71b53cf7 100644 --- a/boost/thread/detail/thread.hpp +++ b/boost/thread/detail/thread.hpp @@ -4,7 +4,9 @@ // 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 +#include <boost/thread/detail/config.hpp> #include <boost/thread/exceptions.hpp> #ifndef BOOST_NO_IOSTREAM #include <ostream> @@ -13,7 +15,6 @@ #include <boost/thread/mutex.hpp> #include <boost/thread/xtime.hpp> #include <boost/thread/detail/thread_heap_alloc.hpp> -#include <boost/utility.hpp> #include <boost/assert.hpp> #include <list> #include <algorithm> @@ -25,6 +26,13 @@ #include <boost/utility/enable_if.hpp> #include <boost/type_traits/remove_reference.hpp> #include <boost/io/ios_state.hpp> +#include <boost/type_traits/is_same.hpp> +#include <boost/type_traits/decay.hpp> +#include <boost/functional/hash.hpp> +#ifdef BOOST_THREAD_USES_CHRONO +#include <boost/chrono/system_clocks.hpp> +#include <boost/chrono/ceil.hpp> +#endif #include <boost/config/abi_prefix.hpp> @@ -35,6 +43,7 @@ namespace boost { + namespace detail { template<typename F> @@ -42,18 +51,21 @@ namespace boost public detail::thread_data_base { public: + BOOST_THREAD_NO_COPYABLE(thread_data) #ifndef BOOST_NO_RVALUE_REFERENCES - thread_data(F&& f_): - f(static_cast<F&&>(f_)) - {} - thread_data(F& f_): - f(f_) - {} + thread_data(BOOST_THREAD_RV_REF(F) f_): + f(boost::forward<F>(f_)) + {} +// This overloading must be removed if we want the packaged_task's tests to pass. +// thread_data(F& f_): +// f(f_) +// {} #else - thread_data(F f_): - f(f_) + + thread_data(BOOST_THREAD_RV_REF(F) f_): + f(f_) {} - thread_data(detail::thread_move_t<F> f_): + thread_data(F f_): f(f_) {} #endif @@ -63,9 +75,6 @@ namespace boost } private: F f; - - void operator=(thread_data&); - thread_data(thread_data&); }; template<typename F> @@ -74,14 +83,11 @@ namespace boost { private: F& f; - - void operator=(thread_data&); - thread_data(thread_data&); public: + BOOST_THREAD_NO_COPYABLE(thread_data) thread_data(boost::reference_wrapper<F> f_): f(f_) {} - void run() { f(); @@ -94,13 +100,11 @@ namespace boost { private: F& f; - void operator=(thread_data&); - thread_data(thread_data&); public: + BOOST_THREAD_NO_COPYABLE(thread_data) thread_data(const boost::reference_wrapper<F> f_): f(f_) {} - void run() { f(); @@ -110,15 +114,18 @@ namespace boost class BOOST_THREAD_DECL thread { + public: + typedef thread_attributes attributes; + + BOOST_THREAD_MOVABLE_ONLY(thread) private: - thread(thread&); - thread& operator=(thread&); void release_handle(); detail::thread_data_ptr thread_info; void start_thread(); + void start_thread(const attributes& attr); explicit thread(detail::thread_data_ptr data); @@ -126,13 +133,15 @@ namespace boost #ifndef BOOST_NO_RVALUE_REFERENCES template<typename F> - static inline detail::thread_data_ptr make_thread_info(F&& 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> >(static_cast<F&&>(f))); + return detail::thread_data_ptr(detail::heap_new<detail::thread_data<typename boost::remove_reference<F>::type> >( + boost::forward<F>(f))); } static inline detail::thread_data_ptr make_thread_info(void (*f)()) { - return detail::thread_data_ptr(detail::heap_new<detail::thread_data<void(*)()> >(static_cast<void(*&&)()>(f))); + return detail::thread_data_ptr(detail::heap_new<detail::thread_data<void(*)()> >( + boost::forward<void(*)()>(f))); } #else template<typename F> @@ -141,7 +150,7 @@ namespace boost return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f)); } template<typename F> - static inline detail::thread_data_ptr make_thread_info(boost::detail::thread_move_t<F> 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<F> >(f)); } @@ -149,44 +158,40 @@ 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) thread(const volatile thread&); #endif - thread(); - ~thread(); - -#ifndef BOOST_NO_RVALUE_REFERENCES -#ifdef BOOST_MSVC - template <class F> - explicit thread(F f,typename disable_if<boost::is_convertible<F&,detail::thread_move_t<F> >, dummy* >::type=0): - thread_info(make_thread_info(static_cast<F&&>(f))) - { - start_thread(); - } -#else - template <class F> - thread(F&& f): - thread_info(make_thread_info(static_cast<F&&>(f))) - { - start_thread(); - } #endif - - thread(thread&& other) + thread() BOOST_NOEXCEPT; + ~thread() { - thread_info.swap(other.thread_info); + #if defined BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE + if (joinable()) { + std::terminate(); + } + #else + detach(); + #endif } - - thread& operator=(thread&& other) +#ifndef BOOST_NO_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 + ): + thread_info(make_thread_info(thread_detail::decay_copy(boost::forward<F>(f)))) { - thread_info=other.thread_info; - other.thread_info.reset(); - return *this; + start_thread(); } - - thread&& move() + template < + class F + > + thread(attributes& attrs, BOOST_THREAD_RV_REF(F) f): + thread_info(make_thread_info(thread_detail::decay_copy(boost::forward<F>(f)))) { - return static_cast<thread&&>(*this); + start_thread(attrs); } #else @@ -197,57 +202,73 @@ namespace boost { start_thread(); } + template <class F> + thread(attributes& attrs, F f): + thread_info(make_thread_info(f)) + { + start_thread(attrs); + } #else template <class F> - explicit thread(F f,typename disable_if<boost::is_convertible<F&,detail::thread_move_t<F> >, dummy* >::type=0): + 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): 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_info(make_thread_info(f)) + { + start_thread(attrs); + } #endif - template <class F> - explicit thread(detail::thread_move_t<F> f): + 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)) { start_thread(); } - thread(detail::thread_move_t<thread> x) + template <class F> + thread(attributes& attrs, BOOST_THREAD_RV_REF(F) f): + thread_info(make_thread_info(f)) { - thread_info=x->thread_info; - x->thread_info.reset(); + start_thread(attrs); } - +#endif + thread(BOOST_THREAD_RV_REF(thread) x) + { + thread_info=BOOST_THREAD_RV(x).thread_info; + BOOST_THREAD_RV(x).thread_info.reset(); + } +#if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF. #if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) thread& operator=(thread x) { swap(x); return *this; } -#else - thread& operator=(detail::thread_move_t<thread> x) - { - thread new_thread(x); - swap(new_thread); - return *this; - } #endif - operator detail::thread_move_t<thread>() - { - return move(); - } +#endif - detail::thread_move_t<thread> move() + thread& operator=(BOOST_THREAD_RV_REF(thread) other) BOOST_NOEXCEPT { - detail::thread_move_t<thread> x(*this); - return x; - } +#if defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE + if (joinable()) std::terminate(); #endif + thread_info=BOOST_THREAD_RV(other).thread_info; + BOOST_THREAD_RV(other).thread_info.reset(); + return *this; + } template <class F,class A1> - thread(F f,A1 a1): + thread(F f,A1 a1,typename disable_if<boost::is_convertible<F&,thread_attributes >, dummy* >::type=0): thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1))) { start_thread(); @@ -308,36 +329,92 @@ namespace boost start_thread(); } - void swap(thread& x) + void swap(thread& x) BOOST_NOEXCEPT { thread_info.swap(x.thread_info); } class BOOST_SYMBOL_VISIBLE id; - id get_id() const; + id get_id() const BOOST_NOEXCEPT; - bool joinable() const; + bool joinable() const BOOST_NOEXCEPT; void join(); - bool timed_join(const system_time& wait_until); +#ifdef BOOST_THREAD_USES_CHRONO + 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); + } + 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)); + } + template <class Duration> + bool try_join_until(const chrono::time_point<chrono::system_clock, Duration>& t) + { + using namespace chrono; + typedef time_point<system_clock, nanoseconds> nano_sys_tmpt; + return try_join_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch()))); + } +#endif +#if defined(BOOST_THREAD_PLATFORM_WIN32) + bool timed_join(const system_time& abs_time); + +#ifdef BOOST_THREAD_USES_CHRONO + bool try_join_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp); +#endif + public: + +#else + bool timed_join(const system_time& abs_time) + { + struct timespec const ts=detail::get_timespec(abs_time); + return do_try_join_until(ts); + } +#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()); + return do_try_join_until(ts); + } +#endif + private: + bool do_try_join_until(struct timespec const &timeout); + public: + +#endif template<typename TimeDuration> inline bool timed_join(TimeDuration const& rel_time) { return timed_join(get_system_time()+rel_time); } - void detach(); - static unsigned hardware_concurrency(); + void detach() BOOST_NOEXCEPT; + + static unsigned hardware_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 + // Use thread::id when comparisions are needed // backwards compatibility bool operator==(const thread& other) const; bool operator!=(const thread& other) const; - - static inline void yield() +#endif + static inline void yield() BOOST_NOEXCEPT { this_thread::yield(); } @@ -349,37 +426,30 @@ namespace boost // extensions void interrupt(); - bool interruption_requested() const; + bool interruption_requested() const BOOST_NOEXCEPT; }; - inline void swap(thread& lhs,thread& rhs) + inline void swap(thread& lhs,thread& rhs) BOOST_NOEXCEPT { return lhs.swap(rhs); } #ifndef BOOST_NO_RVALUE_REFERENCES - inline thread&& move(thread& t) + inline thread&& move(thread& t) BOOST_NOEXCEPT { return static_cast<thread&&>(t); } - inline thread&& move(thread&& t) - { - return static_cast<thread&&>(t); - } -#else - inline detail::thread_move_t<thread> move(detail::thread_move_t<thread> t) - { - return t; - } #endif + BOOST_THREAD_DCL_MOVABLE(thread) + namespace this_thread { - thread::id BOOST_THREAD_DECL get_id(); + thread::id BOOST_THREAD_DECL get_id() BOOST_NOEXCEPT; void BOOST_THREAD_DECL interruption_point(); - bool BOOST_THREAD_DECL interruption_enabled(); - bool BOOST_THREAD_DECL interruption_requested(); + bool BOOST_THREAD_DECL interruption_enabled() BOOST_NOEXCEPT; + bool BOOST_THREAD_DECL interruption_requested() BOOST_NOEXCEPT; inline BOOST_SYMBOL_VISIBLE void sleep(xtime const& abs_time) { @@ -390,48 +460,76 @@ namespace boost class BOOST_SYMBOL_VISIBLE thread::id { private: - detail::thread_data_ptr thread_data; + friend inline + std::size_t + hash_value(const thread::id &v) + { +#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID + return hash_value(v.thread_data); +#else + return hash_value(v.thread_data.get()); +#endif + } - id(detail::thread_data_ptr thread_data_): +#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID +#if defined(BOOST_THREAD_PLATFORM_WIN32) + typedef unsigned int data; +#else + typedef thread::native_handle_type data; +#endif +#else + typedef detail::thread_data_ptr data; +#endif + data thread_data; + + id(data thread_data_): thread_data(thread_data_) {} friend class thread; - friend id BOOST_THREAD_DECL this_thread::get_id(); + friend id BOOST_THREAD_DECL this_thread::get_id() BOOST_NOEXCEPT; public: - id(): - thread_data() + 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 {} - id(const id& other): + id(const id& other) BOOST_NOEXCEPT : thread_data(other.thread_data) {} - bool operator==(const id& y) const + bool operator==(const id& y) const BOOST_NOEXCEPT { return thread_data==y.thread_data; } - bool operator!=(const id& y) const + bool operator!=(const id& y) const BOOST_NOEXCEPT { return thread_data!=y.thread_data; } - bool operator<(const id& y) const + bool operator<(const id& y) const BOOST_NOEXCEPT { return thread_data<y.thread_data; } - bool operator>(const id& y) const + bool operator>(const id& y) const BOOST_NOEXCEPT { return y.thread_data<thread_data; } - bool operator<=(const id& y) const + bool operator<=(const id& y) const BOOST_NOEXCEPT { return !(y.thread_data<thread_data); } - bool operator>=(const id& y) const + bool operator>=(const id& y) const BOOST_NOEXCEPT { return !(thread_data<y.thread_data); } @@ -440,7 +538,7 @@ namespace boost #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS template<class charT, class traits> friend BOOST_SYMBOL_VISIBLE - std::basic_ostream<charT, traits>& + std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os, const id& x) { if(x.thread_data) @@ -456,12 +554,13 @@ namespace boost #else template<class charT, class traits> BOOST_SYMBOL_VISIBLE - std::basic_ostream<charT, traits>& + std::basic_ostream<charT, traits>& print(std::basic_ostream<charT, traits>& os) const { if(thread_data) { - return os<<thread_data; + io::ios_flags_saver ifs( os ); + return os<< std::hex << thread_data; } else { @@ -483,6 +582,7 @@ namespace boost } #endif +#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 inline bool thread::operator==(const thread& other) const { return get_id()==other.get_id(); @@ -492,6 +592,7 @@ namespace boost { return get_id()!=other.get_id(); } +#endif namespace detail { @@ -521,13 +622,6 @@ namespace boost void BOOST_THREAD_DECL add_thread_exit_function(thread_exit_function_base*); } -#ifdef BOOST_NO_RVALUE_REFERENCES - template <> - struct has_move_emulation_enabled_aux<thread> - : BOOST_MOVE_BOOST_NS::integral_constant<bool, true> - {}; -#endif - namespace this_thread { template<typename F> diff --git a/boost/thread/detail/thread_interruption.hpp b/boost/thread/detail/thread_interruption.hpp index 60c0e65b8c..f1a165c33e 100644 --- a/boost/thread/detail/thread_interruption.hpp +++ b/boost/thread/detail/thread_interruption.hpp @@ -4,6 +4,10 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // (C) Copyright 2007-9 Anthony Williams +// (C) Copyright 2012 Vicente J. Botet Escriba + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/detail/delete.hpp> namespace boost { @@ -11,23 +15,20 @@ namespace boost { class BOOST_THREAD_DECL disable_interruption { - disable_interruption(const disable_interruption&); - disable_interruption& operator=(const disable_interruption&); - - bool interruption_was_enabled; - friend class restore_interruption; + bool interruption_was_enabled; + friend class restore_interruption; public: - disable_interruption(); - ~disable_interruption(); + BOOST_THREAD_NO_COPYABLE(disable_interruption) + disable_interruption() BOOST_NOEXCEPT; + ~disable_interruption() BOOST_NOEXCEPT; }; class BOOST_THREAD_DECL restore_interruption { - restore_interruption(const restore_interruption&); - restore_interruption& operator=(const restore_interruption&); public: - explicit restore_interruption(disable_interruption& d); - ~restore_interruption(); + BOOST_THREAD_NO_COPYABLE(restore_interruption) + explicit restore_interruption(disable_interruption& d) BOOST_NOEXCEPT; + ~restore_interruption() BOOST_NOEXCEPT; }; } } diff --git a/boost/thread/exceptions.hpp b/boost/thread/exceptions.hpp index 06ce04e0d1..08c28d3d17 100644 --- a/boost/thread/exceptions.hpp +++ b/boost/thread/exceptions.hpp @@ -1,8 +1,9 @@ // Copyright (C) 2001-2003 // William E. Kempf // Copyright (C) 2007-9 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba // -// Distributed under the Boost Software License, Version 1.0. (See accompanying +// 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_EXCEPTIONS_PDM070801_H @@ -18,6 +19,9 @@ #include <string> #include <stdexcept> +#include <boost/system/system_error.hpp> +#include <boost/system/error_code.hpp> + #include <boost/config/abi_prefix.hpp> @@ -28,151 +32,188 @@ namespace boost {}; class BOOST_SYMBOL_VISIBLE thread_exception: - public std::exception + public system::system_error + //public std::exception { - protected: - thread_exception(): - m_sys_err(0) + typedef system::system_error base_type; + public: + thread_exception() + : base_type(0,system::system_category()) {} - - thread_exception(int sys_err_code): - m_sys_err(sys_err_code) + + thread_exception(int sys_error_code) + : base_type(sys_error_code, system::system_category()) {} - - public: + thread_exception( int ev, const char * what_arg ) + : base_type(system::error_code(ev, system::system_category()), what_arg) + { + } + thread_exception( int ev, const std::string & what_arg ) + : base_type(system::error_code(ev, system::system_category()), what_arg) + { + } + ~thread_exception() throw() {} - + int native_error() const { - return m_sys_err; + return code().value(); } - - private: - int m_sys_err; }; class BOOST_SYMBOL_VISIBLE condition_error: - public std::exception + public system::system_error + //public std::exception { + typedef system::system_error base_type; public: - const char* what() const throw() - { - return "Condition error"; - } + condition_error() + : base_type(system::error_code(0, system::system_category()), "Condition error") + {} + condition_error( int ev ) + : base_type(system::error_code(ev, system::system_category()), "Condition error") + { + } + condition_error( int ev, const char * what_arg ) + : base_type(system::error_code(ev, system::system_category()), what_arg) + { + } + condition_error( int ev, const std::string & what_arg ) + : base_type(system::error_code(ev, system::system_category()), what_arg) + { + } }; - + class BOOST_SYMBOL_VISIBLE lock_error: public thread_exception { + typedef thread_exception base_type; public: lock_error() + : base_type(0, "boost::lock_error") {} - - lock_error(int sys_err_code): - thread_exception(sys_err_code) - {} - - ~lock_error() throw() - {} - - virtual const char* what() const throw() + lock_error( int ev ) + : base_type(ev, "boost::lock_error") + { + } + lock_error( int ev, const char * what_arg ) + : base_type(ev, what_arg) { - return "boost::lock_error"; } + lock_error( int ev, const std::string & what_arg ) + : base_type(ev, what_arg) + { + } + + ~lock_error() throw() + {} + }; class BOOST_SYMBOL_VISIBLE thread_resource_error: public thread_exception { + typedef thread_exception base_type; public: - thread_resource_error() - {} - - thread_resource_error(int sys_err_code): - thread_exception(sys_err_code) - {} - + thread_resource_error() + : base_type(system::errc::resource_unavailable_try_again, "boost::thread_resource_error") + {} + + thread_resource_error( int ev ) + : base_type(ev, "boost::thread_resource_error") + { + } + thread_resource_error( int ev, const char * what_arg ) + : base_type(ev, what_arg) + { + } + thread_resource_error( int ev, const std::string & what_arg ) + : base_type(ev, what_arg) + { + } + + ~thread_resource_error() throw() {} - - virtual const char* what() const throw() - { - return "boost::thread_resource_error"; - } - }; class BOOST_SYMBOL_VISIBLE unsupported_thread_option: public thread_exception { + typedef thread_exception base_type; public: - unsupported_thread_option() - {} - - unsupported_thread_option(int sys_err_code): - thread_exception(sys_err_code) - {} - - ~unsupported_thread_option() throw() - {} - + unsupported_thread_option() + : base_type(system::errc::invalid_argument, "boost::unsupported_thread_option") + {} + + unsupported_thread_option( int ev ) + : base_type(ev, "boost::unsupported_thread_option") + { + } + unsupported_thread_option( int ev, const char * what_arg ) + : base_type(ev, what_arg) + { + } + unsupported_thread_option( int ev, const std::string & what_arg ) + : base_type(ev, what_arg) + { + } - virtual const char* what() const throw() - { - return "boost::unsupported_thread_option"; - } - }; class BOOST_SYMBOL_VISIBLE invalid_thread_argument: public thread_exception { + typedef thread_exception base_type; public: invalid_thread_argument() + : base_type(system::errc::invalid_argument, "boost::invalid_thread_argument") {} - - invalid_thread_argument(int sys_err_code): - thread_exception(sys_err_code) - {} - - ~invalid_thread_argument() throw() - {} - - virtual const char* what() const throw() + invalid_thread_argument( int ev ) + : base_type(ev, "boost::invalid_thread_argument") + { + } + invalid_thread_argument( int ev, const char * what_arg ) + : base_type(ev, what_arg) { - return "boost::invalid_thread_argument"; } - + invalid_thread_argument( int ev, const std::string & what_arg ) + : base_type(ev, what_arg) + { + } + }; class BOOST_SYMBOL_VISIBLE thread_permission_error: public thread_exception { + typedef thread_exception base_type; public: - thread_permission_error() - {} - - thread_permission_error(int sys_err_code): - thread_exception(sys_err_code) - {} - - ~thread_permission_error() throw() - {} - + thread_permission_error() + : base_type(system::errc::permission_denied, "boost::thread_permission_error") + {} + + thread_permission_error( int ev ) + : base_type(ev, "boost::thread_permission_error") + { + } + thread_permission_error( int ev, const char * what_arg ) + : base_type(ev, what_arg) + { + } + thread_permission_error( int ev, const std::string & what_arg ) + : base_type(ev, what_arg) + { + } - virtual const char* what() const throw() - { - return "boost::thread_permission_error"; - } - }; } // namespace boost diff --git a/boost/thread/future.hpp b/boost/thread/future.hpp index bd87158338..8cad994de5 100644 --- a/boost/thread/future.hpp +++ b/boost/thread/future.hpp @@ -1,4 +1,5 @@ // (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 @@ -6,6 +7,15 @@ #ifndef BOOST_THREAD_FUTURE_HPP #define BOOST_THREAD_FUTURE_HPP + +#include <boost/thread/detail/config.hpp> + +// boost::thread::future requires exception handling +// due to boost::exception::exception_ptr dependency + +#ifndef BOOST_NO_EXCEPTIONS + +#include <boost/detail/scoped_enum_emulation.hpp> #include <stdexcept> #include <boost/thread/detail/move.hpp> #include <boost/thread/thread_time.hpp> @@ -16,6 +26,8 @@ #include <boost/scoped_ptr.hpp> #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/config.hpp> #include <boost/throw_exception.hpp> @@ -28,59 +40,168 @@ #include <list> #include <boost/next_prior.hpp> #include <vector> +#include <boost/system/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> +#endif + +#include <boost/utility/result_of.hpp> +//#include <boost/thread.hpp> + +#if defined BOOST_THREAD_PROVIDES_FUTURE +#define BOOST_THREAD_FUTURE future +#else +#define BOOST_THREAD_FUTURE unique_future +#endif + namespace boost { - class future_uninitialized: - public std::logic_error + + //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) + { + async = 1, + deferred = 2, + any = async | deferred + } + BOOST_SCOPED_ENUM_DECLARE_END(launch) + + //enum class future_status + BOOST_SCOPED_ENUM_DECLARE_BEGIN(future_status) + { + ready, + timeout, + deferred + } + 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 + { + system::error_code ec_; + public: + future_error(system::error_code ec) + : logic_error(ec.message()), + ec_(ec) + { + } + + const system::error_code& code() const BOOST_NOEXCEPT + { + return ec_; + } + + //virtual ~future_error() BOOST_NOEXCEPT; + }; + + class BOOST_SYMBOL_VISIBLE future_uninitialized: + public future_error { public: future_uninitialized(): - std::logic_error("Future Uninitialized") + future_error(system::make_error_code(future_errc::no_state)) {} }; - class broken_promise: - public std::logic_error + class BOOST_SYMBOL_VISIBLE broken_promise: + public future_error { public: broken_promise(): - std::logic_error("Broken promise") + future_error(system::make_error_code(future_errc::broken_promise)) {} }; - class future_already_retrieved: - public std::logic_error + class BOOST_SYMBOL_VISIBLE future_already_retrieved: + public future_error { public: future_already_retrieved(): - std::logic_error("Future already retrieved") + future_error(system::make_error_code(future_errc::future_already_retrieved)) {} }; - class promise_already_satisfied: - public std::logic_error + class BOOST_SYMBOL_VISIBLE promise_already_satisfied: + public future_error { public: promise_already_satisfied(): - std::logic_error("Promise already satisfied") + future_error(system::make_error_code(future_errc::promise_already_satisfied)) {} }; - class task_already_started: - public std::logic_error + class BOOST_SYMBOL_VISIBLE task_already_started: + public future_error { public: task_already_started(): - std::logic_error("Task already started") + future_error(system::make_error_code(future_errc::promise_already_satisfied)) + //std::logic_error("Task already started") {} }; - class task_moved: - public std::logic_error - { - public: - task_moved(): - 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)) + //std::logic_error("Task moved") + {} + }; + + class promise_moved: + public future_error + { + public: + promise_moved(): + future_error(system::make_error_code(future_errc::no_state)) + //std::logic_error("Promise moved") + {} + }; namespace future_state { @@ -93,6 +214,7 @@ namespace boost { boost::exception_ptr exception; bool done; + bool thread_was_interrupted; boost::mutex mutex; boost::condition_variable waiters; typedef std::list<boost::condition_variable_any*> waiter_list; @@ -100,7 +222,8 @@ namespace boost boost::function<void()> callback; future_object_base(): - done(false) + done(false), + thread_was_interrupted(false) {} virtual ~future_object_base() {} @@ -165,6 +288,10 @@ namespace boost { waiters.wait(lock); } + if(rethrow && thread_was_interrupted) + { + throw boost::thread_interrupted(); + } if(rethrow && exception) { boost::rethrow_exception(exception); @@ -186,6 +313,25 @@ namespace boost return true; } +#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); + do_callback(lock); + while(!done) + { + cv_status const st=waiters.wait_until(lock,abs_time); + if(st==cv_status::timeout && !done) + { + return future_status::timeout; + } + } + return future_status::ready; + } +#endif void mark_exceptional_finish_internal(boost::exception_ptr const& e) { exception=e; @@ -196,16 +342,21 @@ namespace boost boost::lock_guard<boost::mutex> lock(mutex); mark_exceptional_finish_internal(boost::current_exception()); } - + void mark_interrupted_finish() + { + boost::lock_guard<boost::mutex> lock(mutex); + thread_was_interrupted=true; + mark_finished_internal(); + } bool has_value() { boost::lock_guard<boost::mutex> lock(mutex); - return done && !exception; + return done && !(exception || thread_was_interrupted); } bool has_exception() { boost::lock_guard<boost::mutex> lock(mutex); - return done && exception; + return done && (exception || thread_was_interrupted); } template<typename F,typename U> @@ -226,14 +377,20 @@ namespace boost #ifndef BOOST_NO_RVALUE_REFERENCES typedef T const& source_reference_type; struct dummy; - typedef typename boost::mpl::if_<boost::is_fundamental<T>,dummy&,T&&>::type rvalue_source_type; - typedef typename boost::mpl::if_<boost::is_fundamental<T>,T,T&&>::type move_dest_type; + 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; +#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; #else typedef T& source_reference_type; - typedef typename boost::mpl::if_<boost::is_convertible<T&,boost::detail::thread_move_t<T> >,boost::detail::thread_move_t<T>,T const&>::type rvalue_source_type; - typedef typename boost::mpl::if_<boost::is_convertible<T&,boost::detail::thread_move_t<T> >,boost::detail::thread_move_t<T>,T>::type move_dest_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; #endif + typedef const T& shared_future_get_result_type; + static void init(storage_type& storage,source_reference_type t) { storage.reset(new T(t)); @@ -241,7 +398,7 @@ namespace boost static void init(storage_type& storage,rvalue_source_type t) { - storage.reset(new T(static_cast<rvalue_source_type>(t))); + storage.reset(new T(static_cast<rvalue_source_type>(t))); } static void cleanup(storage_type& storage) @@ -258,6 +415,7 @@ namespace boost struct rvalue_source_type {}; typedef T& move_dest_type; + typedef T& shared_future_get_result_type; static void init(storage_type& storage,T& t) { @@ -275,6 +433,7 @@ namespace boost { typedef bool storage_type; typedef void move_dest_type; + typedef void shared_future_get_result_type; static void init(storage_type& storage) { @@ -296,6 +455,7 @@ namespace boost 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; @@ -308,6 +468,7 @@ namespace boost future_traits<T>::init(result,result_); mark_finished_internal(); } + void mark_finished_with_result_internal(rvalue_source_type result_) { future_traits<T>::init(result,static_cast<rvalue_source_type>(result_)); @@ -319,10 +480,11 @@ namespace boost boost::lock_guard<boost::mutex> lock(mutex); mark_finished_with_result_internal(result_); } + void mark_finished_with_result(rvalue_source_type result_) { boost::lock_guard<boost::mutex> lock(mutex); - mark_finished_with_result_internal(result_); + mark_finished_with_result_internal(static_cast<rvalue_source_type>(result_)); } move_dest_type get() @@ -331,6 +493,12 @@ namespace boost return static_cast<move_dest_type>(*result); } + shared_future_get_result_type get_sh() + { + wait(); + return static_cast<shared_future_get_result_type>(*result); + } + future_state::state get_state() { boost::lock_guard<boost::mutex> guard(mutex); @@ -353,7 +521,7 @@ namespace boost struct future_object<void>: detail::future_object_base { - typedef void move_dest_type; + typedef void shared_future_get_result_type; future_object() {} @@ -373,7 +541,10 @@ namespace boost { wait(); } - + void get_sh() + { + wait(); + } future_state::state get_state() { boost::lock_guard<boost::mutex> guard(mutex); @@ -386,12 +557,22 @@ namespace boost return future_state::ready; } } - private: future_object(future_object const&); future_object& operator=(future_object const&); }; +// 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; @@ -399,38 +580,32 @@ namespace boost struct registered_waiter { - boost::shared_ptr<detail::future_object_base> future; + boost::shared_ptr<detail::future_object_base> future_; detail::future_object_base::waiter_list::iterator wait_iterator; count_type index; - registered_waiter(boost::shared_ptr<detail::future_object_base> const& future_, + registered_waiter(boost::shared_ptr<detail::future_object_base> const& a_future, detail::future_object_base::waiter_list::iterator wait_iterator_, count_type index_): - future(future_),wait_iterator(wait_iterator_),index(index_) + future_(a_future),wait_iterator(wait_iterator_),index(index_) {} }; struct all_futures_lock { -#ifdef _MANAGED - typedef std::ptrdiff_t count_type_portable; -#else - typedef count_type count_type_portable; -#endif - count_type_portable count; - + count_type 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_portable i=0;i<count;++i) + for(count_type i=0;i<count;++i) { #if defined __DECCXX || defined __SUNPRO_CC - locks[i]=boost::unique_lock<boost::mutex>(futures[i].future->mutex).move(); + locks[i]=boost::unique_lock<boost::mutex>(futures[i].future_->mutex).move(); #else - locks[i]=boost::unique_lock<boost::mutex>(futures[i].future->mutex); + locks[i]=boost::unique_lock<boost::mutex>(futures[i].future_->mutex); #endif } } @@ -442,7 +617,7 @@ namespace boost void unlock() { - for(count_type_portable i=0;i<count;++i) + for(count_type i=0;i<count;++i) { locks[i].unlock(); } @@ -461,9 +636,9 @@ namespace boost template<typename F> void add(F& f) { - if(f.future) + if(f.future_) { - futures.push_back(registered_waiter(f.future,f.future->register_external_waiter(cv),future_count)); + futures.push_back(registered_waiter(f.future_,f.future_->register_external_waiter(cv),future_count)); } ++future_count; } @@ -475,7 +650,7 @@ namespace boost { for(count_type i=0;i<futures.size();++i) { - if(futures[i].future->done) + if(futures[i].future_->done) { return futures[i].index; } @@ -488,7 +663,7 @@ namespace boost { for(count_type i=0;i<futures.size();++i) { - futures[i].future->remove_external_waiter(futures[i].wait_iterator); + futures[i].future_->remove_external_waiter(futures[i].wait_iterator); } } @@ -497,7 +672,7 @@ namespace boost } template <typename R> - class unique_future; + class BOOST_THREAD_FUTURE; template <typename R> class shared_future; @@ -509,7 +684,7 @@ namespace boost }; template<typename T> - struct is_future_type<unique_future<T> > + struct is_future_type<BOOST_THREAD_FUTURE<T> > { BOOST_STATIC_CONSTANT(bool, value=true); }; @@ -626,14 +801,13 @@ namespace boost class packaged_task; template <typename R> - class unique_future + class BOOST_THREAD_FUTURE { - unique_future(unique_future & rhs);// = delete; - unique_future& operator=(unique_future& rhs);// = delete; + private: typedef boost::shared_ptr<detail::future_object<R> > future_ptr; - future_ptr future; + future_ptr future_; friend class shared_future<R>; friend class promise<R>; @@ -642,99 +816,92 @@ namespace boost typedef typename detail::future_traits<R>::move_dest_type move_dest_type; - unique_future(future_ptr future_): - future(future_) + BOOST_THREAD_FUTURE(future_ptr a_future): + future_(a_future) {} public: + BOOST_THREAD_MOVABLE_ONLY(BOOST_THREAD_FUTURE) typedef future_state::state state; - unique_future() + BOOST_THREAD_FUTURE() {} - ~unique_future() + ~BOOST_THREAD_FUTURE() {} -#ifndef BOOST_NO_RVALUE_REFERENCES - unique_future(unique_future && other) - { - future.swap(other.future); - } - unique_future& operator=(unique_future && other) - { - future=other.future; - other.future.reset(); - return *this; - } -#else - unique_future(boost::detail::thread_move_t<unique_future> other): - future(other->future) + BOOST_THREAD_FUTURE(BOOST_THREAD_RV_REF(BOOST_THREAD_FUTURE) other) BOOST_NOEXCEPT: + future_(BOOST_THREAD_RV(other).future_) { - other->future.reset(); + BOOST_THREAD_RV(other).future_.reset(); } - unique_future& operator=(boost::detail::thread_move_t<unique_future> other) + BOOST_THREAD_FUTURE& operator=(BOOST_THREAD_RV_REF(BOOST_THREAD_FUTURE) other) BOOST_NOEXCEPT { - future=other->future; - other->future.reset(); + future_=BOOST_THREAD_RV(other).future_; + BOOST_THREAD_RV(other).future_.reset(); return *this; } - operator boost::detail::thread_move_t<unique_future>() + shared_future<R> share() { - return boost::detail::thread_move_t<unique_future>(*this); + return shared_future<R>(::boost::move(*this)); } -#endif - void swap(unique_future& other) + void swap(BOOST_THREAD_FUTURE& other) { - future.swap(other.future); + future_.swap(other.future_); } // retrieving the value move_dest_type get() { - if(!future) + if(!future_) { boost::throw_exception(future_uninitialized()); } - return future->get(); + return future_->get(); } // functions to check state, and wait for ready - state get_state() const + state get_state() const BOOST_NOEXCEPT { - if(!future) + if(!future_) { return future_state::uninitialized; } - return future->get_state(); + return future_->get_state(); } - - bool is_ready() const + bool is_ready() const BOOST_NOEXCEPT { return get_state()==future_state::ready; } - bool has_exception() const + bool has_exception() const BOOST_NOEXCEPT { - return future && future->has_exception(); + return future_ && future_->has_exception(); } - bool has_value() const + bool has_value() const BOOST_NOEXCEPT { - return future && future->has_value(); + return future_ && future_->has_value(); } + bool valid() const BOOST_NOEXCEPT + { + return future_ != 0; + } + + void wait() const { - if(!future) + if(!future_) { boost::throw_exception(future_uninitialized()); } - future->wait(false); + future_->wait(false); } template<typename Duration> @@ -745,43 +912,55 @@ namespace boost bool timed_wait_until(boost::system_time const& abs_time) const { - if(!future) + if(!future_) { boost::throw_exception(future_uninitialized()); } - return future->timed_wait_until(abs_time); + return future_->timed_wait_until(abs_time); } +#ifdef BOOST_THREAD_USES_CHRONO + template <class Rep, class Period> + future_status + wait_for(const chrono::duration<Rep, Period>& rel_time) const + { + return wait_until(chrono::steady_clock::now() + rel_time); + } + template <class Clock, class Duration> + future_status + wait_until(const chrono::time_point<Clock, Duration>& abs_time) const + { + if(!future_) + { + boost::throw_exception(future_uninitialized()); + } + return future_->wait_until(abs_time); + } +#endif }; -#ifdef BOOST_NO_RVALUE_REFERENCES - template <typename T> - struct has_move_emulation_enabled_aux<unique_future<T> > - : BOOST_MOVE_BOOST_NS::integral_constant<bool, true> - {}; -#endif + BOOST_THREAD_DCL_MOVABLE_BEG(T) BOOST_THREAD_FUTURE<T> BOOST_THREAD_DCL_MOVABLE_END template <typename R> class shared_future { typedef boost::shared_ptr<detail::future_object<R> > future_ptr; - future_ptr future; - -// shared_future(const unique_future<R>& other); -// shared_future& operator=(const unique_future<R>& other); + future_ptr future_; friend class detail::future_waiter; friend class promise<R>; friend class packaged_task<R>; - shared_future(future_ptr future_): - future(future_) + shared_future(future_ptr a_future): + future_(a_future) {} public: + BOOST_THREAD_MOVABLE(shared_future) + shared_future(shared_future const& other): - future(other.future) + future_(other.future_) {} typedef future_state::state state; @@ -794,112 +973,85 @@ namespace boost shared_future& operator=(shared_future const& other) { - future=other.future; + future_=other.future_; return *this; } -#ifndef BOOST_NO_RVALUE_REFERENCES - shared_future(shared_future && other) - { - future.swap(other.future); - } - shared_future(unique_future<R> && other) - { - future.swap(other.future); - } - shared_future& operator=(shared_future && other) - { - future.swap(other.future); - other.future.reset(); - return *this; - } - shared_future& operator=(unique_future<R> && other) + shared_future(BOOST_THREAD_RV_REF(shared_future) other) BOOST_NOEXCEPT : + future_(BOOST_THREAD_RV(other).future_) { - future.swap(other.future); - other.future.reset(); - return *this; + BOOST_THREAD_RV(other).future_.reset(); } -#else - shared_future(boost::detail::thread_move_t<shared_future> other): - future(other->future) + 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_) { - other->future.reset(); + BOOST_THREAD_RV(other).future_.reset(); } -// shared_future(const unique_future<R> &) = delete; - shared_future(boost::detail::thread_move_t<unique_future<R> > other): - future(other->future) + shared_future& operator=(BOOST_THREAD_RV_REF(shared_future) other) BOOST_NOEXCEPT { - other->future.reset(); - } - shared_future& operator=(boost::detail::thread_move_t<shared_future> other) - { - future.swap(other->future); - other->future.reset(); + future_.swap(BOOST_THREAD_RV(other).future_); + BOOST_THREAD_RV(other).future_.reset(); return *this; } - shared_future& operator=(boost::detail::thread_move_t<unique_future<R> > other) + shared_future& operator=(BOOST_THREAD_RV_REF_BEG BOOST_THREAD_FUTURE<R> BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT { - future.swap(other->future); - other->future.reset(); + future_.swap(BOOST_THREAD_RV(other).future_); + BOOST_THREAD_RV(other).future_.reset(); return *this; } - operator boost::detail::thread_move_t<shared_future>() - { - return boost::detail::thread_move_t<shared_future>(*this); - } - -#endif - - void swap(shared_future& other) + void swap(shared_future& other) BOOST_NOEXCEPT { - future.swap(other.future); + future_.swap(other.future_); } // retrieving the value - //typename detail::future_object<R>::move_dest_type get() - R get() + typename detail::future_object<R>::shared_future_get_result_type get() { - if(!future) + if(!future_) { boost::throw_exception(future_uninitialized()); } - return future->get(); + return future_->get_sh(); } // functions to check state, and wait for ready - state get_state() const + state get_state() const BOOST_NOEXCEPT { - if(!future) + if(!future_) { return future_state::uninitialized; } - return future->get_state(); + return future_->get_state(); } + bool valid() const BOOST_NOEXCEPT + { + return future_ != 0; + } - bool is_ready() const + bool is_ready() const BOOST_NOEXCEPT { return get_state()==future_state::ready; } - bool has_exception() const + bool has_exception() const BOOST_NOEXCEPT { - return future && future->has_exception(); + return future_ && future_->has_exception(); } - bool has_value() const + bool has_value() const BOOST_NOEXCEPT { - return future && future->has_value(); + return future_ && future_->has_value(); } void wait() const { - if(!future) + if(!future_) { boost::throw_exception(future_uninitialized()); } - future->wait(false); + future_->wait(false); } template<typename Duration> @@ -910,157 +1062,168 @@ namespace boost bool timed_wait_until(boost::system_time const& abs_time) const { - if(!future) + if(!future_) { boost::throw_exception(future_uninitialized()); } - return future->timed_wait_until(abs_time); + return future_->timed_wait_until(abs_time); } +#ifdef BOOST_THREAD_USES_CHRONO - }; + template <class Rep, class Period> + future_status + wait_for(const chrono::duration<Rep, Period>& rel_time) const + { + return wait_until(chrono::steady_clock::now() + rel_time); -#ifdef BOOST_NO_RVALUE_REFERENCES - template <typename T> - struct has_move_emulation_enabled_aux<shared_future<T> > - : BOOST_MOVE_BOOST_NS::integral_constant<bool, true> - {}; + } + template <class Clock, class Duration> + future_status + wait_until(const chrono::time_point<Clock, Duration>& abs_time) const + { + if(!future_) + { + boost::throw_exception(future_uninitialized()); + } + return future_->wait_until(abs_time); + } #endif + }; + + BOOST_THREAD_DCL_MOVABLE_BEG(T) shared_future<T> BOOST_THREAD_DCL_MOVABLE_END template <typename R> class promise { typedef boost::shared_ptr<detail::future_object<R> > future_ptr; - future_ptr future; + future_ptr future_; bool future_obtained; - promise(promise & rhs);// = delete; - promise & operator=(promise & rhs);// = delete; - void lazy_init() { - if(!atomic_load(&future)) +#if defined BOOST_THREAD_PROMISE_LAZY + 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::future_object<R>)); } +#endif } public: -// template <class Allocator> explicit promise(Allocator a); + BOOST_THREAD_MOVABLE_ONLY(promise) +#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS + template <class Allocator> + promise(boost::allocator_arg_t, Allocator a) + { + typedef typename Allocator::template rebind<detail::future_object<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_obtained = false; + } +#endif promise(): - future(),future_obtained(false) +#if defined BOOST_THREAD_PROMISE_LAZY + future_(), +#else + future_(new detail::future_object<R>()), +#endif + future_obtained(false) {} ~promise() { - if(future) + if(future_) { - boost::lock_guard<boost::mutex> lock(future->mutex); + boost::lock_guard<boost::mutex> lock(future_->mutex); - if(!future->done) + if(!future_->done) { - future->mark_exceptional_finish_internal(boost::copy_exception(broken_promise())); + future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise())); } } } // Assignment -#ifndef BOOST_NO_RVALUE_REFERENCES - promise(promise && rhs): - future_obtained(rhs.future_obtained) + promise(BOOST_THREAD_RV_REF(promise) rhs) BOOST_NOEXCEPT : + future_(BOOST_THREAD_RV(rhs).future_),future_obtained(BOOST_THREAD_RV(rhs).future_obtained) { - future.swap(rhs.future); - rhs.future_obtained=false; + BOOST_THREAD_RV(rhs).future_.reset(); + BOOST_THREAD_RV(rhs).future_obtained=false; } - promise & operator=(promise&& rhs) + promise & operator=(BOOST_THREAD_RV_REF(promise) rhs) BOOST_NOEXCEPT { - future.swap(rhs.future); - future_obtained=rhs.future_obtained; - rhs.future.reset(); - rhs.future_obtained=false; + 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; } -#else - promise(boost::detail::thread_move_t<promise> rhs): - future(rhs->future),future_obtained(rhs->future_obtained) - { - rhs->future.reset(); - rhs->future_obtained=false; - } - promise & operator=(boost::detail::thread_move_t<promise> rhs) - { - future=rhs->future; - future_obtained=rhs->future_obtained; - rhs->future.reset(); - rhs->future_obtained=false; - return *this; - } - - operator boost::detail::thread_move_t<promise>() - { - return boost::detail::thread_move_t<promise>(*this); - } -#endif void swap(promise& other) { - future.swap(other.future); + future_.swap(other.future_); std::swap(future_obtained,other.future_obtained); } // Result retrieval - unique_future<R> get_future() + BOOST_THREAD_FUTURE<R> get_future() { lazy_init(); - if(future_obtained) + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + if (future_obtained) { boost::throw_exception(future_already_retrieved()); } future_obtained=true; - return unique_future<R>(future); + return BOOST_THREAD_FUTURE<R>(future_); } void set_value(typename detail::future_traits<R>::source_reference_type r) { lazy_init(); - boost::lock_guard<boost::mutex> lock(future->mutex); - if(future->done) + boost::lock_guard<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); } // void set_value(R && r); void set_value(typename detail::future_traits<R>::rvalue_source_type r) { lazy_init(); - boost::lock_guard<boost::mutex> lock(future->mutex); - if(future->done) + boost::lock_guard<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_finished_with_result_internal(static_cast<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); - if(future->done) + boost::lock_guard<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); } template<typename F> void set_wait_callback(F f) { lazy_init(); - future->set_wait_callback(f,this); + future_->set_wait_callback(f,this); } }; @@ -1070,135 +1233,140 @@ namespace boost { typedef boost::shared_ptr<detail::future_object<void> > future_ptr; - future_ptr future; + future_ptr future_; bool future_obtained; - promise(promise & rhs);// = delete; - promise & operator=(promise & rhs);// = delete; - void lazy_init() { - if(!atomic_load(&future)) +#if defined BOOST_THREAD_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::future_object<void>)); } +#endif } public: -// template <class Allocator> explicit promise(Allocator a); + BOOST_THREAD_MOVABLE_ONLY(promise) + +#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS + template <class Allocator> + promise(boost::allocator_arg_t, Allocator a) + { + typedef typename Allocator::template rebind<detail::future_object<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_obtained = false; + } +#endif promise(): - future(),future_obtained(false) +#if defined BOOST_THREAD_PROMISE_LAZY + future_(), +#else + future_(new detail::future_object<void>), +#endif + future_obtained(false) {} ~promise() { - if(future) + if(future_) { - boost::lock_guard<boost::mutex> lock(future->mutex); + boost::lock_guard<boost::mutex> lock(future_->mutex); - if(!future->done) + if(!future_->done) { - future->mark_exceptional_finish_internal(boost::copy_exception(broken_promise())); + future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise())); } } } // Assignment -#ifndef BOOST_NO_RVALUE_REFERENCES - promise(promise && rhs): - future_obtained(rhs.future_obtained) - { - future.swap(rhs.future); - rhs.future_obtained=false; - } - promise & operator=(promise&& rhs) - { - future.swap(rhs.future); - future_obtained=rhs.future_obtained; - rhs.future.reset(); - rhs.future_obtained=false; - return *this; - } -#else - promise(boost::detail::thread_move_t<promise> rhs): - future(rhs->future),future_obtained(rhs->future_obtained) - { - rhs->future.reset(); - rhs->future_obtained=false; - } - promise & operator=(boost::detail::thread_move_t<promise> rhs) + promise(BOOST_THREAD_RV_REF(promise) rhs) BOOST_NOEXCEPT : + future_(BOOST_THREAD_RV(rhs).future_),future_obtained(BOOST_THREAD_RV(rhs).future_obtained) { - future=rhs->future; - future_obtained=rhs->future_obtained; - rhs->future.reset(); - rhs->future_obtained=false; - return *this; + // we need to release the future as shared_ptr doesn't implements move semantics + BOOST_THREAD_RV(rhs).future_.reset(); + BOOST_THREAD_RV(rhs).future_obtained=false; } - operator boost::detail::thread_move_t<promise>() + promise & operator=(BOOST_THREAD_RV_REF(promise) rhs) BOOST_NOEXCEPT { - return boost::detail::thread_move_t<promise>(*this); + 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; } -#endif void swap(promise& other) { - future.swap(other.future); + future_.swap(other.future_); std::swap(future_obtained,other.future_obtained); } // Result retrieval - unique_future<void> get_future() + BOOST_THREAD_FUTURE<void> get_future() { lazy_init(); + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } if(future_obtained) { boost::throw_exception(future_already_retrieved()); } future_obtained=true; - return unique_future<void>(future); + return BOOST_THREAD_FUTURE<void>(future_); } void set_value() { lazy_init(); - boost::lock_guard<boost::mutex> lock(future->mutex); - if(future->done) + boost::lock_guard<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(); } void set_exception(boost::exception_ptr p) { lazy_init(); - boost::lock_guard<boost::mutex> lock(future->mutex); - if(future->done) + boost::lock_guard<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); } template<typename F> void set_wait_callback(F f) { lazy_init(); - future->set_wait_callback(f,this); + future_->set_wait_callback(f,this); } }; -#ifdef BOOST_NO_RVALUE_REFERENCES - template <typename T> - struct has_move_emulation_enabled_aux<promise<T> > - : BOOST_MOVE_BOOST_NS::integral_constant<bool, true> - {}; +#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS + namespace container + { + template <class R, class Alloc> + struct uses_allocator<promise<R> , Alloc> : true_type + { + }; + } #endif + BOOST_THREAD_DCL_MOVABLE_BEG(T) promise<T> BOOST_THREAD_DCL_MOVABLE_END + namespace detail { template<typename R> @@ -1211,6 +1379,10 @@ namespace boost started(false) {} + void reset() + { + started=false; + } void run() { { @@ -1243,26 +1415,32 @@ namespace boost struct task_object: task_base<R> { + private: + task_object(task_object&); + public: F f; task_object(F const& f_): f(f_) {} #ifndef BOOST_NO_RVALUE_REFERENCES - task_object(F&& f_): - f(f_) + task_object(BOOST_THREAD_RV_REF(F) f_): + f(boost::forward<F>(f_)) {} #else - task_object(boost::detail::thread_move_t<F> f_): - f(f_) + task_object(BOOST_THREAD_RV_REF(F) f_): + f(boost::move(f_)) {} #endif - void do_run() { try { this->mark_finished_with_result(f()); } + catch(thread_interrupted& ) + { + this->mark_interrupted_finish(); + } catch(...) { this->mark_exceptional_finish(); @@ -1274,17 +1452,20 @@ namespace boost struct task_object<void,F>: task_base<void> { + private: + task_object(task_object&); + public: F f; task_object(F const& f_): f(f_) {} #ifndef BOOST_NO_RVALUE_REFERENCES - task_object(F&& f_): - f(f_) + task_object(BOOST_THREAD_RV_REF(F) f_): + f(boost::forward<F>(f_)) {} #else - task_object(boost::detail::thread_move_t<F> f_): - f(f_) + task_object(BOOST_THREAD_RV_REF(F) f_): + f(boost::move(f_)) {} #endif @@ -1295,6 +1476,10 @@ namespace boost f(); this->mark_finished_with_result(); } + catch(thread_interrupted& ) + { + this->mark_interrupted_finish(); + } catch(...) { this->mark_exceptional_finish(); @@ -1304,47 +1489,91 @@ namespace boost } - template<typename R> class packaged_task { + typedef boost::shared_ptr<detail::task_base<R> > task_ptr; boost::shared_ptr<detail::task_base<R> > task; bool future_obtained; - packaged_task(packaged_task&);// = delete; - packaged_task& operator=(packaged_task&);// = delete; - public: + typedef R result_type; + BOOST_THREAD_MOVABLE_ONLY(packaged_task) + packaged_task(): future_obtained(false) {} // construction and destruction - template <class F> - explicit packaged_task(F const& f): - task(new detail::task_object<R,F>(f)),future_obtained(false) - {} + explicit packaged_task(R(*f)()): task(new detail::task_object<R,R(*)()>(f)),future_obtained(false) {} - #ifndef BOOST_NO_RVALUE_REFERENCES template <class F> - explicit packaged_task(F&& f): - task(new detail::task_object<R,F>(f)),future_obtained(false) + 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) {} #else template <class F> - explicit packaged_task(boost::detail::thread_move_t<F> f): + explicit packaged_task(F const& f): task(new detail::task_object<R,F>(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) + {} #endif -// template <class F, class Allocator> -// explicit packaged_task(F const& f, Allocator a); -// template <class F, class Allocator> -// explicit packaged_task(F&& f, Allocator a); +#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS + 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; + 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) ); + future_obtained = false; + } +#ifndef BOOST_NO_RVALUE_REFERENCES + template <class F, class Allocator> + packaged_task(boost::allocator_arg_t, Allocator a, BOOST_THREAD_RV_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; + 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) ); + future_obtained = false; + } +#else + 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; + 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) ); + 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; + 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) ); + future_obtained = false; + } +#endif //BOOST_NO_RVALUE_REFERENCES +#endif // BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS ~packaged_task() { @@ -1355,46 +1584,39 @@ namespace boost } // assignment -#ifndef BOOST_NO_RVALUE_REFERENCES - packaged_task(packaged_task&& other): - future_obtained(other.future_obtained) - { - task.swap(other.task); - other.future_obtained=false; - } - packaged_task& operator=(packaged_task&& other) + packaged_task(BOOST_THREAD_RV_REF(packaged_task) other) BOOST_NOEXCEPT : + future_obtained(BOOST_THREAD_RV(other).future_obtained) { - packaged_task temp(static_cast<packaged_task&&>(other)); - swap(temp); - return *this; + task.swap(BOOST_THREAD_RV(other).task); + BOOST_THREAD_RV(other).future_obtained=false; } -#else - packaged_task(boost::detail::thread_move_t<packaged_task> other): - future_obtained(other->future_obtained) + packaged_task& operator=(BOOST_THREAD_RV_REF(packaged_task) other) BOOST_NOEXCEPT { - task.swap(other->task); - other->future_obtained=false; - } - packaged_task& operator=(boost::detail::thread_move_t<packaged_task> other) - { - packaged_task temp(other); + packaged_task temp(static_cast<BOOST_THREAD_RV_REF(packaged_task)>(other)); swap(temp); return *this; } - operator boost::detail::thread_move_t<packaged_task>() + + void reset() { - return boost::detail::thread_move_t<packaged_task>(*this); + if (!valid()) + throw future_error(system::make_error_code(future_errc::no_state)); + task->reset(); + future_obtained=false; } -#endif - void swap(packaged_task& other) + void swap(packaged_task& other) BOOST_NOEXCEPT { task.swap(other.task); std::swap(future_obtained,other.future_obtained); } + bool valid() const BOOST_NOEXCEPT + { + return task.get()!=0; + } // result retrieval - unique_future<R> get_future() + BOOST_THREAD_FUTURE<R> get_future() { if(!task) { @@ -1403,12 +1625,14 @@ namespace boost else if(!future_obtained) { future_obtained=true; - return unique_future<R>(task); + return BOOST_THREAD_FUTURE<R>(task); } else { boost::throw_exception(future_already_retrieved()); } + return BOOST_THREAD_FUTURE<R>(); + } @@ -1430,14 +1654,50 @@ namespace boost }; -#ifdef BOOST_NO_RVALUE_REFERENCES - template <typename T> - struct has_move_emulation_enabled_aux<packaged_task<T> > - : BOOST_MOVE_BOOST_NS::integral_constant<bool, true> - {}; +#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS + namespace container + { + template <class R, class Alloc> + struct uses_allocator<packaged_task<R>, Alloc> + : public true_type {}; + } #endif -} + BOOST_THREAD_DCL_MOVABLE_BEG(T) packaged_task<T> BOOST_THREAD_DCL_MOVABLE_END + +// 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); +// } -#endif + +} + +#endif // BOOST_NO_EXCEPTION +#endif // header diff --git a/boost/thread/locks.hpp b/boost/thread/locks.hpp index 26012707e7..5111d33e68 100644 --- a/boost/thread/locks.hpp +++ b/boost/thread/locks.hpp @@ -2,6 +2,8 @@ // 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_LOCKS_HPP #define BOOST_THREAD_LOCKS_HPP #include <boost/thread/detail/config.hpp> @@ -12,6 +14,10 @@ #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> @@ -164,9 +170,9 @@ namespace boost struct adopt_lock_t {}; - const defer_lock_t defer_lock={}; - const try_to_lock_t try_to_lock={}; - const adopt_lock_t adopt_lock={}; + 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; @@ -248,9 +254,10 @@ namespace boost private: Mutex& m; - explicit lock_guard(lock_guard&); - lock_guard& operator=(lock_guard&); public: + typedef Mutex mutex_type; + BOOST_THREAD_NO_COPYABLE(lock_guard) + explicit lock_guard(Mutex& m_): m(m_) { @@ -265,22 +272,26 @@ namespace boost } }; - template<typename Mutex> class unique_lock { private: Mutex* m; bool is_locked; - unique_lock(unique_lock&); + + private: explicit unique_lock(upgrade_lock<Mutex>&); - unique_lock& operator=(unique_lock&); 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 - unique_lock(): +#endif + unique_lock() BOOST_NOEXCEPT : m(0),is_locked(false) {} @@ -292,7 +303,7 @@ namespace boost unique_lock(Mutex& m_,adopt_lock_t): m(&m_),is_locked(true) {} - unique_lock(Mutex& m_,defer_lock_t): + unique_lock(Mutex& m_,defer_lock_t) BOOST_NOEXCEPT: m(&m_),is_locked(false) {} unique_lock(Mutex& m_,try_to_lock_t): @@ -311,86 +322,167 @@ namespace boost { timed_lock(target_time); } -#ifndef BOOST_NO_RVALUE_REFERENCES - unique_lock(unique_lock&& other): - m(other.m),is_locked(other.is_locked) + +#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)) { - other.is_locked=false; - other.m=0; } - explicit unique_lock(upgrade_lock<Mutex>&& other); - - unique_lock<Mutex>&& move() + template <class Rep, class Period> + unique_lock(Mutex& mtx, const chrono::duration<Rep, Period>& d) + : m(&mtx), is_locked(mtx.try_lock_for(d)) { - return static_cast<unique_lock<Mutex>&&>(*this); } +#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); - unique_lock& operator=(unique_lock&& 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(other.move()); + unique_lock temp(::boost::move(other)); swap(temp); return *this; } +#endif - unique_lock& operator=(upgrade_lock<Mutex>&& other) + unique_lock& operator=(BOOST_THREAD_RV_REF(unique_lock) other) BOOST_NOEXCEPT { - unique_lock temp(other.move()); + unique_lock temp(::boost::move(other)); swap(temp); return *this; } - void swap(unique_lock&& other) - { - std::swap(m,other.m); - std::swap(is_locked,other.is_locked); - } -#else - unique_lock(detail::thread_move_t<unique_lock<Mutex> > other): - m(other->m),is_locked(other->is_locked) +#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) { - other->is_locked=false; - other->m=0; + swap(other); + return *this; } - unique_lock(detail::thread_move_t<upgrade_lock<Mutex> > other); +#endif // BOOST_WORKAROUND +#endif - operator detail::thread_move_t<unique_lock<Mutex> >() + // 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) { - return move(); + 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(); + } } - detail::thread_move_t<unique_lock<Mutex> > move() +#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) { - return detail::thread_move_t<unique_lock<Mutex> >(*this); + 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(); + } } -#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) - unique_lock& operator=(unique_lock<Mutex> other) + 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) { - swap(other); - return *this; - } -#else - unique_lock& operator=(detail::thread_move_t<unique_lock<Mutex> > other) - { - unique_lock temp(other); - swap(temp); - return *this; + 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 - unique_lock& operator=(detail::thread_move_t<upgrade_lock<Mutex> > other) +#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) { - unique_lock temp(other); - swap(temp); - return *this; + 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(); + } } - void swap(detail::thread_move_t<unique_lock<Mutex> > other) + + 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) { - std::swap(m,other->m); - std::swap(is_locked,other->is_locked); + 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 - void swap(unique_lock& other) +#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); @@ -405,18 +497,26 @@ namespace boost } 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()); + 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()); + 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; @@ -424,50 +524,118 @@ namespace boost 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()); + 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 + operator bool_type() const BOOST_NOEXCEPT { return is_locked?&unique_lock::lock:0; } - bool operator!() const + bool operator!() const BOOST_NOEXCEPT { return !owns_lock(); } - bool owns_lock() const +#else + explicit operator bool() const BOOST_NOEXCEPT + { + return owns_lock(); + } +#endif + bool owns_lock() const BOOST_NOEXCEPT { return is_locked; } - Mutex* mutex() const + Mutex* mutex() const BOOST_NOEXCEPT { return m; } - Mutex* release() + Mutex* release() BOOST_NOEXCEPT { Mutex* const res=m; m=0; @@ -479,51 +647,13 @@ namespace boost friend class upgrade_lock<Mutex>; }; -#ifndef BOOST_NO_RVALUE_REFERENCES template<typename Mutex> - void swap(unique_lock<Mutex>&& lhs,unique_lock<Mutex>&& rhs) + void swap(unique_lock<Mutex>& lhs,unique_lock<Mutex>& rhs) BOOST_NOEXCEPT { lhs.swap(rhs); } - template<typename Mutex> - inline upgrade_lock<Mutex>&& move(upgrade_lock<Mutex>&& ul) - { - return static_cast<upgrade_lock<Mutex>&&>(ul); - } - - template<typename Mutex> - inline upgrade_lock<Mutex>&& move(upgrade_lock<Mutex>& ul) - { - return static_cast<upgrade_lock<Mutex>&&>(ul); - } -#endif - template<typename Mutex> - void swap(unique_lock<Mutex>& lhs,unique_lock<Mutex>& rhs) - { - lhs.swap(rhs); - } - -#ifndef BOOST_NO_RVALUE_REFERENCES - template<typename Mutex> - inline unique_lock<Mutex>&& move(unique_lock<Mutex>&& ul) - { - return static_cast<unique_lock<Mutex>&&>(ul); - } - - template<typename Mutex> - inline unique_lock<Mutex>&& move(unique_lock<Mutex>& ul) - { - return static_cast<unique_lock<Mutex>&&>(ul); - } -#endif - -#ifdef BOOST_NO_RVALUE_REFERENCES - template <typename Mutex> - struct has_move_emulation_enabled_aux<unique_lock<Mutex> > - : BOOST_MOVE_BOOST_NS::integral_constant<bool, true> - {}; -#endif + BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) unique_lock<Mutex> BOOST_THREAD_DCL_MOVABLE_END template<typename Mutex> class shared_lock @@ -531,11 +661,12 @@ namespace boost protected: Mutex* m; bool is_locked; - private: - explicit shared_lock(shared_lock&); - shared_lock& operator=(shared_lock&); + public: - shared_lock(): + typedef Mutex mutex_type; + BOOST_THREAD_MOVABLE_ONLY(shared_lock) + + shared_lock() BOOST_NOEXCEPT: m(0),is_locked(false) {} @@ -547,7 +678,7 @@ namespace boost shared_lock(Mutex& m_,adopt_lock_t): m(&m_),is_locked(true) {} - shared_lock(Mutex& m_,defer_lock_t): + shared_lock(Mutex& m_,defer_lock_t) BOOST_NOEXCEPT: m(&m_),is_locked(false) {} shared_lock(Mutex& m_,try_to_lock_t): @@ -560,93 +691,89 @@ namespace boost { timed_lock(target_time); } -#ifndef BOOST_NO_RVALUE_REFERENCES -#else - shared_lock(detail::thread_move_t<shared_lock<Mutex> > other): - m(other->m),is_locked(other->is_locked) +#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)) { - other->is_locked=false; - other->m=0; + } + 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; } - shared_lock(detail::thread_move_t<unique_lock<Mutex> > other): - m(other->m),is_locked(other->is_locked) + 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(); } - other->is_locked=false; - other->m=0; + BOOST_THREAD_RV(other).is_locked=false; + BOOST_THREAD_RV(other).m=0; } - shared_lock(detail::thread_move_t<upgrade_lock<Mutex> > other): - m(other->m),is_locked(other->is_locked) + 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(); } - other->is_locked=false; - other->m=0; - } - - operator detail::thread_move_t<shared_lock<Mutex> >() - { - return move(); + BOOST_THREAD_RV(other).is_locked=false; + BOOST_THREAD_RV(other).m=0; } - detail::thread_move_t<shared_lock<Mutex> > move() - { - return detail::thread_move_t<shared_lock<Mutex> >(*this); - } - - shared_lock& operator=(detail::thread_move_t<shared_lock<Mutex> > other) + shared_lock& operator=(BOOST_THREAD_RV_REF_BEG shared_lock<Mutex> BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT { - shared_lock temp(other); + shared_lock temp(::boost::move(other)); swap(temp); return *this; } - - shared_lock& operator=(detail::thread_move_t<unique_lock<Mutex> > other) +#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(other); + shared_lock temp(::boost::move(other)); swap(temp); return *this; } - shared_lock& operator=(detail::thread_move_t<upgrade_lock<Mutex> > other) + shared_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other) { - shared_lock temp(other); + shared_lock temp(::boost::move(other)); swap(temp); return *this; } #endif -#ifndef BOOST_NO_RVALUE_REFERENCES - void swap(shared_lock&& other) + void swap(shared_lock& other) BOOST_NOEXCEPT { std::swap(m,other.m); std::swap(is_locked,other.is_locked); } -#else - void swap(boost::detail::thread_move_t<shared_lock<Mutex> > other) - { - std::swap(m,other->m); - std::swap(is_locked,other->is_locked); - } -#endif - void swap(shared_lock& other) + + Mutex* mutex() const BOOST_NOEXCEPT { - std::swap(m,other.m); - std::swap(is_locked,other.is_locked); + return m; } - Mutex* mutex() const + Mutex* release() BOOST_NOEXCEPT { - return m; + Mutex* const res=m; + m=0; + is_locked=false; + return res; } ~shared_lock() @@ -658,27 +785,39 @@ namespace boost } 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()); + 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()); + 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()); + 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; @@ -686,65 +825,91 @@ namespace boost 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()); + 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()); + 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 + operator bool_type() const BOOST_NOEXCEPT { return is_locked?&shared_lock::lock:0; } - bool operator!() const + bool operator!() const BOOST_NOEXCEPT { return !owns_lock(); } - bool owns_lock() const +#else + explicit operator bool() const BOOST_NOEXCEPT + { + return owns_lock(); + } +#endif + bool owns_lock() const BOOST_NOEXCEPT { return is_locked; } }; -#ifdef BOOST_NO_RVALUE_REFERENCES - template <typename Mutex> - struct has_move_emulation_enabled_aux<shared_lock<Mutex> > - : BOOST_MOVE_BOOST_NS::integral_constant<bool, true> - {}; -#endif - + BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) shared_lock<Mutex> BOOST_THREAD_DCL_MOVABLE_END -#ifndef BOOST_NO_RVALUE_REFERENCES - template<typename Mutex> - void swap(shared_lock<Mutex>&& lhs,shared_lock<Mutex>&& rhs) - { - lhs.swap(rhs); - } - template<typename Mutex> - void swap(shared_lock<Mutex>& lhs,shared_lock<Mutex>& rhs) - { - lhs.swap(rhs); - } -#else template<typename Mutex> - void swap(shared_lock<Mutex>& lhs,shared_lock<Mutex>& rhs) + void swap(shared_lock<Mutex>& lhs,shared_lock<Mutex>& rhs) BOOST_NOEXCEPT { lhs.swap(rhs); } -#endif template<typename Mutex> class upgrade_lock @@ -752,11 +917,12 @@ namespace boost protected: Mutex* m; bool is_locked; - private: - explicit upgrade_lock(upgrade_lock&); - upgrade_lock& operator=(upgrade_lock&); + public: - upgrade_lock(): + typedef Mutex mutex_type; + BOOST_THREAD_MOVABLE_ONLY(upgrade_lock) + + upgrade_lock() BOOST_NOEXCEPT: m(0),is_locked(false) {} @@ -768,7 +934,7 @@ namespace boost upgrade_lock(Mutex& m_,adopt_lock_t): m(&m_),is_locked(true) {} - upgrade_lock(Mutex& m_,defer_lock_t): + upgrade_lock(Mutex& m_,defer_lock_t) BOOST_NOEXCEPT: m(&m_),is_locked(false) {} upgrade_lock(Mutex& m_,try_to_lock_t): @@ -776,89 +942,128 @@ namespace boost { try_lock(); } -#ifndef BOOST_NO_RVALUE_REFERENCES - upgrade_lock(upgrade_lock<Mutex>&& other): - m(other.m),is_locked(other.is_locked) + +#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)) { - other.is_locked=false; - other.m=0; } + 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(unique_lock<Mutex>&& other): - m(other.m),is_locked(other.is_locked) + 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(); } - other.is_locked=false; - other.m=0; + BOOST_THREAD_RV(other).is_locked=false; + BOOST_THREAD_RV(other).m=0; } - upgrade_lock& operator=(upgrade_lock<Mutex>&& other) + upgrade_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_lock<Mutex> BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT { - upgrade_lock temp(static_cast<upgrade_lock<Mutex>&&>(other)); + upgrade_lock temp(::boost::move(other)); swap(temp); return *this; } - upgrade_lock& operator=(unique_lock<Mutex>&& other) +#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(static_cast<unique_lock<Mutex>&&>(other)); + upgrade_lock temp(::boost::move(other)); swap(temp); return *this; } -#else - upgrade_lock(detail::thread_move_t<upgrade_lock<Mutex> > other): - m(other->m),is_locked(other->is_locked) - { - other->is_locked=false; - other->m=0; - } +#endif - upgrade_lock(detail::thread_move_t<unique_lock<Mutex> > other): - m(other->m),is_locked(other->is_locked) +#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(is_locked) + if (BOOST_THREAD_RV(sl).owns_lock()) { + if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_upgrade()) { - m->unlock_and_lock_upgrade(); + m = BOOST_THREAD_RV(sl).release(); + is_locked = true; } - other->is_locked=false; - other->m=0; + } + else + { + m = BOOST_THREAD_RV(sl).release(); + } } - operator detail::thread_move_t<upgrade_lock<Mutex> >() +#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) { - return move(); + 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(); + } } - detail::thread_move_t<upgrade_lock<Mutex> > move() + 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) { - return detail::thread_move_t<upgrade_lock<Mutex> >(*this); + 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 - - upgrade_lock& operator=(detail::thread_move_t<upgrade_lock<Mutex> > other) + void swap(upgrade_lock& other) BOOST_NOEXCEPT { - upgrade_lock temp(other); - swap(temp); - return *this; + std::swap(m,other.m); + std::swap(is_locked,other.is_locked); } - - upgrade_lock& operator=(detail::thread_move_t<unique_lock<Mutex> > other) + Mutex* mutex() const BOOST_NOEXCEPT { - upgrade_lock temp(other); - swap(temp); - return *this; + return m; } -#endif - void swap(upgrade_lock& other) + Mutex* release() BOOST_NOEXCEPT { - std::swap(m,other.m); - std::swap(is_locked,other.is_locked); + Mutex* const res=m; + m=0; + is_locked=false; + return res; } - ~upgrade_lock() { if(owns_lock()) @@ -868,42 +1073,90 @@ namespace boost } 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()); + 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()); + 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()); + 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 + operator bool_type() const BOOST_NOEXCEPT { return is_locked?&upgrade_lock::lock:0; } - bool operator!() const + bool operator!() const BOOST_NOEXCEPT { return !owns_lock(); } - bool owns_lock() const +#else + explicit operator bool() const BOOST_NOEXCEPT + { + return owns_lock(); + } +#endif + bool owns_lock() const BOOST_NOEXCEPT { return is_locked; } @@ -911,36 +1164,25 @@ namespace boost friend class unique_lock<Mutex>; }; -#ifdef BOOST_NO_RVALUE_REFERENCES - template <typename Mutex> - struct has_move_emulation_enabled_aux<upgrade_lock<Mutex> > - : BOOST_MOVE_BOOST_NS::integral_constant<bool, true> - {}; -#endif - -#ifndef BOOST_NO_RVALUE_REFERENCES template<typename Mutex> - unique_lock<Mutex>::unique_lock(upgrade_lock<Mutex>&& other): - m(other.m),is_locked(other.is_locked) + void swap(upgrade_lock<Mutex>& lhs,upgrade_lock<Mutex>& rhs) BOOST_NOEXCEPT { - other.is_locked=false; - if(is_locked) - { - m->unlock_upgrade_and_lock(); - } + lhs.swap(rhs); } -#else + + BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) upgrade_lock<Mutex> BOOST_THREAD_DCL_MOVABLE_END + template<typename Mutex> - unique_lock<Mutex>::unique_lock(detail::thread_move_t<upgrade_lock<Mutex> > other): - m(other->m),is_locked(other->is_locked) + 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) { - other->is_locked=false; if(is_locked) { m->unlock_upgrade_and_lock(); } + BOOST_THREAD_RV(other).release(); } -#endif + template <class Mutex> class upgrade_to_unique_lock { @@ -948,73 +1190,64 @@ namespace boost upgrade_lock<Mutex>* source; unique_lock<Mutex> exclusive; - explicit upgrade_to_unique_lock(upgrade_to_unique_lock&); - upgrade_to_unique_lock& operator=(upgrade_to_unique_lock&); 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(move(*source)) + source(&m_),exclusive(::boost::move(*source)) {} ~upgrade_to_unique_lock() { if(source) { - *source=move(exclusive); + *source=BOOST_THREAD_MAKE_RV_REF(upgrade_lock<Mutex>(::boost::move(exclusive))); } } -#ifndef BOOST_NO_RVALUE_REFERENCES - upgrade_to_unique_lock(upgrade_to_unique_lock<Mutex>&& other): - source(other.source),exclusive(move(other.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)) { - other.source=0; + BOOST_THREAD_RV(other).source=0; } - upgrade_to_unique_lock& operator=(upgrade_to_unique_lock<Mutex>&& other) + 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; } -#else - upgrade_to_unique_lock(detail::thread_move_t<upgrade_to_unique_lock<Mutex> > other): - source(other->source),exclusive(move(other->exclusive)) - { - other->source=0; - } - upgrade_to_unique_lock& operator=(detail::thread_move_t<upgrade_to_unique_lock<Mutex> > other) - { - upgrade_to_unique_lock temp(other); - swap(temp); - return *this; - } -#endif - void swap(upgrade_to_unique_lock& other) + 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 + operator bool_type() const BOOST_NOEXCEPT { return exclusive.owns_lock()?&upgrade_to_unique_lock::swap:0; } - bool operator!() const + bool operator!() const BOOST_NOEXCEPT { return !owns_lock(); } - bool owns_lock() const +#else + explicit operator bool() const BOOST_NOEXCEPT + { + return owns_lock(); + } +#endif + + bool owns_lock() const BOOST_NOEXCEPT { return exclusive.owns_lock(); } }; -#ifdef BOOST_NO_RVALUE_REFERENCES - template <typename Mutex> - struct has_move_emulation_enabled_aux<upgrade_to_unique_lock<Mutex> > - : BOOST_MOVE_BOOST_NS::integral_constant<bool, true> - {}; -#endif + BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) upgrade_to_unique_lock<Mutex> BOOST_THREAD_DCL_MOVABLE_END namespace detail { @@ -1024,6 +1257,8 @@ namespace boost { typedef unique_lock<Mutex> base; public: + BOOST_THREAD_MOVABLE_ONLY(try_lock_wrapper) + try_lock_wrapper() {} @@ -1041,53 +1276,26 @@ namespace boost base(m_,try_to_lock) {} #ifndef BOOST_NO_RVALUE_REFERENCES - try_lock_wrapper(try_lock_wrapper&& other): - base(other.move()) + try_lock_wrapper(BOOST_THREAD_RV_REF(try_lock_wrapper) other): + base(::boost::move(other)) {} - try_lock_wrapper&& move() - { - return static_cast<try_lock_wrapper&&>(*this); - } - - try_lock_wrapper& operator=(try_lock_wrapper<Mutex>&& other) - { - try_lock_wrapper temp(other.move()); - swap(temp); - return *this; - } +#elif defined BOOST_THREAD_USES_MOVE + try_lock_wrapper(BOOST_THREAD_RV_REF(try_lock_wrapper) other): + base(::boost::move(static_cast<base&>(other))) + {} - void swap(try_lock_wrapper&& other) - { - base::swap(other); - } #else - try_lock_wrapper(detail::thread_move_t<try_lock_wrapper<Mutex> > other): - base(detail::thread_move_t<base>(*other)) + try_lock_wrapper(BOOST_THREAD_RV_REF(try_lock_wrapper) other): + base(BOOST_THREAD_RV_REF(base)(*other)) {} - - operator detail::thread_move_t<try_lock_wrapper<Mutex> >() - { - return move(); - } - - detail::thread_move_t<try_lock_wrapper<Mutex> > move() - { - return detail::thread_move_t<try_lock_wrapper<Mutex> >(*this); - } - - try_lock_wrapper& operator=(detail::thread_move_t<try_lock_wrapper<Mutex> > 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(detail::thread_move_t<try_lock_wrapper<Mutex> > other) - { - base::swap(*other); - } -#endif void swap(try_lock_wrapper& other) { base::swap(other); @@ -1116,36 +1324,30 @@ namespace boost { return base::release(); } - bool operator!() const - { - return !this->owns_lock(); - } +#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 }; -#ifndef BOOST_NO_RVALUE_REFERENCES - template<typename Mutex> - void swap(try_lock_wrapper<Mutex>&& lhs,try_lock_wrapper<Mutex>&& rhs) - { - lhs.swap(rhs); - } template<typename Mutex> void swap(try_lock_wrapper<Mutex>& lhs,try_lock_wrapper<Mutex>& rhs) { lhs.swap(rhs); } -#else - template<typename Mutex> - void swap(try_lock_wrapper<Mutex>& lhs,try_lock_wrapper<Mutex>& rhs) - { - lhs.swap(rhs); - } -#endif template<typename MutexType1,typename MutexType2> unsigned try_lock_internal(MutexType1& m1,MutexType2& m2) @@ -1620,7 +1822,6 @@ namespace boost } } - #include <boost/config/abi_suffix.hpp> #endif diff --git a/boost/thread/once.hpp b/boost/thread/once.hpp index 975304e147..acd216edd6 100644 --- a/boost/thread/once.hpp +++ b/boost/thread/once.hpp @@ -3,7 +3,7 @@ // once.hpp // -// (C) Copyright 2006-7 Anthony Williams +// (C) Copyright 2006-7 Anthony Williams // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -22,6 +22,8 @@ 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) { call_once(flag,func); diff --git a/boost/thread/pthread/condition_variable.hpp b/boost/thread/pthread/condition_variable.hpp index 48ed8ff731..aa7100766e 100644 --- a/boost/thread/pthread/condition_variable.hpp +++ b/boost/thread/pthread/condition_variable.hpp @@ -4,11 +4,17 @@ // 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 #include <boost/thread/pthread/timespec.hpp> #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp> #include <boost/thread/pthread/thread_data.hpp> #include <boost/thread/pthread/condition_variable_fwd.hpp> +#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/config/abi_prefix.hpp> @@ -59,18 +65,22 @@ namespace boost this_thread::interruption_point(); if(res) { - boost::throw_exception(condition_error()); + boost::throw_exception(condition_error(res, "boost:: condition_variable constructor failed in pthread_cond_wait")); } } - inline bool condition_variable::timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until) + inline bool condition_variable::do_timed_wait( + unique_lock<mutex>& m, + struct timespec const &timeout) { + if (!m.owns_lock()) + boost::throw_exception(condition_error(EPERM, "condition_variable do_timed_wait: mutex not locked")); + thread_cv_detail::lock_on_exit<unique_lock<mutex> > guard; int cond_res; { detail::interruption_checker check_for_interruption(&internal_mutex,&cond); guard.activate(m); - struct timespec const timeout=detail::get_timespec(wait_until); cond_res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout); } this_thread::interruption_point(); @@ -80,18 +90,18 @@ namespace boost } if(cond_res) { - boost::throw_exception(condition_error()); + boost::throw_exception(condition_error(cond_res, "condition_variable failed in pthread_cond_timedwait")); } return true; } - inline void condition_variable::notify_one() + inline void condition_variable::notify_one() BOOST_NOEXCEPT { boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); BOOST_VERIFY(!pthread_cond_signal(&cond)); } - inline void condition_variable::notify_all() + inline void condition_variable::notify_all() BOOST_NOEXCEPT { boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); BOOST_VERIFY(!pthread_cond_broadcast(&cond)); @@ -102,22 +112,20 @@ namespace boost pthread_mutex_t internal_mutex; pthread_cond_t cond; - condition_variable_any(condition_variable_any&); - condition_variable_any& operator=(condition_variable_any&); - public: + BOOST_THREAD_NO_COPYABLE(condition_variable_any) condition_variable_any() { int const res=pthread_mutex_init(&internal_mutex,NULL); if(res) { - boost::throw_exception(thread_resource_error()); + boost::throw_exception(thread_resource_error(res, "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()); + boost::throw_exception(thread_resource_error(res, "condition_variable_any failed in pthread_cond_init")); } } ~condition_variable_any() @@ -139,7 +147,7 @@ namespace boost this_thread::interruption_point(); if(res) { - boost::throw_exception(condition_error()); + boost::throw_exception(condition_error(res, "condition_variable_any failed in pthread_cond_wait")); } } @@ -153,23 +161,7 @@ namespace boost bool timed_wait(lock_type& m,boost::system_time const& wait_until) { struct timespec const timeout=detail::get_timespec(wait_until); - int res=0; - { - thread_cv_detail::lock_on_exit<lock_type> guard; - detail::interruption_checker check_for_interruption(&internal_mutex,&cond); - guard.activate(m); - res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout); - } - this_thread::interruption_point(); - if(res==ETIMEDOUT) - { - return false; - } - if(res) - { - boost::throw_exception(condition_error()); - } - return true; + return do_timed_wait(m, timeout); } template<typename lock_type> bool timed_wait(lock_type& m,xtime const& wait_until) @@ -206,17 +198,134 @@ namespace boost return timed_wait(m,get_system_time()+wait_duration,pred); } - void notify_one() +#ifdef BOOST_THREAD_USES_CHRONO + template <class lock_type,class Duration> + cv_status + wait_until( + lock_type& lock, + const chrono::time_point<chrono::system_clock, Duration>& t) + { + using namespace chrono; + typedef time_point<system_clock, nanoseconds> nano_sys_tmpt; + wait_until(lock, + nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch()))); + return system_clock::now() < t ? cv_status::no_timeout : + cv_status::timeout; + } + + template <class lock_type, class Clock, class Duration> + cv_status + wait_until( + lock_type& lock, + 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(); + wait_until(lock, s_now + ceil<nanoseconds>(t - c_now)); + return Clock::now() < t ? cv_status::no_timeout : cv_status::timeout; + } + + template <class lock_type, class Clock, class Duration, class Predicate> + bool + wait_until( + lock_type& lock, + const chrono::time_point<Clock, Duration>& t, + Predicate pred) + { + while (!pred()) + { + if (wait_until(lock, t) == cv_status::timeout) + return pred(); + } + return true; + } + + + template <class lock_type, class Rep, class Period> + cv_status + wait_for( + lock_type& lock, + const chrono::duration<Rep, Period>& d) + { + using namespace chrono; + system_clock::time_point s_now = system_clock::now(); + steady_clock::time_point c_now = steady_clock::now(); + wait_until(lock, s_now + ceil<nanoseconds>(d)); + return steady_clock::now() - c_now < d ? cv_status::no_timeout : + cv_status::timeout; + + } + + + template <class lock_type, class Rep, class Period, class Predicate> + bool + wait_for( + lock_type& lock, + const chrono::duration<Rep, Period>& d, + Predicate pred) + { + while (!pred()) + { + if (wait_for(lock, d) == cv_status::timeout) + return pred(); + } + return true; + } + + template <class lock_type> + inline void 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); + } +#endif + + void notify_one() BOOST_NOEXCEPT { boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); BOOST_VERIFY(!pthread_cond_signal(&cond)); } - void notify_all() + void notify_all() BOOST_NOEXCEPT { boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); BOOST_VERIFY(!pthread_cond_broadcast(&cond)); } + private: // used by boost::thread::try_join_until + + template <class lock_type> + inline bool do_timed_wait( + lock_type& m, + struct timespec const &timeout) + { + int res=0; + { + thread_cv_detail::lock_on_exit<lock_type> guard; + detail::interruption_checker check_for_interruption(&internal_mutex,&cond); + guard.activate(m); + res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout); + } + this_thread::interruption_point(); + if(res==ETIMEDOUT) + { + return false; + } + if(res) + { + boost::throw_exception(condition_error(res, "condition_variable_any 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 f56bee4789..4f4bd881d9 100644 --- a/boost/thread/pthread/condition_variable_fwd.hpp +++ b/boost/thread/pthread/condition_variable_fwd.hpp @@ -4,41 +4,47 @@ // 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 #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/thread_time.hpp> #include <boost/thread/xtime.hpp> - +#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 { + class condition_variable { private: pthread_mutex_t internal_mutex; pthread_cond_t cond; - condition_variable(condition_variable&); - condition_variable& operator=(condition_variable&); - public: + BOOST_THREAD_NO_COPYABLE(condition_variable) condition_variable() { int const res=pthread_mutex_init(&internal_mutex,NULL); if(res) { - boost::throw_exception(thread_resource_error()); + boost::throw_exception(thread_resource_error(res, "boost:: condition_variable constructor 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()); + boost::throw_exception(thread_resource_error(res2, "boost:: condition_variable constructor failed in pthread_cond_init")); } } ~condition_variable() @@ -59,21 +65,38 @@ namespace boost while(!pred()) wait(m); } - inline bool timed_wait(unique_lock<mutex>& m, - boost::system_time const& wait_until); - bool timed_wait(unique_lock<mutex>& m,xtime const& wait_until) + + inline bool timed_wait( + unique_lock<mutex>& m, + boost::system_time const& wait_until) + { +#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); +#else + struct timespec const timeout=detail::get_timespec(wait_until); + return do_timed_wait(m, timeout); +#endif + } + bool timed_wait( + unique_lock<mutex>& m, + xtime const& wait_until) { return timed_wait(m,system_time(wait_until)); } template<typename duration_type> - bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration) + bool timed_wait( + unique_lock<mutex>& m, + duration_type const& wait_duration) { return timed_wait(m,get_system_time()+wait_duration); } template<typename predicate_type> - bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until,predicate_type pred) + bool timed_wait( + unique_lock<mutex>& m, + boost::system_time const& wait_until,predicate_type pred) { while (!pred()) { @@ -84,25 +107,127 @@ namespace boost } template<typename predicate_type> - bool timed_wait(unique_lock<mutex>& m,xtime const& wait_until,predicate_type pred) + bool timed_wait( + unique_lock<mutex>& m, + xtime const& wait_until,predicate_type pred) { return timed_wait(m,system_time(wait_until),pred); } template<typename duration_type,typename predicate_type> - bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred) + bool timed_wait( + unique_lock<mutex>& m, + duration_type const& wait_duration,predicate_type pred) { return timed_wait(m,get_system_time()+wait_duration,pred); } +#ifdef BOOST_THREAD_USES_CHRONO + + template <class Duration> + cv_status + wait_until( + unique_lock<mutex>& lock, + const chrono::time_point<chrono::system_clock, Duration>& t) + { + using namespace chrono; + typedef time_point<system_clock, nanoseconds> nano_sys_tmpt; + wait_until(lock, + nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch()))); + return system_clock::now() < t ? cv_status::no_timeout : + cv_status::timeout; + } + + template <class Clock, class Duration> + cv_status + wait_until( + unique_lock<mutex>& lock, + 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(); + wait_until(lock, s_now + ceil<nanoseconds>(t - c_now)); + return Clock::now() < t ? cv_status::no_timeout : cv_status::timeout; + } + + template <class Clock, class Duration, class Predicate> + bool + wait_until( + unique_lock<mutex>& lock, + const chrono::time_point<Clock, Duration>& t, + Predicate pred) + { + while (!pred()) + { + if (wait_until(lock, t) == cv_status::timeout) + return pred(); + } + return true; + } + + + template <class Rep, class Period> + cv_status + wait_for( + unique_lock<mutex>& lock, + const chrono::duration<Rep, Period>& d) + { + using namespace chrono; + system_clock::time_point s_now = system_clock::now(); + steady_clock::time_point c_now = steady_clock::now(); + wait_until(lock, s_now + ceil<nanoseconds>(d)); + return steady_clock::now() - c_now < d ? cv_status::no_timeout : + cv_status::timeout; + + } + + + template <class Rep, class Period, class Predicate> + bool + wait_for( + unique_lock<mutex>& lock, + const chrono::duration<Rep, Period>& d, + Predicate pred) + { + while (!pred()) + { + if (wait_for(lock, d) == cv_status::timeout) + return pred(); + } + return true; + } +#endif + +#define BOOST_THREAD_DEFINES_CONDITION_VARIABLE_NATIVE_HANDLE typedef pthread_cond_t* native_handle_type; native_handle_type native_handle() { return &cond; } - void notify_one(); - void notify_all(); + void notify_one() BOOST_NOEXCEPT; + void notify_all() BOOST_NOEXCEPT; + +#ifdef BOOST_THREAD_USES_CHRONO + inline void 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); + } +#endif + //private: // used by boost::thread::try_join_until + + inline bool do_timed_wait( + unique_lock<mutex>& lock, + struct timespec const &timeout); }; } diff --git a/boost/thread/pthread/mutex.hpp b/boost/thread/pthread/mutex.hpp index fc7c9cdfad..2c5af92b8a 100644 --- a/boost/thread/pthread/mutex.hpp +++ b/boost/thread/pthread/mutex.hpp @@ -1,12 +1,12 @@ #ifndef BOOST_THREAD_PTHREAD_MUTEX_HPP #define BOOST_THREAD_PTHREAD_MUTEX_HPP // (C) Copyright 2007-8 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) #include <pthread.h> -#include <boost/utility.hpp> #include <boost/throw_exception.hpp> #include <boost/thread/exceptions.hpp> #include <boost/thread/locks.hpp> @@ -16,6 +16,11 @@ #include <errno.h> #include <boost/thread/pthread/timespec.hpp> #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp> +#ifdef BOOST_THREAD_USES_CHRONO +#include <boost/chrono/system_clocks.hpp> +#include <boost/chrono/ceil.hpp> +#endif +#include <boost/thread/detail/delete.hpp> #ifdef _POSIX_TIMEOUTS #if _POSIX_TIMEOUTS >= 0 && _POSIX_C_SOURCE>=200112L @@ -30,16 +35,16 @@ namespace boost class mutex { private: - mutex(mutex const&); - mutex& operator=(mutex const&); pthread_mutex_t m; public: + BOOST_THREAD_NO_COPYABLE(mutex) + mutex() { int const res=pthread_mutex_init(&m,NULL); if(res) { - boost::throw_exception(thread_resource_error()); + boost::throw_exception(thread_resource_error(res, "boost:: mutex constructor failed in pthread_mutex_init")); } } ~mutex() @@ -58,9 +63,9 @@ namespace boost { res = pthread_mutex_lock(&m); } while (res == EINTR); - if(res) + if (res) { - boost::throw_exception(lock_error(res)); + boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock")); } } @@ -83,12 +88,17 @@ namespace boost } while (res == EINTR); if(res && (res!=EBUSY)) { - boost::throw_exception(lock_error(res)); + // 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; } return !res; } +#define BOOST_THREAD_DEFINES_MUTEX_NATIVE_HANDLE typedef pthread_mutex_t* native_handle_type; native_handle_type native_handle() { @@ -104,28 +114,26 @@ namespace boost class timed_mutex { private: - timed_mutex(timed_mutex const&); - timed_mutex& operator=(timed_mutex const&); - private: pthread_mutex_t m; #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK pthread_cond_t cond; bool is_locked; #endif public: + BOOST_THREAD_NO_COPYABLE(timed_mutex) timed_mutex() { int const res=pthread_mutex_init(&m,NULL); if(res) { - boost::throw_exception(thread_resource_error()); + boost::throw_exception(thread_resource_error(res, "boost:: timed_mutex constructor failed in pthread_mutex_init")); } #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK int const res2=pthread_cond_init(&cond,NULL); if(res2) { BOOST_VERIFY(!pthread_mutex_destroy(&m)); - boost::throw_exception(thread_resource_error()); + boost::throw_exception(thread_resource_error(res2, "boost:: timed_mutex constructor failed in pthread_cond_init")); } is_locked=false; #endif @@ -165,19 +173,16 @@ namespace boost BOOST_ASSERT(!res || res==EBUSY); return !res; } - bool timed_lock(system_time const & abs_time) - { - struct timespec const timeout=detail::get_timespec(abs_time); - int const res=pthread_mutex_timedlock(&m,&timeout); - BOOST_ASSERT(!res || res==ETIMEDOUT); - return !res; - } - typedef pthread_mutex_t* native_handle_type; - native_handle_type native_handle() + + private: + bool do_try_lock_until(struct timespec const &timeout) { - return &m; + int const res=pthread_mutex_timedlock(&m,&timeout); + BOOST_ASSERT(!res || res==ETIMEDOUT); + return !res; } + public: #else void lock() @@ -208,9 +213,9 @@ namespace boost return true; } - bool timed_lock(system_time const & abs_time) + private: + bool do_try_lock_until(struct timespec const &timeout) { - struct timespec const timeout=detail::get_timespec(abs_time); boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); while(is_locked) { @@ -224,8 +229,55 @@ namespace boost is_locked=true; return true; } + public: +#endif + + bool timed_lock(system_time const & abs_time) + { + struct timespec const ts=detail::get_timespec(abs_time); + return do_try_lock_until(ts); + } + +#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>& t) + { + using namespace chrono; + system_clock::time_point s_now = system_clock::now(); + typename Clock::time_point c_now = Clock::now(); + return try_lock_until(s_now + ceil<nanoseconds>(t - c_now)); + } + template <class Duration> + bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t) + { + using namespace chrono; + typedef time_point<system_clock, nanoseconds> nano_sys_tmpt; + return try_lock_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch()))); + } + 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()); + return do_try_lock_until(ts); + } #endif +#define BOOST_THREAD_DEFINES_TIMED_MUTEX_NATIVE_HANDLE + typedef pthread_mutex_t* native_handle_type; + native_handle_type native_handle() + { + return &m; + } + typedef unique_lock<timed_mutex> scoped_timed_lock; typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock; typedef scoped_timed_lock scoped_lock; diff --git a/boost/thread/pthread/once.hpp b/boost/thread/pthread/once.hpp index 81e744e645..80aa09ee12 100644 --- a/boost/thread/pthread/once.hpp +++ b/boost/thread/pthread/once.hpp @@ -4,29 +4,52 @@ // once.hpp // // (C) Copyright 2007-8 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) #include <boost/thread/detail/config.hpp> -#include <boost/config.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/config/abi_prefix.hpp> namespace boost { +#define BOOST_ONCE_INITIAL_FLAG_VALUE 0 + +#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11 + + struct once_flag + { + BOOST_THREAD_NO_COPYABLE(once_flag) + BOOST_CONSTEXPR once_flag() BOOST_NOEXCEPT + : epoch(BOOST_ONCE_INITIAL_FLAG_VALUE) + {} + private: + boost::uintmax_t epoch; + template<typename Function> + friend + void call_once(once_flag& flag,Function f); + }; + +#else // BOOST_THREAD_PROVIDES_ONCE_CXX11 + struct once_flag { boost::uintmax_t epoch; }; +#define BOOST_ONCE_INIT {BOOST_ONCE_INITIAL_FLAG_VALUE} +#endif // BOOST_THREAD_PROVIDES_ONCE_CXX11 + namespace detail { BOOST_THREAD_DECL boost::uintmax_t& get_once_per_thread_epoch(); @@ -35,10 +58,6 @@ namespace boost BOOST_THREAD_DECL extern pthread_cond_t once_epoch_cv; } -#define BOOST_ONCE_INITIAL_FLAG_VALUE 0 -#define BOOST_ONCE_INIT {BOOST_ONCE_INITIAL_FLAG_VALUE} - - // 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> @@ -59,18 +78,18 @@ namespace boost { flag.epoch=being_initialized; #ifndef BOOST_NO_EXCEPTIONS - try + try // BOOST_NO_EXCEPTIONS protected { #endif pthread::pthread_mutex_scoped_unlock relocker(&detail::once_epoch_mutex); f(); #ifndef BOOST_NO_EXCEPTIONS } - catch(...) + catch(...) // BOOST_NO_EXCEPTIONS protected { flag.epoch=uninitialized_flag; BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv)); - throw; + throw; // BOOST_NO_EXCEPTIONS protected } #endif flag.epoch=--detail::once_global_epoch; diff --git a/boost/thread/pthread/recursive_mutex.hpp b/boost/thread/pthread/recursive_mutex.hpp index 113a0ac15e..22acf41fa2 100644 --- a/boost/thread/pthread/recursive_mutex.hpp +++ b/boost/thread/pthread/recursive_mutex.hpp @@ -1,12 +1,12 @@ #ifndef BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP #define BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP // (C) Copyright 2007-8 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) #include <pthread.h> -#include <boost/utility.hpp> #include <boost/throw_exception.hpp> #include <boost/thread/exceptions.hpp> #include <boost/thread/locks.hpp> @@ -19,6 +19,11 @@ #include <errno.h> #include <boost/thread/pthread/timespec.hpp> #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp> +#ifdef BOOST_THREAD_USES_CHRONO +#include <boost/chrono/system_clocks.hpp> +#include <boost/chrono/ceil.hpp> +#endif +#include <boost/thread/detail/delete.hpp> #ifdef _POSIX_TIMEOUTS #if _POSIX_TIMEOUTS >= 0 @@ -37,8 +42,6 @@ namespace boost class recursive_mutex { private: - recursive_mutex(recursive_mutex const&); - recursive_mutex& operator=(recursive_mutex const&); pthread_mutex_t m; #ifndef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE pthread_cond_t cond; @@ -47,6 +50,7 @@ namespace boost unsigned count; #endif public: + BOOST_THREAD_NO_COPYABLE(recursive_mutex) recursive_mutex() { #ifdef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE @@ -55,33 +59,33 @@ namespace boost int const init_attr_res=pthread_mutexattr_init(&attr); if(init_attr_res) { - boost::throw_exception(thread_resource_error()); + boost::throw_exception(thread_resource_error(init_attr_res, "boost:: recursive_mutex constructor failed in pthread_mutexattr_init")); } int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE); if(set_attr_res) { BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); - boost::throw_exception(thread_resource_error()); + boost::throw_exception(thread_resource_error(set_attr_res, "boost:: recursive_mutex constructor failed in pthread_mutexattr_settype")); } int const res=pthread_mutex_init(&m,&attr); if(res) { BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); - boost::throw_exception(thread_resource_error()); + boost::throw_exception(thread_resource_error(res, "boost:: recursive_mutex constructor failed in pthread_mutex_init")); } BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); #else int const res=pthread_mutex_init(&m,NULL); if(res) { - boost::throw_exception(thread_resource_error()); + boost::throw_exception(thread_resource_error(res, "boost:: recursive_mutex constructor failed in pthread_mutex_init")); } int const res2=pthread_cond_init(&cond,NULL); if(res2) { BOOST_VERIFY(!pthread_mutex_destroy(&m)); - boost::throw_exception(thread_resource_error()); + boost::throw_exception(thread_resource_error(res2, "boost:: recursive_mutex constructor failed in pthread_cond_init")); } is_locked=false; count=0; @@ -112,6 +116,7 @@ namespace boost BOOST_ASSERT(!res || res==EBUSY); return !res; } +#define BOOST_THREAD_DEFINES_RECURSIVE_MUTEX_NATIVE_HANDLE typedef pthread_mutex_t* native_handle_type; native_handle_type native_handle() { @@ -171,9 +176,6 @@ namespace boost class recursive_timed_mutex { private: - recursive_timed_mutex(recursive_timed_mutex const&); - recursive_timed_mutex& operator=(recursive_timed_mutex const&); - private: pthread_mutex_t m; #ifndef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK pthread_cond_t cond; @@ -182,6 +184,7 @@ namespace boost unsigned count; #endif public: + BOOST_THREAD_NO_COPYABLE(recursive_timed_mutex) recursive_timed_mutex() { #ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK @@ -190,32 +193,32 @@ namespace boost int const init_attr_res=pthread_mutexattr_init(&attr); if(init_attr_res) { - boost::throw_exception(thread_resource_error()); + boost::throw_exception(thread_resource_error(init_attr_res, "boost:: recursive_timed_mutex constructor failed in pthread_mutexattr_init")); } int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE); if(set_attr_res) { - boost::throw_exception(thread_resource_error()); + boost::throw_exception(thread_resource_error(set_attr_res, "boost:: recursive_timed_mutex constructor failed in pthread_mutexattr_settype")); } int const res=pthread_mutex_init(&m,&attr); if(res) { BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); - boost::throw_exception(thread_resource_error()); + boost::throw_exception(thread_resource_error(res, "boost:: recursive_timed_mutex constructor failed in pthread_mutex_init")); } BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); #else int const res=pthread_mutex_init(&m,NULL); if(res) { - boost::throw_exception(thread_resource_error()); + boost::throw_exception(thread_resource_error(res, "boost:: recursive_timed_mutex constructor failed in pthread_mutex_init")); } int const res2=pthread_cond_init(&cond,NULL); if(res2) { BOOST_VERIFY(!pthread_mutex_destroy(&m)); - boost::throw_exception(thread_resource_error()); + boost::throw_exception(thread_resource_error(res2, "boost:: recursive_timed_mutex constructor failed in pthread_cond_init")); } is_locked=false; count=0; @@ -252,19 +255,15 @@ namespace boost BOOST_ASSERT(!res || res==EBUSY); return !res; } - bool timed_lock(system_time const & abs_time) + private: + bool do_try_lock_until(struct timespec const &timeout) { - struct timespec const timeout=detail::get_timespec(abs_time); int const res=pthread_mutex_timedlock(&m,&timeout); BOOST_ASSERT(!res || res==ETIMEDOUT); return !res; } - typedef pthread_mutex_t* native_handle_type; - native_handle_type native_handle() - { - return &m; - } + public: #else void lock() @@ -308,9 +307,9 @@ namespace boost return true; } - bool timed_lock(system_time const & abs_time) + private: + bool do_try_lock_until(struct timespec const &timeout) { - struct timespec const timeout=detail::get_timespec(abs_time); boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); if(is_locked && pthread_equal(owner,pthread_self())) { @@ -331,8 +330,56 @@ namespace boost owner=pthread_self(); return true; } + public: + +#endif + + bool timed_lock(system_time const & abs_time) + { + struct timespec const ts=detail::get_timespec(abs_time); + return do_try_lock_until(ts); + } + +#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>& t) + { + using namespace chrono; + system_clock::time_point s_now = system_clock::now(); + typename Clock::time_point c_now = Clock::now(); + return try_lock_until(s_now + ceil<nanoseconds>(t - c_now)); + } + template <class Duration> + bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t) + { + using namespace chrono; + typedef time_point<system_clock, nanoseconds> nano_sys_tmpt; + return try_lock_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch()))); + } + 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()); + return do_try_lock_until(ts); + } #endif +#define BOOST_THREAD_DEFINES_RECURSIVE_TIMED_MUTEX_NATIVE_HANDLE + typedef pthread_mutex_t* native_handle_type; + native_handle_type native_handle() + { + return &m; + } + 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; diff --git a/boost/thread/pthread/shared_mutex.hpp b/boost/thread/pthread/shared_mutex.hpp index 56e209acf3..cf45188606 100644 --- a/boost/thread/pthread/shared_mutex.hpp +++ b/boost/thread/pthread/shared_mutex.hpp @@ -2,6 +2,7 @@ #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 @@ -12,6 +13,11 @@ #include <boost/thread/mutex.hpp> #include <boost/thread/condition_variable.hpp> #include <boost/thread/detail/thread_interruption.hpp> +#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/config/abi_prefix.hpp> @@ -42,8 +48,9 @@ namespace boost shared_cond.notify_all(); } - public: + BOOST_THREAD_NO_COPYABLE(shared_mutex) + shared_mutex() { state_data state_={0,0,0,0}; @@ -102,7 +109,29 @@ namespace boost { return timed_lock_shared(get_system_time()+relative_time); } - +#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) + { + boost::this_thread::disable_interruption do_not_disturb; + boost::mutex::scoped_lock lk(state_change); + + while(state.exclusive || state.exclusive_waiting_blocked) + { + if(cv_status::timeout==shared_cond.wait_until(lk,abs_time)) + { + return false; + } + } + ++state.shared_count; + return true; + } +#endif void unlock_shared() { boost::mutex::scoped_lock lk(state_change); @@ -166,6 +195,37 @@ namespace boost return timed_lock(get_system_time()+relative_time); } +#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) + { + boost::this_thread::disable_interruption do_not_disturb; + boost::mutex::scoped_lock lk(state_change); + + while(state.shared_count || state.exclusive) + { + state.exclusive_waiting_blocked=true; + if(cv_status::timeout == exclusive_cond.wait_until(lk,abs_time)) + { + if(state.shared_count || state.exclusive) + { + state.exclusive_waiting_blocked=false; + release_waiters(); + return false; + } + break; + } + } + state.exclusive=true; + return true; + } +#endif + bool try_lock() { boost::mutex::scoped_lock lk(state_change); @@ -228,6 +288,33 @@ namespace boost return timed_lock_upgrade(get_system_time()+relative_time); } +#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) + { + boost::this_thread::disable_interruption do_not_disturb; + boost::mutex::scoped_lock lk(state_change); + while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) + { + if(cv_status::timeout == shared_cond.wait_until(lk,abs_time)) + { + if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) + { + return false; + } + break; + } + } + ++state.shared_count; + state.upgrade=true; + return true; + } +#endif bool try_lock_upgrade() { boost::mutex::scoped_lock lk(state_change); @@ -253,9 +340,12 @@ namespace boost { state.exclusive_waiting_blocked=false; release_waiters(); + } else { + shared_cond.notify_all(); } } + // Upgrade <-> Exclusive void unlock_upgrade_and_lock() { boost::this_thread::disable_interruption do_not_disturb; @@ -279,6 +369,57 @@ namespace boost release_waiters(); } + bool try_unlock_upgrade_and_lock() + { + boost::mutex::scoped_lock lk(state_change); + if( !state.exclusive + && !state.exclusive_waiting_blocked + && state.upgrade + && state.shared_count==1) + { + state.shared_count=0; + state.exclusive=true; + state.upgrade=false; + 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) + { + boost::this_thread::disable_interruption do_not_disturb; + boost::mutex::scoped_lock lk(state_change); + if (state.shared_count != 1) + { + for (;;) + { + cv_status status = shared_cond.wait_until(lk,abs_time); + if (state.shared_count == 1) + break; + if(status == cv_status::timeout) + return false; + } + } + state.upgrade=false; + state.exclusive=true; + state.exclusive_waiting_blocked=false; + state.shared_count=0; + return true; + } +#endif + + // Shared <-> Exclusive void unlock_and_lock_shared() { boost::mutex::scoped_lock lk(state_change); @@ -288,6 +429,58 @@ namespace boost release_waiters(); } +#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS + bool try_unlock_shared_and_lock() + { + boost::mutex::scoped_lock lk(state_change); + if( !state.exclusive + && !state.exclusive_waiting_blocked + && !state.upgrade + && state.shared_count==1) + { + state.shared_count=0; + state.exclusive=true; + 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) + { + boost::this_thread::disable_interruption do_not_disturb; + boost::mutex::scoped_lock lk(state_change); + if (state.shared_count != 1) + { + for (;;) + { + cv_status status = shared_cond.wait_until(lk,abs_time); + if (state.shared_count == 1) + break; + if(status == cv_status::timeout) + return false; + } + } + state.upgrade=false; + state.exclusive=true; + state.exclusive_waiting_blocked=false; + state.shared_count=0; + return true; + } +#endif +#endif + + // Shared <-> Upgrade void unlock_upgrade_and_lock_shared() { boost::mutex::scoped_lock lk(state_change); @@ -295,7 +488,62 @@ namespace boost state.exclusive_waiting_blocked=false; release_waiters(); } + +#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS + bool try_unlock_shared_and_lock_upgrade() + { + boost::mutex::scoped_lock lk(state_change); + if( !state.exclusive + && !state.exclusive_waiting_blocked + && !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) + { + boost::this_thread::disable_interruption do_not_disturb; + boost::mutex::scoped_lock lk(state_change); + if( state.exclusive + || state.exclusive_waiting_blocked + || state.upgrade + ) + { + for (;;) + { + cv_status status = exclusive_cond.wait_until(lk,abs_time); + if( ! state.exclusive + && ! state.exclusive_waiting_blocked + && ! state.upgrade + ) + break; + if(status == cv_status::timeout) + return false; + } + } + state.upgrade=true; + return true; + } +#endif +#endif }; + + typedef shared_mutex upgrade_mutex; } #include <boost/config/abi_suffix.hpp> diff --git a/boost/thread/pthread/thread_data.hpp b/boost/thread/pthread/thread_data.hpp index 3de9b41b17..5f84799f85 100644 --- a/boost/thread/pthread/thread_data.hpp +++ b/boost/thread/pthread/thread_data.hpp @@ -4,6 +4,7 @@ // 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 #include <boost/thread/detail/config.hpp> #include <boost/thread/exceptions.hpp> @@ -15,11 +16,56 @@ #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 <boost/config/abi_prefix.hpp> namespace boost { + class thread_attributes { + public: + thread_attributes() BOOST_NOEXCEPT { + int res = pthread_attr_init(&val_); + BOOST_VERIFY(!res && "pthread_attr_init failed"); + } + ~thread_attributes() { + int res = pthread_attr_destroy(&val_); + BOOST_VERIFY(!res && "pthread_attr_destroy failed"); + } + // stack + void set_stack_size(std::size_t size) BOOST_NOEXCEPT { + if (size==0) return; + std::size_t page_size = getpagesize(); +#ifdef PTHREAD_STACK_MIN + if (size<PTHREAD_STACK_MIN) size=PTHREAD_STACK_MIN; +#endif + size = ((size+page_size-1)/page_size)*page_size; + int res = pthread_attr_setstacksize(&val_, size); + BOOST_VERIFY(!res && "pthread_attr_setstacksize failed"); + } + + std::size_t get_stack_size() const BOOST_NOEXCEPT { + std::size_t size; + int res = pthread_attr_getstacksize(&val_, &size); + BOOST_VERIFY(!res && "pthread_attr_getstacksize failed"); + return size; + } +#define BOOST_THREAD_DEFINES_THREAD_ATTRIBUTES_NATIVE_HANDLE + + typedef pthread_attr_t native_handle_type; + native_handle_type* native_handle() BOOST_NOEXCEPT { + return &val_; + } + const native_handle_type* native_handle() const BOOST_NOEXCEPT { + return &val_; + } + + private: + pthread_attr_t val_; + }; + class thread; namespace detail @@ -83,11 +129,13 @@ namespace boost void check_for_interruption() { +#ifndef BOOST_NO_EXCEPTIONS if(thread_info->interrupt_requested) { thread_info->interrupt_requested=false; - throw thread_interrupted(); + throw thread_interrupted(); // BOOST_NO_EXCEPTIONS protected } +#endif } void operator=(interruption_checker&); @@ -128,7 +176,10 @@ namespace boost namespace this_thread { - void BOOST_THREAD_DECL yield(); +#ifdef BOOST_THREAD_USES_CHRONO + void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns); +#endif + void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT; #ifdef __DECXXX /// Workaround of DECCXX issue of incorrect template substitution diff --git a/boost/thread/reverse_lock.hpp b/boost/thread/reverse_lock.hpp new file mode 100644 index 0000000000..c196cde072 --- /dev/null +++ b/boost/thread/reverse_lock.hpp @@ -0,0 +1,58 @@ +// 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_REVERSE_LOCK_HPP +#define BOOST_THREAD_REVERSE_LOCK_HPP +#include <boost/thread/detail/config.hpp> +#include <boost/thread/locks.hpp> +#include <boost/thread/detail/delete.hpp> + +namespace boost +{ + + template<typename Lock> + class reverse_lock + { + + public: + typedef typename Lock::mutex_type mutex_type; + BOOST_THREAD_NO_COPYABLE(reverse_lock) + + explicit reverse_lock(Lock& m_) + : m(m_), mtx(0) + { + if (m.owns_lock()) + { + m.unlock(); + } + mtx=m.release(); + } + ~reverse_lock() + { + if (mtx) { + mtx->lock(); + m = BOOST_THREAD_MAKE_RV_REF(Lock(*mtx, adopt_lock)); + } + } + + private: + Lock& m; + mutex_type* mtx; + }; + + +#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES + template<typename T> + struct is_mutex_type<reverse_lock<T> > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + +#endif + + +} + +#endif // header diff --git a/boost/thread/shared_lock_guard.hpp b/boost/thread/shared_lock_guard.hpp new file mode 100644 index 0000000000..8a2f2c54d1 --- /dev/null +++ b/boost/thread/shared_lock_guard.hpp @@ -0,0 +1,52 @@ +// 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_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/detail/delete.hpp> + +namespace boost +{ + + template<typename SharedMutex> + class shared_lock_guard + { + private: + SharedMutex& m; + + public: + typedef SharedMutex mutex_type; + BOOST_THREAD_NO_COPYABLE(shared_lock_guard) + explicit shared_lock_guard(SharedMutex& m_): + m(m_) + { + m.lock_shared(); + } + shared_lock_guard(SharedMutex& m_,adopt_lock_t): + m(m_) + {} + ~shared_lock_guard() + { + m.unlock_shared(); + } + }; + +#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES + + template<typename T> + struct is_mutex_type<shared_lock_guard<T> > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + +#endif + + +} + +#endif // header diff --git a/boost/thread/shared_mutex.hpp b/boost/thread/shared_mutex.hpp index 51eda0de0b..e85e269d44 100644 --- a/boost/thread/shared_mutex.hpp +++ b/boost/thread/shared_mutex.hpp @@ -3,15 +3,20 @@ // shared_mutex.hpp // -// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2007 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) -#include <boost/thread/detail/platform.hpp> +#include <boost/thread/detail/config.hpp> #if defined(BOOST_THREAD_PLATFORM_WIN32) +#if defined(BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN) +#include <boost/thread/pthread/shared_mutex.hpp> +#else #include <boost/thread/win32/shared_mutex.hpp> +#endif #elif defined(BOOST_THREAD_PLATFORM_PTHREAD) #include <boost/thread/pthread/shared_mutex.hpp> #else diff --git a/boost/thread/thread.hpp b/boost/thread/thread.hpp index fdfdadcc3e..ee15c6e365 100644 --- a/boost/thread/thread.hpp +++ b/boost/thread/thread.hpp @@ -3,7 +3,7 @@ // thread.hpp // -// (C) Copyright 2007-8 Anthony Williams +// (C) Copyright 2007-8 Anthony Williams // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -22,6 +22,7 @@ #include <boost/thread/detail/thread.hpp> #include <boost/thread/detail/thread_interruption.hpp> #include <boost/thread/detail/thread_group.hpp> +#include <boost/thread/v2/thread.hpp> #endif diff --git a/boost/thread/v2/thread.hpp b/boost/thread/v2/thread.hpp new file mode 100644 index 0000000000..d686c5fe9b --- /dev/null +++ b/boost/thread/v2/thread.hpp @@ -0,0 +1,56 @@ +// 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 2011 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_V2_THREAD_HPP +#define BOOST_THREAD_V2_THREAD_HPP + +#include <boost/thread/detail/config.hpp> +#ifdef BOOST_THREAD_USES_CHRONO +#include <boost/chrono/system_clocks.hpp> +#endif +#include <boost/thread/condition_variable.hpp> +#include <boost/thread/locks.hpp> + +namespace boost +{ + namespace this_thread + { + +#ifdef BOOST_THREAD_USES_CHRONO + + 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); + } + + 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); + } + + 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()); + } + +#endif + } +} + + +#endif diff --git a/boost/thread/win32/basic_recursive_mutex.hpp b/boost/thread/win32/basic_recursive_mutex.hpp index e748aa725c..eb5ec8489d 100644 --- a/boost/thread/win32/basic_recursive_mutex.hpp +++ b/boost/thread/win32/basic_recursive_mutex.hpp @@ -4,6 +4,7 @@ // basic_recursive_mutex.hpp // // (C) Copyright 2006-8 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 @@ -11,6 +12,10 @@ #include <boost/thread/win32/thread_primitives.hpp> #include <boost/thread/win32/basic_timed_mutex.hpp> +#ifdef BOOST_THREAD_USES_CHRONO +#include <boost/chrono/system_clocks.hpp> +#include <boost/chrono/ceil.hpp> +#endif #include <boost/config/abi_prefix.hpp> @@ -64,6 +69,20 @@ namespace boost return timed_lock(get_system_time()+timeout); } +#ifdef BOOST_THREAD_USES_CHRONO + template <class Rep, class Period> + bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) + { + long const current_thread_id=win32::GetCurrentThreadId(); + return try_recursive_lock(current_thread_id) || try_timed_lock_for(current_thread_id,rel_time); + } + template <class Clock, class Duration> + bool try_lock_until(const chrono::time_point<Clock, Duration>& t) + { + long const current_thread_id=win32::GetCurrentThreadId(); + return try_recursive_lock(current_thread_id) || try_timed_lock_until(current_thread_id,t); + } +#endif void unlock() { if(!--recursion_count) @@ -105,7 +124,28 @@ namespace boost } return false; } - + template <typename TP> + bool try_timed_lock_until(long current_thread_id,TP const& target) + { + if(mutex.try_lock_until(target)) + { + BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id); + recursion_count=1; + return true; + } + return false; + } + template <typename D> + bool try_timed_lock_for(long current_thread_id,D const& target) + { + if(mutex.try_lock_for(target)) + { + BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id); + recursion_count=1; + return true; + } + return false; + } }; typedef basic_recursive_mutex_impl<basic_timed_mutex> basic_recursive_mutex; diff --git a/boost/thread/win32/basic_timed_mutex.hpp b/boost/thread/win32/basic_timed_mutex.hpp index a88c2a0f6f..30580e7c17 100644 --- a/boost/thread/win32/basic_timed_mutex.hpp +++ b/boost/thread/win32/basic_timed_mutex.hpp @@ -4,6 +4,7 @@ // basic_timed_mutex_win32.hpp // // (C) Copyright 2006-8 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 @@ -15,7 +16,10 @@ #include <boost/thread/thread_time.hpp> #include <boost/thread/xtime.hpp> #include <boost/detail/interlocked.hpp> - +#ifdef BOOST_THREAD_USES_CHRONO +#include <boost/chrono/system_clocks.hpp> +#include <boost/chrono/ceil.hpp> +#endif #include <boost/config/abi_prefix.hpp> namespace boost @@ -143,6 +147,7 @@ namespace boost return true; } + template<typename Duration> bool timed_lock(Duration const& timeout) { @@ -154,6 +159,59 @@ namespace boost return timed_lock(system_time(timeout)); } +#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>& t) + { + using namespace chrono; + system_clock::time_point s_now = system_clock::now(); + typename Clock::time_point c_now = Clock::now(); + return try_lock_until(s_now + ceil<system_clock::duration>(t - c_now)); + } + template <class Duration> + bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t) + { + using namespace chrono; + typedef time_point<chrono::system_clock, chrono::system_clock::duration> sys_tmpt; + return try_lock_until(sys_tmpt(chrono::ceil<chrono::system_clock::duration>(t.time_since_epoch()))); + } + bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::system_clock::duration>& tp) + { + if(try_lock()) + { + return true; + } + long old_count=active_count; + mark_waiting_and_try_lock(old_count); + + if(old_count&lock_flag_value) + { + bool lock_acquired=false; + void* const sem=get_event(); + + do + { + chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now()); + + if(win32::WaitForSingleObject(sem,static_cast<unsigned long>(rel_time.count()))!=0) + { + BOOST_INTERLOCKED_DECREMENT(&active_count); + return false; + } + clear_waiting_and_try_lock(old_count); + lock_acquired=!(old_count&lock_flag_value); + } + while(!lock_acquired); + } + return true; + } +#endif + void unlock() { long const offset=lock_flag_value; diff --git a/boost/thread/win32/condition_variable.hpp b/boost/thread/win32/condition_variable.hpp index 056bda8086..63f830b186 100644 --- a/boost/thread/win32/condition_variable.hpp +++ b/boost/thread/win32/condition_variable.hpp @@ -4,18 +4,24 @@ // 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-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/thread.hpp> +#include <boost/thread/cv_status.hpp> +#include <boost/thread/win32/thread_data.hpp> #include <boost/thread/thread_time.hpp> #include <boost/thread/win32/interlocked_read.hpp> #include <boost/thread/xtime.hpp> #include <vector> #include <boost/intrusive_ptr.hpp> +#ifdef BOOST_THREAD_USES_CHRONO +#include <boost/chrono/system_clocks.hpp> +#include <boost/chrono/ceil.hpp> +#endif #include <boost/config/abi_prefix.hpp> @@ -36,10 +42,8 @@ namespace boost bool notified; long references; - basic_cv_list_entry(basic_cv_list_entry&); - void operator=(basic_cv_list_entry&); - public: + BOOST_THREAD_NO_COPYABLE(basic_cv_list_entry) explicit basic_cv_list_entry(detail::win32::handle_manager const& wake_sem_): semaphore(detail::win32::create_anonymous_semaphore(0,LONG_MAX)), wake_sem(wake_sem_.duplicate()), @@ -77,9 +81,9 @@ namespace boost return notified; } - bool wait(timeout wait_until) + bool wait(timeout abs_time) { - return this_thread::interruptible_wait(semaphore,wait_until); + return this_thread::interruptible_wait(semaphore,abs_time); } bool woken() @@ -129,6 +133,7 @@ namespace boost template<typename lock_type> struct relocker { + BOOST_THREAD_NO_COPYABLE(relocker) lock_type& lock; bool unlocked; @@ -148,9 +153,6 @@ namespace boost } } - private: - relocker(relocker&); - void operator=(relocker&); }; @@ -182,6 +184,7 @@ namespace boost { entry_ptr const entry; + BOOST_THREAD_NO_COPYABLE(entry_manager) entry_manager(entry_ptr const& entry_): entry(entry_) {} @@ -195,16 +198,12 @@ namespace boost { return entry.get(); } - - private: - void operator=(entry_manager&); - entry_manager(entry_manager&); }; protected: template<typename lock_type> - bool do_wait(lock_type& lock,timeout wait_until) + bool do_wait(lock_type& lock,timeout abs_time) { relocker<lock_type> locker(lock); @@ -215,7 +214,7 @@ namespace boost bool woken=false; while(!woken) { - if(!entry->wait(wait_until)) + if(!entry->wait(abs_time)) { return false; } @@ -226,11 +225,11 @@ namespace boost } template<typename lock_type,typename predicate_type> - bool do_wait(lock_type& m,timeout const& wait_until,predicate_type pred) + bool do_wait(lock_type& m,timeout const& abs_time,predicate_type pred) { while (!pred()) { - if(!do_wait(m, wait_until)) + if(!do_wait(m, abs_time)) return pred(); } return true; @@ -247,7 +246,7 @@ namespace boost ~basic_condition_variable() {} - void notify_one() + void notify_one() BOOST_NOEXCEPT { if(detail::interlocked_read_acquire(&total_count)) { @@ -268,7 +267,7 @@ namespace boost } } - void notify_all() + void notify_all() BOOST_NOEXCEPT { if(detail::interlocked_read_acquire(&total_count)) { @@ -295,10 +294,8 @@ namespace boost class condition_variable: private detail::basic_condition_variable { - private: - condition_variable(condition_variable&); - void operator=(condition_variable&); public: + BOOST_THREAD_NO_COPYABLE(condition_variable) condition_variable() {} @@ -317,14 +314,14 @@ namespace boost } - bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until) + bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time) { - return do_wait(m,wait_until); + return do_wait(m,abs_time); } - bool timed_wait(unique_lock<mutex>& m,boost::xtime const& wait_until) + bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time) { - return do_wait(m,system_time(wait_until)); + return do_wait(m,system_time(abs_time)); } template<typename duration_type> bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration) @@ -333,29 +330,79 @@ namespace boost } template<typename predicate_type> - bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until,predicate_type pred) + bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time,predicate_type pred) { - return do_wait(m,wait_until,pred); + return do_wait(m,abs_time,pred); } template<typename predicate_type> - bool timed_wait(unique_lock<mutex>& m,boost::xtime const& wait_until,predicate_type pred) + bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time,predicate_type pred) { - return do_wait(m,system_time(wait_until),pred); + return do_wait(m,system_time(abs_time),pred); } template<typename duration_type,typename predicate_type> bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred) { return do_wait(m,wait_duration.total_milliseconds(),pred); } + +#ifdef BOOST_THREAD_USES_CHRONO + + template <class Clock, class Duration> + cv_status + wait_until( + unique_lock<mutex>& lock, + const chrono::time_point<Clock, Duration>& t) + { + using namespace chrono; + do_wait(lock, ceil<milliseconds>(t-Clock::now()).count()); + return Clock::now() < t ? cv_status::no_timeout : + cv_status::timeout; + } + + template <class Rep, class Period> + cv_status + wait_for( + unique_lock<mutex>& lock, + const chrono::duration<Rep, Period>& d) + { + using namespace chrono; + 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 : + cv_status::timeout; + } + + template <class Clock, class Duration, class Predicate> + bool + wait_until( + unique_lock<mutex>& lock, + const chrono::time_point<Clock, Duration>& t, + Predicate pred) + { + while (!pred()) + { + if (wait_until(lock, t) == cv_status::timeout) + return pred(); + } + return true; + } + template <class Rep, class Period, class Predicate> + bool + wait_for( + unique_lock<mutex>& lock, + const chrono::duration<Rep, Period>& d, + Predicate pred) + { + return wait_until(lock, chrono::steady_clock::now() + d, pred); + } +#endif }; class condition_variable_any: private detail::basic_condition_variable { - private: - condition_variable_any(condition_variable_any&); - void operator=(condition_variable_any&); public: + BOOST_THREAD_NO_COPYABLE(condition_variable_any) condition_variable_any() {} @@ -375,15 +422,15 @@ namespace boost } 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) { - return do_wait(m,wait_until); + return do_wait(m,abs_time); } template<typename lock_type> - bool timed_wait(lock_type& m,boost::xtime const& wait_until) + bool timed_wait(lock_type& m,boost::xtime const& abs_time) { - return do_wait(m,system_time(wait_until)); + return do_wait(m,system_time(abs_time)); } template<typename lock_type,typename duration_type> @@ -393,15 +440,15 @@ 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) { - return do_wait(m,wait_until,pred); + return do_wait(m,abs_time,pred); } template<typename lock_type,typename predicate_type> - bool timed_wait(lock_type& m,boost::xtime const& wait_until,predicate_type pred) + bool timed_wait(lock_type& m,boost::xtime const& abs_time,predicate_type pred) { - return do_wait(m,system_time(wait_until),pred); + return do_wait(m,system_time(abs_time),pred); } template<typename lock_type,typename duration_type,typename predicate_type> @@ -409,6 +456,58 @@ namespace boost { return do_wait(m,wait_duration.total_milliseconds(),pred); } +#ifdef BOOST_THREAD_USES_CHRONO + + template <class lock_type, class Clock, class Duration> + cv_status + wait_until( + lock_type& lock, + const chrono::time_point<Clock, Duration>& t) + { + using namespace chrono; + do_wait(lock, ceil<milliseconds>(t-Clock::now()).count()); + return Clock::now() < t ? cv_status::no_timeout : + cv_status::timeout; + } + + template <class lock_type, class Rep, class Period> + cv_status + wait_for( + lock_type& lock, + const chrono::duration<Rep, Period>& d) + { + using namespace chrono; + 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 : + cv_status::timeout; + } + + template <class lock_type, class Clock, class Duration, class Predicate> + bool + wait_until( + lock_type& lock, + const chrono::time_point<Clock, Duration>& t, + Predicate pred) + { + while (!pred()) + { + if (wait_until(lock, t) == cv_status::timeout) + return pred(); + } + return true; + } + + template <class lock_type, class Rep, class Period, class Predicate> + bool + wait_for( + lock_type& lock, + const chrono::duration<Rep, Period>& d, + Predicate pred) + { + return wait_until(lock, chrono::steady_clock::now() + d, pred); + } +#endif }; } diff --git a/boost/thread/win32/mutex.hpp b/boost/thread/win32/mutex.hpp index 92b2669e49..85a00e29f9 100644 --- a/boost/thread/win32/mutex.hpp +++ b/boost/thread/win32/mutex.hpp @@ -1,12 +1,12 @@ #ifndef BOOST_THREAD_WIN32_MUTEX_HPP #define BOOST_THREAD_WIN32_MUTEX_HPP // (C) Copyright 2005-7 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) #include <boost/thread/win32/basic_timed_mutex.hpp> -#include <boost/utility.hpp> #include <boost/thread/exceptions.hpp> #include <boost/thread/locks.hpp> @@ -22,10 +22,8 @@ namespace boost class mutex: public ::boost::detail::underlying_mutex { - private: - mutex(mutex const&); - mutex& operator=(mutex const&); public: + BOOST_THREAD_NO_COPYABLE(mutex) mutex() { initialize(); @@ -44,10 +42,8 @@ namespace boost class timed_mutex: public ::boost::detail::basic_timed_mutex { - private: - timed_mutex(timed_mutex const&); - timed_mutex& operator=(timed_mutex const&); public: + BOOST_THREAD_NO_COPYABLE(timed_mutex) timed_mutex() { initialize(); diff --git a/boost/thread/win32/once.hpp b/boost/thread/win32/once.hpp index e1b1843230..3066b50bc3 100644 --- a/boost/thread/win32/once.hpp +++ b/boost/thread/win32/once.hpp @@ -3,8 +3,9 @@ // once.hpp // -// (C) Copyright 2005-7 Anthony Williams +// (C) Copyright 2005-7 Anthony Williams // (C) Copyright 2005 John Maddock +// (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 @@ -30,6 +31,25 @@ namespace std namespace boost { +#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11 + + struct once_flag + { + BOOST_THREAD_NO_COPYABLE(once_flag) + 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); + }; + +#define BOOST_ONCE_INIT once_flag() +#else // BOOST_THREAD_PROVIDES_ONCE_CXX11 + struct once_flag { long status; @@ -37,6 +57,7 @@ namespace boost }; #define BOOST_ONCE_INIT {0,0} +#endif // BOOST_THREAD_PROVIDES_ONCE_CXX11 namespace detail { @@ -71,29 +92,29 @@ namespace boost #else static const once_char_type fixed_mutex_name[]="Local\\{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag"; #endif - BOOST_STATIC_ASSERT(sizeof(fixed_mutex_name) == + BOOST_STATIC_ASSERT(sizeof(fixed_mutex_name) == (sizeof(once_char_type)*(once_mutex_name_fixed_length+1))); - + std::memcpy(mutex_name,fixed_mutex_name,sizeof(fixed_mutex_name)); - detail::int_to_string(reinterpret_cast<std::ptrdiff_t>(flag_address), + detail::int_to_string(reinterpret_cast<std::ptrdiff_t>(flag_address), mutex_name + once_mutex_name_fixed_length); - detail::int_to_string(win32::GetCurrentProcessId(), + detail::int_to_string(win32::GetCurrentProcessId(), mutex_name + once_mutex_name_fixed_length + sizeof(void*)*2); } - + inline void* open_once_event(once_char_type* mutex_name,void* flag_address) { if(!*mutex_name) { name_once_mutex(mutex_name,flag_address); } - -#ifdef BOOST_NO_ANSI_APIS + +#ifdef BOOST_NO_ANSI_APIS return ::boost::detail::win32::OpenEventW( #else return ::boost::detail::win32::OpenEventA( #endif - ::boost::detail::win32::synchronize | + ::boost::detail::win32::synchronize | ::boost::detail::win32::event_modify_state, false, mutex_name); @@ -105,7 +126,7 @@ namespace boost { name_once_mutex(mutex_name,flag_address); } -#ifdef BOOST_NO_ANSI_APIS +#ifdef BOOST_NO_ANSI_APIS return ::boost::detail::win32::CreateEventW( #else return ::boost::detail::win32::CreateEventA( @@ -115,7 +136,7 @@ namespace boost mutex_name); } } - + template<typename Function> void call_once(once_flag& flag,Function f) @@ -136,7 +157,9 @@ namespace boost status=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&flag.status,running_value,0); if(!status) { - try +#ifndef BOOST_NO_EXCEPTIONS + try // BOOST_NO_EXCEPTIONS protected +#endif { if(!event_handle) { @@ -153,7 +176,7 @@ namespace boost counted=true; } BOOST_INTERLOCKED_EXCHANGE(&flag.status,function_complete_flag_value); - if(!event_handle && + if(!event_handle && (::boost::detail::interlocked_read_acquire(&flag.count)>1)) { event_handle=detail::create_once_event(mutex_name,&flag); @@ -164,7 +187,8 @@ namespace boost } break; } - catch(...) +#ifndef BOOST_NO_EXCEPTIONS + catch(...) // BOOST_NO_EXCEPTIONS protected { BOOST_INTERLOCKED_EXCHANGE(&flag.status,0); if(!event_handle) @@ -175,8 +199,9 @@ namespace boost { ::boost::detail::win32::SetEvent(event_handle); } - throw; + throw; // BOOST_NO_EXCEPTIONS protected } +#endif } if(!counted) diff --git a/boost/thread/win32/recursive_mutex.hpp b/boost/thread/win32/recursive_mutex.hpp index 7832bf270d..5144e77aa7 100644 --- a/boost/thread/win32/recursive_mutex.hpp +++ b/boost/thread/win32/recursive_mutex.hpp @@ -10,7 +10,6 @@ // http://www.boost.org/LICENSE_1_0.txt) -#include <boost/utility.hpp> #include <boost/thread/win32/basic_recursive_mutex.hpp> #include <boost/thread/exceptions.hpp> #include <boost/thread/locks.hpp> @@ -22,10 +21,8 @@ namespace boost class recursive_mutex: public ::boost::detail::basic_recursive_mutex { - private: - recursive_mutex(recursive_mutex const&); - recursive_mutex& operator=(recursive_mutex const&); public: + BOOST_THREAD_NO_COPYABLE(recursive_mutex) recursive_mutex() { ::boost::detail::basic_recursive_mutex::initialize(); @@ -44,10 +41,8 @@ namespace boost class recursive_timed_mutex: public ::boost::detail::basic_recursive_timed_mutex { - private: - recursive_timed_mutex(recursive_timed_mutex const&); - recursive_timed_mutex& operator=(recursive_timed_mutex const&); public: + BOOST_THREAD_NO_COPYABLE(recursive_timed_mutex) recursive_timed_mutex() { ::boost::detail::basic_recursive_timed_mutex::initialize(); diff --git a/boost/thread/win32/shared_mutex.hpp b/boost/thread/win32/shared_mutex.hpp index aee40399e4..fef2d5badd 100644 --- a/boost/thread/win32/shared_mutex.hpp +++ b/boost/thread/win32/shared_mutex.hpp @@ -2,6 +2,7 @@ #define BOOST_THREAD_WIN32_SHARED_MUTEX_HPP // (C) Copyright 2006-8 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 @@ -12,8 +13,12 @@ #include <boost/thread/win32/thread_primitives.hpp> #include <boost/static_assert.hpp> #include <limits.h> -#include <boost/utility.hpp> #include <boost/thread/thread_time.hpp> +#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/config/abi_prefix.hpp> @@ -22,9 +27,6 @@ namespace boost class shared_mutex { private: - shared_mutex(shared_mutex const&); - shared_mutex& operator=(shared_mutex const&); - private: struct state_data { unsigned shared_count:11, @@ -76,6 +78,7 @@ namespace boost public: + BOOST_THREAD_NO_COPYABLE(shared_mutex) shared_mutex() { semaphores[unlock_sem]=detail::win32::create_anonymous_semaphore(0,LONG_MAX); @@ -218,6 +221,115 @@ namespace boost } } +#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>& t) + { + using namespace chrono; + system_clock::time_point s_now = system_clock::now(); + typename Clock::time_point c_now = Clock::now(); + return try_lock_shared_until(s_now + ceil<system_clock::duration>(t - c_now)); + } + template <class Duration> + bool try_lock_shared_until(const chrono::time_point<chrono::system_clock, Duration>& t) + { + using namespace chrono; + typedef time_point<chrono::system_clock, chrono::system_clock::duration> sys_tmpt; + return try_lock_shared_until(sys_tmpt(chrono::ceil<chrono::system_clock::duration>(t.time_since_epoch()))); + } + bool try_lock_shared_until(const chrono::time_point<chrono::system_clock, chrono::system_clock::duration>& tp) + { + for(;;) + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + if(new_state.exclusive || new_state.exclusive_waiting_blocked) + { + ++new_state.shared_waiting; + if(!new_state.shared_waiting) + { + boost::throw_exception(boost::lock_error()); + } + } + else + { + ++new_state.shared_count; + if(!new_state.shared_count) + { + boost::throw_exception(boost::lock_error()); + } + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + + if(!(old_state.exclusive| old_state.exclusive_waiting_blocked)) + { + return true; + } + + chrono::system_clock::time_point n = chrono::system_clock::now(); + 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())); + } else { + res=detail::win32::timeout; + } + if(res==detail::win32::timeout) + { + for(;;) + { + state_data new_state=old_state; + if(new_state.exclusive || new_state.exclusive_waiting_blocked) + { + if(new_state.shared_waiting) + { + --new_state.shared_waiting; + } + } + else + { + ++new_state.shared_count; + if(!new_state.shared_count) + { + return false; + } + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + + if(!(old_state.exclusive| old_state.exclusive_waiting_blocked)) + { + return true; + } + return false; + } + + BOOST_ASSERT(res==0); + } + } +#endif + void unlock_shared() { state_data old_state=state; @@ -380,6 +492,116 @@ namespace boost } } +#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>& t) + { + using namespace chrono; + system_clock::time_point s_now = system_clock::now(); + typename Clock::time_point c_now = Clock::now(); + return try_lock_until(s_now + ceil<system_clock::duration>(t - c_now)); + } + template <class Duration> + bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t) + { + using namespace chrono; + typedef time_point<chrono::system_clock, chrono::system_clock::duration> sys_tmpt; + return try_lock_until(sys_tmpt(chrono::ceil<chrono::system_clock::duration>(t.time_since_epoch()))); + } + bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::system_clock::duration>& tp) + { + for(;;) + { + state_data old_state=state; + + for(;;) + { + state_data new_state=old_state; + if(new_state.shared_count || new_state.exclusive) + { + ++new_state.exclusive_waiting; + if(!new_state.exclusive_waiting) + { + boost::throw_exception(boost::lock_error()); + } + + new_state.exclusive_waiting_blocked=true; + } + else + { + new_state.exclusive=true; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + + if(!old_state.shared_count && !old_state.exclusive) + { + return true; + } + #ifndef UNDER_CE + const bool wait_all = true; + #else + const bool wait_all = false; + #endif + + chrono::system_clock::time_point n = chrono::system_clock::now(); + 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())); + } else { + wait_res=detail::win32::timeout; + } + if(wait_res==detail::win32::timeout) + { + for(;;) + { + state_data new_state=old_state; + if(new_state.shared_count || new_state.exclusive) + { + if(new_state.exclusive_waiting) + { + if(!--new_state.exclusive_waiting) + { + new_state.exclusive_waiting_blocked=false; + } + } + } + else + { + new_state.exclusive=true; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + if(!old_state.shared_count && !old_state.exclusive) + { + return true; + } + return false; + } + BOOST_ASSERT(wait_res<2); + } + } +#endif + void unlock() { state_data old_state=state; @@ -502,6 +724,8 @@ namespace boost if(last_reader) { release_waiters(old_state); + } else { + release_waiters(old_state); } break; } @@ -561,6 +785,27 @@ namespace boost } release_waiters(old_state); } +// bool try_unlock_upgrade_and_lock() +// { +// 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) +// { +// return false; +// } +//#endif void unlock_and_lock_shared() { @@ -586,7 +831,6 @@ namespace boost } release_waiters(old_state); } - void unlock_upgrade_and_lock_shared() { state_data old_state=state; @@ -612,6 +856,8 @@ namespace boost } }; + typedef shared_mutex upgrade_mutex; + } #include <boost/config/abi_suffix.hpp> diff --git a/boost/thread/win32/thread_data.hpp b/boost/thread/win32/thread_data.hpp index d5303d897d..5af4fd3ed3 100644 --- a/boost/thread/win32/thread_data.hpp +++ b/boost/thread/win32/thread_data.hpp @@ -4,17 +4,58 @@ // 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 #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> - +#ifdef BOOST_THREAD_USES_CHRONO +#include <boost/chrono/system_clocks.hpp> +#endif #include <boost/config/abi_prefix.hpp> namespace boost { + class thread_attributes { + public: + thread_attributes() BOOST_NOEXCEPT { + val_.stack_size = 0; + //val_.lpThreadAttributes=0; + } + ~thread_attributes() { + } + // stack size + void set_stack_size(std::size_t size) BOOST_NOEXCEPT { + val_.stack_size = size; + } + + std::size_t get_stack_size() const BOOST_NOEXCEPT { + return val_.stack_size; + } + + //void set_security(LPSECURITY_ATTRIBUTES lpThreadAttributes) + //{ + // val_.lpThreadAttributes=lpThreadAttributes; + //} + //LPSECURITY_ATTRIBUTES get_security() + //{ + // return val_.lpThreadAttributes; + //} + + struct win_attrs { + std::size_t stack_size; + //LPSECURITY_ATTRIBUTES lpThreadAttributes; + }; + typedef win_attrs native_handle_type; + native_handle_type* native_handle() {return &val_;} + const native_handle_type* native_handle() const {return &val_;} + + private: + win_attrs val_; + }; + namespace detail { struct thread_exit_callback_node; @@ -153,7 +194,7 @@ namespace boost namespace this_thread { - void BOOST_THREAD_DECL yield(); + void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT; bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time); inline void interruptible_wait(uintmax_t milliseconds) @@ -174,6 +215,12 @@ namespace boost { interruptible_wait(abs_time); } +#ifdef BOOST_THREAD_USES_CHRONO + inline void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns) + { + interruptible_wait(chrono::duration_cast<chrono::milliseconds>(ns).count()); + } +#endif } } diff --git a/boost/thread/win32/thread_heap_alloc.hpp b/boost/thread/win32/thread_heap_alloc.hpp index b7d329f31c..843e46b532 100644 --- a/boost/thread/win32/thread_heap_alloc.hpp +++ b/boost/thread/win32/thread_heap_alloc.hpp @@ -75,16 +75,20 @@ namespace boost inline T* heap_new() { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); - try +#ifndef BOOST_NO_EXCEPTIONS + try // BOOST_NO_EXCEPTIONS protected +#endif { T* const data=new (heap_memory) T(); return data; } - catch(...) +#ifndef BOOST_NO_EXCEPTIONS + catch(...) // BOOST_NO_EXCEPTIONS protected { free_raw_heap_memory(heap_memory); - throw; + throw; // BOOST_NO_EXCEPTIONS protected } +#endif } #ifndef BOOST_NO_RVALUE_REFERENCES @@ -92,127 +96,159 @@ namespace boost inline T* heap_new(A1&& a1) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); - try +#ifndef BOOST_NO_EXCEPTIONS + try // BOOST_NO_EXCEPTIONS protected +#endif { T* const data=new (heap_memory) T(static_cast<A1&&>(a1)); return data; } - catch(...) +#ifndef BOOST_NO_EXCEPTIONS + catch(...) // BOOST_NO_EXCEPTIONS protected { free_raw_heap_memory(heap_memory); - throw; + throw; // BOOST_NO_EXCEPTIONS protected } +#endif } 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)); - try +#ifndef BOOST_NO_EXCEPTIONS + try // BOOST_NO_EXCEPTIONS protected +#endif { T* const data=new (heap_memory) T(static_cast<A1&&>(a1),static_cast<A2&&>(a2)); return data; } - catch(...) +#ifndef BOOST_NO_EXCEPTIONS + catch(...) // BOOST_NO_EXCEPTIONS protected { free_raw_heap_memory(heap_memory); - throw; + throw; // BOOST_NO_EXCEPTIONS protected } +#endif } 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)); - try +#ifndef BOOST_NO_EXCEPTIONS + try // BOOST_NO_EXCEPTIONS protected +#endif { T* const data=new (heap_memory) T(static_cast<A1&&>(a1),static_cast<A2&&>(a2), static_cast<A3&&>(a3)); return data; } - catch(...) +#ifndef BOOST_NO_EXCEPTIONS + catch(...) // BOOST_NO_EXCEPTIONS protected { free_raw_heap_memory(heap_memory); - throw; + throw; // BOOST_NO_EXCEPTIONS protected } +#endif } 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)); - try +#ifndef BOOST_NO_EXCEPTIONS + try // BOOST_NO_EXCEPTIONS protected +#endif { 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; } - catch(...) +#ifndef BOOST_NO_EXCEPTIONS + catch(...) // BOOST_NO_EXCEPTIONS protected { free_raw_heap_memory(heap_memory); - throw; + throw; // BOOST_NO_EXCEPTIONS protected } +#endif } #else template<typename T,typename A1> inline T* heap_new_impl(A1 a1) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); - try +#ifndef BOOST_NO_EXCEPTIONS + try // BOOST_NO_EXCEPTIONS protected +#endif { T* const data=new (heap_memory) T(a1); return data; } - catch(...) +#ifndef BOOST_NO_EXCEPTIONS + catch(...) // BOOST_NO_EXCEPTIONS protected { free_raw_heap_memory(heap_memory); - throw; + throw; // BOOST_NO_EXCEPTIONS protected } +#endif } 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)); - try +#ifndef BOOST_NO_EXCEPTIONS + try // BOOST_NO_EXCEPTIONS protected +#endif { T* const data=new (heap_memory) T(a1,a2); return data; } - catch(...) +#ifndef BOOST_NO_EXCEPTIONS + catch(...) // BOOST_NO_EXCEPTIONS protected { free_raw_heap_memory(heap_memory); - throw; + throw; // BOOST_NO_EXCEPTIONS protected } +#endif } 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)); - try +#ifndef BOOST_NO_EXCEPTIONS + try // BOOST_NO_EXCEPTIONS protected +#endif { T* const data=new (heap_memory) T(a1,a2,a3); return data; } - catch(...) +#ifndef BOOST_NO_EXCEPTIONS + catch(...) // BOOST_NO_EXCEPTIONS protected { free_raw_heap_memory(heap_memory); - throw; + throw; // BOOST_NO_EXCEPTIONS protected } +#endif } 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)); - try +#ifndef BOOST_NO_EXCEPTIONS + try // BOOST_NO_EXCEPTIONS protected +#endif { T* const data=new (heap_memory) T(a1,a2,a3,a4); return data; } - catch(...) +#ifndef BOOST_NO_EXCEPTIONS + catch(...) // BOOST_NO_EXCEPTIONS protected { free_raw_heap_memory(heap_memory); - throw; + throw; // BOOST_NO_EXCEPTIONS protected } +#endif } diff --git a/boost/thread/win32/thread_primitives.hpp b/boost/thread/win32/thread_primitives.hpp index 0166f37d36..294e42ee9b 100644 --- a/boost/thread/win32/thread_primitives.hpp +++ b/boost/thread/win32/thread_primitives.hpp @@ -341,22 +341,42 @@ namespace boost { inline bool interlocked_bit_test_and_set(long* x,long bit) { +#if 0 __asm { mov eax,bit; mov edx,x; lock bts [edx],eax; setc al; }; +#else + bool ret; + __asm { + mov eax,bit; mov edx,x; lock bts [edx],eax; setc al; mov ret, al + }; + return ret; + +#endif } inline bool interlocked_bit_test_and_reset(long* x,long bit) { +#if 0 __asm { mov eax,bit; mov edx,x; lock btr [edx],eax; setc al; }; +#else + + + bool ret; + __asm { + mov eax,bit; mov edx,x; lock btr [edx],eax; setc al; mov ret, al + }; + return ret; + +#endif } } diff --git a/boost/thread/xtime.hpp b/boost/thread/xtime.hpp index 7cc6272d6a..1ca996fa0c 100644 --- a/boost/thread/xtime.hpp +++ b/boost/thread/xtime.hpp @@ -2,7 +2,7 @@ // William E. Kempf // Copyright (C) 2007-8 Anthony Williams // -// Distributed under the Boost Software License, Version 1.0. (See accompanying +// 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_XTIME_WEK070601_HPP @@ -20,7 +20,7 @@ namespace boost { enum xtime_clock_types { - TIME_UTC=1 + TIME_UTC_=1 // TIME_TAI, // TIME_MONOTONIC, // TIME_PROCESS, @@ -53,14 +53,14 @@ struct xtime boost::posix_time::microseconds((nsec+500)/1000); #endif } - + }; inline xtime get_xtime(boost::system_time const& abs_time) { xtime res; boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0); - + res.sec=static_cast<xtime::xtime_sec_t>(time_since_epoch.total_seconds()); res.nsec=static_cast<xtime::xtime_nsec_t>(time_since_epoch.fractional_seconds()*(1000000000/time_since_epoch.ticks_per_second())); return res; @@ -68,7 +68,7 @@ inline xtime get_xtime(boost::system_time const& abs_time) inline int xtime_get(struct xtime* xtp, int clock_type) { - if (clock_type == TIME_UTC) + if (clock_type == TIME_UTC_) { *xtp=get_xtime(get_system_time()); return clock_type; @@ -81,7 +81,7 @@ inline int xtime_cmp(const xtime& xt1, const xtime& xt2) { if (xt1.sec == xt2.sec) return (int)(xt1.nsec - xt2.nsec); - else + else return (xt1.sec > xt2.sec) ? 1 : -1; } |