From 47499b162ae741a247e5f89b7bdb513e51c3648a Mon Sep 17 00:00:00 2001 From: Howard Hinnant Date: Fri, 27 Aug 2010 20:10:19 +0000 Subject: [PATCH] future continues ... git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@112284 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/condition_variable | 2 + include/future | 748 ++++++++++++++++++++++++++++++++++++- include/thread | 82 ++++ src/future.cpp | 157 ++++++++ src/thread.cpp | 55 +++ 5 files changed, 1042 insertions(+), 2 deletions(-) diff --git a/include/condition_variable b/include/condition_variable index ce14b62a..3e766b6c 100644 --- a/include/condition_variable +++ b/include/condition_variable @@ -61,6 +61,8 @@ public: native_handle_type native_handle(); }; +void notify_all_at_thread_exit(condition_variable& cond, unique_lock lk); + class condition_variable_any { public: diff --git a/include/future b/include/future index c8986489..a8b02a6d 100644 --- a/include/future +++ b/include/future @@ -102,7 +102,7 @@ public: void swap(promise& other); // retrieving the result - future get_future(); + future get_future(); // setting the result void set_value(R& r); @@ -130,7 +130,7 @@ public: void swap(promise& other); // retrieving the result - future get_future(); + future get_future(); // setting the result void set_value(); @@ -441,6 +441,11 @@ template struct uses_allocator, Alloc>; #include <__config> #include +#include +#include +#include +#include <__mutex_base> +#include #pragma GCC system_header @@ -523,6 +528,745 @@ public: const error_code& code() const throw() {return __ec_;} }; +class __assoc_sub_state + : public __shared_count +{ +protected: + exception_ptr __exception_; + mutable mutex __mut_; + mutable condition_variable __cv_; + unsigned __state_; + + virtual void __on_zero_shared(); + +public: + enum + { + __constructed = 1, + __future_attached = 2, + ready = 4, + deferred = 8 + }; + + __assoc_sub_state() : __state_(0) {} + + bool __has_value() const + {return (__state_ & __constructed) || (__exception_ != nullptr);} + + void __set_future_attached() {__state_ |= __future_attached;} + bool __has_future_attached() const {return __state_ & __future_attached;} + + void __make_ready(); + bool __is_ready() const {return __state_ & ready;} + + void set_value(); + void set_value_at_thread_exit(); + + void set_exception(exception_ptr __p); + void set_exception_at_thread_exit(exception_ptr __p); + + void copy(); + + void wait() const; + template + future_status + wait_for(const chrono::duration<_Rep, _Period>& __rel_time) const; + template + future_status + wait_until(const chrono::time_point<_Clock, _Duration>& __abs_time) const; +}; + +template +class __assoc_state + : public __assoc_sub_state +{ + typedef __assoc_sub_state base; + typedef typename aligned_storage::value>::type _U; +protected: + _U __value_; + + virtual void __on_zero_shared(); +public: + + template +#ifdef _LIBCPP_MOVE + void set_value(_Arg&& __arg); +#else + void set_value(_Arg& __arg); +#endif + + template +#ifdef _LIBCPP_MOVE + void set_value_at_thread_exit(_Arg&& __arg); +#else + void set_value_at_thread_exit(_Arg& __arg); +#endif + + _R move(); + typename add_lvalue_reference<_R>::type copy(); +}; + +template +void +__assoc_state<_R>::__on_zero_shared() +{ + if (this->__state_ & base::__constructed) + reinterpret_cast<_R*>(&__value_)->~_R(); + delete this; +} + +template +template +void +#ifdef _LIBCPP_MOVE +__assoc_state<_R>::set_value(_Arg&& __arg) +#else +__assoc_state<_R>::set_value(_Arg& __arg) +#endif +{ + unique_lock __lk(this->__mut_); + if (this->__has_value()) + throw future_error(make_error_code(future_errc::promise_already_satisfied)); + ::new(&__value_) _R(_STD::forward<_Arg>(__arg)); + this->__state_ |= base::__constructed | base::ready; + __lk.unlock(); + __cv_.notify_all(); +} + +template +template +void +#ifdef _LIBCPP_MOVE +__assoc_state<_R>::set_value_at_thread_exit(_Arg&& __arg) +#else +__assoc_state<_R>::set_value_at_thread_exit(_Arg& __arg) +#endif +{ + unique_lock __lk(this->__mut_); + if (this->__has_value()) + throw future_error(make_error_code(future_errc::promise_already_satisfied)); + ::new(&__value_) _R(_STD::forward<_Arg>(__arg)); + this->__state_ |= base::__constructed; + __thread_local_data->__make_ready_at_thread_exit(this); + __lk.unlock(); +} + +template +_R +__assoc_state<_R>::move() +{ + unique_lock __lk(this->__mut_); + while (!this->__is_ready()) + this->__cv_.wait(__lk); + if (this->__exception_ != nullptr) + rethrow_exception(this->__exception_); + return _STD::move(*reinterpret_cast<_R*>(&__value_)); +} + +template +typename add_lvalue_reference<_R>::type +__assoc_state<_R>::copy() +{ + unique_lock __lk(this->__mut_); + while (!this->__is_ready()) + this->__cv_.wait(__lk); + if (this->__exception_ != nullptr) + rethrow_exception(this->__exception_); + return *reinterpret_cast<_R*>(&__value_); +} + +template +class __assoc_state_alloc + : public __assoc_state<_R> +{ + typedef __assoc_state<_R> base; + _Alloc __alloc_; + + virtual void __on_zero_shared(); +public: + explicit __assoc_state_alloc(const _Alloc& __a) + : __alloc_(__a) {} +}; + +template +void +__assoc_state_alloc<_R, _Alloc>::__on_zero_shared() +{ + if (this->__state_ & base::__constructed) + reinterpret_cast<_R*>(&this->__value_)->~_R(); + typename _Alloc::template rebind<__assoc_state_alloc>::other __a(__alloc_); + this->~__assoc_state_alloc(); + __a.deallocate(this, 1); +} + +template +class __assoc_sub_state_alloc + : public __assoc_sub_state +{ + typedef __assoc_sub_state base; + _Alloc __alloc_; + + virtual void __on_zero_shared(); +public: + explicit __assoc_sub_state_alloc(const _Alloc& __a) + : __alloc_(__a) {} +}; + +template +void +__assoc_sub_state_alloc<_Alloc>::__on_zero_shared() +{ + this->~base(); + typename _Alloc::template rebind<__assoc_state_alloc>::other __a(__alloc_); + this->~__assoc_sub_state_alloc(); + __a.deallocate(this, 1); +} + +template class promise; + +// future + +template +class future +{ + __assoc_state<_R>* __state_; + + explicit future(__assoc_state<_R>* __state); + + template friend class promise; +public: + future() : __state_(nullptr) {} +#ifdef _LIBCPP_MOVE + future(future&& __rhs) + : __state_(__rhs.__state_) {__rhs.__state_ = nullptr;} + future(const future&) = delete; + future& operator=(const future&) = delete; + future& operator=(future&& __rhs) + { + future(std::move(__rhs)).swap(*this); + return *this; + } +#else // _LIBCPP_MOVE +private: + future(const future&); + future& operator=(const future&); +public: +#endif // _LIBCPP_MOVE + ~future(); + + // retrieving the value + _R get(); + + void swap(future& __rhs) {_STD::swap(__state_, __rhs.__state_);} + + // functions to check state + bool valid() const {return __state_ != nullptr;} + + void wait() const {__state_->wait();} + template + future_status + wait_for(const chrono::duration<_Rep, _Period>& __rel_time) const + {return __state_->wait_for(__rel_time);} + template + future_status + wait_until(const chrono::time_point<_Clock, _Duration>& __abs_time) const + {return __state_->wait_until(__abs_time);} +}; + +template +future<_R>::future(__assoc_state<_R>* __state) + : __state_(__state) +{ + if (__state_->__has_future_attached()) + throw future_error(make_error_code(future_errc::future_already_retrieved)); + __state_->__add_shared(); +} + +template +future<_R>::~future() +{ + if (__state_) + __state_->__release_shared(); +} + +template +_R +future<_R>::get() +{ + __assoc_state<_R>* __s = __state_; + __state_ = nullptr; + return __s->move(); +} + +template +class future<_R&> +{ + __assoc_state<_R&>* __state_; + + explicit future(__assoc_state<_R&>* __state); + + template friend class promise; +public: + future() : __state_(nullptr) {} +#ifdef _LIBCPP_MOVE + future(future&& __rhs) + : __state_(__rhs.__state_) {__rhs.__state_ = nullptr;} + future(const future&) = delete; + future& operator=(const future&) = delete; + future& operator=(future&& __rhs) + { + future(std::move(__rhs)).swap(*this); + return *this; + } +#else // _LIBCPP_MOVE +private: + future(const future&); + future& operator=(const future&); +public: +#endif // _LIBCPP_MOVE + ~future(); + + // retrieving the value + _R& get(); + + void swap(future& __rhs) {_STD::swap(__state_, __rhs.__state_);} + + // functions to check state + bool valid() const {return __state_ != nullptr;} + + void wait() const {__state_->wait();} + template + future_status + wait_for(const chrono::duration<_Rep, _Period>& __rel_time) const + {return __state_->wait_for(__rel_time);} + template + future_status + wait_until(const chrono::time_point<_Clock, _Duration>& __abs_time) const + {return __state_->wait_until(__abs_time);} +}; + +template +future<_R&>::future(__assoc_state<_R&>* __state) + : __state_(__state) +{ + if (__state_->__has_future_attached()) + throw future_error(make_error_code(future_errc::future_already_retrieved)); + __state_->__add_shared(); +} + +template +future<_R&>::~future() +{ + if (__state_) + __state_->__release_shared(); +} + +template +_R& +future<_R&>::get() +{ + __assoc_state<_R>* __s = __state_; + __state_ = nullptr; + return __s->copy(); +} + +template <> +class future +{ + __assoc_sub_state* __state_; + + explicit future(__assoc_sub_state* __state); + + template friend class promise; +public: + future() : __state_(nullptr) {} +#ifdef _LIBCPP_MOVE + future(future&& __rhs) + : __state_(__rhs.__state_) {__rhs.__state_ = nullptr;} + future(const future&) = delete; + future& operator=(const future&) = delete; + future& operator=(future&& __rhs) + { + future(std::move(__rhs)).swap(*this); + return *this; + } +#else // _LIBCPP_MOVE +private: + future(const future&); + future& operator=(const future&); +public: +#endif // _LIBCPP_MOVE + ~future(); + + // retrieving the value + void get(); + + void swap(future& __rhs) {_STD::swap(__state_, __rhs.__state_);} + + // functions to check state + bool valid() const {return __state_ != nullptr;} + + void wait() const {__state_->wait();} + template + future_status + wait_for(const chrono::duration<_Rep, _Period>& __rel_time) const + {return __state_->wait_for(__rel_time);} + template + future_status + wait_until(const chrono::time_point<_Clock, _Duration>& __abs_time) const + {return __state_->wait_until(__abs_time);} +}; + +// promise + +template +class promise +{ + __assoc_state<_R>* __state_; +public: + promise(); + template + promise(allocator_arg_t, const _Alloc& __a); +#ifdef _LIBCPP_MOVE + promise(promise&& __rhs) + : __state_(__rhs.__state_) {__rhs.__state_ = nullptr;} + promise(const promise& __rhs) = delete; +#else // _LIBCPP_MOVE +private: + promise(const promise& __rhs); +public: +#endif // _LIBCPP_MOVE + ~promise(); + + // assignment +#ifdef _LIBCPP_MOVE + promise& operator=(promise&& __rhs) + { + promise(std::move(__rhs)).swap(*this); + return *this; + } + promise& operator=(const promise& __rhs) = delete; +#else // _LIBCPP_MOVE +private: + promise& operator=(const promise& __rhs); +public: +#endif // _LIBCPP_MOVE + void swap(promise& __rhs) {_STD::swap(__state_, __rhs.__state_);} + + // retrieving the result + future<_R> get_future(); + + // setting the result + void set_value(const _R& __r); +#ifdef _LIBCPP_MOVE + void set_value(_R&& __r); +#endif + void set_exception(exception_ptr __p); + + // setting the result with deferred notification + void set_value_at_thread_exit(const _R& __r); +#ifdef _LIBCPP_MOVE + void set_value_at_thread_exit(_R&& __r); +#endif + void set_exception_at_thread_exit(exception_ptr __p); +}; + +template +promise<_R>::promise() + : __state_(new __assoc_state<_R>) +{ +} + +template +template +promise<_R>::promise(allocator_arg_t, const _Alloc& __a0) +{ + typedef typename _Alloc::template rebind<__assoc_state_alloc<_R, _Alloc> >::other _A2; + typedef __allocator_destructor<_A2> _D2; + _A2 __a(__a0); + unique_ptr<__assoc_state_alloc<_R, _Alloc>, _D2> __hold(__a.allocate(1), _D2(__a, 1)); + ::new(__hold.get()) __assoc_state_alloc<_R, _Alloc>(__a0); + __state_ = __hold.release(); +} + +template +promise<_R>::~promise() +{ + if (__state_) + { + if (!__state_->__has_value() && __state_->use_count() > 1) + __state_->set_exception(make_exception_ptr( + future_error(make_error_code(future_errc::broken_promise)) + )); + __state_->__release_shared(); + } +} + +template +future<_R> +promise<_R>::get_future() +{ + if (__state_ == nullptr) + throw future_error(make_error_code(future_errc::no_state)); + return future<_R>(__state_); +} + +template +void +promise<_R>::set_value(const _R& __r) +{ + if (__state_ == nullptr) + throw future_error(make_error_code(future_errc::no_state)); + __state_->set_value(__r); +} + +#ifdef _LIBCPP_MOVE + +template +void +promise<_R>::set_value(_R&& __r) +{ + if (__state_ == nullptr) + throw future_error(make_error_code(future_errc::no_state)); + __state_->set_value(_STD::move(__r)); +} + +#endif // _LIBCPP_MOVE + +template +void +promise<_R>::set_exception(exception_ptr __p) +{ + if (__state_ == nullptr) + throw future_error(make_error_code(future_errc::no_state)); + __state_->set_exception(__p); +} + +template +void +promise<_R>::set_value_at_thread_exit(const _R& __r) +{ + if (__state_ == nullptr) + throw future_error(make_error_code(future_errc::no_state)); + __state_->set_value_at_thread_exit(__r); +} + +#ifdef _LIBCPP_MOVE + +template +void +promise<_R>::set_value_at_thread_exit(_R&& __r) +{ + if (__state_ == nullptr) + throw future_error(make_error_code(future_errc::no_state)); + __state_->set_value_at_thread_exit(_STD::move(__r)); +} + +#endif // _LIBCPP_MOVE + +template +void +promise<_R>::set_exception_at_thread_exit(exception_ptr __p) +{ + if (__state_ == nullptr) + throw future_error(make_error_code(future_errc::no_state)); + __state_->set_exception_at_thread_exit(__p); +} + +// promise + +template +class promise<_R&> +{ + __assoc_state<_R&>* __state_; +public: + promise(); + template + promise(allocator_arg_t, const _Allocator& __a); +#ifdef _LIBCPP_MOVE + promise(promise&& __rhs) + : __state_(__rhs.__state_) {__rhs.__state_ = nullptr;} + promise(const promise& __rhs) = delete; +#else // _LIBCPP_MOVE +private: + promise(const promise& __rhs); +public: +#endif // _LIBCPP_MOVE + ~promise(); + + // assignment +#ifdef _LIBCPP_MOVE + promise& operator=(promise&& __rhs) + { + promise(std::move(__rhs)).swap(*this); + return *this; + } + promise& operator=(const promise& __rhs) = delete; +#else // _LIBCPP_MOVE +private: + promise& operator=(const promise& __rhs); +public: +#endif // _LIBCPP_MOVE + void swap(promise& __rhs) {_STD::swap(__state_, __rhs.__state_);} + + // retrieving the result + future<_R&> get_future(); + + // setting the result + void set_value(_R& __r); + void set_exception(exception_ptr __p); + + // setting the result with deferred notification + void set_value_at_thread_exit(_R&); + void set_exception_at_thread_exit(exception_ptr __p); +}; + +template +promise<_R&>::promise() + : __state_(new __assoc_state<_R&>) +{ +} + +template +template +promise<_R&>::promise(allocator_arg_t, const _Alloc& __a0) +{ + typedef typename _Alloc::template rebind<__assoc_state_alloc<_R&, _Alloc> >::other _A2; + typedef __allocator_destructor<_A2> _D2; + _A2 __a(__a0); + unique_ptr<__assoc_state_alloc<_R&, _Alloc>, _D2> __hold(__a.allocate(1), _D2(__a, 1)); + ::new(__hold.get()) __assoc_state_alloc<_R&, _Alloc>(__a0); + __state_ = __hold.release(); +} + +template +promise<_R&>::~promise() +{ + if (__state_) + { + if (!__state_->__has_value() && __state_->use_count() > 1) + __state_->set_exception(make_exception_ptr( + future_error(make_error_code(future_errc::broken_promise)) + )); + __state_->__release_shared(); + } +} + +template +future<_R&> +promise<_R&>::get_future() +{ + if (__state_ == nullptr) + throw future_error(make_error_code(future_errc::no_state)); + return future<_R&>(__state_); +} + +template +void +promise<_R&>::set_value(_R& __r) +{ + if (__state_ == nullptr) + throw future_error(make_error_code(future_errc::no_state)); + __state_->set_value(__r); +} + +template +void +promise<_R&>::set_exception(exception_ptr __p) +{ + if (__state_ == nullptr) + throw future_error(make_error_code(future_errc::no_state)); + __state_->set_exception(__p); +} + +template +void +promise<_R&>::set_value_at_thread_exit(_R& __r) +{ + if (__state_ == nullptr) + throw future_error(make_error_code(future_errc::no_state)); + __state_->set_value_at_thread_exit(__r); +} + +template +void +promise<_R&>::set_exception_at_thread_exit(exception_ptr __p) +{ + if (__state_ == nullptr) + throw future_error(make_error_code(future_errc::no_state)); + __state_->set_exception_at_thread_exit(__p); +} + +// promise + +template <> +class promise +{ + __assoc_sub_state* __state_; +public: + promise(); + template + promise(allocator_arg_t, const _Allocator& __a); +#ifdef _LIBCPP_MOVE + promise(promise&& __rhs) + : __state_(__rhs.__state_) {__rhs.__state_ = nullptr;} + promise(const promise& __rhs) = delete; +#else // _LIBCPP_MOVE +private: + promise(const promise& __rhs); +public: +#endif // _LIBCPP_MOVE + ~promise(); + + // assignment +#ifdef _LIBCPP_MOVE + promise& operator=(promise&& __rhs) + { + promise(std::move(__rhs)).swap(*this); + return *this; + } + promise& operator=(const promise& __rhs) = delete; +#else // _LIBCPP_MOVE +private: + promise& operator=(const promise& __rhs); +public: +#endif // _LIBCPP_MOVE + void swap(promise& __rhs) {_STD::swap(__state_, __rhs.__state_);} + + // retrieving the result + future get_future(); + + // setting the result + void set_value(); + void set_exception(exception_ptr __p); + + // setting the result with deferred notification + void set_value_at_thread_exit(); + void set_exception_at_thread_exit(exception_ptr __p); +}; + +template +promise::promise(allocator_arg_t, const _Alloc& __a0) +{ + typedef typename _Alloc::template rebind<__assoc_sub_state_alloc<_Alloc> >::other _A2; + typedef __allocator_destructor<_A2> _D2; + _A2 __a(__a0); + unique_ptr<__assoc_sub_state_alloc<_Alloc>, _D2> __hold(__a.allocate(1), _D2(__a, 1)); + ::new(__hold.get()) __assoc_sub_state_alloc<_Alloc>(__a0); + __state_ = __hold.release(); +} + +template +inline _LIBCPP_INLINE_VISIBILITY +void +swap(promise<_R>& __x, promise<_R>& __y) +{ + __x.swap(__y); +} + +template + struct uses_allocator, _Alloc> : public true_type {}; + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP_FUTURE diff --git a/include/thread b/include/thread index fffd2df6..123c472c 100644 --- a/include/thread +++ b/include/thread @@ -103,6 +103,68 @@ void sleep_for(const chrono::duration& rel_time); _LIBCPP_BEGIN_NAMESPACE_STD +template +class __thread_specific_ptr +{ + pthread_key_t __key_; + + __thread_specific_ptr(const __thread_specific_ptr&); + __thread_specific_ptr& operator=(const __thread_specific_ptr&); + + static void __at_thread_exit(void*); +public: + typedef _Tp* pointer; + + __thread_specific_ptr(); + ~__thread_specific_ptr(); + + pointer get() const {return static_cast<_Tp*>(pthread_getspecific(__key_));} + pointer operator*() const {return *get();} + pointer operator->() const {return get();} + pointer release(); + void reset(pointer __p = nullptr); +}; + +template +void +__thread_specific_ptr<_Tp>::__at_thread_exit(void* __p) +{ + delete static_cast(__p); +} + +template +__thread_specific_ptr<_Tp>::__thread_specific_ptr() +{ + int __ec = pthread_key_create(&__key_, &__thread_specific_ptr::__at_thread_exit); + if (__ec) + throw system_error(error_code(__ec, system_category()), + "__thread_specific_ptr construction failed"); +} + +template +__thread_specific_ptr<_Tp>::~__thread_specific_ptr() +{ + pthread_key_delete(__key_); +} + +template +typename __thread_specific_ptr<_Tp>::pointer +__thread_specific_ptr<_Tp>::release() +{ + pointer __p = get(); + pthread_setspecific(__key_, 0); + return __p; +} + +template +void +__thread_specific_ptr<_Tp>::reset(pointer __p) +{ + pointer __p_old = get(); + pthread_setspecific(__key_, __p); + delete __p_old; +} + class thread; class __thread_id; @@ -219,10 +281,30 @@ public: static unsigned hardware_concurrency(); }; +class __assoc_sub_state; + +class __thread_struct_imp; + +class __thread_struct +{ + __thread_struct_imp* __p_; + + __thread_struct(const __thread_struct&); + __thread_struct& operator=(const __thread_struct&); +public: + __thread_struct(); + ~__thread_struct(); + + void __make_ready_at_thread_exit(__assoc_sub_state*); +}; + +extern __thread_specific_ptr<__thread_struct> __thread_local_data; + template void* __thread_proxy(void* __vp) { + __thread_local_data.reset(new __thread_struct); std::unique_ptr<_F> __p(static_cast<_F*>(__vp)); (*__p)(); return nullptr; diff --git a/src/future.cpp b/src/future.cpp index f9547c66..82b9b60e 100644 --- a/src/future.cpp +++ b/src/future.cpp @@ -60,4 +60,161 @@ future_error::future_error(error_code __ec) { } +void +__assoc_sub_state::__on_zero_shared() +{ + delete this; +} + +void +__assoc_sub_state::set_value() +{ + unique_lock __lk(__mut_); + if (__has_value()) + throw future_error(make_error_code(future_errc::promise_already_satisfied)); + __state_ |= __constructed | ready; + __lk.unlock(); + __cv_.notify_all(); +} + +void +__assoc_sub_state::set_value_at_thread_exit() +{ + unique_lock __lk(__mut_); + if (__has_value()) + throw future_error(make_error_code(future_errc::promise_already_satisfied)); + __state_ |= __constructed; + __thread_local_data->__make_ready_at_thread_exit(this); + __lk.unlock(); +} + +void +__assoc_sub_state::set_exception(exception_ptr __p) +{ + unique_lock __lk(__mut_); + if (__has_value()) + throw future_error(make_error_code(future_errc::promise_already_satisfied)); + __exception_ = __p; + __state_ |= ready; + __lk.unlock(); + __cv_.notify_all(); +} + +void +__assoc_sub_state::set_exception_at_thread_exit(exception_ptr __p) +{ + unique_lock __lk(__mut_); + if (__has_value()) + throw future_error(make_error_code(future_errc::promise_already_satisfied)); + __exception_ = __p; + __thread_local_data->__make_ready_at_thread_exit(this); + __lk.unlock(); +} + +void +__assoc_sub_state::__make_ready() +{ + unique_lock __lk(__mut_); + __state_ |= ready; + __lk.unlock(); + __cv_.notify_all(); +} + +void +__assoc_sub_state::copy() +{ + unique_lock __lk(__mut_); + while (!__is_ready()) + __cv_.wait(__lk); + if (__exception_ != nullptr) + rethrow_exception(__exception_); +} + +void +__assoc_sub_state::wait() const +{ + unique_lock __lk(__mut_); + while (!__is_ready()) + __cv_.wait(__lk); +} + +future::future(__assoc_sub_state* __state) + : __state_(__state) +{ + if (__state_->__has_future_attached()) + throw future_error(make_error_code(future_errc::future_already_retrieved)); + __state_->__add_shared(); +} + +future::~future() +{ + if (__state_) + __state_->__release_shared(); +} + +void +future::get() +{ + __assoc_sub_state* __s = __state_; + __state_ = nullptr; + return __s->copy(); +} + +promise::promise() + : __state_(new __assoc_sub_state) +{ +} + +promise::~promise() +{ + if (__state_) + { + if (!__state_->__has_value() && __state_->use_count() > 1) + __state_->set_exception(make_exception_ptr( + future_error(make_error_code(future_errc::broken_promise)) + )); + __state_->__release_shared(); + } +} + +future +promise::get_future() +{ + if (__state_ == nullptr) + throw future_error(make_error_code(future_errc::no_state)); + return future(__state_); +} + +void +promise::set_value() +{ + if (__state_ == nullptr) + throw future_error(make_error_code(future_errc::no_state)); + __state_->set_value(); +} + +void +promise::set_exception(exception_ptr __p) +{ + if (__state_ == nullptr) + throw future_error(make_error_code(future_errc::no_state)); + __state_->set_exception(__p); +} + +void +promise::set_value_at_thread_exit() +{ + if (__state_ == nullptr) + throw future_error(make_error_code(future_errc::no_state)); + __state_->set_value_at_thread_exit(); +} + +void +promise::set_exception_at_thread_exit(exception_ptr __p) +{ + if (__state_ == nullptr) + throw future_error(make_error_code(future_errc::no_state)); + __state_->set_exception_at_thread_exit(__p); +} + _LIBCPP_END_NAMESPACE_STD diff --git a/src/thread.cpp b/src/thread.cpp index 99297650..f8407067 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -9,6 +9,8 @@ #include "thread" #include "exception" +#include "vector" +#include "future" #include #include @@ -81,4 +83,57 @@ sleep_for(const chrono::nanoseconds& ns) } // this_thread +__thread_specific_ptr<__thread_struct> __thread_local_data; + +// __thread_struct_imp + +class __thread_struct_imp +{ + typedef vector<__assoc_sub_state*> _AsyncStates; + _AsyncStates async_states_; + + __thread_struct_imp(const __thread_struct_imp&); + __thread_struct_imp& operator=(const __thread_struct_imp&); +public: + __thread_struct_imp() {} + ~__thread_struct_imp(); + + void __make_ready_at_thread_exit(__assoc_sub_state* __s); +}; + +__thread_struct_imp::~__thread_struct_imp() +{ + for (_AsyncStates::iterator i = async_states_.begin(), e = async_states_.end(); + i != e; ++i) + { + (*i)->__make_ready(); + (*i)->__release_shared(); + } +} + +void +__thread_struct_imp::__make_ready_at_thread_exit(__assoc_sub_state* __s) +{ + async_states_.push_back(__s); + __s->__add_shared(); +} + +// __thread_struct + +__thread_struct::__thread_struct() + : __p_(new __thread_struct_imp) +{ +} + +__thread_struct::~__thread_struct() +{ + delete __p_; +} + +void +__thread_struct::__make_ready_at_thread_exit(__assoc_sub_state* __s) +{ + __p_->__make_ready_at_thread_exit(__s); +} + _LIBCPP_END_NAMESPACE_STD