#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-2010 Anthony Williams // (C) Copyright 2011-2012 Vicente J. Botet Escriba #include #include #include #ifndef BOOST_NO_IOSTREAM #include #endif #include #include #if defined BOOST_THREAD_USES_DATETIME #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef BOOST_THREAD_USES_CHRONO #include #include #endif #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) #include #endif #include #ifdef BOOST_MSVC #pragma warning(push) #pragma warning(disable:4251) #endif namespace boost { namespace detail { #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) template class thread_data: public detail::thread_data_base { public: BOOST_THREAD_NO_COPYABLE(thread_data) thread_data(BOOST_THREAD_RV_REF(F) f_, BOOST_THREAD_RV_REF(ArgTypes)... args_): fp(boost::forward(f_), boost::forward(args_)...) {} template void run2(tuple_indices) { invoke(std::move(std::get<0>(fp)), std::move(std::get(fp))...); } void run() { typedef typename make_tuple_indices >::value, 1>::type index_type; run2(index_type()); } private: std::tuple::type, typename decay::type...> fp; }; #else // defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) template class thread_data: public detail::thread_data_base { public: BOOST_THREAD_NO_COPYABLE(thread_data) #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES thread_data(BOOST_THREAD_RV_REF(F) f_): f(boost::forward(f_)) {} // This overloading must be removed if we want the packaged_task's tests to pass. // thread_data(F& f_): // f(f_) // {} #else thread_data(BOOST_THREAD_RV_REF(F) f_): f(f_) {} thread_data(F f_): f(f_) {} #endif //thread_data() {} void run() { f(); } private: F f; }; template class thread_data >: public detail::thread_data_base { private: F& f; public: BOOST_THREAD_NO_COPYABLE(thread_data) thread_data(boost::reference_wrapper f_): f(f_) {} void run() { f(); } }; template class thread_data >: public detail::thread_data_base { private: F& f; public: BOOST_THREAD_NO_COPYABLE(thread_data) thread_data(const boost::reference_wrapper f_): f(f_) {} void run() { f(); } }; #endif } class BOOST_THREAD_DECL thread { public: typedef thread_attributes attributes; BOOST_THREAD_MOVABLE_ONLY(thread) private: struct dummy; void release_handle(); detail::thread_data_ptr thread_info; private: bool start_thread_noexcept(); bool start_thread_noexcept(const attributes& attr); //public: void start_thread() { if (!start_thread_noexcept()) { boost::throw_exception(thread_resource_error()); } } void start_thread(const attributes& attr) { if (!start_thread_noexcept(attr)) { boost::throw_exception(thread_resource_error()); } } explicit thread(detail::thread_data_ptr data); detail::thread_data_ptr get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const; #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) template static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_RV_REF(ArgTypes)... args) { return detail::thread_data_ptr(detail::heap_new< detail::thread_data::type, ArgTypes...> >( boost::forward(f), boost::forward(args)... ) ); } #else template static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f) { return detail::thread_data_ptr(detail::heap_new::type> >( boost::forward(f))); } #endif static inline detail::thread_data_ptr make_thread_info(void (*f)()) { return detail::thread_data_ptr(detail::heap_new >( boost::forward(f))); } #else template static inline detail::thread_data_ptr make_thread_info(F f , typename disable_if_c< //boost::thread_detail::is_convertible::value || is_same::type, thread>::value, dummy* >::type=0 ) { return detail::thread_data_ptr(detail::heap_new >(f)); } template static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f) { return detail::thread_data_ptr(detail::heap_new >(f)); } #endif public: #if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF. #if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) thread(const volatile thread&); #endif #endif thread() BOOST_NOEXCEPT; ~thread() { #if defined BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE if (joinable()) { std::terminate(); } #else detach(); #endif } #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template < class F > explicit thread(BOOST_THREAD_RV_REF(F) f //, typename disable_if::type, thread>, dummy* >::type=0 ): thread_info(make_thread_info(thread_detail::decay_copy(boost::forward(f)))) { start_thread(); } template < class F > thread(attributes const& attrs, BOOST_THREAD_RV_REF(F) f): thread_info(make_thread_info(thread_detail::decay_copy(boost::forward(f)))) { start_thread(attrs); } #else #ifdef BOOST_NO_SFINAE template explicit thread(F f): thread_info(make_thread_info(f)) { start_thread(); } template thread(attributes const& attrs, F f): thread_info(make_thread_info(f)) { start_thread(attrs); } #else template explicit thread(F f , typename disable_if_c< boost::thread_detail::is_rv::value // todo ass a thread_detail::is_rv //boost::thread_detail::is_convertible::value //|| is_same::type, thread>::value , dummy* >::type=0 ): thread_info(make_thread_info(f)) { start_thread(); } template thread(attributes const& attrs, F f , typename disable_if, dummy* >::type=0 //, typename disable_if, dummy* >::type=0 ): thread_info(make_thread_info(f)) { start_thread(attrs); } #endif template explicit thread(BOOST_THREAD_RV_REF(F) f , typename disable_if::type, thread>, dummy* >::type=0 ): #ifdef BOOST_THREAD_USES_MOVE thread_info(make_thread_info(boost::move(f))) // todo : Add forward #else thread_info(make_thread_info(f)) // todo : Add forward #endif { start_thread(); } template thread(attributes const& attrs, BOOST_THREAD_RV_REF(F) f): #ifdef BOOST_THREAD_USES_MOVE thread_info(make_thread_info(boost::move(f))) // todo : Add forward #else thread_info(make_thread_info(f)) // todo : Add forward #endif { start_thread(attrs); } #endif thread(BOOST_THREAD_RV_REF(thread) x) BOOST_NOEXCEPT { thread_info=BOOST_THREAD_RV(x).thread_info; BOOST_THREAD_RV(x).thread_info.reset(); } #if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF. #if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) thread& operator=(thread x) { swap(x); return *this; } #endif #endif thread& operator=(BOOST_THREAD_RV_REF(thread) other) BOOST_NOEXCEPT { #if defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE if (joinable()) std::terminate(); #endif thread_info=BOOST_THREAD_RV(other).thread_info; BOOST_THREAD_RV(other).thread_info.reset(); return *this; } #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) template thread(F&& f, Arg&& arg, Args&&... args) : thread_info(make_thread_info( thread_detail::decay_copy(boost::forward(f)), thread_detail::decay_copy(boost::forward(arg)), thread_detail::decay_copy(boost::forward(args))...) ) { start_thread(); } template thread(attributes const& attrs, F&& f, Arg&& arg, Args&&... args) : thread_info(make_thread_info( thread_detail::decay_copy(boost::forward(f)), thread_detail::decay_copy(boost::forward(arg)), thread_detail::decay_copy(boost::forward(args))...) ) { start_thread(attrs); } #else template thread(F f,A1 a1,typename disable_if, dummy* >::type=0): thread_info(make_thread_info(boost::bind(boost::type(),f,a1))) { start_thread(); } template thread(F f,A1 a1,A2 a2): thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2))) { start_thread(); } template thread(F f,A1 a1,A2 a2,A3 a3): thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3))) { start_thread(); } template thread(F f,A1 a1,A2 a2,A3 a3,A4 a4): thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4))) { start_thread(); } template thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5): thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4,a5))) { start_thread(); } template thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6): thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4,a5,a6))) { start_thread(); } template 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(),f,a1,a2,a3,a4,a5,a6,a7))) { start_thread(); } template 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(),f,a1,a2,a3,a4,a5,a6,a7,a8))) { start_thread(); } template 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(),f,a1,a2,a3,a4,a5,a6,a7,a8,a9))) { start_thread(); } #endif void swap(thread& x) BOOST_NOEXCEPT { thread_info.swap(x.thread_info); } class id; #ifdef BOOST_THREAD_PLATFORM_PTHREAD inline id get_id() const BOOST_NOEXCEPT; #else id get_id() const BOOST_NOEXCEPT; #endif bool joinable() const BOOST_NOEXCEPT; private: bool join_noexcept(); public: inline void join(); #ifdef BOOST_THREAD_USES_CHRONO #if defined(BOOST_THREAD_PLATFORM_WIN32) template bool try_join_for(const chrono::duration& rel_time) { chrono::milliseconds rel_time2= chrono::ceil(rel_time); return do_try_join_until(rel_time2.count()); } #else template bool try_join_for(const chrono::duration& rel_time) { return try_join_until(chrono::steady_clock::now() + rel_time); } #endif template bool try_join_until(const chrono::time_point& t) { using namespace chrono; system_clock::time_point s_now = system_clock::now(); bool joined= false; do { typename Clock::duration d = ceil(t-Clock::now()); if (d <= Clock::duration::zero()) return false; // in case the Clock::time_point t is already reached joined = try_join_until(s_now + d); } while (! joined); return true; } template bool try_join_until(const chrono::time_point& t) { using namespace chrono; typedef time_point nano_sys_tmpt; return try_join_until(nano_sys_tmpt(ceil(t.time_since_epoch()))); } #endif #if defined(BOOST_THREAD_PLATFORM_WIN32) private: bool do_try_join_until_noexcept(uintmax_t milli, bool& res); inline bool do_try_join_until(uintmax_t milli); public: bool timed_join(const system_time& abs_time); //{ // return do_try_join_until(get_milliseconds_until(wait_until)); //} #ifdef BOOST_THREAD_USES_CHRONO bool try_join_until(const chrono::time_point& tp) { chrono::milliseconds rel_time= chrono::ceil(tp-chrono::system_clock::now()); return do_try_join_until(rel_time.count()); } #endif #else private: bool do_try_join_until_noexcept(struct timespec const &timeout, bool& res); inline bool do_try_join_until(struct timespec const &timeout); public: #if defined BOOST_THREAD_USES_DATETIME bool timed_join(const system_time& abs_time) { struct timespec const ts=detail::to_timespec(abs_time); return do_try_join_until(ts); } #endif #ifdef BOOST_THREAD_USES_CHRONO bool try_join_until(const chrono::time_point& tp) { using namespace chrono; nanoseconds d = tp.time_since_epoch(); timespec ts = boost::detail::to_timespec(d); return do_try_join_until(ts); } #endif #endif public: #if defined BOOST_THREAD_USES_DATETIME template inline bool timed_join(TimeDuration const& rel_time) { return timed_join(get_system_time()+rel_time); } #endif void detach(); static unsigned hardware_concurrency() BOOST_NOEXCEPT; static unsigned physical_concurrency() BOOST_NOEXCEPT; #define BOOST_THREAD_DEFINES_THREAD_NATIVE_HANDLE typedef detail::thread_data_base::native_handle_type native_handle_type; native_handle_type native_handle(); #if defined BOOST_THREAD_PROVIDES_THREAD_EQ // Use thread::id when comparisions are needed // backwards compatibility bool operator==(const thread& other) const; bool operator!=(const thread& other) const; #endif #if defined BOOST_THREAD_USES_DATETIME static inline void yield() BOOST_NOEXCEPT { this_thread::yield(); } static inline void sleep(const system_time& xt) { this_thread::sleep(xt); } #endif #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS // extensions void interrupt(); bool interruption_requested() const BOOST_NOEXCEPT; #endif }; inline void swap(thread& lhs,thread& rhs) BOOST_NOEXCEPT { return lhs.swap(rhs); } #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES inline thread&& move(thread& t) BOOST_NOEXCEPT { return static_cast(t); } #endif BOOST_THREAD_DCL_MOVABLE(thread) namespace this_thread { #ifdef BOOST_THREAD_PLATFORM_PTHREAD inline thread::id get_id() BOOST_NOEXCEPT; #else thread::id BOOST_THREAD_DECL get_id() BOOST_NOEXCEPT; #endif #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS void BOOST_THREAD_DECL interruption_point(); bool BOOST_THREAD_DECL interruption_enabled() BOOST_NOEXCEPT; bool BOOST_THREAD_DECL interruption_requested() BOOST_NOEXCEPT; #endif #if defined BOOST_THREAD_USES_DATETIME inline BOOST_SYMBOL_VISIBLE void sleep(xtime const& abs_time) { sleep(system_time(abs_time)); } #endif } class BOOST_SYMBOL_VISIBLE thread::id { private: friend inline std::size_t hash_value(const thread::id &v) { #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID return hash_value(v.thread_data); #else return hash_value(v.thread_data.get()); #endif } #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID #if defined(BOOST_THREAD_PLATFORM_WIN32) typedef unsigned int data; #else typedef thread::native_handle_type data; #endif #else typedef detail::thread_data_ptr data; #endif data thread_data; id(data thread_data_): thread_data(thread_data_) {} friend class thread; friend id BOOST_THREAD_DECL this_thread::get_id() BOOST_NOEXCEPT; public: id() BOOST_NOEXCEPT: #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID thread_data(0) #else thread_data() #endif {} id(const id& other) BOOST_NOEXCEPT : thread_data(other.thread_data) {} bool operator==(const id& y) const BOOST_NOEXCEPT { return thread_data==y.thread_data; } bool operator!=(const id& y) const BOOST_NOEXCEPT { return thread_data!=y.thread_data; } bool operator<(const id& y) const BOOST_NOEXCEPT { return thread_data(const id& y) const BOOST_NOEXCEPT { return y.thread_data=(const id& y) const BOOST_NOEXCEPT { return !(thread_data friend BOOST_SYMBOL_VISIBLE std::basic_ostream& operator<<(std::basic_ostream& 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 BOOST_SYMBOL_VISIBLE std::basic_ostream& print(std::basic_ostream& os) const { if(thread_data) { io::ios_flags_saver ifs( os ); return os<< std::hex << thread_data; } else { return os<<"{Not-any-thread}"; } } #endif #endif }; #ifdef BOOST_THREAD_PLATFORM_PTHREAD thread::id thread::get_id() const BOOST_NOEXCEPT { #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID return const_cast(this)->native_handle(); #else detail::thread_data_ptr const local_thread_info=(get_thread_info)(); return (local_thread_info? id(local_thread_info) : id()); #endif } namespace this_thread { inline thread::id get_id() BOOST_NOEXCEPT { #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID return pthread_self(); #else boost::detail::thread_data_base* const thread_info=get_or_make_current_thread_data(); return (thread_info?thread::id(thread_info->shared_from_this()):thread::id()); #endif } } #endif void thread::join() { if (this_thread::get_id() == get_id()) boost::throw_exception(thread_resource_error(static_cast(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself")); BOOST_THREAD_VERIFY_PRECONDITION( join_noexcept(), thread_resource_error(static_cast(system::errc::invalid_argument), "boost thread: thread not joinable") ); } #ifdef BOOST_THREAD_PLATFORM_PTHREAD bool thread::do_try_join_until(struct timespec const &timeout) #else bool thread::do_try_join_until(uintmax_t timeout) #endif { if (this_thread::get_id() == get_id()) boost::throw_exception(thread_resource_error(static_cast(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself")); bool res; if (do_try_join_until_noexcept(timeout, res)) { return res; } else { BOOST_THREAD_THROW_ELSE_RETURN( (thread_resource_error(static_cast(system::errc::invalid_argument), "boost thread: thread not joinable")), false ); } } #if !defined(BOOST_NO_IOSTREAM) && defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) template BOOST_SYMBOL_VISIBLE std::basic_ostream& operator<<(std::basic_ostream& os, const thread::id& x) { return x.print(os); } #endif #if defined BOOST_THREAD_PROVIDES_THREAD_EQ 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(); } #endif namespace detail { struct thread_exit_function_base { virtual ~thread_exit_function_base() {} virtual void operator()()=0; }; template 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*); struct shared_state_base; #if defined(BOOST_THREAD_PLATFORM_WIN32) inline void make_ready_at_thread_exit(shared_ptr as) { detail::thread_data_base* const current_thread_data(detail::get_current_thread_data()); if(current_thread_data) { current_thread_data->make_ready_at_thread_exit(as); } } #else void BOOST_THREAD_DECL make_ready_at_thread_exit(shared_ptr as); #endif } namespace this_thread { template void at_thread_exit(F f) { detail::thread_exit_function_base* const thread_exit_func=detail::heap_new >(f); detail::add_thread_exit_function(thread_exit_func); } } } #ifdef BOOST_MSVC #pragma warning(pop) #endif #include #endif