2013-06-05 19:19:00 +00:00
|
|
|
#include <fc/thread/future.hpp>
|
|
|
|
|
#include <fc/thread/spin_yield_lock.hpp>
|
|
|
|
|
#include <fc/thread/thread.hpp>
|
|
|
|
|
#include <fc/thread/unique_lock.hpp>
|
|
|
|
|
#include <fc/exception/exception.hpp>
|
2012-09-08 02:50:37 +00:00
|
|
|
|
|
|
|
|
#include <boost/assert.hpp>
|
|
|
|
|
|
2012-09-09 23:44:49 +00:00
|
|
|
|
2012-09-08 02:50:37 +00:00
|
|
|
namespace fc {
|
|
|
|
|
|
|
|
|
|
promise_base::promise_base( const char* desc )
|
2012-09-09 23:44:49 +00:00
|
|
|
:_ready(false),
|
2012-09-08 02:50:37 +00:00
|
|
|
_blocked_thread(nullptr),
|
2013-06-05 19:19:00 +00:00
|
|
|
#ifndef NDEBUG
|
|
|
|
|
_blocked_fiber_count(0),
|
|
|
|
|
#endif
|
|
|
|
|
_timeout(time_point::maximum()),
|
2012-09-08 02:50:37 +00:00
|
|
|
_canceled(false),
|
|
|
|
|
_desc(desc),
|
|
|
|
|
_compl(nullptr)
|
2012-09-09 23:44:49 +00:00
|
|
|
{ }
|
2012-09-08 02:50:37 +00:00
|
|
|
|
|
|
|
|
const char* promise_base::get_desc()const{
|
|
|
|
|
return _desc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void promise_base::cancel(){
|
|
|
|
|
_canceled = true;
|
|
|
|
|
}
|
|
|
|
|
bool promise_base::ready()const {
|
|
|
|
|
return _ready;
|
|
|
|
|
}
|
|
|
|
|
bool promise_base::error()const {
|
|
|
|
|
{ synchronized(_spin_yield)
|
2013-06-05 19:19:00 +00:00
|
|
|
return _exceptp != nullptr;
|
2012-09-08 02:50:37 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void promise_base::set_exception( const fc::exception_ptr& e ){
|
2012-12-03 19:51:31 +00:00
|
|
|
_exceptp = e;
|
2012-09-08 02:50:37 +00:00
|
|
|
_set_value(nullptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void promise_base::_wait( const microseconds& timeout_us ){
|
2013-06-05 19:19:00 +00:00
|
|
|
if( timeout_us == microseconds::maximum() ) _wait_until( time_point::maximum() );
|
2012-09-08 02:50:37 +00:00
|
|
|
else _wait_until( time_point::now() + timeout_us );
|
|
|
|
|
}
|
|
|
|
|
void promise_base::_wait_until( const time_point& timeout_us ){
|
|
|
|
|
{ synchronized(_spin_yield)
|
|
|
|
|
if( _ready ) {
|
2013-06-05 19:19:00 +00:00
|
|
|
if( _exceptp ) _exceptp->dynamic_rethrow_exception();
|
2012-09-08 02:50:37 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
_enqueue_thread();
|
|
|
|
|
}
|
|
|
|
|
thread::current().wait_until( ptr(this,true), timeout_us );
|
2013-06-05 19:19:00 +00:00
|
|
|
_dequeue_thread();
|
2012-09-08 02:50:37 +00:00
|
|
|
if( _ready ) {
|
2013-06-05 19:19:00 +00:00
|
|
|
if( _exceptp ) _exceptp->dynamic_rethrow_exception();
|
2012-09-08 02:50:37 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2013-06-05 19:19:00 +00:00
|
|
|
FC_THROW_EXCEPTION( timeout_exception, "" );
|
2012-09-08 02:50:37 +00:00
|
|
|
}
|
|
|
|
|
void promise_base::_enqueue_thread(){
|
2013-06-05 19:19:00 +00:00
|
|
|
#ifndef NDEBUG
|
|
|
|
|
++_blocked_fiber_count;
|
|
|
|
|
// only one thread can wait on a promise at any given time
|
|
|
|
|
assert(!_blocked_thread ||
|
|
|
|
|
_blocked_thread == &thread::current());
|
|
|
|
|
#endif
|
|
|
|
|
_blocked_thread = &thread::current();
|
|
|
|
|
}
|
|
|
|
|
void promise_base::_dequeue_thread(){
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
|
synchronized(_spin_yield)
|
|
|
|
|
if (!--_blocked_fiber_count)
|
|
|
|
|
_blocked_thread = nullptr;
|
|
|
|
|
#endif
|
2012-09-08 02:50:37 +00:00
|
|
|
}
|
|
|
|
|
void promise_base::_notify(){
|
2012-09-09 23:44:49 +00:00
|
|
|
if( _blocked_thread != nullptr )
|
2012-09-08 02:50:37 +00:00
|
|
|
_blocked_thread->notify(ptr(this,true));
|
|
|
|
|
}
|
2012-09-09 23:44:49 +00:00
|
|
|
promise_base::~promise_base() { }
|
2012-09-08 02:50:37 +00:00
|
|
|
void promise_base::_set_timeout(){
|
|
|
|
|
if( _ready )
|
|
|
|
|
return;
|
2013-06-05 19:19:00 +00:00
|
|
|
set_exception( std::make_shared<fc::timeout_exception>() );
|
2012-09-08 02:50:37 +00:00
|
|
|
}
|
|
|
|
|
void promise_base::_set_value(const void* s){
|
2012-09-09 23:44:49 +00:00
|
|
|
// slog( "%p == %d", &_ready, int(_ready));
|
|
|
|
|
// BOOST_ASSERT( !_ready );
|
2012-09-08 02:50:37 +00:00
|
|
|
{ synchronized(_spin_yield)
|
|
|
|
|
_ready = true;
|
|
|
|
|
}
|
|
|
|
|
_notify();
|
2012-09-09 23:44:49 +00:00
|
|
|
if( nullptr != _compl ) {
|
2012-12-03 19:51:31 +00:00
|
|
|
_compl->on_complete(s,_exceptp);
|
2012-09-08 02:50:37 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void promise_base::_on_complete( detail::completion_handler* c ) {
|
|
|
|
|
{ synchronized(_spin_yield)
|
|
|
|
|
delete _compl;
|
|
|
|
|
_compl = c;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|