future continues ...
git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@112284 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -61,6 +61,8 @@ public:
|
||||
native_handle_type native_handle();
|
||||
};
|
||||
|
||||
void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
|
||||
|
||||
class condition_variable_any
|
||||
{
|
||||
public:
|
||||
|
748
include/future
748
include/future
@@ -102,7 +102,7 @@ public:
|
||||
void swap(promise& other);
|
||||
|
||||
// retrieving the result
|
||||
future<R> get_future();
|
||||
future<R&> get_future();
|
||||
|
||||
// setting the result
|
||||
void set_value(R& r);
|
||||
@@ -130,7 +130,7 @@ public:
|
||||
void swap(promise& other);
|
||||
|
||||
// retrieving the result
|
||||
future<R> get_future();
|
||||
future<void> get_future();
|
||||
|
||||
// setting the result
|
||||
void set_value();
|
||||
@@ -441,6 +441,11 @@ template <class R, class Alloc> struct uses_allocator<packaged_task<R>, Alloc>;
|
||||
|
||||
#include <__config>
|
||||
#include <system_error>
|
||||
#include <memory>
|
||||
#include <chrono>
|
||||
#include <exception>
|
||||
#include <__mutex_base>
|
||||
#include <thread>
|
||||
|
||||
#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 <class _Rep, class _Period>
|
||||
future_status
|
||||
wait_for(const chrono::duration<_Rep, _Period>& __rel_time) const;
|
||||
template <class _Clock, class _Duration>
|
||||
future_status
|
||||
wait_until(const chrono::time_point<_Clock, _Duration>& __abs_time) const;
|
||||
};
|
||||
|
||||
template <class _R>
|
||||
class __assoc_state
|
||||
: public __assoc_sub_state
|
||||
{
|
||||
typedef __assoc_sub_state base;
|
||||
typedef typename aligned_storage<sizeof(_R), alignment_of<_R>::value>::type _U;
|
||||
protected:
|
||||
_U __value_;
|
||||
|
||||
virtual void __on_zero_shared();
|
||||
public:
|
||||
|
||||
template <class _Arg>
|
||||
#ifdef _LIBCPP_MOVE
|
||||
void set_value(_Arg&& __arg);
|
||||
#else
|
||||
void set_value(_Arg& __arg);
|
||||
#endif
|
||||
|
||||
template <class _Arg>
|
||||
#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 <class _R>
|
||||
void
|
||||
__assoc_state<_R>::__on_zero_shared()
|
||||
{
|
||||
if (this->__state_ & base::__constructed)
|
||||
reinterpret_cast<_R*>(&__value_)->~_R();
|
||||
delete this;
|
||||
}
|
||||
|
||||
template <class _R>
|
||||
template <class _Arg>
|
||||
void
|
||||
#ifdef _LIBCPP_MOVE
|
||||
__assoc_state<_R>::set_value(_Arg&& __arg)
|
||||
#else
|
||||
__assoc_state<_R>::set_value(_Arg& __arg)
|
||||
#endif
|
||||
{
|
||||
unique_lock<mutex> __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 <class _R>
|
||||
template <class _Arg>
|
||||
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<mutex> __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 <class _R>
|
||||
_R
|
||||
__assoc_state<_R>::move()
|
||||
{
|
||||
unique_lock<mutex> __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 <class _R>
|
||||
typename add_lvalue_reference<_R>::type
|
||||
__assoc_state<_R>::copy()
|
||||
{
|
||||
unique_lock<mutex> __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 _R, class _Alloc>
|
||||
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 <class _R, class _Alloc>
|
||||
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 _Alloc>
|
||||
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 <class _Alloc>
|
||||
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> class promise;
|
||||
|
||||
// future
|
||||
|
||||
template <class _R>
|
||||
class future
|
||||
{
|
||||
__assoc_state<_R>* __state_;
|
||||
|
||||
explicit future(__assoc_state<_R>* __state);
|
||||
|
||||
template <class> 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 <class _Rep, class _Period>
|
||||
future_status
|
||||
wait_for(const chrono::duration<_Rep, _Period>& __rel_time) const
|
||||
{return __state_->wait_for(__rel_time);}
|
||||
template <class _Clock, class _Duration>
|
||||
future_status
|
||||
wait_until(const chrono::time_point<_Clock, _Duration>& __abs_time) const
|
||||
{return __state_->wait_until(__abs_time);}
|
||||
};
|
||||
|
||||
template <class _R>
|
||||
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 <class _R>
|
||||
future<_R>::~future()
|
||||
{
|
||||
if (__state_)
|
||||
__state_->__release_shared();
|
||||
}
|
||||
|
||||
template <class _R>
|
||||
_R
|
||||
future<_R>::get()
|
||||
{
|
||||
__assoc_state<_R>* __s = __state_;
|
||||
__state_ = nullptr;
|
||||
return __s->move();
|
||||
}
|
||||
|
||||
template <class _R>
|
||||
class future<_R&>
|
||||
{
|
||||
__assoc_state<_R&>* __state_;
|
||||
|
||||
explicit future(__assoc_state<_R&>* __state);
|
||||
|
||||
template <class> 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 <class _Rep, class _Period>
|
||||
future_status
|
||||
wait_for(const chrono::duration<_Rep, _Period>& __rel_time) const
|
||||
{return __state_->wait_for(__rel_time);}
|
||||
template <class _Clock, class _Duration>
|
||||
future_status
|
||||
wait_until(const chrono::time_point<_Clock, _Duration>& __abs_time) const
|
||||
{return __state_->wait_until(__abs_time);}
|
||||
};
|
||||
|
||||
template <class _R>
|
||||
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 <class _R>
|
||||
future<_R&>::~future()
|
||||
{
|
||||
if (__state_)
|
||||
__state_->__release_shared();
|
||||
}
|
||||
|
||||
template <class _R>
|
||||
_R&
|
||||
future<_R&>::get()
|
||||
{
|
||||
__assoc_state<_R>* __s = __state_;
|
||||
__state_ = nullptr;
|
||||
return __s->copy();
|
||||
}
|
||||
|
||||
template <>
|
||||
class future<void>
|
||||
{
|
||||
__assoc_sub_state* __state_;
|
||||
|
||||
explicit future(__assoc_sub_state* __state);
|
||||
|
||||
template <class> 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 <class _Rep, class _Period>
|
||||
future_status
|
||||
wait_for(const chrono::duration<_Rep, _Period>& __rel_time) const
|
||||
{return __state_->wait_for(__rel_time);}
|
||||
template <class _Clock, class _Duration>
|
||||
future_status
|
||||
wait_until(const chrono::time_point<_Clock, _Duration>& __abs_time) const
|
||||
{return __state_->wait_until(__abs_time);}
|
||||
};
|
||||
|
||||
// promise<R>
|
||||
|
||||
template <class _R>
|
||||
class promise
|
||||
{
|
||||
__assoc_state<_R>* __state_;
|
||||
public:
|
||||
promise();
|
||||
template <class _Alloc>
|
||||
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 <class _R>
|
||||
promise<_R>::promise()
|
||||
: __state_(new __assoc_state<_R>)
|
||||
{
|
||||
}
|
||||
|
||||
template <class _R>
|
||||
template <class _Alloc>
|
||||
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 <class _R>
|
||||
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 <class _R>
|
||||
future<_R>
|
||||
promise<_R>::get_future()
|
||||
{
|
||||
if (__state_ == nullptr)
|
||||
throw future_error(make_error_code(future_errc::no_state));
|
||||
return future<_R>(__state_);
|
||||
}
|
||||
|
||||
template <class _R>
|
||||
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 <class _R>
|
||||
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 <class _R>
|
||||
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 <class _R>
|
||||
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 <class _R>
|
||||
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 <class _R>
|
||||
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<R&>
|
||||
|
||||
template <class _R>
|
||||
class promise<_R&>
|
||||
{
|
||||
__assoc_state<_R&>* __state_;
|
||||
public:
|
||||
promise();
|
||||
template <class _Allocator>
|
||||
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 <class _R>
|
||||
promise<_R&>::promise()
|
||||
: __state_(new __assoc_state<_R&>)
|
||||
{
|
||||
}
|
||||
|
||||
template <class _R>
|
||||
template <class _Alloc>
|
||||
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 <class _R>
|
||||
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 <class _R>
|
||||
future<_R&>
|
||||
promise<_R&>::get_future()
|
||||
{
|
||||
if (__state_ == nullptr)
|
||||
throw future_error(make_error_code(future_errc::no_state));
|
||||
return future<_R&>(__state_);
|
||||
}
|
||||
|
||||
template <class _R>
|
||||
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 <class _R>
|
||||
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 <class _R>
|
||||
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 <class _R>
|
||||
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<void>
|
||||
|
||||
template <>
|
||||
class promise<void>
|
||||
{
|
||||
__assoc_sub_state* __state_;
|
||||
public:
|
||||
promise();
|
||||
template <class _Allocator>
|
||||
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<void> 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 <class _Alloc>
|
||||
promise<void>::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 <class _R>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
void
|
||||
swap(promise<_R>& __x, promise<_R>& __y)
|
||||
{
|
||||
__x.swap(__y);
|
||||
}
|
||||
|
||||
template <class _R, class _Alloc>
|
||||
struct uses_allocator<promise<_R>, _Alloc> : public true_type {};
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP_FUTURE
|
||||
|
@@ -103,6 +103,68 @@ void sleep_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
template <class _Tp>
|
||||
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 <class _Tp>
|
||||
void
|
||||
__thread_specific_ptr<_Tp>::__at_thread_exit(void* __p)
|
||||
{
|
||||
delete static_cast<pointer>(__p);
|
||||
}
|
||||
|
||||
template <class _Tp>
|
||||
__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 <class _Tp>
|
||||
__thread_specific_ptr<_Tp>::~__thread_specific_ptr()
|
||||
{
|
||||
pthread_key_delete(__key_);
|
||||
}
|
||||
|
||||
template <class _Tp>
|
||||
typename __thread_specific_ptr<_Tp>::pointer
|
||||
__thread_specific_ptr<_Tp>::release()
|
||||
{
|
||||
pointer __p = get();
|
||||
pthread_setspecific(__key_, 0);
|
||||
return __p;
|
||||
}
|
||||
|
||||
template <class _Tp>
|
||||
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 <class _F>
|
||||
void*
|
||||
__thread_proxy(void* __vp)
|
||||
{
|
||||
__thread_local_data.reset(new __thread_struct);
|
||||
std::unique_ptr<_F> __p(static_cast<_F*>(__vp));
|
||||
(*__p)();
|
||||
return nullptr;
|
||||
|
157
src/future.cpp
157
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<mutex> __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<mutex> __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<mutex> __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<mutex> __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<mutex> __lk(__mut_);
|
||||
__state_ |= ready;
|
||||
__lk.unlock();
|
||||
__cv_.notify_all();
|
||||
}
|
||||
|
||||
void
|
||||
__assoc_sub_state::copy()
|
||||
{
|
||||
unique_lock<mutex> __lk(__mut_);
|
||||
while (!__is_ready())
|
||||
__cv_.wait(__lk);
|
||||
if (__exception_ != nullptr)
|
||||
rethrow_exception(__exception_);
|
||||
}
|
||||
|
||||
void
|
||||
__assoc_sub_state::wait() const
|
||||
{
|
||||
unique_lock<mutex> __lk(__mut_);
|
||||
while (!__is_ready())
|
||||
__cv_.wait(__lk);
|
||||
}
|
||||
|
||||
future<void>::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<void>::~future()
|
||||
{
|
||||
if (__state_)
|
||||
__state_->__release_shared();
|
||||
}
|
||||
|
||||
void
|
||||
future<void>::get()
|
||||
{
|
||||
__assoc_sub_state* __s = __state_;
|
||||
__state_ = nullptr;
|
||||
return __s->copy();
|
||||
}
|
||||
|
||||
promise<void>::promise()
|
||||
: __state_(new __assoc_sub_state)
|
||||
{
|
||||
}
|
||||
|
||||
promise<void>::~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<void>
|
||||
promise<void>::get_future()
|
||||
{
|
||||
if (__state_ == nullptr)
|
||||
throw future_error(make_error_code(future_errc::no_state));
|
||||
return future<void>(__state_);
|
||||
}
|
||||
|
||||
void
|
||||
promise<void>::set_value()
|
||||
{
|
||||
if (__state_ == nullptr)
|
||||
throw future_error(make_error_code(future_errc::no_state));
|
||||
__state_->set_value();
|
||||
}
|
||||
|
||||
void
|
||||
promise<void>::set_exception(exception_ptr __p)
|
||||
{
|
||||
if (__state_ == nullptr)
|
||||
throw future_error(make_error_code(future_errc::no_state));
|
||||
__state_->set_exception(__p);
|
||||
}
|
||||
|
||||
void
|
||||
promise<void>::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<void>::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
|
||||
|
@@ -9,6 +9,8 @@
|
||||
|
||||
#include "thread"
|
||||
#include "exception"
|
||||
#include "vector"
|
||||
#include "future"
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
@@ -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
|
||||
|
Reference in New Issue
Block a user