diff options
author | Anas Nashif <anas.nashif@intel.com> | 2012-10-30 12:57:26 -0700 |
---|---|---|
committer | Anas Nashif <anas.nashif@intel.com> | 2012-10-30 12:57:26 -0700 |
commit | 1a78a62555be32868418fe52f8e330c9d0f95d5a (patch) | |
tree | d3765a80e7d3b9640ec2e930743630cd6b9fce2b /boost/thread | |
download | boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.gz boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.bz2 boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.zip |
Imported Upstream version 1.49.0upstream/1.49.0
Diffstat (limited to 'boost/thread')
45 files changed, 9466 insertions, 0 deletions
diff --git a/boost/thread/barrier.hpp b/boost/thread/barrier.hpp new file mode 100644 index 0000000000..4ca30cb4df --- /dev/null +++ b/boost/thread/barrier.hpp @@ -0,0 +1,64 @@ +// Copyright (C) 2002-2003 +// David Moore, William E. Kempf +// Copyright (C) 2007-8 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_BARRIER_JDM030602_HPP +#define BOOST_BARRIER_JDM030602_HPP + +#include <boost/thread/detail/config.hpp> +#include <boost/throw_exception.hpp> + +#include <boost/thread/mutex.hpp> +#include <boost/thread/condition_variable.hpp> +#include <string> +#include <stdexcept> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + + class barrier + { + public: + barrier(unsigned int count) + : m_threshold(count), m_count(count), m_generation(0) + { + if (count == 0) + boost::throw_exception(std::invalid_argument("count cannot be zero.")); + } + + bool wait() + { + boost::mutex::scoped_lock lock(m_mutex); + unsigned int gen = m_generation; + + if (--m_count == 0) + { + m_generation++; + m_count = m_threshold; + m_cond.notify_all(); + return true; + } + + while (gen == m_generation) + m_cond.wait(lock); + return false; + } + + private: + mutex m_mutex; + condition_variable m_cond; + unsigned int m_threshold; + unsigned int m_count; + unsigned int m_generation; + }; + +} // namespace boost + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/condition.hpp b/boost/thread/condition.hpp new file mode 100644 index 0000000000..35b879fe03 --- /dev/null +++ b/boost/thread/condition.hpp @@ -0,0 +1,16 @@ +#ifndef BOOST_THREAD_CONDITION_HPP +#define BOOST_THREAD_CONDITION_HPP +// (C) Copyright 2007 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/thread/condition_variable.hpp> + +namespace boost +{ + typedef condition_variable_any condition; +} + +#endif diff --git a/boost/thread/condition_variable.hpp b/boost/thread/condition_variable.hpp new file mode 100644 index 0000000000..8f8e9f2ed6 --- /dev/null +++ b/boost/thread/condition_variable.hpp @@ -0,0 +1,21 @@ +#ifndef BOOST_THREAD_CONDITION_VARIABLE_HPP +#define BOOST_THREAD_CONDITION_VARIABLE_HPP + +// condition_variable.hpp +// +// (C) Copyright 2007 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/thread/detail/platform.hpp> +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#include <boost/thread/win32/condition_variable.hpp> +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +#include <boost/thread/pthread/condition_variable.hpp> +#else +#error "Boost threads unavailable on this platform" +#endif + +#endif diff --git a/boost/thread/detail/config.hpp b/boost/thread/detail/config.hpp new file mode 100644 index 0000000000..b59550669c --- /dev/null +++ b/boost/thread/detail/config.hpp @@ -0,0 +1,115 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// +// 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_CONFIG_WEK01032003_HPP +#define BOOST_THREAD_CONFIG_WEK01032003_HPP + +#include <boost/config.hpp> +#include <boost/detail/workaround.hpp> + + +#if !defined BOOST_THREAD_VERSION +#define BOOST_THREAD_VERSION 1 +#else +#if BOOST_THREAD_VERSION!=1 && BOOST_THREAD_VERSION!=2 +#error "BOOST_THREAD_VERSION must be 1 or 2" +#endif +#endif + +#if BOOST_WORKAROUND(__BORLANDC__, < 0x600) +# pragma warn -8008 // Condition always true/false +# pragma warn -8080 // Identifier declared but never used +# pragma warn -8057 // Parameter never used +# pragma warn -8066 // Unreachable code +#endif + +#include "platform.hpp" + +// provided for backwards compatibility, since this +// macro was used for several releases by mistake. +#if defined(BOOST_THREAD_DYN_DLL) +# define BOOST_THREAD_DYN_LINK +#endif + +// compatibility with the rest of Boost's auto-linking code: +#if defined(BOOST_THREAD_DYN_LINK) || defined(BOOST_ALL_DYN_LINK) +# undef BOOST_THREAD_USE_LIB +# define BOOST_THREAD_USE_DLL +#endif + +#if defined(BOOST_THREAD_BUILD_DLL) //Build dll +#elif defined(BOOST_THREAD_BUILD_LIB) //Build lib +#elif defined(BOOST_THREAD_USE_DLL) //Use dll +#elif defined(BOOST_THREAD_USE_LIB) //Use lib +#else //Use default +# if defined(BOOST_THREAD_PLATFORM_WIN32) +# if defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN) + //For compilers supporting auto-tss cleanup + //with Boost.Threads lib, use Boost.Threads lib +# define BOOST_THREAD_USE_LIB +# else + //For compilers not yet supporting auto-tss cleanup + //with Boost.Threads lib, use Boost.Threads dll +# define BOOST_THREAD_USE_DLL +# endif +# else +# define BOOST_THREAD_USE_LIB +# endif +#endif + +#if defined(BOOST_HAS_DECLSPEC) +# if defined(BOOST_THREAD_BUILD_DLL) //Build dll +# define BOOST_THREAD_DECL BOOST_SYMBOL_EXPORT +//# define BOOST_THREAD_DECL __declspec(dllexport) + +# elif defined(BOOST_THREAD_USE_DLL) //Use dll +# define BOOST_THREAD_DECL BOOST_SYMBOL_IMPORT +//# define BOOST_THREAD_DECL __declspec(dllimport) +# else +# define BOOST_THREAD_DECL +# endif +#elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# define BOOST_THREAD_DECL BOOST_SYMBOL_VISIBLE + +#else +# define BOOST_THREAD_DECL +#endif // BOOST_HAS_DECLSPEC + +// +// Automatically link to the correct build variant where possible. +// +#if !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_THREAD_NO_LIB) && !defined(BOOST_THREAD_BUILD_DLL) && !defined(BOOST_THREAD_BUILD_LIB) +// +// Tell the autolink to link dynamically, this will get undef'ed by auto_link.hpp +// once it's done with it: +// +#if defined(BOOST_THREAD_USE_DLL) +# define BOOST_DYN_LINK +#endif +// +// Set the name of our library, this will get undef'ed by auto_link.hpp +// once it's done with it: +// +#if defined(BOOST_THREAD_LIB_NAME) +# define BOOST_LIB_NAME BOOST_THREAD_LIB_NAME +#else +# define BOOST_LIB_NAME boost_thread +#endif +// +// If we're importing code from a dll, then tell auto_link.hpp about it: +// +// And include the header that does the work: +// +#include <boost/config/auto_link.hpp> +#endif // auto-linking disabled + +#endif // BOOST_THREAD_CONFIG_WEK1032003_HPP + +// Change Log: +// 22 Jan 05 Roland Schwarz (speedsnail) +// Usage of BOOST_HAS_DECLSPEC macro. +// Default again is static lib usage. +// BOOST_DYN_LINK only defined when autolink included. diff --git a/boost/thread/detail/force_cast.hpp b/boost/thread/detail/force_cast.hpp new file mode 100644 index 0000000000..d5d15adc1a --- /dev/null +++ b/boost/thread/detail/force_cast.hpp @@ -0,0 +1,39 @@ +// Copyright (C) 2001-2003 +// Mac Murrett +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org for most recent version including documentation. + +#ifndef BOOST_FORCE_CAST_MJM012402_HPP +#define BOOST_FORCE_CAST_MJM012402_HPP + +#include <boost/thread/detail/config.hpp> + +namespace boost { +namespace detail { +namespace thread { + +// force_cast will convert anything to anything. + +// general case +template<class Return_Type, class Argument_Type> +inline Return_Type &force_cast(Argument_Type &rSrc) +{ + return(*reinterpret_cast<Return_Type *>(&rSrc)); +} + +// specialization for const +template<class Return_Type, class Argument_Type> +inline const Return_Type &force_cast(const Argument_Type &rSrc) +{ + return(*reinterpret_cast<const Return_Type *>(&rSrc)); +} + +} // namespace thread +} // namespace detail +} // namespace boost + +#endif // BOOST_FORCE_CAST_MJM012402_HPP diff --git a/boost/thread/detail/move.hpp b/boost/thread/detail/move.hpp new file mode 100644 index 0000000000..665a0b5978 --- /dev/null +++ b/boost/thread/detail/move.hpp @@ -0,0 +1,66 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2007-8 Anthony Williams + +#ifndef BOOST_THREAD_MOVE_HPP +#define BOOST_THREAD_MOVE_HPP + +#include <boost/thread/detail/config.hpp> +#ifndef BOOST_NO_SFINAE +#include <boost/utility/enable_if.hpp> +#include <boost/type_traits/is_convertible.hpp> +#include <boost/type_traits/remove_reference.hpp> +#endif + +#include <boost/move/move.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + + namespace detail + { + template<typename T> + struct thread_move_t + { + T& t; + explicit thread_move_t(T& t_): + t(t_) + {} + + T& operator*() const + { + return t; + } + + T* operator->() const + { + return &t; + } + private: + void operator=(thread_move_t&); + }; + } + +#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) + { + return boost::detail::thread_move_t<T>(t); + } +#endif + + template<typename T> + boost::detail::thread_move_t<T> move(boost::detail::thread_move_t<T> t) + { + return t; + } + + +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/detail/platform.hpp b/boost/thread/detail/platform.hpp new file mode 100644 index 0000000000..58601b04b2 --- /dev/null +++ b/boost/thread/detail/platform.hpp @@ -0,0 +1,71 @@ +// Copyright 2006 Roland Schwarz. +// (C) Copyright 2007 Anthony Williams +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// This work is a reimplementation along the design and ideas +// of William E. Kempf. + +#ifndef BOOST_THREAD_RS06040501_HPP +#define BOOST_THREAD_RS06040501_HPP + +// fetch compiler and platform configuration +#include <boost/config.hpp> + +// insist on threading support being available: +#include <boost/config/requires_threads.hpp> + +// choose platform +#if defined(linux) || defined(__linux) || defined(__linux__) +# define BOOST_THREAD_LINUX +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) +# define BOOST_THREAD_BSD +#elif defined(sun) || defined(__sun) +# define BOOST_THREAD_SOLARIS +#elif defined(__sgi) +# define BOOST_THREAD_IRIX +#elif defined(__hpux) +# define BOOST_THREAD_HPUX +#elif defined(__CYGWIN__) +# define BOOST_THREAD_CYGWIN +#elif (defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) && !defined(BOOST_DISABLE_WIN32) +# define BOOST_THREAD_WIN32 +#elif defined(__BEOS__) +# define BOOST_THREAD_BEOS +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) +# define BOOST_THREAD_MACOS +#elif defined(__IBMCPP__) || defined(_AIX) +# define BOOST_THREAD_AIX +#elif defined(__amigaos__) +# define BOOST_THREAD_AMIGAOS +#elif defined(__QNXNTO__) +# define BOOST_THREAD_QNXNTO +#elif defined(unix) || defined(__unix) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE) +# if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_THREAD_POSIX) +# define BOOST_THREAD_POSIX +# endif +#endif + +// For every supported platform add a new entry into the dispatch table below. +// BOOST_THREAD_POSIX is tested first, so on platforms where posix and native +// threading is available, the user may choose, by defining BOOST_THREAD_POSIX +// in her source. If a platform is known to support pthreads and no native +// port of boost_thread is available just specify "pthread" in the +// 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 +# if defined(BOOST_THREAD_WIN32) +# define BOOST_THREAD_PLATFORM_WIN32 +# elif defined(BOOST_HAS_PTHREADS) +# define BOOST_THREAD_PLATFORM_PTHREAD +# else +# error "Sorry, no boost threads are available for this platform." +# endif +#endif + +#endif // BOOST_THREAD_RS06040501_HPP diff --git a/boost/thread/detail/singleton.hpp b/boost/thread/detail/singleton.hpp new file mode 100644 index 0000000000..a20a42908d --- /dev/null +++ b/boost/thread/detail/singleton.hpp @@ -0,0 +1,59 @@ +// Copyright (C) 2001-2003 +// Mac Murrett +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org for most recent version including documentation. + +#ifndef BOOST_SINGLETON_MJM012402_HPP +#define BOOST_SINGLETON_MJM012402_HPP + +#include <boost/thread/detail/config.hpp> + +namespace boost { +namespace detail { +namespace thread { + +// class singleton has the same goal as all singletons: create one instance of +// a class on demand, then dish it out as requested. + +template <class T> +class singleton : private T +{ +private: + singleton(); + ~singleton(); + +public: + static T &instance(); +}; + + +template <class T> +inline singleton<T>::singleton() +{ + /* no-op */ +} + +template <class T> +inline singleton<T>::~singleton() +{ + /* no-op */ +} + +template <class T> +/*static*/ T &singleton<T>::instance() +{ + // function-local static to force this to work correctly at static + // initialization time. + static singleton<T> s_oT; + return(s_oT); +} + +} // namespace thread +} // namespace detail +} // namespace boost + +#endif // BOOST_SINGLETON_MJM012402_HPP diff --git a/boost/thread/detail/thread.hpp b/boost/thread/detail/thread.hpp new file mode 100644 index 0000000000..7ac342bfc6 --- /dev/null +++ b/boost/thread/detail/thread.hpp @@ -0,0 +1,548 @@ +#ifndef BOOST_THREAD_THREAD_COMMON_HPP +#define BOOST_THREAD_THREAD_COMMON_HPP +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2007-10 Anthony Williams + +#include <boost/thread/exceptions.hpp> +#ifndef BOOST_NO_IOSTREAM +#include <ostream> +#endif +#include <boost/thread/detail/move.hpp> +#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> +#include <boost/ref.hpp> +#include <boost/cstdint.hpp> +#include <boost/bind.hpp> +#include <stdlib.h> +#include <memory> +#include <boost/utility/enable_if.hpp> +#include <boost/type_traits/remove_reference.hpp> +#include <boost/io/ios_state.hpp> + +#include <boost/config/abi_prefix.hpp> + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4251) +#endif + +namespace boost +{ + namespace detail + { + template<typename F> + class thread_data: + public detail::thread_data_base + { + public: +#ifndef BOOST_NO_RVALUE_REFERENCES + thread_data(F&& f_): + f(static_cast<F&&>(f_)) + {} + thread_data(F& f_): + f(f_) + {} +#else + thread_data(F f_): + f(f_) + {} + thread_data(detail::thread_move_t<F> f_): + f(f_) + {} +#endif + void run() + { + f(); + } + private: + F f; + + void operator=(thread_data&); + thread_data(thread_data&); + }; + + template<typename F> + class thread_data<boost::reference_wrapper<F> >: + public detail::thread_data_base + { + private: + F& f; + + void operator=(thread_data&); + thread_data(thread_data&); + public: + thread_data(boost::reference_wrapper<F> f_): + f(f_) + {} + + void run() + { + f(); + } + }; + + template<typename F> + class thread_data<const boost::reference_wrapper<F> >: + public detail::thread_data_base + { + private: + F& f; + void operator=(thread_data&); + thread_data(thread_data&); + public: + thread_data(const boost::reference_wrapper<F> f_): + f(f_) + {} + + void run() + { + f(); + } + }; + } + + class BOOST_THREAD_DECL thread + { + private: + thread(thread&); + thread& operator=(thread&); + + void release_handle(); + + detail::thread_data_ptr thread_info; + + void start_thread(); + + explicit thread(detail::thread_data_ptr data); + + detail::thread_data_ptr get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const; + +#ifndef BOOST_NO_RVALUE_REFERENCES + template<typename F> + static inline detail::thread_data_ptr make_thread_info(F&& f) + { + return detail::thread_data_ptr(detail::heap_new<detail::thread_data<typename boost::remove_reference<F>::type> >(static_cast<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))); + } +#else + template<typename F> + static inline detail::thread_data_ptr make_thread_info(F f) + { + 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) + { + return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f)); + } + +#endif + struct dummy; + public: +#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_info.swap(other.thread_info); + } + + thread& operator=(thread&& other) + { + thread_info=other.thread_info; + other.thread_info.reset(); + return *this; + } + + thread&& move() + { + return static_cast<thread&&>(*this); + } + +#else +#ifdef BOOST_NO_SFINAE + template <class F> + explicit thread(F f): + thread_info(make_thread_info(f)) + { + start_thread(); + } +#else + 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(f)) + { + start_thread(); + } +#endif + + template <class F> + explicit thread(detail::thread_move_t<F> f): + thread_info(make_thread_info(f)) + { + start_thread(); + } + + thread(detail::thread_move_t<thread> x) + { + thread_info=x->thread_info; + x->thread_info.reset(); + } + +#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(); + } + + detail::thread_move_t<thread> move() + { + detail::thread_move_t<thread> x(*this); + return x; + } + +#endif + + template <class F,class A1> + thread(F f,A1 a1): + thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1))) + { + start_thread(); + } + template <class F,class A1,class A2> + thread(F f,A1 a1,A2 a2): + thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2))) + { + start_thread(); + } + + template <class F,class A1,class A2,class A3> + thread(F f,A1 a1,A2 a2,A3 a3): + thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3))) + { + start_thread(); + } + + template <class F,class A1,class A2,class A3,class A4> + thread(F f,A1 a1,A2 a2,A3 a3,A4 a4): + thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4))) + { + start_thread(); + } + + template <class F,class A1,class A2,class A3,class A4,class A5> + thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5): + thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5))) + { + start_thread(); + } + + template <class F,class A1,class A2,class A3,class A4,class A5,class A6> + thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6): + thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6))) + { + start_thread(); + } + + template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7> + thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7): + thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7))) + { + start_thread(); + } + + template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7,class A8> + thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8): + thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7,a8))) + { + start_thread(); + } + + template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7,class A8,class A9> + thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8,A9 a9): + thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7,a8,a9))) + { + start_thread(); + } + + void swap(thread& x) + { + thread_info.swap(x.thread_info); + } + + class BOOST_SYMBOL_VISIBLE id; + id get_id() const; + + + bool joinable() const; + void join(); + bool timed_join(const system_time& wait_until); + + 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(); + + typedef detail::thread_data_base::native_handle_type native_handle_type; + native_handle_type native_handle(); + + // backwards compatibility + bool operator==(const thread& other) const; + bool operator!=(const thread& other) const; + + static inline void yield() + { + this_thread::yield(); + } + + static inline void sleep(const system_time& xt) + { + this_thread::sleep(xt); + } + + // extensions + void interrupt(); + bool interruption_requested() const; + }; + + inline void swap(thread& lhs,thread& rhs) + { + return lhs.swap(rhs); + } + +#ifndef BOOST_NO_RVALUE_REFERENCES + inline thread&& move(thread& t) + { + 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 + + namespace this_thread + { + thread::id BOOST_THREAD_DECL get_id(); + + void BOOST_THREAD_DECL interruption_point(); + bool BOOST_THREAD_DECL interruption_enabled(); + bool BOOST_THREAD_DECL interruption_requested(); + + inline BOOST_SYMBOL_VISIBLE void sleep(xtime const& abs_time) + { + sleep(system_time(abs_time)); + } + } + + class BOOST_SYMBOL_VISIBLE thread::id + { + private: + detail::thread_data_ptr thread_data; + + id(detail::thread_data_ptr thread_data_): + thread_data(thread_data_) + {} + friend class thread; + friend id BOOST_THREAD_DECL this_thread::get_id(); + public: + id(): + thread_data() + {} + + id(const id& other): + thread_data(other.thread_data) + {} + + bool operator==(const id& y) const + { + return thread_data==y.thread_data; + } + + bool operator!=(const id& y) const + { + return thread_data!=y.thread_data; + } + + bool operator<(const id& y) const + { + return thread_data<y.thread_data; + } + + bool operator>(const id& y) const + { + return y.thread_data<thread_data; + } + + bool operator<=(const id& y) const + { + return !(y.thread_data<thread_data); + } + + bool operator>=(const id& y) const + { + return !(thread_data<y.thread_data); + } + +#ifndef BOOST_NO_IOSTREAM +#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS + template<class charT, class traits> + friend BOOST_SYMBOL_VISIBLE + std::basic_ostream<charT, traits>& + operator<<(std::basic_ostream<charT, traits>& os, const id& x) + { + if(x.thread_data) + { + io::ios_flags_saver ifs( os ); + return os<< std::hex << x.thread_data; + } + else + { + return os<<"{Not-any-thread}"; + } + } +#else + template<class charT, class traits> + BOOST_SYMBOL_VISIBLE + std::basic_ostream<charT, traits>& + print(std::basic_ostream<charT, traits>& os) const + { + if(thread_data) + { + return os<<thread_data; + } + else + { + return os<<"{Not-any-thread}"; + } + } + +#endif +#endif + }; + +#if !defined(BOOST_NO_IOSTREAM) && defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) + template<class charT, class traits> + BOOST_SYMBOL_VISIBLE + std::basic_ostream<charT, traits>& + operator<<(std::basic_ostream<charT, traits>& os, const thread::id& x) + { + return x.print(os); + } +#endif + + inline bool thread::operator==(const thread& other) const + { + return get_id()==other.get_id(); + } + + inline bool thread::operator!=(const thread& other) const + { + return get_id()!=other.get_id(); + } + + namespace detail + { + struct thread_exit_function_base + { + virtual ~thread_exit_function_base() + {} + virtual void operator()()=0; + }; + + template<typename F> + struct thread_exit_function: + thread_exit_function_base + { + F f; + + thread_exit_function(F f_): + f(f_) + {} + + void operator()() + { + f(); + } + }; + + 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> + void at_thread_exit(F f) + { + detail::thread_exit_function_base* const thread_exit_func=detail::heap_new<detail::thread_exit_function<F> >(f); + detail::add_thread_exit_function(thread_exit_func); + } + } +} + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/detail/thread_group.hpp b/boost/thread/detail/thread_group.hpp new file mode 100644 index 0000000000..f1ccdf84e2 --- /dev/null +++ b/boost/thread/detail/thread_group.hpp @@ -0,0 +1,108 @@ +#ifndef BOOST_THREAD_DETAIL_THREAD_GROUP_HPP +#define BOOST_THREAD_DETAIL_THREAD_GROUP_HPP +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2007-9 Anthony Williams + +#include <list> +#include <boost/thread/shared_mutex.hpp> +#include <boost/thread/mutex.hpp> + +#include <boost/config/abi_prefix.hpp> + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4251) +#endif + +namespace boost +{ + class thread_group + { + private: + thread_group(thread_group const&); + thread_group& operator=(thread_group const&); + public: + thread_group() {} + ~thread_group() + { + for(std::list<thread*>::iterator it=threads.begin(),end=threads.end(); + it!=end; + ++it) + { + delete *it; + } + } + + template<typename F> + thread* create_thread(F threadfunc) + { + boost::lock_guard<shared_mutex> guard(m); + std::auto_ptr<thread> new_thread(new thread(threadfunc)); + threads.push_back(new_thread.get()); + return new_thread.release(); + } + + void add_thread(thread* thrd) + { + if(thrd) + { + boost::lock_guard<shared_mutex> guard(m); + threads.push_back(thrd); + } + } + + void remove_thread(thread* thrd) + { + boost::lock_guard<shared_mutex> guard(m); + std::list<thread*>::iterator const it=std::find(threads.begin(),threads.end(),thrd); + if(it!=threads.end()) + { + threads.erase(it); + } + } + + void join_all() + { + boost::shared_lock<shared_mutex> guard(m); + + for(std::list<thread*>::iterator it=threads.begin(),end=threads.end(); + it!=end; + ++it) + { + (*it)->join(); + } + } + + void interrupt_all() + { + boost::shared_lock<shared_mutex> guard(m); + + for(std::list<thread*>::iterator it=threads.begin(),end=threads.end(); + it!=end; + ++it) + { + (*it)->interrupt(); + } + } + + size_t size() const + { + boost::shared_lock<shared_mutex> guard(m); + return threads.size(); + } + + private: + std::list<thread*> threads; + mutable shared_mutex m; + }; +} + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/detail/thread_heap_alloc.hpp b/boost/thread/detail/thread_heap_alloc.hpp new file mode 100644 index 0000000000..2f9bfd5c0b --- /dev/null +++ b/boost/thread/detail/thread_heap_alloc.hpp @@ -0,0 +1,23 @@ +#ifndef BOOST_THREAD_THREAD_HEAP_ALLOC_HPP +#define BOOST_THREAD_THREAD_HEAP_ALLOC_HPP + +// thread_heap_alloc.hpp +// +// (C) Copyright 2008 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/thread/detail/platform.hpp> + +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#include <boost/thread/win32/thread_heap_alloc.hpp> +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +#include <boost/thread/pthread/thread_heap_alloc.hpp> +#else +#error "Boost threads unavailable on this platform" +#endif + + +#endif diff --git a/boost/thread/detail/thread_interruption.hpp b/boost/thread/detail/thread_interruption.hpp new file mode 100644 index 0000000000..60c0e65b8c --- /dev/null +++ b/boost/thread/detail/thread_interruption.hpp @@ -0,0 +1,35 @@ +#ifndef BOOST_THREAD_DETAIL_THREAD_INTERRUPTION_HPP +#define BOOST_THREAD_DETAIL_THREAD_INTERRUPTION_HPP +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2007-9 Anthony Williams + +namespace boost +{ + namespace this_thread + { + 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; + public: + disable_interruption(); + ~disable_interruption(); + }; + + 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(); + }; + } +} + +#endif diff --git a/boost/thread/detail/tss_hooks.hpp b/boost/thread/detail/tss_hooks.hpp new file mode 100644 index 0000000000..b2ceece3dd --- /dev/null +++ b/boost/thread/detail/tss_hooks.hpp @@ -0,0 +1,65 @@ +// (C) Copyright Michael Glassford 2004. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(BOOST_TLS_HOOKS_HPP) +#define BOOST_TLS_HOOKS_HPP + +#include <boost/thread/detail/config.hpp> + +#include <boost/config/abi_prefix.hpp> + +#if defined(BOOST_HAS_WINTHREADS) + +namespace boost +{ + BOOST_THREAD_DECL void __cdecl on_process_enter(void); + //Function to be called when the exe or dll + //that uses Boost.Threads first starts + //or is first loaded. + //Should be called only before the first call to + //on_thread_enter(). + //Called automatically by Boost.Threads when + //a method for doing so has been discovered. + //May be omitted; may be called multiple times. + + BOOST_THREAD_DECL void __cdecl on_process_exit(void); + //Function to be called when the exe or dll + //that uses Boost.Threads first starts + //or is first loaded. + //Should be called only after the last call to + //on_exit_thread(). + //Called automatically by Boost.Threads when + //a method for doing so has been discovered. + //Must not be omitted; may be called multiple times. + + BOOST_THREAD_DECL void __cdecl on_thread_enter(void); + //Function to be called just after a thread starts + //in an exe or dll that uses Boost.Threads. + //Must be called in the context of the thread + //that is starting. + //Called automatically by Boost.Threads when + //a method for doing so has been discovered. + //May be omitted; may be called multiple times. + + BOOST_THREAD_DECL void __cdecl on_thread_exit(void); + //Function to be called just be fore a thread ends + //in an exe or dll that uses Boost.Threads. + //Must be called in the context of the thread + //that is ending. + //Called automatically by Boost.Threads when + //a method for doing so has been discovered. + //Must not be omitted; may be called multiple times. + + void tss_cleanup_implemented(); + //Dummy function used both to detect whether tss cleanup + //cleanup has been implemented and to force + //it to be linked into the Boost.Threads library. +} + +#endif //defined(BOOST_HAS_WINTHREADS) + +#include <boost/config/abi_suffix.hpp> + +#endif //!defined(BOOST_TLS_HOOKS_HPP) diff --git a/boost/thread/exceptions.hpp b/boost/thread/exceptions.hpp new file mode 100644 index 0000000000..06ce04e0d1 --- /dev/null +++ b/boost/thread/exceptions.hpp @@ -0,0 +1,182 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// Copyright (C) 2007-9 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_THREAD_EXCEPTIONS_PDM070801_H +#define BOOST_THREAD_EXCEPTIONS_PDM070801_H + +#include <boost/thread/detail/config.hpp> + +// pdm: Sorry, but this class is used all over the place & I end up +// with recursive headers if I don't separate it +// wek: Not sure why recursive headers would cause compilation problems +// given the include guards, but regardless it makes sense to +// seperate this out any way. + +#include <string> +#include <stdexcept> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + + class BOOST_SYMBOL_VISIBLE thread_interrupted + {}; + + class BOOST_SYMBOL_VISIBLE thread_exception: + public std::exception + { + protected: + thread_exception(): + m_sys_err(0) + {} + + thread_exception(int sys_err_code): + m_sys_err(sys_err_code) + {} + + + public: + ~thread_exception() throw() + {} + + + int native_error() const + { + return m_sys_err; + } + + + private: + int m_sys_err; + }; + + class BOOST_SYMBOL_VISIBLE condition_error: + public std::exception + { + public: + const char* what() const throw() + { + return "Condition error"; + } + }; + + + class BOOST_SYMBOL_VISIBLE lock_error: + public thread_exception + { + public: + lock_error() + {} + + lock_error(int sys_err_code): + thread_exception(sys_err_code) + {} + + ~lock_error() throw() + {} + + + virtual const char* what() const throw() + { + return "boost::lock_error"; + } + }; + + class BOOST_SYMBOL_VISIBLE thread_resource_error: + public thread_exception + { + public: + thread_resource_error() + {} + + thread_resource_error(int sys_err_code): + thread_exception(sys_err_code) + {} + + ~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 + { + public: + unsupported_thread_option() + {} + + unsupported_thread_option(int sys_err_code): + thread_exception(sys_err_code) + {} + + ~unsupported_thread_option() throw() + {} + + + virtual const char* what() const throw() + { + return "boost::unsupported_thread_option"; + } + + }; + + class BOOST_SYMBOL_VISIBLE invalid_thread_argument: + public thread_exception + { + public: + 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() + { + return "boost::invalid_thread_argument"; + } + + }; + + class BOOST_SYMBOL_VISIBLE thread_permission_error: + public thread_exception + { + public: + thread_permission_error() + {} + + thread_permission_error(int sys_err_code): + thread_exception(sys_err_code) + {} + + ~thread_permission_error() throw() + {} + + + virtual const char* what() const throw() + { + return "boost::thread_permission_error"; + } + + }; + +} // namespace boost + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/future.hpp b/boost/thread/future.hpp new file mode 100644 index 0000000000..bd87158338 --- /dev/null +++ b/boost/thread/future.hpp @@ -0,0 +1,1443 @@ +// (C) Copyright 2008-10 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_THREAD_FUTURE_HPP +#define BOOST_THREAD_FUTURE_HPP +#include <stdexcept> +#include <boost/thread/detail/move.hpp> +#include <boost/thread/thread_time.hpp> +#include <boost/thread/mutex.hpp> +#include <boost/thread/condition_variable.hpp> +#include <boost/exception_ptr.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/scoped_ptr.hpp> +#include <boost/type_traits/is_fundamental.hpp> +#include <boost/type_traits/is_convertible.hpp> +#include <boost/mpl/if.hpp> +#include <boost/config.hpp> +#include <boost/throw_exception.hpp> +#include <algorithm> +#include <boost/function.hpp> +#include <boost/bind.hpp> +#include <boost/ref.hpp> +#include <boost/scoped_array.hpp> +#include <boost/utility/enable_if.hpp> +#include <list> +#include <boost/next_prior.hpp> +#include <vector> + +namespace boost +{ + class future_uninitialized: + public std::logic_error + { + public: + future_uninitialized(): + std::logic_error("Future Uninitialized") + {} + }; + class broken_promise: + public std::logic_error + { + public: + broken_promise(): + std::logic_error("Broken promise") + {} + }; + class future_already_retrieved: + public std::logic_error + { + public: + future_already_retrieved(): + std::logic_error("Future already retrieved") + {} + }; + class promise_already_satisfied: + public std::logic_error + { + public: + promise_already_satisfied(): + std::logic_error("Promise already satisfied") + {} + }; + + class task_already_started: + public std::logic_error + { + public: + task_already_started(): + std::logic_error("Task already started") + {} + }; + + class task_moved: + public std::logic_error + { + public: + task_moved(): + std::logic_error("Task moved") + {} + }; + + namespace future_state + { + enum state { uninitialized, waiting, ready, moved }; + } + + namespace detail + { + struct future_object_base + { + boost::exception_ptr exception; + bool done; + boost::mutex mutex; + boost::condition_variable waiters; + typedef std::list<boost::condition_variable_any*> waiter_list; + waiter_list external_waiters; + boost::function<void()> callback; + + future_object_base(): + done(false) + {} + virtual ~future_object_base() + {} + + waiter_list::iterator register_external_waiter(boost::condition_variable_any& cv) + { + boost::unique_lock<boost::mutex> lock(mutex); + do_callback(lock); + return external_waiters.insert(external_waiters.end(),&cv); + } + + void remove_external_waiter(waiter_list::iterator it) + { + boost::lock_guard<boost::mutex> lock(mutex); + external_waiters.erase(it); + } + + void mark_finished_internal() + { + done=true; + waiters.notify_all(); + for(waiter_list::const_iterator it=external_waiters.begin(), + end=external_waiters.end();it!=end;++it) + { + (*it)->notify_all(); + } + } + + struct relocker + { + boost::unique_lock<boost::mutex>& lock; + + relocker(boost::unique_lock<boost::mutex>& lock_): + lock(lock_) + { + lock.unlock(); + } + ~relocker() + { + lock.lock(); + } + private: + relocker& operator=(relocker const&); + }; + + void do_callback(boost::unique_lock<boost::mutex>& lock) + { + if(callback && !done) + { + boost::function<void()> local_callback=callback; + relocker relock(lock); + local_callback(); + } + } + + + void wait(bool rethrow=true) + { + boost::unique_lock<boost::mutex> lock(mutex); + do_callback(lock); + while(!done) + { + waiters.wait(lock); + } + if(rethrow && exception) + { + boost::rethrow_exception(exception); + } + } + + bool timed_wait_until(boost::system_time const& target_time) + { + boost::unique_lock<boost::mutex> lock(mutex); + do_callback(lock); + while(!done) + { + bool const success=waiters.timed_wait(lock,target_time); + if(!success && !done) + { + return false; + } + } + return true; + } + + void mark_exceptional_finish_internal(boost::exception_ptr const& e) + { + exception=e; + mark_finished_internal(); + } + void mark_exceptional_finish() + { + boost::lock_guard<boost::mutex> lock(mutex); + mark_exceptional_finish_internal(boost::current_exception()); + } + + bool has_value() + { + boost::lock_guard<boost::mutex> lock(mutex); + return done && !exception; + } + bool has_exception() + { + boost::lock_guard<boost::mutex> lock(mutex); + return done && exception; + } + + template<typename F,typename U> + void set_wait_callback(F f,U* u) + { + callback=boost::bind(f,boost::ref(*u)); + } + + private: + future_object_base(future_object_base const&); + future_object_base& operator=(future_object_base const&); + }; + + template<typename T> + struct future_traits + { + typedef boost::scoped_ptr<T> storage_type; +#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; +#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; +#endif + + static void init(storage_type& storage,source_reference_type t) + { + storage.reset(new T(t)); + } + + static void init(storage_type& storage,rvalue_source_type t) + { + storage.reset(new T(static_cast<rvalue_source_type>(t))); + } + + static void cleanup(storage_type& storage) + { + storage.reset(); + } + }; + + template<typename T> + struct future_traits<T&> + { + typedef T* storage_type; + typedef T& source_reference_type; + struct rvalue_source_type + {}; + typedef T& move_dest_type; + + static void init(storage_type& storage,T& t) + { + storage=&t; + } + + static void cleanup(storage_type& storage) + { + storage=0; + } + }; + + template<> + struct future_traits<void> + { + typedef bool storage_type; + typedef void move_dest_type; + + static void init(storage_type& storage) + { + storage=true; + } + + static void cleanup(storage_type& storage) + { + storage=false; + } + + }; + + template<typename T> + struct future_object: + detail::future_object_base + { + typedef typename future_traits<T>::storage_type storage_type; + typedef typename future_traits<T>::source_reference_type source_reference_type; + typedef typename future_traits<T>::rvalue_source_type rvalue_source_type; + typedef typename future_traits<T>::move_dest_type move_dest_type; + + storage_type result; + + future_object(): + result(0) + {} + + void mark_finished_with_result_internal(source_reference_type result_) + { + 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_)); + mark_finished_internal(); + } + + void mark_finished_with_result(source_reference_type result_) + { + 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_); + } + + move_dest_type get() + { + wait(); + return static_cast<move_dest_type>(*result); + } + + future_state::state get_state() + { + boost::lock_guard<boost::mutex> guard(mutex); + if(!done) + { + return future_state::waiting; + } + else + { + return future_state::ready; + } + } + + private: + future_object(future_object const&); + future_object& operator=(future_object const&); + }; + + template<> + struct future_object<void>: + detail::future_object_base + { + typedef void move_dest_type; + + future_object() + {} + + void mark_finished_with_result_internal() + { + mark_finished_internal(); + } + + void mark_finished_with_result() + { + boost::lock_guard<boost::mutex> lock(mutex); + mark_finished_with_result_internal(); + } + + void get() + { + wait(); + } + + future_state::state get_state() + { + boost::lock_guard<boost::mutex> guard(mutex); + if(!done) + { + return future_state::waiting; + } + else + { + return future_state::ready; + } + } + + private: + future_object(future_object const&); + future_object& operator=(future_object const&); + }; + + class future_waiter + { + struct registered_waiter; + typedef std::vector<registered_waiter>::size_type count_type; + + struct registered_waiter + { + 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_, + detail::future_object_base::waiter_list::iterator wait_iterator_, + count_type index_): + future(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; + + 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) + { +#if defined __DECCXX || defined __SUNPRO_CC + locks[i]=boost::unique_lock<boost::mutex>(futures[i].future->mutex).move(); +#else + locks[i]=boost::unique_lock<boost::mutex>(futures[i].future->mutex); +#endif + } + } + + void lock() + { + boost::lock(locks.get(),locks.get()+count); + } + + void unlock() + { + for(count_type_portable i=0;i<count;++i) + { + locks[i].unlock(); + } + } + }; + + boost::condition_variable_any cv; + std::vector<registered_waiter> futures; + count_type future_count; + + public: + future_waiter(): + future_count(0) + {} + + template<typename F> + void add(F& f) + { + if(f.future) + { + futures.push_back(registered_waiter(f.future,f.future->register_external_waiter(cv),future_count)); + } + ++future_count; + } + + count_type wait() + { + all_futures_lock lk(futures); + for(;;) + { + for(count_type i=0;i<futures.size();++i) + { + if(futures[i].future->done) + { + return futures[i].index; + } + } + cv.wait(lk); + } + } + + ~future_waiter() + { + for(count_type i=0;i<futures.size();++i) + { + futures[i].future->remove_external_waiter(futures[i].wait_iterator); + } + } + + }; + + } + + template <typename R> + class unique_future; + + template <typename R> + class shared_future; + + template<typename T> + struct is_future_type + { + BOOST_STATIC_CONSTANT(bool, value=false); + }; + + template<typename T> + struct is_future_type<unique_future<T> > + { + BOOST_STATIC_CONSTANT(bool, value=true); + }; + + template<typename T> + struct is_future_type<shared_future<T> > + { + BOOST_STATIC_CONSTANT(bool, value=true); + }; + + template<typename Iterator> + typename boost::disable_if<is_future_type<Iterator>,void>::type wait_for_all(Iterator begin,Iterator end) + { + for(Iterator current=begin;current!=end;++current) + { + current->wait(); + } + } + + template<typename F1,typename F2> + typename boost::enable_if<is_future_type<F1>,void>::type wait_for_all(F1& f1,F2& f2) + { + f1.wait(); + f2.wait(); + } + + template<typename F1,typename F2,typename F3> + void wait_for_all(F1& f1,F2& f2,F3& f3) + { + f1.wait(); + f2.wait(); + f3.wait(); + } + + template<typename F1,typename F2,typename F3,typename F4> + void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4) + { + f1.wait(); + f2.wait(); + f3.wait(); + f4.wait(); + } + + template<typename F1,typename F2,typename F3,typename F4,typename F5> + void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5) + { + f1.wait(); + f2.wait(); + f3.wait(); + f4.wait(); + f5.wait(); + } + + template<typename Iterator> + typename boost::disable_if<is_future_type<Iterator>,Iterator>::type wait_for_any(Iterator begin,Iterator end) + { + if(begin==end) + return end; + + detail::future_waiter waiter; + for(Iterator current=begin;current!=end;++current) + { + waiter.add(*current); + } + return boost::next(begin,waiter.wait()); + } + + template<typename F1,typename F2> + typename boost::enable_if<is_future_type<F1>,unsigned>::type wait_for_any(F1& f1,F2& f2) + { + detail::future_waiter waiter; + waiter.add(f1); + waiter.add(f2); + return waiter.wait(); + } + + template<typename F1,typename F2,typename F3> + unsigned wait_for_any(F1& f1,F2& f2,F3& f3) + { + detail::future_waiter waiter; + waiter.add(f1); + waiter.add(f2); + waiter.add(f3); + return waiter.wait(); + } + + template<typename F1,typename F2,typename F3,typename F4> + unsigned wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4) + { + detail::future_waiter waiter; + waiter.add(f1); + waiter.add(f2); + waiter.add(f3); + waiter.add(f4); + return waiter.wait(); + } + + template<typename F1,typename F2,typename F3,typename F4,typename F5> + unsigned wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5) + { + detail::future_waiter waiter; + waiter.add(f1); + waiter.add(f2); + waiter.add(f3); + waiter.add(f4); + waiter.add(f5); + return waiter.wait(); + } + + template <typename R> + class promise; + + template <typename R> + class packaged_task; + + template <typename R> + class unique_future + { + unique_future(unique_future & rhs);// = delete; + unique_future& operator=(unique_future& rhs);// = delete; + + typedef boost::shared_ptr<detail::future_object<R> > future_ptr; + + future_ptr future; + + friend class shared_future<R>; + friend class promise<R>; + friend class packaged_task<R>; + friend class detail::future_waiter; + + typedef typename detail::future_traits<R>::move_dest_type move_dest_type; + + unique_future(future_ptr future_): + future(future_) + {} + + public: + typedef future_state::state state; + + unique_future() + {} + + ~unique_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) + { + other->future.reset(); + } + + unique_future& operator=(boost::detail::thread_move_t<unique_future> other) + { + future=other->future; + other->future.reset(); + return *this; + } + + operator boost::detail::thread_move_t<unique_future>() + { + return boost::detail::thread_move_t<unique_future>(*this); + } +#endif + + void swap(unique_future& other) + { + future.swap(other.future); + } + + // retrieving the value + move_dest_type get() + { + if(!future) + { + boost::throw_exception(future_uninitialized()); + } + + return future->get(); + } + + // functions to check state, and wait for ready + state get_state() const + { + if(!future) + { + return future_state::uninitialized; + } + return future->get_state(); + } + + + bool is_ready() const + { + return get_state()==future_state::ready; + } + + bool has_exception() const + { + return future && future->has_exception(); + } + + bool has_value() const + { + return future && future->has_value(); + } + + void wait() const + { + if(!future) + { + boost::throw_exception(future_uninitialized()); + } + future->wait(false); + } + + template<typename Duration> + bool timed_wait(Duration const& rel_time) const + { + return timed_wait_until(boost::get_system_time()+rel_time); + } + + bool timed_wait_until(boost::system_time const& abs_time) const + { + if(!future) + { + boost::throw_exception(future_uninitialized()); + } + return future->timed_wait_until(abs_time); + } + + }; + +#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 + + 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); + + friend class detail::future_waiter; + friend class promise<R>; + friend class packaged_task<R>; + + shared_future(future_ptr future_): + future(future_) + {} + + public: + shared_future(shared_future const& other): + future(other.future) + {} + + typedef future_state::state state; + + shared_future() + {} + + ~shared_future() + {} + + shared_future& operator=(shared_future const& other) + { + 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) + { + future.swap(other.future); + other.future.reset(); + return *this; + } +#else + shared_future(boost::detail::thread_move_t<shared_future> other): + future(other->future) + { + other->future.reset(); + } +// shared_future(const unique_future<R> &) = delete; + shared_future(boost::detail::thread_move_t<unique_future<R> > other): + future(other->future) + { + other->future.reset(); + } + shared_future& operator=(boost::detail::thread_move_t<shared_future> other) + { + future.swap(other->future); + other->future.reset(); + return *this; + } + shared_future& operator=(boost::detail::thread_move_t<unique_future<R> > other) + { + future.swap(other->future); + 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) + { + future.swap(other.future); + } + + // retrieving the value + //typename detail::future_object<R>::move_dest_type get() + R get() + { + if(!future) + { + boost::throw_exception(future_uninitialized()); + } + + return future->get(); + } + + // functions to check state, and wait for ready + state get_state() const + { + if(!future) + { + return future_state::uninitialized; + } + return future->get_state(); + } + + + bool is_ready() const + { + return get_state()==future_state::ready; + } + + bool has_exception() const + { + return future && future->has_exception(); + } + + bool has_value() const + { + return future && future->has_value(); + } + + void wait() const + { + if(!future) + { + boost::throw_exception(future_uninitialized()); + } + future->wait(false); + } + + template<typename Duration> + bool timed_wait(Duration const& rel_time) const + { + return timed_wait_until(boost::get_system_time()+rel_time); + } + + bool timed_wait_until(boost::system_time const& abs_time) const + { + if(!future) + { + boost::throw_exception(future_uninitialized()); + } + return future->timed_wait_until(abs_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> + {}; +#endif + + template <typename R> + class promise + { + typedef boost::shared_ptr<detail::future_object<R> > future_ptr; + + future_ptr future; + bool future_obtained; + + promise(promise & rhs);// = delete; + promise & operator=(promise & rhs);// = delete; + + void lazy_init() + { + if(!atomic_load(&future)) + { + future_ptr blank; + atomic_compare_exchange(&future,&blank,future_ptr(new detail::future_object<R>)); + } + } + + public: +// template <class Allocator> explicit promise(Allocator a); + + promise(): + future(),future_obtained(false) + {} + + ~promise() + { + if(future) + { + boost::lock_guard<boost::mutex> lock(future->mutex); + + if(!future->done) + { + 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) + { + 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); + std::swap(future_obtained,other.future_obtained); + } + + // Result retrieval + unique_future<R> get_future() + { + lazy_init(); + if(future_obtained) + { + boost::throw_exception(future_already_retrieved()); + } + future_obtained=true; + return unique_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::throw_exception(promise_already_satisfied()); + } + 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::throw_exception(promise_already_satisfied()); + } + 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::throw_exception(promise_already_satisfied()); + } + future->mark_exceptional_finish_internal(p); + } + + template<typename F> + void set_wait_callback(F f) + { + lazy_init(); + future->set_wait_callback(f,this); + } + + }; + + template <> + class promise<void> + { + typedef boost::shared_ptr<detail::future_object<void> > future_ptr; + + future_ptr future; + bool future_obtained; + + promise(promise & rhs);// = delete; + promise & operator=(promise & rhs);// = delete; + + void lazy_init() + { + if(!atomic_load(&future)) + { + future_ptr blank; + atomic_compare_exchange(&future,&blank,future_ptr(new detail::future_object<void>)); + } + } + public: +// template <class Allocator> explicit promise(Allocator a); + + promise(): + future(),future_obtained(false) + {} + + ~promise() + { + if(future) + { + boost::lock_guard<boost::mutex> lock(future->mutex); + + if(!future->done) + { + 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) + { + 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); + std::swap(future_obtained,other.future_obtained); + } + + // Result retrieval + unique_future<void> get_future() + { + lazy_init(); + + if(future_obtained) + { + boost::throw_exception(future_already_retrieved()); + } + future_obtained=true; + return unique_future<void>(future); + } + + void set_value() + { + lazy_init(); + boost::lock_guard<boost::mutex> lock(future->mutex); + if(future->done) + { + boost::throw_exception(promise_already_satisfied()); + } + 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::throw_exception(promise_already_satisfied()); + } + future->mark_exceptional_finish_internal(p); + } + + template<typename F> + void set_wait_callback(F f) + { + lazy_init(); + 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> + {}; +#endif + + namespace detail + { + template<typename R> + struct task_base: + detail::future_object<R> + { + bool started; + + task_base(): + started(false) + {} + + void run() + { + { + boost::lock_guard<boost::mutex> lk(this->mutex); + if(started) + { + boost::throw_exception(task_already_started()); + } + started=true; + } + do_run(); + } + + void owner_destroyed() + { + boost::lock_guard<boost::mutex> lk(this->mutex); + if(!started) + { + started=true; + this->mark_exceptional_finish_internal(boost::copy_exception(boost::broken_promise())); + } + } + + + virtual void do_run()=0; + }; + + + template<typename R,typename F> + struct task_object: + task_base<R> + { + F f; + task_object(F const& f_): + f(f_) + {} +#ifndef BOOST_NO_RVALUE_REFERENCES + task_object(F&& f_): + f(f_) + {} +#else + task_object(boost::detail::thread_move_t<F> f_): + f(f_) + {} +#endif + + void do_run() + { + try + { + this->mark_finished_with_result(f()); + } + catch(...) + { + this->mark_exceptional_finish(); + } + } + }; + + template<typename F> + struct task_object<void,F>: + task_base<void> + { + F f; + task_object(F const& f_): + f(f_) + {} +#ifndef BOOST_NO_RVALUE_REFERENCES + task_object(F&& f_): + f(f_) + {} +#else + task_object(boost::detail::thread_move_t<F> f_): + f(f_) + {} +#endif + + void do_run() + { + try + { + f(); + this->mark_finished_with_result(); + } + catch(...) + { + this->mark_exceptional_finish(); + } + } + }; + + } + + + template<typename R> + class packaged_task + { + boost::shared_ptr<detail::task_base<R> > task; + bool future_obtained; + + packaged_task(packaged_task&);// = delete; + packaged_task& operator=(packaged_task&);// = delete; + + public: + 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) + {} +#else + template <class F> + explicit packaged_task(boost::detail::thread_move_t<F> f): + task(new detail::task_object<R,F>(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); + + + ~packaged_task() + { + if(task) + { + task->owner_destroyed(); + } + } + + // 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 temp(static_cast<packaged_task&&>(other)); + swap(temp); + return *this; + } +#else + packaged_task(boost::detail::thread_move_t<packaged_task> other): + future_obtained(other->future_obtained) + { + task.swap(other->task); + other->future_obtained=false; + } + packaged_task& operator=(boost::detail::thread_move_t<packaged_task> other) + { + packaged_task temp(other); + swap(temp); + return *this; + } + operator boost::detail::thread_move_t<packaged_task>() + { + return boost::detail::thread_move_t<packaged_task>(*this); + } +#endif + + void swap(packaged_task& other) + { + task.swap(other.task); + std::swap(future_obtained,other.future_obtained); + } + + // result retrieval + unique_future<R> get_future() + { + if(!task) + { + boost::throw_exception(task_moved()); + } + else if(!future_obtained) + { + future_obtained=true; + return unique_future<R>(task); + } + else + { + boost::throw_exception(future_already_retrieved()); + } + } + + + // execution + void operator()() + { + if(!task) + { + boost::throw_exception(task_moved()); + } + task->run(); + } + + template<typename F> + void set_wait_callback(F f) + { + task->set_wait_callback(f,this); + } + + }; + +#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> + {}; +#endif + +} + + +#endif diff --git a/boost/thread/locks.hpp b/boost/thread/locks.hpp new file mode 100644 index 0000000000..26012707e7 --- /dev/null +++ b/boost/thread/locks.hpp @@ -0,0 +1,1626 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2007 Anthony Williams +#ifndef BOOST_THREAD_LOCKS_HPP +#define BOOST_THREAD_LOCKS_HPP +#include <boost/thread/detail/config.hpp> +#include <boost/thread/exceptions.hpp> +#include <boost/thread/detail/move.hpp> +#include <algorithm> +#include <iterator> +#include <boost/thread/thread_time.hpp> +#include <boost/detail/workaround.hpp> +#include <boost/type_traits/is_class.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + struct xtime; + +#if defined(BOOST_NO_SFINAE) || \ + BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600)) || \ + BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) +#define BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES +#endif + +#ifndef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES + namespace detail + { +#define BOOST_DEFINE_HAS_MEMBER_CALLED(member_name) \ + template<typename T, bool=boost::is_class<T>::value> \ + struct has_member_called_##member_name \ + { \ + BOOST_STATIC_CONSTANT(bool, value=false); \ + }; \ + \ + template<typename T> \ + struct has_member_called_##member_name<T,true> \ + { \ + typedef char true_type; \ + struct false_type \ + { \ + true_type dummy[2]; \ + }; \ + \ + struct fallback { int member_name; }; \ + struct derived: \ + T, fallback \ + { \ + derived(); \ + }; \ + \ + template<int fallback::*> struct tester; \ + \ + template<typename U> \ + static false_type has_member(tester<&U::member_name>*); \ + template<typename U> \ + static true_type has_member(...); \ + \ + BOOST_STATIC_CONSTANT( \ + bool, value=sizeof(has_member<derived>(0))==sizeof(true_type)); \ + } + + BOOST_DEFINE_HAS_MEMBER_CALLED(lock); + BOOST_DEFINE_HAS_MEMBER_CALLED(unlock); + BOOST_DEFINE_HAS_MEMBER_CALLED(try_lock); + + template<typename T,bool=has_member_called_lock<T>::value > + struct has_member_lock + { + BOOST_STATIC_CONSTANT(bool, value=false); + }; + + template<typename T> + struct has_member_lock<T,true> + { + typedef char true_type; + struct false_type + { + true_type dummy[2]; + }; + + template<typename U,typename V> + static true_type has_member(V (U::*)()); + template<typename U> + static false_type has_member(U); + + BOOST_STATIC_CONSTANT( + bool,value=sizeof(has_member_lock<T>::has_member(&T::lock))==sizeof(true_type)); + }; + + template<typename T,bool=has_member_called_unlock<T>::value > + struct has_member_unlock + { + BOOST_STATIC_CONSTANT(bool, value=false); + }; + + template<typename T> + struct has_member_unlock<T,true> + { + typedef char true_type; + struct false_type + { + true_type dummy[2]; + }; + + template<typename U,typename V> + static true_type has_member(V (U::*)()); + template<typename U> + static false_type has_member(U); + + BOOST_STATIC_CONSTANT( + bool,value=sizeof(has_member_unlock<T>::has_member(&T::unlock))==sizeof(true_type)); + }; + + template<typename T,bool=has_member_called_try_lock<T>::value > + struct has_member_try_lock + { + BOOST_STATIC_CONSTANT(bool, value=false); + }; + + template<typename T> + struct has_member_try_lock<T,true> + { + typedef char true_type; + struct false_type + { + true_type dummy[2]; + }; + + template<typename U> + static true_type has_member(bool (U::*)()); + template<typename U> + static false_type has_member(U); + + BOOST_STATIC_CONSTANT( + bool,value=sizeof(has_member_try_lock<T>::has_member(&T::try_lock))==sizeof(true_type)); + }; + + } + + + template<typename T> + struct is_mutex_type + { + BOOST_STATIC_CONSTANT(bool, value = detail::has_member_lock<T>::value && + detail::has_member_unlock<T>::value && + detail::has_member_try_lock<T>::value); + + }; +#else + template<typename T> + struct is_mutex_type + { + BOOST_STATIC_CONSTANT(bool, value = false); + }; +#endif + + struct defer_lock_t + {}; + struct try_to_lock_t + {}; + struct adopt_lock_t + {}; + + const defer_lock_t defer_lock={}; + const try_to_lock_t try_to_lock={}; + const adopt_lock_t adopt_lock={}; + + template<typename Mutex> + class shared_lock; + + template<typename Mutex> + class upgrade_lock; + + template<typename Mutex> + class unique_lock; + + namespace detail + { + template<typename Mutex> + class try_lock_wrapper; + } + +#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES + template<typename T> + struct is_mutex_type<unique_lock<T> > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + template<typename T> + struct is_mutex_type<shared_lock<T> > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + template<typename T> + struct is_mutex_type<upgrade_lock<T> > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + template<typename T> + struct is_mutex_type<detail::try_lock_wrapper<T> > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + class mutex; + class timed_mutex; + class recursive_mutex; + class recursive_timed_mutex; + class shared_mutex; + + template<> + struct is_mutex_type<mutex> + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_mutex_type<timed_mutex> + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_mutex_type<recursive_mutex> + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_mutex_type<recursive_timed_mutex> + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_mutex_type<shared_mutex> + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + +#endif + + template<typename Mutex> + class lock_guard + { + private: + Mutex& m; + + explicit lock_guard(lock_guard&); + lock_guard& operator=(lock_guard&); + public: + explicit lock_guard(Mutex& m_): + m(m_) + { + m.lock(); + } + lock_guard(Mutex& m_,adopt_lock_t): + m(m_) + {} + ~lock_guard() + { + m.unlock(); + } + }; + + + template<typename Mutex> + class unique_lock + { + private: + Mutex* m; + bool is_locked; + unique_lock(unique_lock&); + explicit unique_lock(upgrade_lock<Mutex>&); + unique_lock& operator=(unique_lock&); + unique_lock& operator=(upgrade_lock<Mutex>& other); + public: +#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) + unique_lock(const volatile unique_lock&); +#endif + unique_lock(): + m(0),is_locked(false) + {} + + explicit unique_lock(Mutex& m_): + m(&m_),is_locked(false) + { + lock(); + } + unique_lock(Mutex& m_,adopt_lock_t): + m(&m_),is_locked(true) + {} + unique_lock(Mutex& m_,defer_lock_t): + m(&m_),is_locked(false) + {} + unique_lock(Mutex& m_,try_to_lock_t): + m(&m_),is_locked(false) + { + try_lock(); + } + template<typename TimeDuration> + unique_lock(Mutex& m_,TimeDuration const& target_time): + m(&m_),is_locked(false) + { + timed_lock(target_time); + } + unique_lock(Mutex& m_,system_time const& target_time): + m(&m_),is_locked(false) + { + timed_lock(target_time); + } +#ifndef BOOST_NO_RVALUE_REFERENCES + unique_lock(unique_lock&& other): + m(other.m),is_locked(other.is_locked) + { + other.is_locked=false; + other.m=0; + } + explicit unique_lock(upgrade_lock<Mutex>&& other); + + unique_lock<Mutex>&& move() + { + return static_cast<unique_lock<Mutex>&&>(*this); + } + + + unique_lock& operator=(unique_lock&& other) + { + unique_lock temp(other.move()); + swap(temp); + return *this; + } + + unique_lock& operator=(upgrade_lock<Mutex>&& other) + { + unique_lock temp(other.move()); + 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) + { + other->is_locked=false; + other->m=0; + } + unique_lock(detail::thread_move_t<upgrade_lock<Mutex> > other); + + operator detail::thread_move_t<unique_lock<Mutex> >() + { + return move(); + } + + detail::thread_move_t<unique_lock<Mutex> > move() + { + return detail::thread_move_t<unique_lock<Mutex> >(*this); + } + +#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) + unique_lock& operator=(unique_lock<Mutex> other) + { + swap(other); + return *this; + } +#else + unique_lock& operator=(detail::thread_move_t<unique_lock<Mutex> > other) + { + unique_lock temp(other); + swap(temp); + return *this; + } +#endif + + unique_lock& operator=(detail::thread_move_t<upgrade_lock<Mutex> > other) + { + unique_lock temp(other); + swap(temp); + return *this; + } + void swap(detail::thread_move_t<unique_lock<Mutex> > other) + { + std::swap(m,other->m); + std::swap(is_locked,other->is_locked); + } +#endif + void swap(unique_lock& other) + { + std::swap(m,other.m); + std::swap(is_locked,other.is_locked); + } + + ~unique_lock() + { + if(owns_lock()) + { + m->unlock(); + } + } + void lock() + { + if(owns_lock()) + { + boost::throw_exception(boost::lock_error()); + } + m->lock(); + is_locked=true; + } + bool try_lock() + { + if(owns_lock()) + { + boost::throw_exception(boost::lock_error()); + } + is_locked=m->try_lock(); + return is_locked; + } + template<typename TimeDuration> + bool timed_lock(TimeDuration const& relative_time) + { + is_locked=m->timed_lock(relative_time); + return is_locked; + } + + bool timed_lock(::boost::system_time const& absolute_time) + { + is_locked=m->timed_lock(absolute_time); + return is_locked; + } + bool timed_lock(::boost::xtime const& absolute_time) + { + is_locked=m->timed_lock(absolute_time); + return is_locked; + } + void unlock() + { + if(!owns_lock()) + { + boost::throw_exception(boost::lock_error()); + } + m->unlock(); + is_locked=false; + } + + typedef void (unique_lock::*bool_type)(); + operator bool_type() const + { + return is_locked?&unique_lock::lock:0; + } + bool operator!() const + { + return !owns_lock(); + } + bool owns_lock() const + { + return is_locked; + } + + Mutex* mutex() const + { + return m; + } + + Mutex* release() + { + Mutex* const res=m; + m=0; + is_locked=false; + return res; + } + + friend class shared_lock<Mutex>; + friend class upgrade_lock<Mutex>; + }; + +#ifndef BOOST_NO_RVALUE_REFERENCES + template<typename Mutex> + void swap(unique_lock<Mutex>&& lhs,unique_lock<Mutex>&& rhs) + { + 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 + + template<typename Mutex> + class shared_lock + { + protected: + Mutex* m; + bool is_locked; + private: + explicit shared_lock(shared_lock&); + shared_lock& operator=(shared_lock&); + public: + shared_lock(): + m(0),is_locked(false) + {} + + explicit shared_lock(Mutex& m_): + m(&m_),is_locked(false) + { + lock(); + } + shared_lock(Mutex& m_,adopt_lock_t): + m(&m_),is_locked(true) + {} + shared_lock(Mutex& m_,defer_lock_t): + m(&m_),is_locked(false) + {} + shared_lock(Mutex& m_,try_to_lock_t): + m(&m_),is_locked(false) + { + try_lock(); + } + shared_lock(Mutex& m_,system_time const& target_time): + m(&m_),is_locked(false) + { + timed_lock(target_time); + } +#ifndef BOOST_NO_RVALUE_REFERENCES + +#else + shared_lock(detail::thread_move_t<shared_lock<Mutex> > other): + m(other->m),is_locked(other->is_locked) + { + other->is_locked=false; + other->m=0; + } + + shared_lock(detail::thread_move_t<unique_lock<Mutex> > other): + m(other->m),is_locked(other->is_locked) + { + if(is_locked) + { + m->unlock_and_lock_shared(); + } + other->is_locked=false; + other->m=0; + } + + shared_lock(detail::thread_move_t<upgrade_lock<Mutex> > other): + m(other->m),is_locked(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(); + } + + 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 temp(other); + swap(temp); + return *this; + } + + shared_lock& operator=(detail::thread_move_t<unique_lock<Mutex> > other) + { + shared_lock temp(other); + swap(temp); + return *this; + } + + shared_lock& operator=(detail::thread_move_t<upgrade_lock<Mutex> > other) + { + shared_lock temp(other); + swap(temp); + return *this; + } +#endif + +#ifndef BOOST_NO_RVALUE_REFERENCES + void swap(shared_lock&& other) + { + 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) + { + std::swap(m,other.m); + std::swap(is_locked,other.is_locked); + } + + Mutex* mutex() const + { + return m; + } + + ~shared_lock() + { + if(owns_lock()) + { + m->unlock_shared(); + } + } + void lock() + { + if(owns_lock()) + { + boost::throw_exception(boost::lock_error()); + } + m->lock_shared(); + is_locked=true; + } + bool try_lock() + { + if(owns_lock()) + { + boost::throw_exception(boost::lock_error()); + } + is_locked=m->try_lock_shared(); + return is_locked; + } + bool timed_lock(boost::system_time const& target_time) + { + if(owns_lock()) + { + boost::throw_exception(boost::lock_error()); + } + is_locked=m->timed_lock_shared(target_time); + return is_locked; + } + template<typename Duration> + bool timed_lock(Duration const& target_time) + { + if(owns_lock()) + { + boost::throw_exception(boost::lock_error()); + } + is_locked=m->timed_lock_shared(target_time); + return is_locked; + } + void unlock() + { + if(!owns_lock()) + { + boost::throw_exception(boost::lock_error()); + } + m->unlock_shared(); + is_locked=false; + } + + typedef void (shared_lock<Mutex>::*bool_type)(); + operator bool_type() const + { + return is_locked?&shared_lock::lock:0; + } + bool operator!() const + { + return !owns_lock(); + } + bool owns_lock() const + { + 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 + + +#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) + { + lhs.swap(rhs); + } +#endif + + template<typename Mutex> + class upgrade_lock + { + protected: + Mutex* m; + bool is_locked; + private: + explicit upgrade_lock(upgrade_lock&); + upgrade_lock& operator=(upgrade_lock&); + public: + upgrade_lock(): + m(0),is_locked(false) + {} + + explicit upgrade_lock(Mutex& m_): + m(&m_),is_locked(false) + { + lock(); + } + upgrade_lock(Mutex& m_,adopt_lock_t): + m(&m_),is_locked(true) + {} + upgrade_lock(Mutex& m_,defer_lock_t): + m(&m_),is_locked(false) + {} + upgrade_lock(Mutex& m_,try_to_lock_t): + m(&m_),is_locked(false) + { + try_lock(); + } +#ifndef BOOST_NO_RVALUE_REFERENCES + upgrade_lock(upgrade_lock<Mutex>&& other): + m(other.m),is_locked(other.is_locked) + { + other.is_locked=false; + other.m=0; + } + + upgrade_lock(unique_lock<Mutex>&& other): + m(other.m),is_locked(other.is_locked) + { + if(is_locked) + { + m->unlock_and_lock_upgrade(); + } + other.is_locked=false; + other.m=0; + } + + upgrade_lock& operator=(upgrade_lock<Mutex>&& other) + { + upgrade_lock temp(static_cast<upgrade_lock<Mutex>&&>(other)); + swap(temp); + return *this; + } + + upgrade_lock& operator=(unique_lock<Mutex>&& other) + { + upgrade_lock temp(static_cast<unique_lock<Mutex>&&>(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; + } + + upgrade_lock(detail::thread_move_t<unique_lock<Mutex> > other): + m(other->m),is_locked(other->is_locked) + { + if(is_locked) + { + m->unlock_and_lock_upgrade(); + } + other->is_locked=false; + other->m=0; + } + + operator detail::thread_move_t<upgrade_lock<Mutex> >() + { + return move(); + } + + detail::thread_move_t<upgrade_lock<Mutex> > move() + { + return detail::thread_move_t<upgrade_lock<Mutex> >(*this); + } + + + upgrade_lock& operator=(detail::thread_move_t<upgrade_lock<Mutex> > other) + { + upgrade_lock temp(other); + swap(temp); + return *this; + } + + upgrade_lock& operator=(detail::thread_move_t<unique_lock<Mutex> > other) + { + upgrade_lock temp(other); + swap(temp); + return *this; + } +#endif + + void swap(upgrade_lock& other) + { + std::swap(m,other.m); + std::swap(is_locked,other.is_locked); + } + + ~upgrade_lock() + { + if(owns_lock()) + { + m->unlock_upgrade(); + } + } + void lock() + { + if(owns_lock()) + { + boost::throw_exception(boost::lock_error()); + } + m->lock_upgrade(); + is_locked=true; + } + bool try_lock() + { + if(owns_lock()) + { + boost::throw_exception(boost::lock_error()); + } + is_locked=m->try_lock_upgrade(); + return is_locked; + } + void unlock() + { + if(!owns_lock()) + { + boost::throw_exception(boost::lock_error()); + } + m->unlock_upgrade(); + is_locked=false; + } + + typedef void (upgrade_lock::*bool_type)(); + operator bool_type() const + { + return is_locked?&upgrade_lock::lock:0; + } + bool operator!() const + { + return !owns_lock(); + } + bool owns_lock() const + { + return is_locked; + } + friend class shared_lock<Mutex>; + 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) + { + other.is_locked=false; + if(is_locked) + { + m->unlock_upgrade_and_lock(); + } + } +#else + template<typename Mutex> + unique_lock<Mutex>::unique_lock(detail::thread_move_t<upgrade_lock<Mutex> > other): + m(other->m),is_locked(other->is_locked) + { + other->is_locked=false; + if(is_locked) + { + m->unlock_upgrade_and_lock(); + } + } +#endif + template <class Mutex> + class upgrade_to_unique_lock + { + private: + 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: + explicit upgrade_to_unique_lock(upgrade_lock<Mutex>& m_): + source(&m_),exclusive(move(*source)) + {} + ~upgrade_to_unique_lock() + { + if(source) + { + *source=move(exclusive); + } + } + +#ifndef BOOST_NO_RVALUE_REFERENCES + upgrade_to_unique_lock(upgrade_to_unique_lock<Mutex>&& other): + source(other.source),exclusive(move(other.exclusive)) + { + other.source=0; + } + + upgrade_to_unique_lock& operator=(upgrade_to_unique_lock<Mutex>&& other) + { + 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) + { + std::swap(source,other.source); + exclusive.swap(other.exclusive); + } + typedef void (upgrade_to_unique_lock::*bool_type)(upgrade_to_unique_lock&); + operator bool_type() const + { + return exclusive.owns_lock()?&upgrade_to_unique_lock::swap:0; + } + bool operator!() const + { + return !owns_lock(); + } + bool owns_lock() const + { + 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 + + namespace detail + { + template<typename Mutex> + class try_lock_wrapper: + private unique_lock<Mutex> + { + typedef unique_lock<Mutex> base; + public: + try_lock_wrapper() + {} + + explicit try_lock_wrapper(Mutex& m): + base(m,try_to_lock) + {} + + try_lock_wrapper(Mutex& m_,adopt_lock_t): + base(m_,adopt_lock) + {} + try_lock_wrapper(Mutex& m_,defer_lock_t): + base(m_,defer_lock) + {} + try_lock_wrapper(Mutex& m_,try_to_lock_t): + base(m_,try_to_lock) + {} +#ifndef BOOST_NO_RVALUE_REFERENCES + try_lock_wrapper(try_lock_wrapper&& other): + base(other.move()) + {} + + 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; + } + + 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)) + {} + + 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) + { + 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); + } + void lock() + { + base::lock(); + } + bool try_lock() + { + return base::try_lock(); + } + void unlock() + { + base::unlock(); + } + bool owns_lock() const + { + return base::owns_lock(); + } + Mutex* mutex() const + { + return base::mutex(); + } + Mutex* release() + { + return base::release(); + } + bool operator!() const + { + return !this->owns_lock(); + } + + typedef typename base::bool_type bool_type; + operator bool_type() const + { + return base::operator bool_type(); + } + }; + +#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) + { + boost::unique_lock<MutexType1> l1(m1,boost::try_to_lock); + if(!l1) + { + return 1; + } + if(!m2.try_lock()) + { + return 2; + } + l1.release(); + return 0; + } + + template<typename MutexType1,typename MutexType2,typename MutexType3> + unsigned try_lock_internal(MutexType1& m1,MutexType2& m2,MutexType3& m3) + { + boost::unique_lock<MutexType1> l1(m1,boost::try_to_lock); + if(!l1) + { + return 1; + } + if(unsigned const failed_lock=try_lock_internal(m2,m3)) + { + return failed_lock+1; + } + l1.release(); + return 0; + } + + + template<typename MutexType1,typename MutexType2,typename MutexType3, + typename MutexType4> + unsigned try_lock_internal(MutexType1& m1,MutexType2& m2,MutexType3& m3, + MutexType4& m4) + { + boost::unique_lock<MutexType1> l1(m1,boost::try_to_lock); + if(!l1) + { + return 1; + } + if(unsigned const failed_lock=try_lock_internal(m2,m3,m4)) + { + return failed_lock+1; + } + l1.release(); + return 0; + } + + template<typename MutexType1,typename MutexType2,typename MutexType3, + typename MutexType4,typename MutexType5> + unsigned try_lock_internal(MutexType1& m1,MutexType2& m2,MutexType3& m3, + MutexType4& m4,MutexType5& m5) + { + boost::unique_lock<MutexType1> l1(m1,boost::try_to_lock); + if(!l1) + { + return 1; + } + if(unsigned const failed_lock=try_lock_internal(m2,m3,m4,m5)) + { + return failed_lock+1; + } + l1.release(); + return 0; + } + + + template<typename MutexType1,typename MutexType2> + unsigned lock_helper(MutexType1& m1,MutexType2& m2) + { + boost::unique_lock<MutexType1> l1(m1); + if(!m2.try_lock()) + { + return 1; + } + l1.release(); + return 0; + } + + template<typename MutexType1,typename MutexType2,typename MutexType3> + unsigned lock_helper(MutexType1& m1,MutexType2& m2,MutexType3& m3) + { + boost::unique_lock<MutexType1> l1(m1); + if(unsigned const failed_lock=try_lock_internal(m2,m3)) + { + return failed_lock; + } + l1.release(); + return 0; + } + + template<typename MutexType1,typename MutexType2,typename MutexType3, + typename MutexType4> + unsigned lock_helper(MutexType1& m1,MutexType2& m2,MutexType3& m3, + MutexType4& m4) + { + boost::unique_lock<MutexType1> l1(m1); + if(unsigned const failed_lock=try_lock_internal(m2,m3,m4)) + { + return failed_lock; + } + l1.release(); + return 0; + } + + template<typename MutexType1,typename MutexType2,typename MutexType3, + typename MutexType4,typename MutexType5> + unsigned lock_helper(MutexType1& m1,MutexType2& m2,MutexType3& m3, + MutexType4& m4,MutexType5& m5) + { + boost::unique_lock<MutexType1> l1(m1); + if(unsigned const failed_lock=try_lock_internal(m2,m3,m4,m5)) + { + return failed_lock; + } + l1.release(); + return 0; + } + } + + namespace detail + { + template<bool x> + struct is_mutex_type_wrapper + {}; + + template<typename MutexType1,typename MutexType2> + void lock_impl(MutexType1& m1,MutexType2& m2,is_mutex_type_wrapper<true>) + { + unsigned const lock_count=2; + unsigned lock_first=0; + for(;;) + { + switch(lock_first) + { + case 0: + lock_first=detail::lock_helper(m1,m2); + if(!lock_first) + return; + break; + case 1: + lock_first=detail::lock_helper(m2,m1); + if(!lock_first) + return; + lock_first=(lock_first+1)%lock_count; + break; + } + } + } + + template<typename Iterator> + void lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper<false>); + } + + + template<typename MutexType1,typename MutexType2> + void lock(MutexType1& m1,MutexType2& m2) + { + detail::lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); + } + + template<typename MutexType1,typename MutexType2> + void lock(const MutexType1& m1,MutexType2& m2) + { + detail::lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); + } + + template<typename MutexType1,typename MutexType2> + void lock(MutexType1& m1,const MutexType2& m2) + { + detail::lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); + } + + template<typename MutexType1,typename MutexType2> + void lock(const MutexType1& m1,const MutexType2& m2) + { + detail::lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); + } + + template<typename MutexType1,typename MutexType2,typename MutexType3> + void lock(MutexType1& m1,MutexType2& m2,MutexType3& m3) + { + unsigned const lock_count=3; + unsigned lock_first=0; + for(;;) + { + switch(lock_first) + { + case 0: + lock_first=detail::lock_helper(m1,m2,m3); + if(!lock_first) + return; + break; + case 1: + lock_first=detail::lock_helper(m2,m3,m1); + if(!lock_first) + return; + lock_first=(lock_first+1)%lock_count; + break; + case 2: + lock_first=detail::lock_helper(m3,m1,m2); + if(!lock_first) + return; + lock_first=(lock_first+2)%lock_count; + break; + } + } + } + + template<typename MutexType1,typename MutexType2,typename MutexType3, + typename MutexType4> + void lock(MutexType1& m1,MutexType2& m2,MutexType3& m3, + MutexType4& m4) + { + unsigned const lock_count=4; + unsigned lock_first=0; + for(;;) + { + switch(lock_first) + { + case 0: + lock_first=detail::lock_helper(m1,m2,m3,m4); + if(!lock_first) + return; + break; + case 1: + lock_first=detail::lock_helper(m2,m3,m4,m1); + if(!lock_first) + return; + lock_first=(lock_first+1)%lock_count; + break; + case 2: + lock_first=detail::lock_helper(m3,m4,m1,m2); + if(!lock_first) + return; + lock_first=(lock_first+2)%lock_count; + break; + case 3: + lock_first=detail::lock_helper(m4,m1,m2,m3); + if(!lock_first) + return; + lock_first=(lock_first+3)%lock_count; + break; + } + } + } + + template<typename MutexType1,typename MutexType2,typename MutexType3, + typename MutexType4,typename MutexType5> + void lock(MutexType1& m1,MutexType2& m2,MutexType3& m3, + MutexType4& m4,MutexType5& m5) + { + unsigned const lock_count=5; + unsigned lock_first=0; + for(;;) + { + switch(lock_first) + { + case 0: + lock_first=detail::lock_helper(m1,m2,m3,m4,m5); + if(!lock_first) + return; + break; + case 1: + lock_first=detail::lock_helper(m2,m3,m4,m5,m1); + if(!lock_first) + return; + lock_first=(lock_first+1)%lock_count; + break; + case 2: + lock_first=detail::lock_helper(m3,m4,m5,m1,m2); + if(!lock_first) + return; + lock_first=(lock_first+2)%lock_count; + break; + case 3: + lock_first=detail::lock_helper(m4,m5,m1,m2,m3); + if(!lock_first) + return; + lock_first=(lock_first+3)%lock_count; + break; + case 4: + lock_first=detail::lock_helper(m5,m1,m2,m3,m4); + if(!lock_first) + return; + lock_first=(lock_first+4)%lock_count; + break; + } + } + } + + namespace detail + { + template<typename Mutex,bool x=is_mutex_type<Mutex>::value> + struct try_lock_impl_return + { + typedef int type; + }; + + template<typename Iterator> + struct try_lock_impl_return<Iterator,false> + { + typedef Iterator type; + }; + + template<typename MutexType1,typename MutexType2> + int try_lock_impl(MutexType1& m1,MutexType2& m2,is_mutex_type_wrapper<true>) + { + return ((int)detail::try_lock_internal(m1,m2))-1; + } + + template<typename Iterator> + Iterator try_lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper<false>); + } + + template<typename MutexType1,typename MutexType2> + typename detail::try_lock_impl_return<MutexType1>::type try_lock(MutexType1& m1,MutexType2& m2) + { + return detail::try_lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); + } + + template<typename MutexType1,typename MutexType2> + typename detail::try_lock_impl_return<MutexType1>::type try_lock(const MutexType1& m1,MutexType2& m2) + { + return detail::try_lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); + } + + template<typename MutexType1,typename MutexType2> + typename detail::try_lock_impl_return<MutexType1>::type try_lock(MutexType1& m1,const MutexType2& m2) + { + return detail::try_lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); + } + + template<typename MutexType1,typename MutexType2> + typename detail::try_lock_impl_return<MutexType1>::type try_lock(const MutexType1& m1,const MutexType2& m2) + { + return detail::try_lock_impl(m1,m2,detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>()); + } + + template<typename MutexType1,typename MutexType2,typename MutexType3> + int try_lock(MutexType1& m1,MutexType2& m2,MutexType3& m3) + { + return ((int)detail::try_lock_internal(m1,m2,m3))-1; + } + + template<typename MutexType1,typename MutexType2,typename MutexType3,typename MutexType4> + int try_lock(MutexType1& m1,MutexType2& m2,MutexType3& m3,MutexType4& m4) + { + return ((int)detail::try_lock_internal(m1,m2,m3,m4))-1; + } + + template<typename MutexType1,typename MutexType2,typename MutexType3,typename MutexType4,typename MutexType5> + int try_lock(MutexType1& m1,MutexType2& m2,MutexType3& m3,MutexType4& m4,MutexType5& m5) + { + return ((int)detail::try_lock_internal(m1,m2,m3,m4,m5))-1; + } + + + namespace detail + { + template<typename Iterator> + struct range_lock_guard + { + Iterator begin; + Iterator end; + + range_lock_guard(Iterator begin_,Iterator end_): + begin(begin_),end(end_) + { + boost::lock(begin,end); + } + + void release() + { + begin=end; + } + + ~range_lock_guard() + { + for(;begin!=end;++begin) + { + begin->unlock(); + } + } + }; + + template<typename Iterator> + Iterator try_lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper<false>) + + { + if(begin==end) + { + return end; + } + typedef typename std::iterator_traits<Iterator>::value_type lock_type; + unique_lock<lock_type> guard(*begin,try_to_lock); + + if(!guard.owns_lock()) + { + return begin; + } + Iterator const failed=boost::try_lock(++begin,end); + if(failed==end) + { + guard.release(); + } + + return failed; + } + } + + + namespace detail + { + template<typename Iterator> + void lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper<false>) + { + typedef typename std::iterator_traits<Iterator>::value_type lock_type; + + if(begin==end) + { + return; + } + bool start_with_begin=true; + Iterator second=begin; + ++second; + Iterator next=second; + + for(;;) + { + unique_lock<lock_type> begin_lock(*begin,defer_lock); + if(start_with_begin) + { + begin_lock.lock(); + Iterator const failed_lock=boost::try_lock(next,end); + if(failed_lock==end) + { + begin_lock.release(); + return; + } + start_with_begin=false; + next=failed_lock; + } + else + { + detail::range_lock_guard<Iterator> guard(next,end); + if(begin_lock.try_lock()) + { + Iterator const failed_lock=boost::try_lock(second,next); + if(failed_lock==next) + { + begin_lock.release(); + guard.release(); + return; + } + start_with_begin=false; + next=failed_lock; + } + else + { + start_with_begin=true; + next=second; + } + } + } + } + + } + +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/mutex.hpp b/boost/thread/mutex.hpp new file mode 100644 index 0000000000..4669886c7f --- /dev/null +++ b/boost/thread/mutex.hpp @@ -0,0 +1,21 @@ +#ifndef BOOST_THREAD_MUTEX_HPP +#define BOOST_THREAD_MUTEX_HPP + +// mutex.hpp +// +// (C) Copyright 2007 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/thread/detail/platform.hpp> +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#include <boost/thread/win32/mutex.hpp> +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +#include <boost/thread/pthread/mutex.hpp> +#else +#error "Boost threads unavailable on this platform" +#endif + +#endif diff --git a/boost/thread/once.hpp b/boost/thread/once.hpp new file mode 100644 index 0000000000..975304e147 --- /dev/null +++ b/boost/thread/once.hpp @@ -0,0 +1,33 @@ +#ifndef BOOST_THREAD_ONCE_HPP +#define BOOST_THREAD_ONCE_HPP + +// once.hpp +// +// (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 +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/thread/detail/platform.hpp> +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#include <boost/thread/win32/once.hpp> +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +#include <boost/thread/pthread/once.hpp> +#else +#error "Boost threads unavailable on this platform" +#endif + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + inline void call_once(void (*func)(),once_flag& flag) + { + call_once(flag,func); + } +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/pthread/condition_variable.hpp b/boost/thread/pthread/condition_variable.hpp new file mode 100644 index 0000000000..48ed8ff731 --- /dev/null +++ b/boost/thread/pthread/condition_variable.hpp @@ -0,0 +1,226 @@ +#ifndef BOOST_THREAD_CONDITION_VARIABLE_PTHREAD_HPP +#define BOOST_THREAD_CONDITION_VARIABLE_PTHREAD_HPP +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2007-10 Anthony Williams + +#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> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + namespace this_thread + { + void BOOST_THREAD_DECL interruption_point(); + } + + namespace thread_cv_detail + { + template<typename MutexType> + struct lock_on_exit + { + MutexType* m; + + lock_on_exit(): + m(0) + {} + + void activate(MutexType& m_) + { + m_.unlock(); + m=&m_; + } + ~lock_on_exit() + { + if(m) + { + m->lock(); + } + } + }; + } + + inline void condition_variable::wait(unique_lock<mutex>& m) + { + int res=0; + { + thread_cv_detail::lock_on_exit<unique_lock<mutex> > guard; + detail::interruption_checker check_for_interruption(&internal_mutex,&cond); + guard.activate(m); + do { + res = pthread_cond_wait(&cond,&internal_mutex); + } while (res == EINTR); + } + this_thread::interruption_point(); + if(res) + { + boost::throw_exception(condition_error()); + } + } + + inline bool condition_variable::timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until) + { + 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(); + if(cond_res==ETIMEDOUT) + { + return false; + } + if(cond_res) + { + boost::throw_exception(condition_error()); + } + return true; + } + + inline void condition_variable::notify_one() + { + boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); + BOOST_VERIFY(!pthread_cond_signal(&cond)); + } + + inline void condition_variable::notify_all() + { + boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); + BOOST_VERIFY(!pthread_cond_broadcast(&cond)); + } + + class condition_variable_any + { + pthread_mutex_t internal_mutex; + pthread_cond_t cond; + + condition_variable_any(condition_variable_any&); + condition_variable_any& operator=(condition_variable_any&); + + public: + condition_variable_any() + { + int const res=pthread_mutex_init(&internal_mutex,NULL); + if(res) + { + boost::throw_exception(thread_resource_error()); + } + int const res2=pthread_cond_init(&cond,NULL); + if(res2) + { + BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex)); + boost::throw_exception(thread_resource_error()); + } + } + ~condition_variable_any() + { + BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex)); + BOOST_VERIFY(!pthread_cond_destroy(&cond)); + } + + template<typename lock_type> + void wait(lock_type& m) + { + 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_wait(&cond,&internal_mutex); + } + this_thread::interruption_point(); + if(res) + { + boost::throw_exception(condition_error()); + } + } + + template<typename lock_type,typename predicate_type> + void wait(lock_type& m,predicate_type pred) + { + while(!pred()) wait(m); + } + + template<typename lock_type> + 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; + } + template<typename lock_type> + bool timed_wait(lock_type& m,xtime const& wait_until) + { + return timed_wait(m,system_time(wait_until)); + } + + template<typename lock_type,typename duration_type> + bool timed_wait(lock_type& m,duration_type const& wait_duration) + { + return timed_wait(m,get_system_time()+wait_duration); + } + + template<typename lock_type,typename predicate_type> + bool timed_wait(lock_type& m,boost::system_time const& wait_until,predicate_type pred) + { + while (!pred()) + { + if(!timed_wait(m, wait_until)) + return pred(); + } + return true; + } + + template<typename lock_type,typename predicate_type> + bool timed_wait(lock_type& m,xtime const& wait_until,predicate_type pred) + { + return timed_wait(m,system_time(wait_until),pred); + } + + template<typename lock_type,typename duration_type,typename predicate_type> + bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred) + { + return timed_wait(m,get_system_time()+wait_duration,pred); + } + + void notify_one() + { + boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); + BOOST_VERIFY(!pthread_cond_signal(&cond)); + } + + void notify_all() + { + boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); + BOOST_VERIFY(!pthread_cond_broadcast(&cond)); + } + }; + +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/pthread/condition_variable_fwd.hpp b/boost/thread/pthread/condition_variable_fwd.hpp new file mode 100644 index 0000000000..f56bee4789 --- /dev/null +++ b/boost/thread/pthread/condition_variable_fwd.hpp @@ -0,0 +1,111 @@ +#ifndef BOOST_THREAD_PTHREAD_CONDITION_VARIABLE_FWD_HPP +#define BOOST_THREAD_PTHREAD_CONDITION_VARIABLE_FWD_HPP +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2007-8 Anthony Williams + +#include <boost/assert.hpp> +#include <boost/throw_exception.hpp> +#include <pthread.h> +#include <boost/thread/mutex.hpp> +#include <boost/thread/locks.hpp> +#include <boost/thread/thread_time.hpp> +#include <boost/thread/xtime.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: + condition_variable() + { + int const res=pthread_mutex_init(&internal_mutex,NULL); + if(res) + { + boost::throw_exception(thread_resource_error()); + } + int const res2=pthread_cond_init(&cond,NULL); + if(res2) + { + BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex)); + boost::throw_exception(thread_resource_error()); + } + } + ~condition_variable() + { + BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex)); + int ret; + do { + ret = pthread_cond_destroy(&cond); + } while (ret == EINTR); + BOOST_VERIFY(!ret); + } + + void wait(unique_lock<mutex>& m); + + template<typename predicate_type> + void wait(unique_lock<mutex>& m,predicate_type pred) + { + 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) + { + return timed_wait(m,system_time(wait_until)); + } + + template<typename duration_type> + 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) + { + while (!pred()) + { + if(!timed_wait(m, wait_until)) + return pred(); + } + return true; + } + + template<typename predicate_type> + 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) + { + return timed_wait(m,get_system_time()+wait_duration,pred); + } + + typedef pthread_cond_t* native_handle_type; + native_handle_type native_handle() + { + return &cond; + } + + void notify_one(); + void notify_all(); + }; +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/pthread/mutex.hpp b/boost/thread/pthread/mutex.hpp new file mode 100644 index 0000000000..fc7c9cdfad --- /dev/null +++ b/boost/thread/pthread/mutex.hpp @@ -0,0 +1,239 @@ +#ifndef BOOST_THREAD_PTHREAD_MUTEX_HPP +#define BOOST_THREAD_PTHREAD_MUTEX_HPP +// (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 +// 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> +#include <boost/thread/thread_time.hpp> +#include <boost/thread/xtime.hpp> +#include <boost/assert.hpp> +#include <errno.h> +#include <boost/thread/pthread/timespec.hpp> +#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp> + +#ifdef _POSIX_TIMEOUTS +#if _POSIX_TIMEOUTS >= 0 && _POSIX_C_SOURCE>=200112L +#define BOOST_PTHREAD_HAS_TIMEDLOCK +#endif +#endif + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + class mutex + { + private: + mutex(mutex const&); + mutex& operator=(mutex const&); + pthread_mutex_t m; + public: + mutex() + { + int const res=pthread_mutex_init(&m,NULL); + if(res) + { + boost::throw_exception(thread_resource_error()); + } + } + ~mutex() + { + int ret; + do + { + ret = pthread_mutex_destroy(&m); + } while (ret == EINTR); + } + + void lock() + { + int res; + do + { + res = pthread_mutex_lock(&m); + } while (res == EINTR); + if(res) + { + boost::throw_exception(lock_error(res)); + } + } + + void unlock() + { + int ret; + do + { + ret = pthread_mutex_unlock(&m); + } while (ret == EINTR); + BOOST_VERIFY(!ret); + } + + bool try_lock() + { + int res; + do + { + res = pthread_mutex_trylock(&m); + } while (res == EINTR); + if(res && (res!=EBUSY)) + { + boost::throw_exception(lock_error(res)); + } + + return !res; + } + + typedef pthread_mutex_t* native_handle_type; + native_handle_type native_handle() + { + return &m; + } + + typedef unique_lock<mutex> scoped_lock; + typedef detail::try_lock_wrapper<mutex> scoped_try_lock; + }; + + typedef mutex try_mutex; + + 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: + timed_mutex() + { + int const res=pthread_mutex_init(&m,NULL); + if(res) + { + boost::throw_exception(thread_resource_error()); + } +#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()); + } + is_locked=false; +#endif + } + ~timed_mutex() + { + BOOST_VERIFY(!pthread_mutex_destroy(&m)); +#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK + BOOST_VERIFY(!pthread_cond_destroy(&cond)); +#endif + } + + template<typename TimeDuration> + bool timed_lock(TimeDuration const & relative_time) + { + return timed_lock(get_system_time()+relative_time); + } + bool timed_lock(boost::xtime const & absolute_time) + { + return timed_lock(system_time(absolute_time)); + } + +#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK + void lock() + { + BOOST_VERIFY(!pthread_mutex_lock(&m)); + } + + void unlock() + { + BOOST_VERIFY(!pthread_mutex_unlock(&m)); + } + + bool try_lock() + { + int const res=pthread_mutex_trylock(&m); + 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() + { + return &m; + } + +#else + void lock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + while(is_locked) + { + BOOST_VERIFY(!pthread_cond_wait(&cond,&m)); + } + is_locked=true; + } + + void unlock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + is_locked=false; + BOOST_VERIFY(!pthread_cond_signal(&cond)); + } + + bool try_lock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + if(is_locked) + { + return false; + } + is_locked=true; + return true; + } + + bool timed_lock(system_time const & abs_time) + { + struct timespec const timeout=detail::get_timespec(abs_time); + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + while(is_locked) + { + int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout); + if(cond_res==ETIMEDOUT) + { + return false; + } + BOOST_ASSERT(!cond_res); + } + is_locked=true; + return true; + } +#endif + + typedef unique_lock<timed_mutex> scoped_timed_lock; + typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock; + typedef scoped_timed_lock scoped_lock; + }; + +} + +#include <boost/config/abi_suffix.hpp> + + +#endif diff --git a/boost/thread/pthread/once.hpp b/boost/thread/pthread/once.hpp new file mode 100644 index 0000000000..81e744e645 --- /dev/null +++ b/boost/thread/pthread/once.hpp @@ -0,0 +1,94 @@ +#ifndef BOOST_THREAD_PTHREAD_ONCE_HPP +#define BOOST_THREAD_PTHREAD_ONCE_HPP + +// once.hpp +// +// (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 +// 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/config/abi_prefix.hpp> + +namespace boost +{ + + struct once_flag + { + boost::uintmax_t epoch; + }; + + namespace detail + { + BOOST_THREAD_DECL boost::uintmax_t& get_once_per_thread_epoch(); + BOOST_THREAD_DECL extern boost::uintmax_t once_global_epoch; + BOOST_THREAD_DECL extern pthread_mutex_t once_epoch_mutex; + 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> + void call_once(once_flag& flag,Function f) + { + static boost::uintmax_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE; + static boost::uintmax_t const being_initialized=uninitialized_flag+1; + boost::uintmax_t const epoch=flag.epoch; + boost::uintmax_t& this_thread_epoch=detail::get_once_per_thread_epoch(); + + if(epoch<this_thread_epoch) + { + pthread::pthread_mutex_scoped_lock lk(&detail::once_epoch_mutex); + + while(flag.epoch<=being_initialized) + { + if(flag.epoch==uninitialized_flag) + { + flag.epoch=being_initialized; +#ifndef BOOST_NO_EXCEPTIONS + try + { +#endif + pthread::pthread_mutex_scoped_unlock relocker(&detail::once_epoch_mutex); + f(); +#ifndef BOOST_NO_EXCEPTIONS + } + catch(...) + { + flag.epoch=uninitialized_flag; + BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv)); + throw; + } +#endif + flag.epoch=--detail::once_global_epoch; + BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv)); + } + else + { + while(flag.epoch==being_initialized) + { + BOOST_VERIFY(!pthread_cond_wait(&detail::once_epoch_cv,&detail::once_epoch_mutex)); + } + } + } + this_thread_epoch=detail::once_global_epoch; + } + } +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/pthread/pthread_mutex_scoped_lock.hpp b/boost/thread/pthread/pthread_mutex_scoped_lock.hpp new file mode 100644 index 0000000000..cdbf8c6740 --- /dev/null +++ b/boost/thread/pthread/pthread_mutex_scoped_lock.hpp @@ -0,0 +1,64 @@ +#ifndef BOOST_PTHREAD_MUTEX_SCOPED_LOCK_HPP +#define BOOST_PTHREAD_MUTEX_SCOPED_LOCK_HPP +// (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 +// http://www.boost.org/LICENSE_1_0.txt) + +#include <pthread.h> +#include <boost/assert.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + namespace pthread + { + class pthread_mutex_scoped_lock + { + pthread_mutex_t* m; + bool locked; + public: + explicit pthread_mutex_scoped_lock(pthread_mutex_t* m_): + m(m_),locked(true) + { + BOOST_VERIFY(!pthread_mutex_lock(m)); + } + void unlock() + { + BOOST_VERIFY(!pthread_mutex_unlock(m)); + locked=false; + } + + ~pthread_mutex_scoped_lock() + { + if(locked) + { + unlock(); + } + } + + }; + + class pthread_mutex_scoped_unlock + { + pthread_mutex_t* m; + public: + explicit pthread_mutex_scoped_unlock(pthread_mutex_t* m_): + m(m_) + { + BOOST_VERIFY(!pthread_mutex_unlock(m)); + } + ~pthread_mutex_scoped_unlock() + { + BOOST_VERIFY(!pthread_mutex_lock(m)); + } + + }; + } +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/pthread/recursive_mutex.hpp b/boost/thread/pthread/recursive_mutex.hpp new file mode 100644 index 0000000000..113a0ac15e --- /dev/null +++ b/boost/thread/pthread/recursive_mutex.hpp @@ -0,0 +1,345 @@ +#ifndef BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP +#define BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP +// (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 +// 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> +#include <boost/thread/thread_time.hpp> +#include <boost/assert.hpp> +#ifndef _WIN32 +#include <unistd.h> +#endif +#include <boost/date_time/posix_time/conversion.hpp> +#include <errno.h> +#include <boost/thread/pthread/timespec.hpp> +#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp> + +#ifdef _POSIX_TIMEOUTS +#if _POSIX_TIMEOUTS >= 0 +#define BOOST_PTHREAD_HAS_TIMEDLOCK +#endif +#endif + +#if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) && defined(BOOST_PTHREAD_HAS_TIMEDLOCK) +#define BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK +#endif + +#include <boost/config/abi_prefix.hpp> + +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; + bool is_locked; + pthread_t owner; + unsigned count; +#endif + public: + recursive_mutex() + { +#ifdef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE + pthread_mutexattr_t attr; + + int const init_attr_res=pthread_mutexattr_init(&attr); + if(init_attr_res) + { + boost::throw_exception(thread_resource_error()); + } + 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()); + } + + int const res=pthread_mutex_init(&m,&attr); + if(res) + { + BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); + boost::throw_exception(thread_resource_error()); + } + BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); +#else + int const res=pthread_mutex_init(&m,NULL); + if(res) + { + boost::throw_exception(thread_resource_error()); + } + int const res2=pthread_cond_init(&cond,NULL); + if(res2) + { + BOOST_VERIFY(!pthread_mutex_destroy(&m)); + boost::throw_exception(thread_resource_error()); + } + is_locked=false; + count=0; +#endif + } + ~recursive_mutex() + { + BOOST_VERIFY(!pthread_mutex_destroy(&m)); +#ifndef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE + BOOST_VERIFY(!pthread_cond_destroy(&cond)); +#endif + } + +#ifdef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE + void lock() + { + BOOST_VERIFY(!pthread_mutex_lock(&m)); + } + + void unlock() + { + BOOST_VERIFY(!pthread_mutex_unlock(&m)); + } + + bool try_lock() + { + int const res=pthread_mutex_trylock(&m); + BOOST_ASSERT(!res || res==EBUSY); + return !res; + } + typedef pthread_mutex_t* native_handle_type; + native_handle_type native_handle() + { + return &m; + } + +#else + void lock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + if(is_locked && pthread_equal(owner,pthread_self())) + { + ++count; + return; + } + + while(is_locked) + { + BOOST_VERIFY(!pthread_cond_wait(&cond,&m)); + } + is_locked=true; + ++count; + owner=pthread_self(); + } + + void unlock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + if(!--count) + { + is_locked=false; + } + BOOST_VERIFY(!pthread_cond_signal(&cond)); + } + + bool try_lock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + if(is_locked && !pthread_equal(owner,pthread_self())) + { + return false; + } + is_locked=true; + ++count; + owner=pthread_self(); + return true; + } + +#endif + + typedef unique_lock<recursive_mutex> scoped_lock; + typedef detail::try_lock_wrapper<recursive_mutex> scoped_try_lock; + }; + + typedef recursive_mutex recursive_try_mutex; + + 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; + bool is_locked; + pthread_t owner; + unsigned count; +#endif + public: + recursive_timed_mutex() + { +#ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK + pthread_mutexattr_t attr; + + int const init_attr_res=pthread_mutexattr_init(&attr); + if(init_attr_res) + { + boost::throw_exception(thread_resource_error()); + } + int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE); + if(set_attr_res) + { + boost::throw_exception(thread_resource_error()); + } + + int const res=pthread_mutex_init(&m,&attr); + if(res) + { + BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); + boost::throw_exception(thread_resource_error()); + } + BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); +#else + int const res=pthread_mutex_init(&m,NULL); + if(res) + { + boost::throw_exception(thread_resource_error()); + } + int const res2=pthread_cond_init(&cond,NULL); + if(res2) + { + BOOST_VERIFY(!pthread_mutex_destroy(&m)); + boost::throw_exception(thread_resource_error()); + } + is_locked=false; + count=0; +#endif + } + ~recursive_timed_mutex() + { + BOOST_VERIFY(!pthread_mutex_destroy(&m)); +#ifndef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK + BOOST_VERIFY(!pthread_cond_destroy(&cond)); +#endif + } + + template<typename TimeDuration> + bool timed_lock(TimeDuration const & relative_time) + { + return timed_lock(get_system_time()+relative_time); + } + +#ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK + void lock() + { + BOOST_VERIFY(!pthread_mutex_lock(&m)); + } + + void unlock() + { + BOOST_VERIFY(!pthread_mutex_unlock(&m)); + } + + bool try_lock() + { + int const res=pthread_mutex_trylock(&m); + 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() + { + return &m; + } + +#else + void lock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + if(is_locked && pthread_equal(owner,pthread_self())) + { + ++count; + return; + } + + while(is_locked) + { + BOOST_VERIFY(!pthread_cond_wait(&cond,&m)); + } + is_locked=true; + ++count; + owner=pthread_self(); + } + + void unlock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + if(!--count) + { + is_locked=false; + } + BOOST_VERIFY(!pthread_cond_signal(&cond)); + } + + bool try_lock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + if(is_locked && !pthread_equal(owner,pthread_self())) + { + return false; + } + is_locked=true; + ++count; + owner=pthread_self(); + return true; + } + + bool timed_lock(system_time const & abs_time) + { + 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())) + { + ++count; + return true; + } + while(is_locked) + { + int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout); + if(cond_res==ETIMEDOUT) + { + return false; + } + BOOST_ASSERT(!cond_res); + } + is_locked=true; + ++count; + owner=pthread_self(); + return true; + } +#endif + + 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; + }; + +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/pthread/shared_mutex.hpp b/boost/thread/pthread/shared_mutex.hpp new file mode 100644 index 0000000000..56e209acf3 --- /dev/null +++ b/boost/thread/pthread/shared_mutex.hpp @@ -0,0 +1,303 @@ +#ifndef BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP +#define BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP + +// (C) Copyright 2006-8 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/assert.hpp> +#include <boost/static_assert.hpp> +#include <boost/thread/mutex.hpp> +#include <boost/thread/condition_variable.hpp> +#include <boost/thread/detail/thread_interruption.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + class shared_mutex + { + private: + struct state_data + { + unsigned shared_count; + bool exclusive; + bool upgrade; + bool exclusive_waiting_blocked; + }; + + + + state_data state; + boost::mutex state_change; + boost::condition_variable shared_cond; + boost::condition_variable exclusive_cond; + boost::condition_variable upgrade_cond; + + void release_waiters() + { + exclusive_cond.notify_one(); + shared_cond.notify_all(); + } + + + public: + shared_mutex() + { + state_data state_={0,0,0,0}; + state=state_; + } + + ~shared_mutex() + { + } + + void lock_shared() + { + boost::this_thread::disable_interruption do_not_disturb; + boost::mutex::scoped_lock lk(state_change); + + while(state.exclusive || state.exclusive_waiting_blocked) + { + shared_cond.wait(lk); + } + ++state.shared_count; + } + + bool try_lock_shared() + { + boost::mutex::scoped_lock lk(state_change); + + if(state.exclusive || state.exclusive_waiting_blocked) + { + return false; + } + else + { + ++state.shared_count; + return true; + } + } + + bool timed_lock_shared(system_time const& timeout) + { + boost::this_thread::disable_interruption do_not_disturb; + boost::mutex::scoped_lock lk(state_change); + + while(state.exclusive || state.exclusive_waiting_blocked) + { + if(!shared_cond.timed_wait(lk,timeout)) + { + return false; + } + } + ++state.shared_count; + return true; + } + + template<typename TimeDuration> + bool timed_lock_shared(TimeDuration const & relative_time) + { + return timed_lock_shared(get_system_time()+relative_time); + } + + void unlock_shared() + { + boost::mutex::scoped_lock lk(state_change); + bool const last_reader=!--state.shared_count; + + if(last_reader) + { + if(state.upgrade) + { + state.upgrade=false; + state.exclusive=true; + upgrade_cond.notify_one(); + } + else + { + state.exclusive_waiting_blocked=false; + } + release_waiters(); + } + } + + void lock() + { + 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; + exclusive_cond.wait(lk); + } + state.exclusive=true; + } + + bool timed_lock(system_time const& timeout) + { + 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(!exclusive_cond.timed_wait(lk,timeout)) + { + if(state.shared_count || state.exclusive) + { + state.exclusive_waiting_blocked=false; + release_waiters(); + return false; + } + break; + } + } + state.exclusive=true; + return true; + } + + template<typename TimeDuration> + bool timed_lock(TimeDuration const & relative_time) + { + return timed_lock(get_system_time()+relative_time); + } + + bool try_lock() + { + boost::mutex::scoped_lock lk(state_change); + + if(state.shared_count || state.exclusive) + { + return false; + } + else + { + state.exclusive=true; + return true; + } + + } + + void unlock() + { + boost::mutex::scoped_lock lk(state_change); + state.exclusive=false; + state.exclusive_waiting_blocked=false; + release_waiters(); + } + + void lock_upgrade() + { + boost::this_thread::disable_interruption do_not_disturb; + boost::mutex::scoped_lock lk(state_change); + while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) + { + shared_cond.wait(lk); + } + ++state.shared_count; + state.upgrade=true; + } + + bool timed_lock_upgrade(system_time const& timeout) + { + 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(!shared_cond.timed_wait(lk,timeout)) + { + if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) + { + return false; + } + break; + } + } + ++state.shared_count; + state.upgrade=true; + return true; + } + + template<typename TimeDuration> + bool timed_lock_upgrade(TimeDuration const & relative_time) + { + return timed_lock_upgrade(get_system_time()+relative_time); + } + + bool try_lock_upgrade() + { + boost::mutex::scoped_lock lk(state_change); + if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) + { + return false; + } + else + { + ++state.shared_count; + state.upgrade=true; + return true; + } + } + + void unlock_upgrade() + { + boost::mutex::scoped_lock lk(state_change); + state.upgrade=false; + bool const last_reader=!--state.shared_count; + + if(last_reader) + { + state.exclusive_waiting_blocked=false; + release_waiters(); + } + } + + void unlock_upgrade_and_lock() + { + boost::this_thread::disable_interruption do_not_disturb; + boost::mutex::scoped_lock lk(state_change); + --state.shared_count; + while(state.shared_count) + { + upgrade_cond.wait(lk); + } + state.upgrade=false; + state.exclusive=true; + } + + void unlock_and_lock_upgrade() + { + boost::mutex::scoped_lock lk(state_change); + state.exclusive=false; + state.upgrade=true; + ++state.shared_count; + state.exclusive_waiting_blocked=false; + release_waiters(); + } + + void unlock_and_lock_shared() + { + boost::mutex::scoped_lock lk(state_change); + state.exclusive=false; + ++state.shared_count; + state.exclusive_waiting_blocked=false; + release_waiters(); + } + + void unlock_upgrade_and_lock_shared() + { + boost::mutex::scoped_lock lk(state_change); + state.upgrade=false; + state.exclusive_waiting_blocked=false; + release_waiters(); + } + }; +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/pthread/thread_data.hpp b/boost/thread/pthread/thread_data.hpp new file mode 100644 index 0000000000..3de9b41b17 --- /dev/null +++ b/boost/thread/pthread/thread_data.hpp @@ -0,0 +1,157 @@ +#ifndef BOOST_THREAD_PTHREAD_THREAD_DATA_HPP +#define BOOST_THREAD_PTHREAD_THREAD_DATA_HPP +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2007 Anthony Williams + +#include <boost/thread/detail/config.hpp> +#include <boost/thread/exceptions.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <boost/thread/mutex.hpp> +#include <boost/optional.hpp> +#include <pthread.h> +#include <boost/assert.hpp> +#include <boost/thread/pthread/condition_variable_fwd.hpp> +#include <map> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + class thread; + + namespace detail + { + struct tss_cleanup_function; + struct thread_exit_callback_node; + struct tss_data_node + { + boost::shared_ptr<boost::detail::tss_cleanup_function> func; + void* value; + + tss_data_node(boost::shared_ptr<boost::detail::tss_cleanup_function> func_, + void* value_): + func(func_),value(value_) + {} + }; + + struct thread_data_base; + typedef boost::shared_ptr<thread_data_base> thread_data_ptr; + + struct BOOST_THREAD_DECL thread_data_base: + enable_shared_from_this<thread_data_base> + { + thread_data_ptr self; + pthread_t thread_handle; + boost::mutex data_mutex; + boost::condition_variable done_condition; + boost::mutex sleep_mutex; + boost::condition_variable sleep_condition; + bool done; + bool join_started; + bool joined; + boost::detail::thread_exit_callback_node* thread_exit_callbacks; + std::map<void const*,boost::detail::tss_data_node> tss_data; + bool interrupt_enabled; + bool interrupt_requested; + pthread_mutex_t* cond_mutex; + pthread_cond_t* current_cond; + + thread_data_base(): + done(false),join_started(false),joined(false), + thread_exit_callbacks(0), + interrupt_enabled(true), + interrupt_requested(false), + current_cond(0) + {} + virtual ~thread_data_base(); + + typedef pthread_t native_handle_type; + + virtual void run()=0; + }; + + BOOST_THREAD_DECL thread_data_base* get_current_thread_data(); + + class interruption_checker + { + thread_data_base* const thread_info; + pthread_mutex_t* m; + bool set; + + void check_for_interruption() + { + if(thread_info->interrupt_requested) + { + thread_info->interrupt_requested=false; + throw thread_interrupted(); + } + } + + void operator=(interruption_checker&); + public: + explicit interruption_checker(pthread_mutex_t* cond_mutex,pthread_cond_t* cond): + thread_info(detail::get_current_thread_data()),m(cond_mutex), + set(thread_info && thread_info->interrupt_enabled) + { + if(set) + { + lock_guard<mutex> guard(thread_info->data_mutex); + check_for_interruption(); + thread_info->cond_mutex=cond_mutex; + thread_info->current_cond=cond; + BOOST_VERIFY(!pthread_mutex_lock(m)); + } + else + { + BOOST_VERIFY(!pthread_mutex_lock(m)); + } + } + ~interruption_checker() + { + if(set) + { + BOOST_VERIFY(!pthread_mutex_unlock(m)); + lock_guard<mutex> guard(thread_info->data_mutex); + thread_info->cond_mutex=NULL; + thread_info->current_cond=NULL; + } + else + { + BOOST_VERIFY(!pthread_mutex_unlock(m)); + } + } + }; + } + + namespace this_thread + { + void BOOST_THREAD_DECL yield(); + +#ifdef __DECXXX + /// Workaround of DECCXX issue of incorrect template substitution + template<typename TimeDuration> + inline void sleep(TimeDuration const& rel_time) + { + this_thread::sleep(get_system_time()+rel_time); + } + + template<> + void BOOST_THREAD_DECL sleep(system_time const& abs_time); +#else + void BOOST_THREAD_DECL sleep(system_time const& abs_time); + + template<typename TimeDuration> + inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time) + { + this_thread::sleep(get_system_time()+rel_time); + } +#endif + } +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/pthread/thread_heap_alloc.hpp b/boost/thread/pthread/thread_heap_alloc.hpp new file mode 100644 index 0000000000..737c29858b --- /dev/null +++ b/boost/thread/pthread/thread_heap_alloc.hpp @@ -0,0 +1,242 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2008 Anthony Williams +#ifndef THREAD_HEAP_ALLOC_PTHREAD_HPP +#define THREAD_HEAP_ALLOC_PTHREAD_HPP + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + namespace detail + { + template<typename T> + inline T* heap_new() + { + return new T(); + } + +#ifndef BOOST_NO_RVALUE_REFERENCES + template<typename T,typename A1> + inline T* heap_new(A1&& a1) + { + return new T(static_cast<A1&&>(a1)); + } + template<typename T,typename A1,typename A2> + inline T* heap_new(A1&& a1,A2&& a2) + { + return new T(static_cast<A1&&>(a1),static_cast<A2&&>(a2)); + } + template<typename T,typename A1,typename A2,typename A3> + inline T* heap_new(A1&& a1,A2&& a2,A3&& a3) + { + return new T(static_cast<A1&&>(a1),static_cast<A2&&>(a2), + static_cast<A3&&>(a3)); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1&& a1,A2&& a2,A3&& a3,A4&& a4) + { + return new T(static_cast<A1&&>(a1),static_cast<A2&&>(a2), + static_cast<A3&&>(a3),static_cast<A4&&>(a4)); + } +#else + template<typename T,typename A1> + inline T* heap_new_impl(A1 a1) + { + return new T(a1); + } + template<typename T,typename A1,typename A2> + inline T* heap_new_impl(A1 a1,A2 a2) + { + return new T(a1,a2); + } + template<typename T,typename A1,typename A2,typename A3> + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3) + { + return new T(a1,a2,a3); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4) + { + return new T(a1,a2,a3,a4); + } + + template<typename T,typename A1> + inline T* heap_new(A1 const& a1) + { + return heap_new_impl<T,A1 const&>(a1); + } + template<typename T,typename A1> + inline T* heap_new(A1& a1) + { + return heap_new_impl<T,A1&>(a1); + } + + template<typename T,typename A1,typename A2> + inline T* heap_new(A1 const& a1,A2 const& a2) + { + return heap_new_impl<T,A1 const&,A2 const&>(a1,a2); + } + template<typename T,typename A1,typename A2> + inline T* heap_new(A1& a1,A2 const& a2) + { + return heap_new_impl<T,A1&,A2 const&>(a1,a2); + } + template<typename T,typename A1,typename A2> + inline T* heap_new(A1 const& a1,A2& a2) + { + return heap_new_impl<T,A1 const&,A2&>(a1,a2); + } + template<typename T,typename A1,typename A2> + inline T* heap_new(A1& a1,A2& a2) + { + return heap_new_impl<T,A1&,A2&>(a1,a2); + } + + template<typename T,typename A1,typename A2,typename A3> + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3) + { + return heap_new_impl<T,A1 const&,A2 const&,A3 const&>(a1,a2,a3); + } + template<typename T,typename A1,typename A2,typename A3> + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3) + { + return heap_new_impl<T,A1&,A2 const&,A3 const&>(a1,a2,a3); + } + template<typename T,typename A1,typename A2,typename A3> + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3) + { + return heap_new_impl<T,A1 const&,A2&,A3 const&>(a1,a2,a3); + } + template<typename T,typename A1,typename A2,typename A3> + inline T* heap_new(A1& a1,A2& a2,A3 const& a3) + { + return heap_new_impl<T,A1&,A2&,A3 const&>(a1,a2,a3); + } + + template<typename T,typename A1,typename A2,typename A3> + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3) + { + return heap_new_impl<T,A1 const&,A2 const&,A3&>(a1,a2,a3); + } + template<typename T,typename A1,typename A2,typename A3> + inline T* heap_new(A1& a1,A2 const& a2,A3& a3) + { + return heap_new_impl<T,A1&,A2 const&,A3&>(a1,a2,a3); + } + template<typename T,typename A1,typename A2,typename A3> + inline T* heap_new(A1 const& a1,A2& a2,A3& a3) + { + return heap_new_impl<T,A1 const&,A2&,A3&>(a1,a2,a3); + } + template<typename T,typename A1,typename A2,typename A3> + inline T* heap_new(A1& a1,A2& a2,A3& a3) + { + return heap_new_impl<T,A1&,A2&,A3&>(a1,a2,a3); + } + + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl<T,A1 const&,A2 const&,A3 const&,A4 const&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl<T,A1&,A2 const&,A3 const&,A4 const&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl<T,A1 const&,A2&,A3 const&,A4 const&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl<T,A1&,A2&,A3 const&,A4 const&>(a1,a2,a3,a4); + } + + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4 const& a4) + { + return heap_new_impl<T,A1 const&,A2 const&,A3&,A4 const&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4 const& a4) + { + return heap_new_impl<T,A1&,A2 const&,A3&,A4 const&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4 const& a4) + { + return heap_new_impl<T,A1 const&,A2&,A3&,A4 const&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1& a1,A2& a2,A3& a3,A4 const& a4) + { + return heap_new_impl<T,A1&,A2&,A3&,A4 const&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4& a4) + { + return heap_new_impl<T,A1 const&,A2 const&,A3 const&,A4&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4& a4) + { + return heap_new_impl<T,A1&,A2 const&,A3 const&,A4&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4& a4) + { + return heap_new_impl<T,A1 const&,A2&,A3 const&,A4&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4& a4) + { + return heap_new_impl<T,A1&,A2&,A3 const&,A4&>(a1,a2,a3,a4); + } + + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4& a4) + { + return heap_new_impl<T,A1 const&,A2 const&,A3&,A4&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4& a4) + { + return heap_new_impl<T,A1&,A2 const&,A3&,A4&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4& a4) + { + return heap_new_impl<T,A1 const&,A2&,A3&,A4&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1& a1,A2& a2,A3& a3,A4& a4) + { + return heap_new_impl<T,A1&,A2&,A3&,A4&>(a1,a2,a3,a4); + } + +#endif + template<typename T> + inline void heap_delete(T* data) + { + delete data; + } + + template<typename T> + struct do_heap_delete + { + void operator()(T* data) const + { + detail::heap_delete(data); + } + }; + } +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/pthread/timespec.hpp b/boost/thread/pthread/timespec.hpp new file mode 100644 index 0000000000..d7465c1ac3 --- /dev/null +++ b/boost/thread/pthread/timespec.hpp @@ -0,0 +1,36 @@ +#ifndef BOOST_THREAD_PTHREAD_TIMESPEC_HPP +#define BOOST_THREAD_PTHREAD_TIMESPEC_HPP +// (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 +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/thread/thread_time.hpp> +#include <boost/date_time/posix_time/conversion.hpp> +#include <pthread.h> +#ifndef _WIN32 +#include <unistd.h> +#endif + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + namespace detail + { + inline struct timespec get_timespec(boost::system_time const& abs_time) + { + struct timespec timeout={0,0}; + boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0); + + timeout.tv_sec=time_since_epoch.total_seconds(); + timeout.tv_nsec=(long)(time_since_epoch.fractional_seconds()*(1000000000l/time_since_epoch.ticks_per_second())); + return timeout; + } + } +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/recursive_mutex.hpp b/boost/thread/recursive_mutex.hpp new file mode 100644 index 0000000000..d5f6116e72 --- /dev/null +++ b/boost/thread/recursive_mutex.hpp @@ -0,0 +1,21 @@ +#ifndef BOOST_THREAD_RECURSIVE_MUTEX_HPP +#define BOOST_THREAD_RECURSIVE_MUTEX_HPP + +// recursive_mutex.hpp +// +// (C) Copyright 2007 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/thread/detail/platform.hpp> +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#include <boost/thread/win32/recursive_mutex.hpp> +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +#include <boost/thread/pthread/recursive_mutex.hpp> +#else +#error "Boost threads unavailable on this platform" +#endif + +#endif diff --git a/boost/thread/shared_mutex.hpp b/boost/thread/shared_mutex.hpp new file mode 100644 index 0000000000..51eda0de0b --- /dev/null +++ b/boost/thread/shared_mutex.hpp @@ -0,0 +1,21 @@ +#ifndef BOOST_THREAD_SHARED_MUTEX_HPP +#define BOOST_THREAD_SHARED_MUTEX_HPP + +// shared_mutex.hpp +// +// (C) Copyright 2007 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/thread/detail/platform.hpp> +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#include <boost/thread/win32/shared_mutex.hpp> +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +#include <boost/thread/pthread/shared_mutex.hpp> +#else +#error "Boost threads unavailable on this platform" +#endif + +#endif diff --git a/boost/thread/thread.hpp b/boost/thread/thread.hpp new file mode 100644 index 0000000000..fdfdadcc3e --- /dev/null +++ b/boost/thread/thread.hpp @@ -0,0 +1,27 @@ +#ifndef BOOST_THREAD_THREAD_HPP +#define BOOST_THREAD_THREAD_HPP + +// thread.hpp +// +// (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 +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/thread/detail/platform.hpp> + +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#include <boost/thread/win32/thread_data.hpp> +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +#include <boost/thread/pthread/thread_data.hpp> +#else +#error "Boost threads unavailable on this platform" +#endif + +#include <boost/thread/detail/thread.hpp> +#include <boost/thread/detail/thread_interruption.hpp> +#include <boost/thread/detail/thread_group.hpp> + + +#endif diff --git a/boost/thread/thread_time.hpp b/boost/thread/thread_time.hpp new file mode 100644 index 0000000000..ffdcf850f7 --- /dev/null +++ b/boost/thread/thread_time.hpp @@ -0,0 +1,55 @@ +#ifndef BOOST_THREAD_TIME_HPP +#define BOOST_THREAD_TIME_HPP +// (C) Copyright 2007 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/date_time/time_clock.hpp> +#include <boost/date_time/microsec_time_clock.hpp> +#include <boost/date_time/posix_time/posix_time_types.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + typedef boost::posix_time::ptime system_time; + + inline system_time get_system_time() + { +#if defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK) + return boost::date_time::microsec_clock<system_time>::universal_time(); +#else // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK) + return boost::date_time::second_clock<system_time>::universal_time(); +#endif // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK) + } + + namespace detail + { + inline system_time get_system_time_sentinel() + { + return system_time(boost::posix_time::pos_infin); + } + + inline unsigned long get_milliseconds_until(system_time const& target_time) + { + if(target_time.is_pos_infinity()) + { + return ~(unsigned long)0; + } + system_time const now=get_system_time(); + if(target_time<=now) + { + return 0; + } + return static_cast<unsigned long>((target_time-now).total_milliseconds()+1); + } + + } + +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/tss.hpp b/boost/thread/tss.hpp new file mode 100644 index 0000000000..c920024b0f --- /dev/null +++ b/boost/thread/tss.hpp @@ -0,0 +1,113 @@ +#ifndef BOOST_THREAD_TSS_HPP +#define BOOST_THREAD_TSS_HPP +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2007-8 Anthony Williams + +#include <boost/thread/detail/config.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/thread/detail/thread_heap_alloc.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + namespace detail + { + struct tss_cleanup_function + { + virtual ~tss_cleanup_function() + {} + + virtual void operator()(void* data)=0; + }; + + BOOST_THREAD_DECL void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing); + BOOST_THREAD_DECL void* get_tss_data(void const* key); + } + + template <typename T> + class thread_specific_ptr + { + private: + thread_specific_ptr(thread_specific_ptr&); + thread_specific_ptr& operator=(thread_specific_ptr&); + + struct delete_data: + detail::tss_cleanup_function + { + void operator()(void* data) + { + delete static_cast<T*>(data); + } + }; + + struct run_custom_cleanup_function: + detail::tss_cleanup_function + { + void (*cleanup_function)(T*); + + explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)): + cleanup_function(cleanup_function_) + {} + + void operator()(void* data) + { + cleanup_function(static_cast<T*>(data)); + } + }; + + + boost::shared_ptr<detail::tss_cleanup_function> cleanup; + + public: + typedef T element_type; + + thread_specific_ptr(): + cleanup(detail::heap_new<delete_data>(),detail::do_heap_delete<delete_data>()) + {} + explicit thread_specific_ptr(void (*func_)(T*)) + { + if(func_) + { + cleanup.reset(detail::heap_new<run_custom_cleanup_function>(func_),detail::do_heap_delete<run_custom_cleanup_function>()); + } + } + ~thread_specific_ptr() + { + detail::set_tss_data(this,boost::shared_ptr<detail::tss_cleanup_function>(),0,true); + } + + T* get() const + { + return static_cast<T*>(detail::get_tss_data(this)); + } + T* operator->() const + { + return get(); + } + T& operator*() const + { + return *get(); + } + T* release() + { + T* const temp=get(); + detail::set_tss_data(this,boost::shared_ptr<detail::tss_cleanup_function>(),0,false); + return temp; + } + void reset(T* new_value=0) + { + T* const current_value=get(); + if(current_value!=new_value) + { + detail::set_tss_data(this,cleanup,new_value,true); + } + } + }; +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/win32/basic_recursive_mutex.hpp b/boost/thread/win32/basic_recursive_mutex.hpp new file mode 100644 index 0000000000..e748aa725c --- /dev/null +++ b/boost/thread/win32/basic_recursive_mutex.hpp @@ -0,0 +1,120 @@ +#ifndef BOOST_BASIC_RECURSIVE_MUTEX_WIN32_HPP +#define BOOST_BASIC_RECURSIVE_MUTEX_WIN32_HPP + +// basic_recursive_mutex.hpp +// +// (C) Copyright 2006-8 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/thread/win32/thread_primitives.hpp> +#include <boost/thread/win32/basic_timed_mutex.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + namespace detail + { + template<typename underlying_mutex_type> + struct basic_recursive_mutex_impl + { + long recursion_count; + long locking_thread_id; + underlying_mutex_type mutex; + + void initialize() + { + recursion_count=0; + locking_thread_id=0; + mutex.initialize(); + } + + void destroy() + { + mutex.destroy(); + } + + bool try_lock() + { + long const current_thread_id=win32::GetCurrentThreadId(); + return try_recursive_lock(current_thread_id) || try_basic_lock(current_thread_id); + } + + void lock() + { + long const current_thread_id=win32::GetCurrentThreadId(); + if(!try_recursive_lock(current_thread_id)) + { + mutex.lock(); + BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id); + recursion_count=1; + } + } + bool timed_lock(::boost::system_time const& target) + { + long const current_thread_id=win32::GetCurrentThreadId(); + return try_recursive_lock(current_thread_id) || try_timed_lock(current_thread_id,target); + } + template<typename Duration> + bool timed_lock(Duration const& timeout) + { + return timed_lock(get_system_time()+timeout); + } + + void unlock() + { + if(!--recursion_count) + { + BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,0); + mutex.unlock(); + } + } + + private: + bool try_recursive_lock(long current_thread_id) + { + if(::boost::detail::interlocked_read_acquire(&locking_thread_id)==current_thread_id) + { + ++recursion_count; + return true; + } + return false; + } + + bool try_basic_lock(long current_thread_id) + { + if(mutex.try_lock()) + { + BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id); + recursion_count=1; + return true; + } + return false; + } + + bool try_timed_lock(long current_thread_id,::boost::system_time const& target) + { + if(mutex.timed_lock(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; + typedef basic_recursive_mutex_impl<basic_timed_mutex> basic_recursive_timed_mutex; + } +} + +#define BOOST_BASIC_RECURSIVE_MUTEX_INITIALIZER {0} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/win32/basic_timed_mutex.hpp b/boost/thread/win32/basic_timed_mutex.hpp new file mode 100644 index 0000000000..a88c2a0f6f --- /dev/null +++ b/boost/thread/win32/basic_timed_mutex.hpp @@ -0,0 +1,209 @@ +#ifndef BOOST_BASIC_TIMED_MUTEX_WIN32_HPP +#define BOOST_BASIC_TIMED_MUTEX_WIN32_HPP + +// basic_timed_mutex_win32.hpp +// +// (C) Copyright 2006-8 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/assert.hpp> +#include <boost/thread/win32/thread_primitives.hpp> +#include <boost/thread/win32/interlocked_read.hpp> +#include <boost/thread/thread_time.hpp> +#include <boost/thread/xtime.hpp> +#include <boost/detail/interlocked.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + namespace detail + { + struct basic_timed_mutex + { + BOOST_STATIC_CONSTANT(unsigned char,lock_flag_bit=31); + BOOST_STATIC_CONSTANT(unsigned char,event_set_flag_bit=30); + BOOST_STATIC_CONSTANT(long,lock_flag_value=1<<lock_flag_bit); + BOOST_STATIC_CONSTANT(long,event_set_flag_value=1<<event_set_flag_bit); + long active_count; + void* event; + + void initialize() + { + active_count=0; + event=0; + } + + void destroy() + { +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4312) +#endif + void* const old_event=BOOST_INTERLOCKED_EXCHANGE_POINTER(&event,0); +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + if(old_event) + { + win32::CloseHandle(old_event); + } + } + + + bool try_lock() + { + return !win32::interlocked_bit_test_and_set(&active_count,lock_flag_bit); + } + + void lock() + { + if(try_lock()) + { + return; + } + 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 + { + BOOST_VERIFY(win32::WaitForSingleObject( + sem,::boost::detail::win32::infinite)==0); + clear_waiting_and_try_lock(old_count); + lock_acquired=!(old_count&lock_flag_value); + } + while(!lock_acquired); + } + } + void mark_waiting_and_try_lock(long& old_count) + { + for(;;) + { + long const new_count=(old_count&lock_flag_value)?(old_count+1):(old_count|lock_flag_value); + long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count); + if(current==old_count) + { + break; + } + old_count=current; + } + } + + void clear_waiting_and_try_lock(long& old_count) + { + old_count&=~lock_flag_value; + old_count|=event_set_flag_value; + for(;;) + { + long const new_count=((old_count&lock_flag_value)?old_count:((old_count-1)|lock_flag_value))&~event_set_flag_value; + long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count); + if(current==old_count) + { + break; + } + old_count=current; + } + } + + + bool timed_lock(::boost::system_time const& wait_until) + { + 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 + { + if(win32::WaitForSingleObject(sem,::boost::detail::get_milliseconds_until(wait_until))!=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; + } + + template<typename Duration> + bool timed_lock(Duration const& timeout) + { + return timed_lock(get_system_time()+timeout); + } + + bool timed_lock(boost::xtime const& timeout) + { + return timed_lock(system_time(timeout)); + } + + void unlock() + { + long const offset=lock_flag_value; + long const old_count=BOOST_INTERLOCKED_EXCHANGE_ADD(&active_count,lock_flag_value); + if(!(old_count&event_set_flag_value) && (old_count>offset)) + { + if(!win32::interlocked_bit_test_and_set(&active_count,event_set_flag_bit)) + { + win32::SetEvent(get_event()); + } + } + } + + private: + void* get_event() + { + void* current_event=::boost::detail::interlocked_read_acquire(&event); + + if(!current_event) + { + void* const new_event=win32::create_anonymous_event(win32::auto_reset_event,win32::event_initially_reset); +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4311) +#pragma warning(disable:4312) +#endif + void* const old_event=BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(&event,new_event,0); +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + if(old_event!=0) + { + win32::CloseHandle(new_event); + return old_event; + } + else + { + return new_event; + } + } + return current_event; + } + + }; + + } +} + +#define BOOST_BASIC_TIMED_MUTEX_INITIALIZER {0} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/win32/condition_variable.hpp b/boost/thread/win32/condition_variable.hpp new file mode 100644 index 0000000000..056bda8086 --- /dev/null +++ b/boost/thread/win32/condition_variable.hpp @@ -0,0 +1,418 @@ +#ifndef BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP +#define BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2007-8 Anthony Williams + +#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/thread_time.hpp> +#include <boost/thread/win32/interlocked_read.hpp> +#include <boost/thread/xtime.hpp> +#include <vector> +#include <boost/intrusive_ptr.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + namespace detail + { + class basic_cv_list_entry; + void intrusive_ptr_add_ref(basic_cv_list_entry * p); + void intrusive_ptr_release(basic_cv_list_entry * p); + + class basic_cv_list_entry + { + private: + detail::win32::handle_manager semaphore; + detail::win32::handle_manager wake_sem; + long waiters; + bool notified; + long references; + + basic_cv_list_entry(basic_cv_list_entry&); + void operator=(basic_cv_list_entry&); + + public: + 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()), + waiters(1),notified(false),references(0) + {} + + static bool no_waiters(boost::intrusive_ptr<basic_cv_list_entry> const& entry) + { + return !detail::interlocked_read_acquire(&entry->waiters); + } + + void add_waiter() + { + BOOST_INTERLOCKED_INCREMENT(&waiters); + } + + void remove_waiter() + { + BOOST_INTERLOCKED_DECREMENT(&waiters); + } + + void release(unsigned count_to_release) + { + notified=true; + detail::win32::ReleaseSemaphore(semaphore,count_to_release,0); + } + + void release_waiters() + { + release(detail::interlocked_read_acquire(&waiters)); + } + + bool is_notified() const + { + return notified; + } + + bool wait(timeout wait_until) + { + return this_thread::interruptible_wait(semaphore,wait_until); + } + + bool woken() + { + unsigned long const woken_result=detail::win32::WaitForSingleObject(wake_sem,0); + BOOST_ASSERT((woken_result==detail::win32::timeout) || (woken_result==0)); + return woken_result==0; + } + + friend void intrusive_ptr_add_ref(basic_cv_list_entry * p); + friend void intrusive_ptr_release(basic_cv_list_entry * p); + }; + + inline void intrusive_ptr_add_ref(basic_cv_list_entry * p) + { + BOOST_INTERLOCKED_INCREMENT(&p->references); + } + + inline void intrusive_ptr_release(basic_cv_list_entry * p) + { + if(!BOOST_INTERLOCKED_DECREMENT(&p->references)) + { + delete p; + } + } + + class basic_condition_variable + { + boost::mutex internal_mutex; + long total_count; + unsigned active_generation_count; + + typedef basic_cv_list_entry list_entry; + + typedef boost::intrusive_ptr<list_entry> entry_ptr; + typedef std::vector<entry_ptr> generation_list; + + generation_list generations; + detail::win32::handle_manager wake_sem; + + void wake_waiters(long count_to_wake) + { + detail::interlocked_write_release(&total_count,total_count-count_to_wake); + detail::win32::ReleaseSemaphore(wake_sem,count_to_wake,0); + } + + template<typename lock_type> + struct relocker + { + lock_type& lock; + bool unlocked; + + relocker(lock_type& lock_): + lock(lock_),unlocked(false) + {} + void unlock() + { + lock.unlock(); + unlocked=true; + } + ~relocker() + { + if(unlocked) + { + lock.lock(); + } + + } + private: + relocker(relocker&); + void operator=(relocker&); + }; + + + entry_ptr get_wait_entry() + { + boost::lock_guard<boost::mutex> internal_lock(internal_mutex); + + if(!wake_sem) + { + wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX); + BOOST_ASSERT(wake_sem); + } + + detail::interlocked_write_release(&total_count,total_count+1); + if(generations.empty() || generations.back()->is_notified()) + { + entry_ptr new_entry(new list_entry(wake_sem)); + generations.push_back(new_entry); + return new_entry; + } + else + { + generations.back()->add_waiter(); + return generations.back(); + } + } + + struct entry_manager + { + entry_ptr const entry; + + entry_manager(entry_ptr const& entry_): + entry(entry_) + {} + + ~entry_manager() + { + entry->remove_waiter(); + } + + list_entry* operator->() + { + 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) + { + relocker<lock_type> locker(lock); + + entry_manager entry(get_wait_entry()); + + locker.unlock(); + + bool woken=false; + while(!woken) + { + if(!entry->wait(wait_until)) + { + return false; + } + + woken=entry->woken(); + } + return woken; + } + + template<typename lock_type,typename predicate_type> + bool do_wait(lock_type& m,timeout const& wait_until,predicate_type pred) + { + while (!pred()) + { + if(!do_wait(m, wait_until)) + return pred(); + } + return true; + } + + basic_condition_variable(const basic_condition_variable& other); + basic_condition_variable& operator=(const basic_condition_variable& other); + + public: + basic_condition_variable(): + total_count(0),active_generation_count(0),wake_sem(0) + {} + + ~basic_condition_variable() + {} + + void notify_one() + { + if(detail::interlocked_read_acquire(&total_count)) + { + boost::lock_guard<boost::mutex> internal_lock(internal_mutex); + if(!total_count) + { + return; + } + wake_waiters(1); + + for(generation_list::iterator it=generations.begin(), + end=generations.end(); + it!=end;++it) + { + (*it)->release(1); + } + generations.erase(std::remove_if(generations.begin(),generations.end(),&basic_cv_list_entry::no_waiters),generations.end()); + } + } + + void notify_all() + { + if(detail::interlocked_read_acquire(&total_count)) + { + boost::lock_guard<boost::mutex> internal_lock(internal_mutex); + if(!total_count) + { + return; + } + wake_waiters(total_count); + for(generation_list::iterator it=generations.begin(), + end=generations.end(); + it!=end;++it) + { + (*it)->release_waiters(); + } + generations.clear(); + wake_sem=detail::win32::handle(0); + } + } + + }; + } + + class condition_variable: + private detail::basic_condition_variable + { + private: + condition_variable(condition_variable&); + void operator=(condition_variable&); + public: + condition_variable() + {} + + using detail::basic_condition_variable::notify_one; + using detail::basic_condition_variable::notify_all; + + void wait(unique_lock<mutex>& m) + { + do_wait(m,detail::timeout::sentinel()); + } + + template<typename predicate_type> + void wait(unique_lock<mutex>& m,predicate_type pred) + { + while(!pred()) wait(m); + } + + + bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until) + { + return do_wait(m,wait_until); + } + + bool timed_wait(unique_lock<mutex>& m,boost::xtime const& wait_until) + { + return do_wait(m,system_time(wait_until)); + } + template<typename duration_type> + bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration) + { + return do_wait(m,wait_duration.total_milliseconds()); + } + + template<typename predicate_type> + bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until,predicate_type pred) + { + return do_wait(m,wait_until,pred); + } + template<typename predicate_type> + bool timed_wait(unique_lock<mutex>& m,boost::xtime const& wait_until,predicate_type pred) + { + return do_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) + { + return do_wait(m,wait_duration.total_milliseconds(),pred); + } + }; + + class condition_variable_any: + private detail::basic_condition_variable + { + private: + condition_variable_any(condition_variable_any&); + void operator=(condition_variable_any&); + public: + condition_variable_any() + {} + + using detail::basic_condition_variable::notify_one; + using detail::basic_condition_variable::notify_all; + + template<typename lock_type> + void wait(lock_type& m) + { + do_wait(m,detail::timeout::sentinel()); + } + + template<typename lock_type,typename predicate_type> + void wait(lock_type& m,predicate_type pred) + { + while(!pred()) wait(m); + } + + template<typename lock_type> + bool timed_wait(lock_type& m,boost::system_time const& wait_until) + { + return do_wait(m,wait_until); + } + + template<typename lock_type> + bool timed_wait(lock_type& m,boost::xtime const& wait_until) + { + return do_wait(m,system_time(wait_until)); + } + + template<typename lock_type,typename duration_type> + bool timed_wait(lock_type& m,duration_type const& wait_duration) + { + return do_wait(m,wait_duration.total_milliseconds()); + } + + template<typename lock_type,typename predicate_type> + bool timed_wait(lock_type& m,boost::system_time const& wait_until,predicate_type pred) + { + return do_wait(m,wait_until,pred); + } + + template<typename lock_type,typename predicate_type> + bool timed_wait(lock_type& m,boost::xtime const& wait_until,predicate_type pred) + { + return do_wait(m,system_time(wait_until),pred); + } + + template<typename lock_type,typename duration_type,typename predicate_type> + bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred) + { + return do_wait(m,wait_duration.total_milliseconds(),pred); + } + }; + +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/win32/interlocked_read.hpp b/boost/thread/win32/interlocked_read.hpp new file mode 100644 index 0000000000..133fb6f975 --- /dev/null +++ b/boost/thread/win32/interlocked_read.hpp @@ -0,0 +1,80 @@ +#ifndef BOOST_THREAD_DETAIL_INTERLOCKED_READ_WIN32_HPP +#define BOOST_THREAD_DETAIL_INTERLOCKED_READ_WIN32_HPP + +// interlocked_read_win32.hpp +// +// (C) Copyright 2005-8 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/detail/interlocked.hpp> + +#include <boost/config/abi_prefix.hpp> + +#ifdef BOOST_MSVC + +extern "C" void _ReadWriteBarrier(void); +#pragma intrinsic(_ReadWriteBarrier) + +namespace boost +{ + namespace detail + { + inline long interlocked_read_acquire(long volatile* x) + { + long const res=*x; + _ReadWriteBarrier(); + return res; + } + inline void* interlocked_read_acquire(void* volatile* x) + { + void* const res=*x; + _ReadWriteBarrier(); + return res; + } + + inline void interlocked_write_release(long volatile* x,long value) + { + _ReadWriteBarrier(); + *x=value; + } + inline void interlocked_write_release(void* volatile* x,void* value) + { + _ReadWriteBarrier(); + *x=value; + } + } +} + +#else + +namespace boost +{ + namespace detail + { + inline long interlocked_read_acquire(long volatile* x) + { + return BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,0,0); + } + inline void* interlocked_read_acquire(void* volatile* x) + { + return BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(x,0,0); + } + inline void interlocked_write_release(long volatile* x,long value) + { + BOOST_INTERLOCKED_EXCHANGE(x,value); + } + inline void interlocked_write_release(void* volatile* x,void* value) + { + BOOST_INTERLOCKED_EXCHANGE_POINTER(x,value); + } + } +} + +#endif + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/win32/mutex.hpp b/boost/thread/win32/mutex.hpp new file mode 100644 index 0000000000..92b2669e49 --- /dev/null +++ b/boost/thread/win32/mutex.hpp @@ -0,0 +1,69 @@ +#ifndef BOOST_THREAD_WIN32_MUTEX_HPP +#define BOOST_THREAD_WIN32_MUTEX_HPP +// (C) Copyright 2005-7 Anthony Williams +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/thread/win32/basic_timed_mutex.hpp> +#include <boost/utility.hpp> +#include <boost/thread/exceptions.hpp> +#include <boost/thread/locks.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + namespace detail + { + typedef ::boost::detail::basic_timed_mutex underlying_mutex; + } + + class mutex: + public ::boost::detail::underlying_mutex + { + private: + mutex(mutex const&); + mutex& operator=(mutex const&); + public: + mutex() + { + initialize(); + } + ~mutex() + { + destroy(); + } + + typedef unique_lock<mutex> scoped_lock; + typedef detail::try_lock_wrapper<mutex> scoped_try_lock; + }; + + typedef mutex try_mutex; + + class timed_mutex: + public ::boost::detail::basic_timed_mutex + { + private: + timed_mutex(timed_mutex const&); + timed_mutex& operator=(timed_mutex const&); + public: + timed_mutex() + { + initialize(); + } + + ~timed_mutex() + { + destroy(); + } + + typedef unique_lock<timed_mutex> scoped_timed_lock; + typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock; + typedef scoped_timed_lock scoped_lock; + }; +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/win32/once.hpp b/boost/thread/win32/once.hpp new file mode 100644 index 0000000000..e1b1843230 --- /dev/null +++ b/boost/thread/win32/once.hpp @@ -0,0 +1,205 @@ +#ifndef BOOST_THREAD_WIN32_ONCE_HPP +#define BOOST_THREAD_WIN32_ONCE_HPP + +// once.hpp +// +// (C) Copyright 2005-7 Anthony Williams +// (C) Copyright 2005 John Maddock +// +// 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 <cstring> +#include <cstddef> +#include <boost/assert.hpp> +#include <boost/static_assert.hpp> +#include <boost/detail/interlocked.hpp> +#include <boost/thread/win32/thread_primitives.hpp> +#include <boost/thread/win32/interlocked_read.hpp> + +#include <boost/config/abi_prefix.hpp> + +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std +{ + using ::memcpy; + using ::ptrdiff_t; +} +#endif + +namespace boost +{ + struct once_flag + { + long status; + long count; + }; + +#define BOOST_ONCE_INIT {0,0} + + namespace detail + { +#ifdef BOOST_NO_ANSI_APIS + typedef wchar_t once_char_type; +#else + typedef char once_char_type; +#endif + unsigned const once_mutex_name_fixed_length=54; + unsigned const once_mutex_name_length=once_mutex_name_fixed_length+ + sizeof(void*)*2+sizeof(unsigned long)*2+1; + + template <class I> + void int_to_string(I p, once_char_type* buf) + { + for(unsigned i=0; i < sizeof(I)*2; ++i,++buf) + { +#ifdef BOOST_NO_ANSI_APIS + once_char_type const a=L'A'; +#else + once_char_type const a='A'; +#endif + *buf = a + static_cast<once_char_type>((p >> (i*4)) & 0x0f); + } + *buf = 0; + } + + inline void name_once_mutex(once_char_type* mutex_name,void* flag_address) + { +#ifdef BOOST_NO_ANSI_APIS + static const once_char_type fixed_mutex_name[]=L"Local\\{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag"; +#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) == + (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), + mutex_name + once_mutex_name_fixed_length); + 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 + return ::boost::detail::win32::OpenEventW( +#else + return ::boost::detail::win32::OpenEventA( +#endif + ::boost::detail::win32::synchronize | + ::boost::detail::win32::event_modify_state, + false, + mutex_name); + } + + inline void* create_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 + return ::boost::detail::win32::CreateEventW( +#else + return ::boost::detail::win32::CreateEventA( +#endif + 0,::boost::detail::win32::manual_reset_event, + ::boost::detail::win32::event_initially_reset, + mutex_name); + } + } + + + template<typename Function> + void call_once(once_flag& flag,Function f) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + long const function_complete_flag_value=0xc15730e2; + long const running_value=0x7f0725e3; + long status; + bool counted=false; + detail::win32::handle_manager event_handle; + detail::once_char_type mutex_name[detail::once_mutex_name_length]; + mutex_name[0]=0; + + while((status=::boost::detail::interlocked_read_acquire(&flag.status)) + !=function_complete_flag_value) + { + status=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&flag.status,running_value,0); + if(!status) + { + try + { + if(!event_handle) + { + event_handle=detail::open_once_event(mutex_name,&flag); + } + if(event_handle) + { + ::boost::detail::win32::ResetEvent(event_handle); + } + f(); + if(!counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + counted=true; + } + BOOST_INTERLOCKED_EXCHANGE(&flag.status,function_complete_flag_value); + if(!event_handle && + (::boost::detail::interlocked_read_acquire(&flag.count)>1)) + { + event_handle=detail::create_once_event(mutex_name,&flag); + } + if(event_handle) + { + ::boost::detail::win32::SetEvent(event_handle); + } + break; + } + catch(...) + { + BOOST_INTERLOCKED_EXCHANGE(&flag.status,0); + if(!event_handle) + { + event_handle=detail::open_once_event(mutex_name,&flag); + } + if(event_handle) + { + ::boost::detail::win32::SetEvent(event_handle); + } + throw; + } + } + + if(!counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + counted=true; + status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==function_complete_flag_value) + { + break; + } + if(!event_handle) + { + event_handle=detail::create_once_event(mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject( + event_handle,::boost::detail::win32::infinite)); + } + } +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/win32/recursive_mutex.hpp b/boost/thread/win32/recursive_mutex.hpp new file mode 100644 index 0000000000..7832bf270d --- /dev/null +++ b/boost/thread/win32/recursive_mutex.hpp @@ -0,0 +1,68 @@ +#ifndef BOOST_RECURSIVE_MUTEX_WIN32_HPP +#define BOOST_RECURSIVE_MUTEX_WIN32_HPP + +// recursive_mutex.hpp +// +// (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 +// 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> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + class recursive_mutex: + public ::boost::detail::basic_recursive_mutex + { + private: + recursive_mutex(recursive_mutex const&); + recursive_mutex& operator=(recursive_mutex const&); + public: + recursive_mutex() + { + ::boost::detail::basic_recursive_mutex::initialize(); + } + ~recursive_mutex() + { + ::boost::detail::basic_recursive_mutex::destroy(); + } + + typedef unique_lock<recursive_mutex> scoped_lock; + typedef detail::try_lock_wrapper<recursive_mutex> scoped_try_lock; + }; + + typedef recursive_mutex recursive_try_mutex; + + 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: + recursive_timed_mutex() + { + ::boost::detail::basic_recursive_timed_mutex::initialize(); + } + ~recursive_timed_mutex() + { + ::boost::detail::basic_recursive_timed_mutex::destroy(); + } + + 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; + }; +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/win32/shared_mutex.hpp b/boost/thread/win32/shared_mutex.hpp new file mode 100644 index 0000000000..aee40399e4 --- /dev/null +++ b/boost/thread/win32/shared_mutex.hpp @@ -0,0 +1,619 @@ +#ifndef BOOST_THREAD_WIN32_SHARED_MUTEX_HPP +#define BOOST_THREAD_WIN32_SHARED_MUTEX_HPP + +// (C) Copyright 2006-8 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/assert.hpp> +#include <boost/detail/interlocked.hpp> +#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> + +#include <boost/config/abi_prefix.hpp> + +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, + shared_waiting:11, + exclusive:1, + upgrade:1, + exclusive_waiting:7, + exclusive_waiting_blocked:1; + + friend bool operator==(state_data const& lhs,state_data const& rhs) + { + return *reinterpret_cast<unsigned const*>(&lhs)==*reinterpret_cast<unsigned const*>(&rhs); + } + }; + + + template<typename T> + T interlocked_compare_exchange(T* target,T new_value,T comparand) + { + BOOST_STATIC_ASSERT(sizeof(T)==sizeof(long)); + long const res=BOOST_INTERLOCKED_COMPARE_EXCHANGE(reinterpret_cast<long*>(target), + *reinterpret_cast<long*>(&new_value), + *reinterpret_cast<long*>(&comparand)); + return *reinterpret_cast<T const*>(&res); + } + + enum + { + unlock_sem = 0, + exclusive_sem = 1 + }; + + state_data state; + detail::win32::handle semaphores[2]; + detail::win32::handle upgrade_sem; + + void release_waiters(state_data old_state) + { + if(old_state.exclusive_waiting) + { + BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[exclusive_sem],1,0)!=0); + } + + if(old_state.shared_waiting || old_state.exclusive_waiting) + { + BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0); + } + } + + + public: + shared_mutex() + { + semaphores[unlock_sem]=detail::win32::create_anonymous_semaphore(0,LONG_MAX); + semaphores[exclusive_sem]=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX); + if (!semaphores[exclusive_sem]) + { + detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX); + boost::throw_exception(thread_resource_error()); + } + upgrade_sem=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX); + if (!upgrade_sem) + { + detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX); + detail::win32::release_semaphore(semaphores[exclusive_sem],LONG_MAX); + boost::throw_exception(thread_resource_error()); + } + state_data state_={0}; + state=state_; + } + + ~shared_mutex() + { + detail::win32::CloseHandle(upgrade_sem); + detail::win32::CloseHandle(semaphores[unlock_sem]); + detail::win32::CloseHandle(semaphores[exclusive_sem]); + } + + bool try_lock_shared() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + if(!new_state.exclusive && !new_state.exclusive_waiting_blocked) + { + ++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; + } + return !(old_state.exclusive| old_state.exclusive_waiting_blocked); + } + + void lock_shared() + { + BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel())); + } + + template<typename TimeDuration> + bool timed_lock_shared(TimeDuration const & relative_time) + { + return timed_lock_shared(get_system_time()+relative_time); + } + + bool timed_lock_shared(boost::system_time const& wait_until) + { + for(;;) + { + 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; + } + + unsigned long const res=detail::win32::WaitForSingleObject(semaphores[unlock_sem],::boost::detail::get_milliseconds_until(wait_until)); + 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); + } + } + + void unlock_shared() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + bool const last_reader=!--new_state.shared_count; + + if(last_reader) + { + if(new_state.upgrade) + { + new_state.upgrade=false; + new_state.exclusive=true; + } + else + { + if(new_state.exclusive_waiting) + { + --new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=false; + } + new_state.shared_waiting=0; + } + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + if(last_reader) + { + if(old_state.upgrade) + { + BOOST_VERIFY(detail::win32::ReleaseSemaphore(upgrade_sem,1,0)!=0); + } + else + { + release_waiters(old_state); + } + } + break; + } + old_state=current_state; + } + } + + void lock() + { + BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel())); + } + + template<typename TimeDuration> + bool timed_lock(TimeDuration const & relative_time) + { + return timed_lock(get_system_time()+relative_time); + } + + bool try_lock() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + if(new_state.shared_count || new_state.exclusive) + { + return 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; + } + return true; + } + + + bool timed_lock(boost::system_time const& wait_until) + { + 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 + unsigned long const wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,wait_all,::boost::detail::get_milliseconds_until(wait_until)); + 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); + } + } + + void unlock() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + new_state.exclusive=false; + if(new_state.exclusive_waiting) + { + --new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=false; + } + new_state.shared_waiting=0; + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + release_waiters(old_state); + } + + void lock_upgrade() + { + for(;;) + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade) + { + ++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()); + } + new_state.upgrade=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.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgrade)) + { + return; + } + + BOOST_VERIFY(!detail::win32::WaitForSingleObject(semaphores[unlock_sem],detail::win32::infinite)); + } + } + + bool try_lock_upgrade() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade) + { + return false; + } + else + { + ++new_state.shared_count; + if(!new_state.shared_count) + { + return false; + } + new_state.upgrade=true; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + return true; + } + + void unlock_upgrade() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + new_state.upgrade=false; + bool const last_reader=!--new_state.shared_count; + + if(last_reader) + { + if(new_state.exclusive_waiting) + { + --new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=false; + } + new_state.shared_waiting=0; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + if(last_reader) + { + release_waiters(old_state); + } + break; + } + old_state=current_state; + } + } + + void unlock_upgrade_and_lock() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + bool const last_reader=!--new_state.shared_count; + + if(last_reader) + { + new_state.upgrade=false; + new_state.exclusive=true; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + if(!last_reader) + { + BOOST_VERIFY(!detail::win32::WaitForSingleObject(upgrade_sem,detail::win32::infinite)); + } + break; + } + old_state=current_state; + } + } + + void unlock_and_lock_upgrade() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + new_state.exclusive=false; + new_state.upgrade=true; + ++new_state.shared_count; + if(new_state.exclusive_waiting) + { + --new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=false; + } + new_state.shared_waiting=0; + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + release_waiters(old_state); + } + + void unlock_and_lock_shared() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + new_state.exclusive=false; + ++new_state.shared_count; + if(new_state.exclusive_waiting) + { + --new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=false; + } + new_state.shared_waiting=0; + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + release_waiters(old_state); + } + + void unlock_upgrade_and_lock_shared() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + new_state.upgrade=false; + if(new_state.exclusive_waiting) + { + --new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=false; + } + new_state.shared_waiting=0; + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + release_waiters(old_state); + } + + }; +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/win32/thread_data.hpp b/boost/thread/win32/thread_data.hpp new file mode 100644 index 0000000000..d5303d897d --- /dev/null +++ b/boost/thread/win32/thread_data.hpp @@ -0,0 +1,183 @@ +#ifndef BOOST_THREAD_PTHREAD_THREAD_DATA_HPP +#define BOOST_THREAD_PTHREAD_THREAD_DATA_HPP +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2008 Anthony Williams + +#include <boost/thread/detail/config.hpp> +#include <boost/intrusive_ptr.hpp> +#include <boost/thread/thread_time.hpp> +#include <boost/thread/win32/thread_primitives.hpp> +#include <boost/thread/win32/thread_heap_alloc.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + namespace detail + { + struct thread_exit_callback_node; + struct tss_data_node; + + struct thread_data_base; + void intrusive_ptr_add_ref(thread_data_base * p); + void intrusive_ptr_release(thread_data_base * p); + + struct BOOST_SYMBOL_VISIBLE thread_data_base + { + long count; + detail::win32::handle_manager thread_handle; + detail::win32::handle_manager interruption_handle; + boost::detail::thread_exit_callback_node* thread_exit_callbacks; + boost::detail::tss_data_node* tss_data; + bool interruption_enabled; + unsigned id; + + thread_data_base(): + count(0),thread_handle(detail::win32::invalid_handle_value), + interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset)), + thread_exit_callbacks(0),tss_data(0), + interruption_enabled(true), + id(0) + {} + virtual ~thread_data_base() + {} + + friend void intrusive_ptr_add_ref(thread_data_base * p) + { + BOOST_INTERLOCKED_INCREMENT(&p->count); + } + + friend void intrusive_ptr_release(thread_data_base * p) + { + if(!BOOST_INTERLOCKED_DECREMENT(&p->count)) + { + detail::heap_delete(p); + } + } + + void interrupt() + { + BOOST_VERIFY(detail::win32::SetEvent(interruption_handle)!=0); + } + + typedef detail::win32::handle native_handle_type; + + virtual void run()=0; + }; + + typedef boost::intrusive_ptr<detail::thread_data_base> thread_data_ptr; + + struct BOOST_SYMBOL_VISIBLE timeout + { + unsigned long start; + uintmax_t milliseconds; + bool relative; + boost::system_time abs_time; + + static unsigned long const max_non_infinite_wait=0xfffffffe; + + timeout(uintmax_t milliseconds_): + start(win32::GetTickCount()), + milliseconds(milliseconds_), + relative(true), + abs_time(boost::get_system_time()) + {} + + timeout(boost::system_time const& abs_time_): + start(win32::GetTickCount()), + milliseconds(0), + relative(false), + abs_time(abs_time_) + {} + + struct BOOST_SYMBOL_VISIBLE remaining_time + { + bool more; + unsigned long milliseconds; + + remaining_time(uintmax_t remaining): + more(remaining>max_non_infinite_wait), + milliseconds(more?max_non_infinite_wait:(unsigned long)remaining) + {} + }; + + remaining_time remaining_milliseconds() const + { + if(is_sentinel()) + { + return remaining_time(win32::infinite); + } + else if(relative) + { + unsigned long const now=win32::GetTickCount(); + unsigned long const elapsed=now-start; + return remaining_time((elapsed<milliseconds)?(milliseconds-elapsed):0); + } + else + { + system_time const now=get_system_time(); + if(abs_time<=now) + { + return remaining_time(0); + } + return remaining_time((abs_time-now).total_milliseconds()+1); + } + } + + bool is_sentinel() const + { + return milliseconds==~uintmax_t(0); + } + + + static timeout sentinel() + { + return timeout(sentinel_type()); + } + private: + struct sentinel_type + {}; + + explicit timeout(sentinel_type): + start(0),milliseconds(~uintmax_t(0)),relative(true) + {} + }; + + inline uintmax_t pin_to_zero(intmax_t value) + { + return (value<0)?0u:(uintmax_t)value; + } + } + + namespace this_thread + { + void BOOST_THREAD_DECL yield(); + + bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time); + inline void interruptible_wait(uintmax_t milliseconds) + { + interruptible_wait(detail::win32::invalid_handle_value,milliseconds); + } + inline BOOST_SYMBOL_VISIBLE void interruptible_wait(system_time const& abs_time) + { + interruptible_wait(detail::win32::invalid_handle_value,abs_time); + } + + template<typename TimeDuration> + inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time) + { + interruptible_wait(detail::pin_to_zero(rel_time.total_milliseconds())); + } + inline BOOST_SYMBOL_VISIBLE void sleep(system_time const& abs_time) + { + interruptible_wait(abs_time); + } + } + +} + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/win32/thread_heap_alloc.hpp b/boost/thread/win32/thread_heap_alloc.hpp new file mode 100644 index 0000000000..b7d329f31c --- /dev/null +++ b/boost/thread/win32/thread_heap_alloc.hpp @@ -0,0 +1,398 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2007 Anthony Williams +#ifndef THREAD_HEAP_ALLOC_HPP +#define THREAD_HEAP_ALLOC_HPP +#include <new> +#include <boost/thread/win32/thread_primitives.hpp> +#include <stdexcept> +#include <boost/assert.hpp> +#include <boost/throw_exception.hpp> + +#if defined( BOOST_USE_WINDOWS_H ) +# include <windows.h> + +namespace boost +{ + namespace detail + { + namespace win32 + { + using ::GetProcessHeap; + using ::HeapAlloc; + using ::HeapFree; + } + } +} + +#else + +# ifdef HeapAlloc +# undef HeapAlloc +# endif + +namespace boost +{ + namespace detail + { + namespace win32 + { + extern "C" + { + __declspec(dllimport) handle __stdcall GetProcessHeap(); + __declspec(dllimport) void* __stdcall HeapAlloc(handle,unsigned long,ulong_ptr); + __declspec(dllimport) int __stdcall HeapFree(handle,unsigned long,void*); + } + } + } +} + +#endif + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + namespace detail + { + inline void* allocate_raw_heap_memory(unsigned size) + { + void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,size); + if(!heap_memory) + { + boost::throw_exception(std::bad_alloc()); + } + return heap_memory; + } + + inline void free_raw_heap_memory(void* heap_memory) + { + BOOST_VERIFY(detail::win32::HeapFree(detail::win32::GetProcessHeap(),0,heap_memory)!=0); + } + + template<typename T> + inline T* heap_new() + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + try + { + T* const data=new (heap_memory) T(); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } + +#ifndef BOOST_NO_RVALUE_REFERENCES + template<typename T,typename A1> + inline T* heap_new(A1&& a1) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + try + { + T* const data=new (heap_memory) T(static_cast<A1&&>(a1)); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } + 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 + { + T* const data=new (heap_memory) T(static_cast<A1&&>(a1),static_cast<A2&&>(a2)); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } + 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 + { + T* const data=new (heap_memory) T(static_cast<A1&&>(a1),static_cast<A2&&>(a2), + static_cast<A3&&>(a3)); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } + 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 + { + 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(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } +#else + template<typename T,typename A1> + inline T* heap_new_impl(A1 a1) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + try + { + T* const data=new (heap_memory) T(a1); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } + + 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 + { + T* const data=new (heap_memory) T(a1,a2); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } + + 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 + { + T* const data=new (heap_memory) T(a1,a2,a3); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } + + 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 + { + T* const data=new (heap_memory) T(a1,a2,a3,a4); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } + + + template<typename T,typename A1> + inline T* heap_new(A1 const& a1) + { + return heap_new_impl<T,A1 const&>(a1); + } + template<typename T,typename A1> + inline T* heap_new(A1& a1) + { + return heap_new_impl<T,A1&>(a1); + } + + template<typename T,typename A1,typename A2> + inline T* heap_new(A1 const& a1,A2 const& a2) + { + return heap_new_impl<T,A1 const&,A2 const&>(a1,a2); + } + template<typename T,typename A1,typename A2> + inline T* heap_new(A1& a1,A2 const& a2) + { + return heap_new_impl<T,A1&,A2 const&>(a1,a2); + } + template<typename T,typename A1,typename A2> + inline T* heap_new(A1 const& a1,A2& a2) + { + return heap_new_impl<T,A1 const&,A2&>(a1,a2); + } + template<typename T,typename A1,typename A2> + inline T* heap_new(A1& a1,A2& a2) + { + return heap_new_impl<T,A1&,A2&>(a1,a2); + } + + template<typename T,typename A1,typename A2,typename A3> + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3) + { + return heap_new_impl<T,A1 const&,A2 const&,A3 const&>(a1,a2,a3); + } + template<typename T,typename A1,typename A2,typename A3> + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3) + { + return heap_new_impl<T,A1&,A2 const&,A3 const&>(a1,a2,a3); + } + template<typename T,typename A1,typename A2,typename A3> + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3) + { + return heap_new_impl<T,A1 const&,A2&,A3 const&>(a1,a2,a3); + } + template<typename T,typename A1,typename A2,typename A3> + inline T* heap_new(A1& a1,A2& a2,A3 const& a3) + { + return heap_new_impl<T,A1&,A2&,A3 const&>(a1,a2,a3); + } + + template<typename T,typename A1,typename A2,typename A3> + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3) + { + return heap_new_impl<T,A1 const&,A2 const&,A3&>(a1,a2,a3); + } + template<typename T,typename A1,typename A2,typename A3> + inline T* heap_new(A1& a1,A2 const& a2,A3& a3) + { + return heap_new_impl<T,A1&,A2 const&,A3&>(a1,a2,a3); + } + template<typename T,typename A1,typename A2,typename A3> + inline T* heap_new(A1 const& a1,A2& a2,A3& a3) + { + return heap_new_impl<T,A1 const&,A2&,A3&>(a1,a2,a3); + } + template<typename T,typename A1,typename A2,typename A3> + inline T* heap_new(A1& a1,A2& a2,A3& a3) + { + return heap_new_impl<T,A1&,A2&,A3&>(a1,a2,a3); + } + + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl<T,A1 const&,A2 const&,A3 const&,A4 const&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl<T,A1&,A2 const&,A3 const&,A4 const&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl<T,A1 const&,A2&,A3 const&,A4 const&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl<T,A1&,A2&,A3 const&,A4 const&>(a1,a2,a3,a4); + } + + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4 const& a4) + { + return heap_new_impl<T,A1 const&,A2 const&,A3&,A4 const&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4 const& a4) + { + return heap_new_impl<T,A1&,A2 const&,A3&,A4 const&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4 const& a4) + { + return heap_new_impl<T,A1 const&,A2&,A3&,A4 const&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1& a1,A2& a2,A3& a3,A4 const& a4) + { + return heap_new_impl<T,A1&,A2&,A3&,A4 const&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4& a4) + { + return heap_new_impl<T,A1 const&,A2 const&,A3 const&,A4&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4& a4) + { + return heap_new_impl<T,A1&,A2 const&,A3 const&,A4&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4& a4) + { + return heap_new_impl<T,A1 const&,A2&,A3 const&,A4&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4& a4) + { + return heap_new_impl<T,A1&,A2&,A3 const&,A4&>(a1,a2,a3,a4); + } + + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4& a4) + { + return heap_new_impl<T,A1 const&,A2 const&,A3&,A4&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4& a4) + { + return heap_new_impl<T,A1&,A2 const&,A3&,A4&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4& a4) + { + return heap_new_impl<T,A1 const&,A2&,A3&,A4&>(a1,a2,a3,a4); + } + template<typename T,typename A1,typename A2,typename A3,typename A4> + inline T* heap_new(A1& a1,A2& a2,A3& a3,A4& a4) + { + return heap_new_impl<T,A1&,A2&,A3&,A4&>(a1,a2,a3,a4); + } + +#endif + template<typename T> + inline void heap_delete(T* data) + { + data->~T(); + free_raw_heap_memory(data); + } + + template<typename T> + struct do_heap_delete + { + void operator()(T* data) const + { + detail::heap_delete(data); + } + }; + } +} + +#include <boost/config/abi_suffix.hpp> + + +#endif diff --git a/boost/thread/win32/thread_primitives.hpp b/boost/thread/win32/thread_primitives.hpp new file mode 100644 index 0000000000..0166f37d36 --- /dev/null +++ b/boost/thread/win32/thread_primitives.hpp @@ -0,0 +1,416 @@ +#ifndef BOOST_WIN32_THREAD_PRIMITIVES_HPP +#define BOOST_WIN32_THREAD_PRIMITIVES_HPP + +// win32_thread_primitives.hpp +// +// (C) Copyright 2005-7 Anthony Williams +// (C) Copyright 2007 David Deakins +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/config.hpp> +#include <boost/throw_exception.hpp> +#include <boost/assert.hpp> +#include <boost/thread/exceptions.hpp> +#include <boost/detail/interlocked.hpp> +#include <algorithm> + +#if defined( BOOST_USE_WINDOWS_H ) +# include <windows.h> + +namespace boost +{ + namespace detail + { + namespace win32 + { + typedef ULONG_PTR ulong_ptr; + typedef HANDLE handle; + unsigned const infinite=INFINITE; + unsigned const timeout=WAIT_TIMEOUT; + handle const invalid_handle_value=INVALID_HANDLE_VALUE; + unsigned const event_modify_state=EVENT_MODIFY_STATE; + unsigned const synchronize=SYNCHRONIZE; + +# ifdef BOOST_NO_ANSI_APIS + using ::CreateMutexW; + using ::CreateEventW; + using ::OpenEventW; + using ::CreateSemaphoreW; +# else + using ::CreateMutexA; + using ::CreateEventA; + using ::OpenEventA; + using ::CreateSemaphoreA; +# endif + using ::CloseHandle; + using ::ReleaseMutex; + using ::ReleaseSemaphore; + using ::SetEvent; + using ::ResetEvent; + using ::WaitForMultipleObjects; + using ::WaitForSingleObject; + using ::GetCurrentProcessId; + using ::GetCurrentThreadId; + using ::GetCurrentThread; + using ::GetCurrentProcess; + using ::DuplicateHandle; + using ::SleepEx; + using ::Sleep; + using ::QueueUserAPC; + using ::GetTickCount; + } + } +} +#elif defined( WIN32 ) || defined( _WIN32 ) || defined( __WIN32__ ) + +# ifdef UNDER_CE +# ifndef WINAPI +# ifndef _WIN32_WCE_EMULATION +# define WINAPI __cdecl // Note this doesn't match the desktop definition +# else +# define WINAPI __stdcall +# endif +# endif + +# ifdef __cplusplus +extern "C" { +# endif +typedef int BOOL; +typedef unsigned long DWORD; +typedef void* HANDLE; + +# include <kfuncs.h> +# ifdef __cplusplus +} +# endif +# endif + +namespace boost +{ + namespace detail + { + namespace win32 + { + +# ifdef _WIN64 + typedef unsigned __int64 ulong_ptr; +# else + typedef unsigned long ulong_ptr; +# endif + typedef void* handle; + unsigned const infinite=~0U; + unsigned const timeout=258U; + handle const invalid_handle_value=(handle)(-1); + unsigned const event_modify_state=2; + unsigned const synchronize=0x100000u; + + extern "C" + { + struct _SECURITY_ATTRIBUTES; +# ifdef BOOST_NO_ANSI_APIS + __declspec(dllimport) void* __stdcall CreateMutexW(_SECURITY_ATTRIBUTES*,int,wchar_t const*); + __declspec(dllimport) void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES*,long,long,wchar_t const*); + __declspec(dllimport) void* __stdcall CreateEventW(_SECURITY_ATTRIBUTES*,int,int,wchar_t const*); + __declspec(dllimport) void* __stdcall OpenEventW(unsigned long,int,wchar_t const*); +# else + __declspec(dllimport) void* __stdcall CreateMutexA(_SECURITY_ATTRIBUTES*,int,char const*); + __declspec(dllimport) void* __stdcall CreateSemaphoreA(_SECURITY_ATTRIBUTES*,long,long,char const*); + __declspec(dllimport) void* __stdcall CreateEventA(_SECURITY_ATTRIBUTES*,int,int,char const*); + __declspec(dllimport) void* __stdcall OpenEventA(unsigned long,int,char const*); +# endif + __declspec(dllimport) int __stdcall CloseHandle(void*); + __declspec(dllimport) int __stdcall ReleaseMutex(void*); + __declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void*,unsigned long); + __declspec(dllimport) unsigned long __stdcall WaitForMultipleObjects(unsigned long nCount,void* const * lpHandles,int bWaitAll,unsigned long dwMilliseconds); + __declspec(dllimport) int __stdcall ReleaseSemaphore(void*,long,long*); + __declspec(dllimport) int __stdcall DuplicateHandle(void*,void*,void*,void**,unsigned long,int,unsigned long); + __declspec(dllimport) unsigned long __stdcall SleepEx(unsigned long,int); + __declspec(dllimport) void __stdcall Sleep(unsigned long); + typedef void (__stdcall *queue_user_apc_callback_function)(ulong_ptr); + __declspec(dllimport) unsigned long __stdcall QueueUserAPC(queue_user_apc_callback_function,void*,ulong_ptr); + + __declspec(dllimport) unsigned long __stdcall GetTickCount(); + +# ifndef UNDER_CE + __declspec(dllimport) unsigned long __stdcall GetCurrentProcessId(); + __declspec(dllimport) unsigned long __stdcall GetCurrentThreadId(); + __declspec(dllimport) void* __stdcall GetCurrentThread(); + __declspec(dllimport) void* __stdcall GetCurrentProcess(); + __declspec(dllimport) int __stdcall SetEvent(void*); + __declspec(dllimport) int __stdcall ResetEvent(void*); +# else + using ::GetCurrentProcessId; + using ::GetCurrentThreadId; + using ::GetCurrentThread; + using ::GetCurrentProcess; + using ::SetEvent; + using ::ResetEvent; +# endif + } + } + } +} +#else +# error "Win32 functions not available" +#endif + +#include <boost/config/abi_prefix.hpp> + +namespace boost +{ + namespace detail + { + namespace win32 + { + enum event_type + { + auto_reset_event=false, + manual_reset_event=true + }; + + enum initial_event_state + { + event_initially_reset=false, + event_initially_set=true + }; + + inline handle create_anonymous_event(event_type type,initial_event_state state) + { +#if !defined(BOOST_NO_ANSI_APIS) + handle const res=win32::CreateEventA(0,type,state,0); +#else + handle const res=win32::CreateEventW(0,type,state,0); +#endif + if(!res) + { + boost::throw_exception(thread_resource_error()); + } + return res; + } + + inline handle create_anonymous_semaphore(long initial_count,long max_count) + { +#if !defined(BOOST_NO_ANSI_APIS) + handle const res=CreateSemaphoreA(0,initial_count,max_count,0); +#else + handle const res=CreateSemaphoreW(0,initial_count,max_count,0); +#endif + if(!res) + { + boost::throw_exception(thread_resource_error()); + } + return res; + } + inline handle create_anonymous_semaphore_nothrow(long initial_count,long max_count) + { +#if !defined(BOOST_NO_ANSI_APIS) + handle const res=CreateSemaphoreA(0,initial_count,max_count,0); +#else + handle const res=CreateSemaphoreW(0,initial_count,max_count,0); +#endif + return res; + } + + inline handle duplicate_handle(handle source) + { + handle const current_process=GetCurrentProcess(); + long const same_access_flag=2; + handle new_handle=0; + bool const success=DuplicateHandle(current_process,source,current_process,&new_handle,0,false,same_access_flag)!=0; + if(!success) + { + boost::throw_exception(thread_resource_error()); + } + return new_handle; + } + + inline void release_semaphore(handle semaphore,long count) + { + BOOST_VERIFY(ReleaseSemaphore(semaphore,count,0)!=0); + } + + class handle_manager + { + private: + handle handle_to_manage; + handle_manager(handle_manager&); + handle_manager& operator=(handle_manager&); + + void cleanup() + { + if(handle_to_manage && handle_to_manage!=invalid_handle_value) + { + BOOST_VERIFY(CloseHandle(handle_to_manage)); + } + } + + public: + explicit handle_manager(handle handle_to_manage_): + handle_to_manage(handle_to_manage_) + {} + handle_manager(): + handle_to_manage(0) + {} + + handle_manager& operator=(handle new_handle) + { + cleanup(); + handle_to_manage=new_handle; + return *this; + } + + operator handle() const + { + return handle_to_manage; + } + + handle duplicate() const + { + return duplicate_handle(handle_to_manage); + } + + void swap(handle_manager& other) + { + std::swap(handle_to_manage,other.handle_to_manage); + } + + handle release() + { + handle const res=handle_to_manage; + handle_to_manage=0; + return res; + } + + bool operator!() const + { + return !handle_to_manage; + } + + ~handle_manager() + { + cleanup(); + } + }; + + } + } +} + +#if defined(BOOST_MSVC) && (_MSC_VER>=1400) && !defined(UNDER_CE) + +namespace boost +{ + namespace detail + { + namespace win32 + { +#if _MSC_VER==1400 + extern "C" unsigned char _interlockedbittestandset(long *a,long b); + extern "C" unsigned char _interlockedbittestandreset(long *a,long b); +#else + extern "C" unsigned char _interlockedbittestandset(volatile long *a,long b); + extern "C" unsigned char _interlockedbittestandreset(volatile long *a,long b); +#endif + +#pragma intrinsic(_interlockedbittestandset) +#pragma intrinsic(_interlockedbittestandreset) + + inline bool interlocked_bit_test_and_set(long* x,long bit) + { + return _interlockedbittestandset(x,bit)!=0; + } + + inline bool interlocked_bit_test_and_reset(long* x,long bit) + { + return _interlockedbittestandreset(x,bit)!=0; + } + + } + } +} +#define BOOST_THREAD_BTS_DEFINED +#elif (defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)) && defined(_M_IX86) +namespace boost +{ + namespace detail + { + namespace win32 + { + inline bool interlocked_bit_test_and_set(long* x,long bit) + { + __asm { + mov eax,bit; + mov edx,x; + lock bts [edx],eax; + setc al; + }; + } + + inline bool interlocked_bit_test_and_reset(long* x,long bit) + { + __asm { + mov eax,bit; + mov edx,x; + lock btr [edx],eax; + setc al; + }; + } + + } + } +} +#define BOOST_THREAD_BTS_DEFINED +#endif + +#ifndef BOOST_THREAD_BTS_DEFINED + +namespace boost +{ + namespace detail + { + namespace win32 + { + inline bool interlocked_bit_test_and_set(long* x,long bit) + { + long const value=1<<bit; + long old=*x; + do + { + long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,old|value,old); + if(current==old) + { + break; + } + old=current; + } + while(true); + return (old&value)!=0; + } + + inline bool interlocked_bit_test_and_reset(long* x,long bit) + { + long const value=1<<bit; + long old=*x; + do + { + long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,old&~value,old); + if(current==old) + { + break; + } + old=current; + } + while(true); + return (old&value)!=0; + } + } + } +} +#endif + +#include <boost/config/abi_suffix.hpp> + +#endif diff --git a/boost/thread/xtime.hpp b/boost/thread/xtime.hpp new file mode 100644 index 0000000000..7cc6272d6a --- /dev/null +++ b/boost/thread/xtime.hpp @@ -0,0 +1,92 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// Copyright (C) 2007-8 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_XTIME_WEK070601_HPP +#define BOOST_XTIME_WEK070601_HPP + +#include <boost/thread/detail/config.hpp> + +#include <boost/cstdint.hpp> +#include <boost/thread/thread_time.hpp> +#include <boost/date_time/posix_time/conversion.hpp> + +#include <boost/config/abi_prefix.hpp> + +namespace boost { + +enum xtime_clock_types +{ + TIME_UTC=1 +// TIME_TAI, +// TIME_MONOTONIC, +// TIME_PROCESS, +// TIME_THREAD, +// TIME_LOCAL, +// TIME_SYNC, +// TIME_RESOLUTION +}; + +struct xtime +{ +#if defined(BOOST_NO_INT64_T) + typedef int_fast32_t xtime_sec_t; //INT_FAST32_MIN <= sec <= INT_FAST32_MAX +#else + typedef int_fast64_t xtime_sec_t; //INT_FAST64_MIN <= sec <= INT_FAST64_MAX +#endif + + typedef int_fast32_t xtime_nsec_t; //0 <= xtime.nsec < NANOSECONDS_PER_SECOND + + xtime_sec_t sec; + xtime_nsec_t nsec; + + operator system_time() const + { + return boost::posix_time::from_time_t(0)+ + boost::posix_time::seconds(static_cast<long>(sec))+ +#ifdef BOOST_DATE_TIME_HAS_NANOSECONDS + boost::posix_time::nanoseconds(nsec); +#else + 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; +} + +inline int xtime_get(struct xtime* xtp, int clock_type) +{ + if (clock_type == TIME_UTC) + { + *xtp=get_xtime(get_system_time()); + return clock_type; + } + return 0; +} + + +inline int xtime_cmp(const xtime& xt1, const xtime& xt2) +{ + if (xt1.sec == xt2.sec) + return (int)(xt1.nsec - xt2.nsec); + else + return (xt1.sec > xt2.sec) ? 1 : -1; +} + +} // namespace boost + +#include <boost/config/abi_suffix.hpp> + +#endif //BOOST_XTIME_WEK070601_HPP |