From 315af061cd4fc97b0115a13a6892668a0a90ea25 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Sun, 4 Nov 2012 16:47:02 +0000 Subject: [PATCH] Thread: Added promise::set_..._at_thread_exit [SVN r81172] --- include/boost/thread/detail/config.hpp | 4 +- include/boost/thread/future.hpp | 434 +++++++++++++++++- include/boost/thread/lockable_traits.hpp | 186 ++++---- include/boost/thread/pthread/thread_data.hpp | 15 +- include/boost/thread/win32/thread_data.hpp | 12 +- src/pthread/thread.cpp | 40 +- src/win32/thread.cpp | 64 +-- test/Jamfile.v2 | 6 + .../set_exception_at_thread_exit_pass.cpp | 78 ++++ .../set_lvalue_at_thread_exit_pass.cpp | 49 ++ .../set_rvalue_at_thread_exit_pass.cpp | 48 ++ .../set_value_at_thread_exit_const_pass.cpp | 45 ++ .../set_value_at_thread_exit_void_pass.cpp | 87 ++++ test/test_4882.cpp | 17 +- 14 files changed, 952 insertions(+), 133 deletions(-) create mode 100644 test/sync/futures/promise/set_exception_at_thread_exit_pass.cpp create mode 100644 test/sync/futures/promise/set_lvalue_at_thread_exit_pass.cpp create mode 100644 test/sync/futures/promise/set_rvalue_at_thread_exit_pass.cpp create mode 100644 test/sync/futures/promise/set_value_at_thread_exit_const_pass.cpp create mode 100644 test/sync/futures/promise/set_value_at_thread_exit_void_pass.cpp diff --git a/include/boost/thread/detail/config.hpp b/include/boost/thread/detail/config.hpp index 71033f3b..e0d28783 100644 --- a/include/boost/thread/detail/config.hpp +++ b/include/boost/thread/detail/config.hpp @@ -73,8 +73,8 @@ // PROVIDE_PROMISE_LAZY #if ! defined BOOST_THREAD_DONT_PROVIDE_PROMISE_LAZY \ - && ! defined BOOST_THREAD_PROMISE_LAZY -#define BOOST_THREAD_PROMISE_LAZY + && ! defined BOOST_THREAD_PROVIDES_PROMISE_LAZY +#define BOOST_THREAD_PROVIDES_PROMISE_LAZY #endif // PROVIDE_THREAD_EQ diff --git a/include/boost/thread/future.hpp b/include/boost/thread/future.hpp index 27fc8c3c..9a8e3bf2 100644 --- a/include/boost/thread/future.hpp +++ b/include/boost/thread/future.hpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -257,11 +258,13 @@ namespace boost relocker& operator=(relocker const&); }; - struct future_object_base + struct future_object_base : enable_shared_from_this { + boost::exception_ptr exception; bool done; bool is_deferred; + bool is_constructed; #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS bool thread_was_interrupted; #endif @@ -276,7 +279,8 @@ namespace boost future_object_base(): done(false), - is_deferred(false) + is_deferred(false), + is_constructed(false) #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS , thread_was_interrupted(false) #endif @@ -334,6 +338,13 @@ namespace boost } do_continuation(lock); } + void make_ready() + { + //std::cout << __FILE__ << ":" << __LINE__ < lock(mutex); + mark_finished_internal(lock); + //std::cout << __FILE__ << ":" << __LINE__ <& lock) { @@ -348,17 +359,24 @@ namespace boost void wait_internal(boost::unique_lock &lock, bool rethrow=true) { + //std::cout << __FILE__ << ":" << __LINE__ < lock(mutex); + //std::cout << __FILE__ << ":" << __LINE__ <& lock) { + //std::cout << "**************"<<__FILE__ << ":" << __LINE__ < lock(mutex); + //std::cout << __FILE__ << ":" << __LINE__ < lk(mutex); + //std::cout << __FILE__ << ":" << __LINE__ <make_ready_at_thread_exit(shared_from_this()); + //std::cout << __FILE__ << ":" << __LINE__ < lock(mutex); return done && !(exception #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS || thread_was_interrupted +#endif + ); + } + bool has_value(unique_lock& ) + { + //std::cout << __FILE__ << ":" << __LINE__ <&) + { + return done && (exception +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + || thread_was_interrupted +#endif + ); + } template void set_wait_callback(F f,U* u) @@ -596,7 +660,9 @@ namespace boost move_dest_type get() { + //std::cout << __FILE__ << ":" << __LINE__ <(*result); //return boost::move(*result); // todo check why this doesn't works (references?) } @@ -621,6 +687,138 @@ namespace boost } } + + //void set_value_at_thread_exit(source_reference_type result_) + void set_value_at_thread_exit(const T & result_) + { + //std::cout << __FILE__ << ":" << __LINE__ < lk(this->mutex); + //std::cout << __FILE__ << ":" << __LINE__ <has_value(lk)) + { + //std::cout << __FILE__ << ":" << __LINE__ <::init(result,result_); + //std::cout << __FILE__ << ":" << __LINE__ <is_constructed = true; + //std::cout << __FILE__ << ":" << __LINE__ <make_ready_at_thread_exit(shared_from_this()); + //std::cout << __FILE__ << ":" << __LINE__ < lk(this->mutex); + if (this->has_value(lk)) + throw_exception(promise_already_satisfied()); + future_traits::init(result,static_cast(result_)); + this->is_constructed = true; + get_current_thread_data()->make_ready_at_thread_exit(shared_from_this()); + } + + + private: + future_object(future_object const&); + future_object& operator=(future_object const&); + }; + + template + struct future_object: + detail::future_object_base + { + typedef typename future_traits::storage_type storage_type; + typedef typename future_traits::source_reference_type source_reference_type; + typedef typename future_traits::rvalue_source_type rvalue_source_type; + typedef typename future_traits::move_dest_type move_dest_type; + typedef typename future_traits::shared_future_get_result_type shared_future_get_result_type; + + T* result; + + future_object(): + result(0) + {} + + ~future_object() + { + } + + void mark_finished_with_result_internal(T& result_, boost::unique_lock& lock) + { + //future_traits::init(result,result_); + result= &result_; + mark_finished_internal(lock); + } + +// void mark_finished_with_result_internal(rvalue_source_type result_, boost::unique_lock& lock) +// { +// future_traits::init(result,static_cast(result_)); +// mark_finished_internal(lock); +// } + + void mark_finished_with_result(T& result_) + { + boost::unique_lock lock(mutex); + mark_finished_with_result_internal(result_, lock); + } + +// void mark_finished_with_result(rvalue_source_type result_) +// { +// boost::unique_lock lock(mutex); +// mark_finished_with_result_internal(static_cast(result_), lock); +// } + + + T& get() + { + wait(); + //return static_cast(*result); + return *result; + } + + T& get_sh() + { + wait(); + //return static_cast(*result); + return *result; + } + + // todo move this to detail::future_object_base + future_state::state get_state() + { + boost::lock_guard guard(mutex); + if(!done) + { + return future_state::waiting; + } + else + { + return future_state::ready; + } + } + + void set_value_at_thread_exit(T& result_) + { + unique_lock lk(this->mutex); + if (this->has_value(lk)) + throw_exception(promise_already_satisfied()); + //future_traits::init(result,result_); + result= &result_; + this->is_constructed = true; + get_current_thread_data()->make_ready_at_thread_exit(shared_from_this()); + } +// void set_value_at_thread_exit(rvalue_source_type result_) +// { +// unique_lock lk(this->mutex); +// if (this->has_value()) +// throw_exception(promise_already_satisfied()); +// future_traits::init(result,static_cast(result_)); +// this->is_constructed = true; +// get_current_thread_data()->make_ready_at_thread_exit(shared_from_this()); +// } + + private: future_object(future_object const&); future_object& operator=(future_object const&); @@ -648,7 +846,9 @@ namespace boost void get() { - wait(); + //std::cout << __FILE__ << ":" << __LINE__ <wait(); + //std::cout << __FILE__ << ":" << __LINE__ < lk(this->mutex); + //std::cout << __FILE__ << ":" << __LINE__ <has_value(lk)) + { + //std::cout << __FILE__ << ":" << __LINE__ <is_constructed = true; + //std::cout << __FILE__ << ":" << __LINE__ <make_ready_at_thread_exit(shared_from_this()); + //std::cout << __FILE__ << ":" << __LINE__ <future_) { + //std::cout << __FILE__ << ":" << __LINE__ <future_; + //std::cout << __FILE__ << ":" << __LINE__ <future_.reset(); + //std::cout << __FILE__ << ":" << __LINE__ <get(); #else + //std::cout << __FILE__ << ":" << __LINE__ <future_->get(); #endif } @@ -1408,7 +1631,7 @@ namespace boost void lazy_init() { -#if defined BOOST_THREAD_PROMISE_LAZY +#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY if(!atomic_load(&future_)) { future_ptr blank; @@ -1432,7 +1655,7 @@ namespace boost } #endif promise(): -#if defined BOOST_THREAD_PROMISE_LAZY +#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY future_(), #else future_(new detail::future_object()), @@ -1526,9 +1749,31 @@ namespace boost } // setting the result with deferred notification - //void set_value_at_thread_exit(const R& r); // NOT YET IMPLEMENTED - //void set_value_at_thread_exit(see below); // NOT YET IMPLEMENTED - //void set_exception_at_thread_exit(exception_ptr p); // NOT YET IMPLEMENTED + void set_value_at_thread_exit(const R& r) + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_value_at_thread_exit(r); + } + + void set_value_at_thread_exit(BOOST_THREAD_RV_REF(R) r) + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_value_at_thread_exit(boost::move(r)); + } + void set_exception_at_thread_exit(exception_ptr e) + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_exception_at_thread_exit(e); + } template void set_wait_callback(F f) @@ -1539,6 +1784,148 @@ namespace boost }; + template + class promise + { + typedef boost::shared_ptr > future_ptr; + + future_ptr future_; + bool future_obtained; + + void lazy_init() + { +#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY + if(!atomic_load(&future_)) + { + future_ptr blank; + atomic_compare_exchange(&future_,&blank,future_ptr(new detail::future_object)); + } +#endif + } + + public: + BOOST_THREAD_MOVABLE_ONLY(promise) +#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS + template + promise(boost::allocator_arg_t, Allocator a) + { + typedef typename Allocator::template rebind >::other A2; + A2 a2(a); + typedef thread_detail::allocator_destructor D; + + future_ = future_ptr(::new(a2.allocate(1)) detail::future_object(), D(a2, 1) ); + future_obtained = false; + } +#endif + promise(): +#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY + future_(), +#else + future_(new detail::future_object()), +#endif + future_obtained(false) + {} + + ~promise() + { + if(future_) + { + boost::unique_lock lock(future_->mutex); + + if(!future_->done) + { + future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise()), lock); + } + } + } + + // Assignment + promise(BOOST_THREAD_RV_REF(promise) rhs) BOOST_NOEXCEPT : + future_(BOOST_THREAD_RV(rhs).future_),future_obtained(BOOST_THREAD_RV(rhs).future_obtained) + { + BOOST_THREAD_RV(rhs).future_.reset(); + BOOST_THREAD_RV(rhs).future_obtained=false; + } + promise & operator=(BOOST_THREAD_RV_REF(promise) rhs) BOOST_NOEXCEPT + { + future_=BOOST_THREAD_RV(rhs).future_; + future_obtained=BOOST_THREAD_RV(rhs).future_obtained; + BOOST_THREAD_RV(rhs).future_.reset(); + BOOST_THREAD_RV(rhs).future_obtained=false; + return *this; + } + + void swap(promise& other) + { + future_.swap(other.future_); + std::swap(future_obtained,other.future_obtained); + } + + // Result retrieval + BOOST_THREAD_FUTURE get_future() + { + lazy_init(); + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + if (future_obtained) + { + boost::throw_exception(future_already_retrieved()); + } + future_obtained=true; + return BOOST_THREAD_FUTURE(future_); + } + + void set_value(R& r) + { + lazy_init(); + boost::unique_lock lock(future_->mutex); + if(future_->done) + { + boost::throw_exception(promise_already_satisfied()); + } + future_->mark_finished_with_result_internal(r, lock); + } + + void set_exception(boost::exception_ptr p) + { + lazy_init(); + boost::unique_lock lock(future_->mutex); + if(future_->done) + { + boost::throw_exception(promise_already_satisfied()); + } + future_->mark_exceptional_finish_internal(p, lock); + } + + // setting the result with deferred notification + void set_value_at_thread_exit(R& r) + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_value_at_thread_exit(r); + } + + void set_exception_at_thread_exit(exception_ptr e) + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_exception_at_thread_exit(e); + } + + template + void set_wait_callback(F f) + { + lazy_init(); + future_->set_wait_callback(f,this); + } + + }; template <> class promise { @@ -1549,7 +1936,7 @@ namespace boost void lazy_init() { -#if defined BOOST_THREAD_PROMISE_LAZY +#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY if(!atomic_load(&future_)) { future_ptr blank; @@ -1573,7 +1960,7 @@ namespace boost } #endif promise(): -#if defined BOOST_THREAD_PROMISE_LAZY +#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY future_(), #else future_(new detail::future_object), @@ -1657,6 +2044,31 @@ namespace boost future_->mark_exceptional_finish_internal(p,lock); } + // setting the result with deferred notification + void set_value_at_thread_exit() + { + + //std::cout << __FILE__ << ":" << __LINE__ <set_value_at_thread_exit(); + //std::cout << __FILE__ << ":" << __LINE__ <set_exception_at_thread_exit(e); + } + template void set_wait_callback(F f) { diff --git a/include/boost/thread/lockable_traits.hpp b/include/boost/thread/lockable_traits.hpp index 607099df..135b1a74 100644 --- a/include/boost/thread/lockable_traits.hpp +++ b/include/boost/thread/lockable_traits.hpp @@ -8,26 +8,17 @@ #define BOOST_THREAD_LOCKABLE_TRAITS_HPP #include -#include -#include -//#include -#include #include -#ifdef BOOST_THREAD_USES_CHRONO -#include -#include -#endif #include #include -#include -#include - #include namespace boost { + namespace sync + { #if defined(BOOST_NO_SFINAE) || \ BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600)) || \ @@ -72,101 +63,130 @@ namespace boost bool, value=sizeof(has_member(0))==sizeof(true_type)); \ } - BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(lock); - BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(unlock); - BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(try_lock); + BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(lock) +; BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(unlock); + BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(try_lock); - template::value > - struct has_member_lock + template::value > + struct has_member_lock + { + BOOST_STATIC_CONSTANT(bool, value=false); + }; + + template + struct has_member_lock + { + typedef char true_type; + struct false_type { - BOOST_STATIC_CONSTANT(bool, value=false); + true_type dummy[2]; }; - template - struct has_member_lock + template + static true_type has_member(V (U::*)()); + template + static false_type has_member(U); + + BOOST_STATIC_CONSTANT( + bool,value=sizeof(has_member_lock::has_member(&T::lock))==sizeof(true_type)); + }; + + template::value > + struct has_member_unlock + { + BOOST_STATIC_CONSTANT(bool, value=false); + }; + + template + struct has_member_unlock + { + typedef char true_type; + struct false_type { - typedef char true_type; - struct false_type - { - true_type dummy[2]; - }; - - template - static true_type has_member(V (U::*)()); - template - static false_type has_member(U); - - BOOST_STATIC_CONSTANT( - bool,value=sizeof(has_member_lock::has_member(&T::lock))==sizeof(true_type)); + true_type dummy[2]; }; - template::value > - struct has_member_unlock + template + static true_type has_member(V (U::*)()); + template + static false_type has_member(U); + + BOOST_STATIC_CONSTANT( + bool,value=sizeof(has_member_unlock::has_member(&T::unlock))==sizeof(true_type)); + }; + + template::value > + struct has_member_try_lock + { + BOOST_STATIC_CONSTANT(bool, value=false); + }; + + template + struct has_member_try_lock + { + typedef char true_type; + struct false_type { - BOOST_STATIC_CONSTANT(bool, value=false); + true_type dummy[2]; }; - template - struct has_member_unlock - { - typedef char true_type; - struct false_type - { - true_type dummy[2]; - }; + template + static true_type has_member(bool (U::*)()); + template + static false_type has_member(U); - template - static true_type has_member(V (U::*)()); - template - static false_type has_member(U); - - BOOST_STATIC_CONSTANT( - bool,value=sizeof(has_member_unlock::has_member(&T::unlock))==sizeof(true_type)); - }; - - template::value > - struct has_member_try_lock - { - BOOST_STATIC_CONSTANT(bool, value=false); - }; - - template - struct has_member_try_lock - { - typedef char true_type; - struct false_type - { - true_type dummy[2]; - }; - - template - static true_type has_member(bool (U::*)()); - template - static false_type has_member(U); - - BOOST_STATIC_CONSTANT( - bool,value=sizeof(has_member_try_lock::has_member(&T::try_lock))==sizeof(true_type)); - }; + BOOST_STATIC_CONSTANT( + bool,value=sizeof(has_member_try_lock::has_member(&T::try_lock))==sizeof(true_type)); + }; } - template - struct is_mutex_type + struct is_basic_lockable { - BOOST_STATIC_CONSTANT(bool, value = detail::has_member_lock::value && - detail::has_member_unlock::value && - detail::has_member_try_lock::value); - + BOOST_STATIC_CONSTANT(bool, value = detail::has_member_lock::value && + detail::has_member_unlock::value); }; + template + struct is_lockable + { + BOOST_STATIC_CONSTANT(bool, value = + is_basic_lockable::value && + detail::has_member_try_lock::value); + }; + #else template - struct is_mutex_type + struct is_basic_lockable { - BOOST_STATIC_CONSTANT(bool, value = false); + BOOST_STATIC_CONSTANT(bool, value = false); + }; + template + struct is_lockable + { + BOOST_STATIC_CONSTANT(bool, value = false); }; #endif + template + struct is_recursive_mutex_sur_parolle + { + BOOST_STATIC_CONSTANT(bool, value = false); + }; + + template + struct is_recursive_basic_lockable + { + BOOST_STATIC_CONSTANT(bool, value = is_basic_lockable::value && + is_recursive_mutex_sur_parolle::value); + }; + } + template + struct is_mutex_type + { + BOOST_STATIC_CONSTANT(bool, value = sync::is_lockable::value); + }; + } #include diff --git a/include/boost/thread/pthread/thread_data.hpp b/include/boost/thread/pthread/thread_data.hpp index 7eb2d69e..49199e4e 100644 --- a/include/boost/thread/pthread/thread_data.hpp +++ b/include/boost/thread/pthread/thread_data.hpp @@ -78,6 +78,7 @@ namespace boost namespace detail { + struct future_object_base; struct tss_cleanup_function; struct thread_exit_callback_node; struct tss_data_node @@ -119,6 +120,9 @@ namespace boost > notify_list_t; notify_list_t notify; + typedef std::vector > async_states_t; + async_states_t async_states_; + thread_data_base(): done(false),join_started(false),joined(false), thread_exit_callbacks(0), @@ -127,7 +131,8 @@ namespace boost interrupt_requested(false), #endif current_cond(0), - notify() + notify(), + async_states_() {} virtual ~thread_data_base(); @@ -138,6 +143,14 @@ namespace boost { notify.push_back(std::pair(cv, m)); } + + void make_ready_at_thread_exit(shared_ptr as) + { + //std::cout << __FILE__ << ":" << __LINE__ < notify_list_t; notify_list_t notify; + typedef std::vector > async_states_t; + async_states_t async_states_; thread_data_base(): count(0),thread_handle(detail::win32::invalid_handle_value), @@ -118,7 +121,8 @@ namespace boost interruption_enabled(true), #endif id(0), - notify() + notify(), + async_states_() {} virtual ~thread_data_base(); @@ -150,7 +154,13 @@ namespace boost notify.push_back(std::pair(cv, m)); } + void make_ready_at_thread_exit(shared_ptr as) + { + async_states_.push_back(as); + } + }; + BOOST_THREAD_DECL thread_data_base* get_current_thread_data(); typedef boost::intrusive_ptr thread_data_ptr; diff --git a/src/pthread/thread.cpp b/src/pthread/thread.cpp index e3ca3a58..56a7937e 100644 --- a/src/pthread/thread.cpp +++ b/src/pthread/thread.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #ifdef __GLIBC__ #include @@ -34,14 +35,22 @@ namespace boost { thread_data_base::~thread_data_base() { - { for (notify_list_t::iterator i = notify.begin(), e = notify.end(); i != e; ++i) { i->second->unlock(); i->first->notify_all(); } - } + //std::cout << __FILE__ << ":" << __LINE__ <make_ready(); + //std::cout << __FILE__ << ":" << __LINE__ <(data); + //std::cout << __FILE__ << ":" << __LINE__ <tss_data.empty() || thread_info->thread_exit_callbacks) { + //std::cout << __FILE__ << ":" << __LINE__ <thread_exit_callbacks) { detail::thread_exit_callback_node* const current_node=thread_info->thread_exit_callbacks; @@ -98,8 +112,17 @@ namespace boost thread_info->tss_data.erase(current); } } + //std::cout << __FILE__ << ":" << __LINE__ <self.reset(); + } else{ + //std::cout << __FILE__ << ":" << __LINE__ < lock(thread_info->data_mutex); thread_info->done=true; thread_info->done_condition.notify_all(); + //std::cout << __FILE__ << ":" << __LINE__ < #include #include +#include #include #include @@ -37,16 +38,20 @@ namespace boost { thread_data_base::~thread_data_base() { - { for (notify_list_t::iterator i = notify.begin(), e = notify.end(); i != e; ++i) { i->second->unlock(); i->first->notify_all(); } - } + for (async_states_t::iterator i = async_states_.begin(), e = async_states_.end(); + i != e; ++i) + { + (*i)->make_ready(); + } } } + namespace { #ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11 @@ -76,15 +81,6 @@ namespace boost } } - detail::thread_data_base* get_current_thread_data() - { - if(current_thread_tls_key==TLS_OUT_OF_INDEXES) - { - return 0; - } - return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key); - } - void set_current_thread_data(detail::thread_data_base* new_data) { boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key); @@ -99,6 +95,20 @@ namespace boost } } + } + namespace detail + { + thread_data_base* get_current_thread_data() + { + if(current_thread_tls_key==TLS_OUT_OF_INDEXES) + { + return 0; + } + return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key); + } + } + namespace + { #ifndef BOOST_HAS_THREADEX // Windows CE doesn't define _beginthreadex @@ -157,7 +167,7 @@ namespace boost { void run_thread_exit_callbacks() { - detail::thread_data_ptr current_thread_data(get_current_thread_data(),false); + detail::thread_data_ptr current_thread_data(detail::get_current_thread_data(),false); if(current_thread_data) { while(! current_thread_data->tss_data.empty() || current_thread_data->thread_exit_callbacks) @@ -295,11 +305,11 @@ namespace boost detail::thread_data_base* get_or_make_current_thread_data() { - detail::thread_data_base* current_thread_data(get_current_thread_data()); + detail::thread_data_base* current_thread_data(detail::get_current_thread_data()); if(!current_thread_data) { make_external_thread_data(); - current_thread_data=get_current_thread_data(); + current_thread_data=detail::get_current_thread_data(); } return current_thread_data; } @@ -487,10 +497,10 @@ namespace boost handles[handle_count++]=handle_to_wait_for; } #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - if(get_current_thread_data() && get_current_thread_data()->interruption_enabled) + if(detail::get_current_thread_data() && detail::get_current_thread_data()->interruption_enabled) { interruption_index=handle_count; - handles[handle_count++]=get_current_thread_data()->interruption_handle; + handles[handle_count++]=detail::get_current_thread_data()->interruption_handle; } #endif detail::win32::handle_manager timer_handle; @@ -547,7 +557,7 @@ namespace boost #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS else if(notified_index==interruption_index) { - detail::win32::ResetEvent(get_current_thread_data()->interruption_handle); + detail::win32::ResetEvent(detail::get_current_thread_data()->interruption_handle); throw thread_interrupted(); } #endif @@ -584,19 +594,19 @@ namespace boost { if(interruption_enabled() && interruption_requested()) { - detail::win32::ResetEvent(get_current_thread_data()->interruption_handle); + detail::win32::ResetEvent(detail::get_current_thread_data()->interruption_handle); throw thread_interrupted(); } } bool interruption_enabled() BOOST_NOEXCEPT { - return get_current_thread_data() && get_current_thread_data()->interruption_enabled; + return detail::get_current_thread_data() && detail::get_current_thread_data()->interruption_enabled; } bool interruption_requested() BOOST_NOEXCEPT { - return get_current_thread_data() && (detail::win32::WaitForSingleObject(get_current_thread_data()->interruption_handle,0)==0); + return detail::get_current_thread_data() && (detail::win32::WaitForSingleObject(detail::get_current_thread_data()->interruption_handle,0)==0); } #endif @@ -611,15 +621,15 @@ namespace boost { if(interruption_was_enabled) { - get_current_thread_data()->interruption_enabled=false; + detail::get_current_thread_data()->interruption_enabled=false; } } disable_interruption::~disable_interruption() BOOST_NOEXCEPT { - if(get_current_thread_data()) + if(detail::get_current_thread_data()) { - get_current_thread_data()->interruption_enabled=interruption_was_enabled; + detail::get_current_thread_data()->interruption_enabled=interruption_was_enabled; } } @@ -627,15 +637,15 @@ namespace boost { if(d.interruption_was_enabled) { - get_current_thread_data()->interruption_enabled=true; + detail::get_current_thread_data()->interruption_enabled=true; } } restore_interruption::~restore_interruption() BOOST_NOEXCEPT { - if(get_current_thread_data()) + if(detail::get_current_thread_data()) { - get_current_thread_data()->interruption_enabled=false; + detail::get_current_thread_data()->interruption_enabled=false; } } } @@ -734,7 +744,7 @@ namespace boost BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock lk) { - detail::thread_data_base* const current_thread_data(get_current_thread_data()); + detail::thread_data_base* const current_thread_data(detail::get_current_thread_data()); if(current_thread_data) { current_thread_data->notify_all_at_thread_exit(&cond, lk.release()); diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index e30374d8..5ec37382 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -267,6 +267,11 @@ rule thread-compile-fail ( sources : reqs * : name ) [ thread-run2 ./sync/futures/promise/set_value_const_pass.cpp : promise__set_value_const_p ] [ thread-run2 ./sync/futures/promise/set_value_void_pass.cpp : promise__set_value_void_p ] [ thread-run2 ./sync/futures/promise/use_allocator_pass.cpp : promise__use_allocator_p ] + [ thread-run2 ./sync/futures/promise/set_exception_at_thread_exit_pass.cpp : promise__set_exception_at_thread_exit_p ] + [ thread-run2 ./sync/futures/promise/set_lvalue_at_thread_exit_pass.cpp : promise__set_lvalue_at_thread_exit_p ] + [ thread-run2 ./sync/futures/promise/set_rvalue_at_thread_exit_pass.cpp : promise__set_rvalue_at_thread_exit_p ] + [ thread-run2 ./sync/futures/promise/set_value_at_thread_exit_const_pass.cpp : promise__set_value_at_thread_exit_const_p ] + [ thread-run2 ./sync/futures/promise/set_value_at_thread_exit_void_pass.cpp : promise__set_value_at_thread_exit_void_p ] ; #explicit ts_future ; @@ -582,6 +587,7 @@ rule thread-compile-fail ( sources : reqs * : name ) explicit ts_ ; test-suite ts_ : + #[ thread-run ../example/unwrap.cpp ] ; diff --git a/test/sync/futures/promise/set_exception_at_thread_exit_pass.cpp b/test/sync/futures/promise/set_exception_at_thread_exit_pass.cpp new file mode 100644 index 00000000..7fd7a4f5 --- /dev/null +++ b/test/sync/futures/promise/set_exception_at_thread_exit_pass.cpp @@ -0,0 +1,78 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Copyright (C) 2011 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// + +// class promise + +// void promise::set_exception_at_thread_exit(exception_ptr p); + +#define BOOST_THREAD_VERSION 4 + +#include +#include +#include + +namespace boost +{ + template + struct wrap + { + wrap(T const& v) : + value(v) + { + } + T value; + + }; + + template + exception_ptr make_exception_ptr(T v) + { + return copy_exception(wrap (v)); + } +} + +//void func(boost::promise p) +boost::promise p; +void func() +{ + p.set_exception_at_thread_exit(boost::make_exception_ptr(3)); +} + +int main() +{ + { + typedef int T; + //boost::promise p; + boost::future f = p.get_future(); + //boost::thread(func, boost::move(p)).detach(); + boost::thread(func).detach(); + try + { + f.get(); + BOOST_TEST(false); + } + catch (boost::wrap i) + { + BOOST_TEST(i.value == 3); + } + catch (...) + { + BOOST_TEST(false); + } + } + return boost::report_errors(); +} + diff --git a/test/sync/futures/promise/set_lvalue_at_thread_exit_pass.cpp b/test/sync/futures/promise/set_lvalue_at_thread_exit_pass.cpp new file mode 100644 index 00000000..a143dc63 --- /dev/null +++ b/test/sync/futures/promise/set_lvalue_at_thread_exit_pass.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Copyright (C) 2011 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// + +// class promise + +// void promise::set_value_at_thread_exit(R& r); + +#define BOOST_THREAD_VERSION 4 + +#include +#include +#include + +int i = 0; + +//void func(boost::promise p) +boost::promise p; +void func() +{ + p.set_value_at_thread_exit(i); + i = 4; +} + +int main() +{ + { + //boost::promise p; + boost::future f = p.get_future(); + //boost::thread(func, boost::move(p)).detach(); + boost::thread(func).detach(); + int r = f.get(); + BOOST_TEST(r == 4); + } + return boost::report_errors(); +} + diff --git a/test/sync/futures/promise/set_rvalue_at_thread_exit_pass.cpp b/test/sync/futures/promise/set_rvalue_at_thread_exit_pass.cpp new file mode 100644 index 00000000..c7822983 --- /dev/null +++ b/test/sync/futures/promise/set_rvalue_at_thread_exit_pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Copyright (C) 2011 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// + +// class promise + +// void promise::set_exception_at_thread_exit(exception_ptr p); + +#define BOOST_THREAD_VERSION 3 + +#include +#include +#include +#include + +//void func(boost::promise > > p) +boost::promise > > p; +void func() +{ + boost::interprocess::unique_ptr > uptr(new int(5)); + p.set_value_at_thread_exit(boost::move(uptr)); +} + +int main() +{ + { + //boost::promise> > p; + boost::future > > f = p.get_future(); + //boost::thread(func, boost::move(p)).detach(); + boost::thread(func).detach(); + BOOST_TEST(*f.get() == 5); + } + + return boost::report_errors(); +} + diff --git a/test/sync/futures/promise/set_value_at_thread_exit_const_pass.cpp b/test/sync/futures/promise/set_value_at_thread_exit_const_pass.cpp new file mode 100644 index 00000000..a4abb431 --- /dev/null +++ b/test/sync/futures/promise/set_value_at_thread_exit_const_pass.cpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Copyright (C) 2011 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// + +// class promise + +// void promise::set_value_at_thread_exit(const R& r); + +#define BOOST_THREAD_VERSION 4 + +#include +#include + +boost::promise p; +//void func(boost::promise p) +void func() +{ + const int i = 5; + p.set_value_at_thread_exit(i); +} + +int main() +{ + { + //boost::promise p; + boost::future f = p.get_future(); + //boost::thread(func, boost::move(p)).detach(); + boost::thread(func).detach(); + BOOST_TEST(f.get() == 5); + } + return boost::report_errors(); +} + diff --git a/test/sync/futures/promise/set_value_at_thread_exit_void_pass.cpp b/test/sync/futures/promise/set_value_at_thread_exit_void_pass.cpp new file mode 100644 index 00000000..b434652a --- /dev/null +++ b/test/sync/futures/promise/set_value_at_thread_exit_void_pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Copyright (C) 2011 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// + +// class promise + +// void promise::set_value_at_thread_exit(); + +#define BOOST_THREAD_VERSION 4 + +#include +#include + +int i = 0; + +boost::promise p; +void func() +{ + p.set_value_at_thread_exit(); + i = 1; +} + +void func2(boost::promise p2) +{ + p2.set_value_at_thread_exit(); + i = 1; +} + +int main() +{ + try + { + boost::future f = p.get_future(); + boost::thread(func).detach(); + f.get(); + BOOST_TEST(i == 1); + + } + catch(std::exception ex) + { + BOOST_TEST(false); + } + catch(...) + { + BOOST_TEST(false); + } + + // BUG when moving promise. fixme +// try +// { +// std::cout << __FILE__ << ":" << __LINE__ < p2; // BUG +// std::cout << __FILE__ << ":" << __LINE__ < f = p2.get_future(); +// std::cout << __FILE__ << ":" << __LINE__ <