2013-06-05 19:19:00 +00:00
|
|
|
#pragma once
|
2012-09-08 02:50:37 +00:00
|
|
|
#include <fc/utility.hpp>
|
|
|
|
|
#include <fc/time.hpp>
|
|
|
|
|
#include <fc/shared_ptr.hpp>
|
2013-06-05 19:19:00 +00:00
|
|
|
#include <fc/exception/exception.hpp>
|
|
|
|
|
#include <fc/thread/spin_yield_lock.hpp>
|
2012-09-08 02:50:37 +00:00
|
|
|
#include <fc/optional.hpp>
|
|
|
|
|
|
2022-04-01 11:11:39 +00:00
|
|
|
#include <fc/fwd.hpp>
|
|
|
|
|
|
2014-07-27 21:37:21 +00:00
|
|
|
//#define FC_TASK_NAMES_ARE_MANDATORY 1
|
|
|
|
|
#ifdef FC_TASK_NAMES_ARE_MANDATORY
|
|
|
|
|
# define FC_TASK_NAME_DEFAULT_ARG
|
|
|
|
|
#else
|
|
|
|
|
# define FC_TASK_NAME_DEFAULT_ARG = "?"
|
|
|
|
|
#endif
|
|
|
|
|
|
2014-08-28 19:42:01 +00:00
|
|
|
//#define FC_CANCELATION_REASONS_ARE_MANDATORY 1
|
2014-08-27 18:07:44 +00:00
|
|
|
#ifdef FC_CANCELATION_REASONS_ARE_MANDATORY
|
|
|
|
|
# define FC_CANCELATION_REASON_DEFAULT_ARG
|
|
|
|
|
#else
|
|
|
|
|
# define FC_CANCELATION_REASON_DEFAULT_ARG = nullptr
|
|
|
|
|
#endif
|
|
|
|
|
|
2012-09-08 02:50:37 +00:00
|
|
|
namespace fc {
|
|
|
|
|
class abstract_thread;
|
2013-06-05 19:19:00 +00:00
|
|
|
struct void_t{};
|
2012-09-08 02:50:37 +00:00
|
|
|
class priority;
|
|
|
|
|
class thread;
|
2022-04-01 11:11:39 +00:00
|
|
|
class spin_lock;
|
2012-09-08 02:50:37 +00:00
|
|
|
|
|
|
|
|
namespace detail {
|
|
|
|
|
class completion_handler {
|
|
|
|
|
public:
|
|
|
|
|
virtual ~completion_handler(){};
|
|
|
|
|
virtual void on_complete( const void* v, const fc::exception_ptr& e ) = 0;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<typename Functor, typename T>
|
|
|
|
|
class completion_handler_impl : public completion_handler {
|
|
|
|
|
public:
|
|
|
|
|
completion_handler_impl( Functor&& f ):_func(fc::move(f)){}
|
|
|
|
|
completion_handler_impl( const Functor& f ):_func(f){}
|
|
|
|
|
|
|
|
|
|
virtual void on_complete( const void* v, const fc::exception_ptr& e ) {
|
|
|
|
|
_func( *static_cast<const T*>(v), e);
|
|
|
|
|
}
|
|
|
|
|
private:
|
|
|
|
|
Functor _func;
|
|
|
|
|
};
|
|
|
|
|
template<typename Functor>
|
|
|
|
|
class completion_handler_impl<Functor,void> : public completion_handler {
|
|
|
|
|
public:
|
|
|
|
|
completion_handler_impl( Functor&& f ):_func(fc::move(f)){}
|
|
|
|
|
completion_handler_impl( const Functor& f ):_func(f){}
|
|
|
|
|
virtual void on_complete( const void* v, const fc::exception_ptr& e ) {
|
|
|
|
|
_func(e);
|
|
|
|
|
}
|
|
|
|
|
private:
|
|
|
|
|
Functor _func;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-05 19:19:00 +00:00
|
|
|
class promise_base : public virtual retainable{
|
2012-09-08 02:50:37 +00:00
|
|
|
public:
|
2013-06-05 19:19:00 +00:00
|
|
|
typedef fc::shared_ptr<promise_base> ptr;
|
2014-07-27 21:37:21 +00:00
|
|
|
promise_base(const char* desc FC_TASK_NAME_DEFAULT_ARG);
|
2012-09-08 02:50:37 +00:00
|
|
|
|
|
|
|
|
const char* get_desc()const;
|
|
|
|
|
|
2014-08-27 18:07:44 +00:00
|
|
|
virtual void cancel(const char* reason FC_CANCELATION_REASON_DEFAULT_ARG);
|
2013-08-06 16:45:49 +00:00
|
|
|
bool canceled()const { return _canceled; }
|
2012-09-08 02:50:37 +00:00
|
|
|
bool ready()const;
|
2022-04-04 06:03:56 +00:00
|
|
|
bool error()const;
|
2012-09-08 02:50:37 +00:00
|
|
|
|
|
|
|
|
void set_exception( const fc::exception_ptr& e );
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
void _wait( const microseconds& timeout_us );
|
|
|
|
|
void _wait_until( const time_point& timeout_us );
|
|
|
|
|
void _enqueue_thread();
|
2013-06-05 19:19:00 +00:00
|
|
|
void _dequeue_thread();
|
2012-09-08 02:50:37 +00:00
|
|
|
void _notify();
|
|
|
|
|
void _set_timeout();
|
|
|
|
|
void _set_value(const void* v);
|
|
|
|
|
|
|
|
|
|
void _on_complete( detail::completion_handler* c );
|
2012-09-09 23:44:49 +00:00
|
|
|
~promise_base();
|
|
|
|
|
|
2022-04-04 06:03:56 +00:00
|
|
|
//fwd<spin_lock,8> _spinlock;
|
2022-04-01 11:11:39 +00:00
|
|
|
|
2012-09-08 02:50:37 +00:00
|
|
|
private:
|
|
|
|
|
friend class thread;
|
|
|
|
|
friend struct context;
|
|
|
|
|
friend class thread_d;
|
|
|
|
|
|
|
|
|
|
bool _ready;
|
2022-04-04 06:03:56 +00:00
|
|
|
mutable spin_yield_lock _spin_yield;
|
2012-09-08 02:50:37 +00:00
|
|
|
thread* _blocked_thread;
|
2013-06-05 19:19:00 +00:00
|
|
|
unsigned _blocked_fiber_count;
|
2012-09-08 02:50:37 +00:00
|
|
|
time_point _timeout;
|
2012-12-03 19:51:31 +00:00
|
|
|
fc::exception_ptr _exceptp;
|
2012-09-08 02:50:37 +00:00
|
|
|
bool _canceled;
|
2014-08-28 19:42:01 +00:00
|
|
|
#ifndef NDEBUG
|
|
|
|
|
protected:
|
2014-08-27 18:07:44 +00:00
|
|
|
const char* _cancellation_reason;
|
2014-08-28 19:42:01 +00:00
|
|
|
private:
|
|
|
|
|
#endif
|
2012-09-08 02:50:37 +00:00
|
|
|
const char* _desc;
|
|
|
|
|
detail::completion_handler* _compl;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<typename T = void>
|
|
|
|
|
class promise : virtual public promise_base {
|
|
|
|
|
public:
|
2013-06-05 19:19:00 +00:00
|
|
|
typedef fc::shared_ptr< promise<T> > ptr;
|
2014-07-27 21:37:21 +00:00
|
|
|
promise( const char* desc FC_TASK_NAME_DEFAULT_ARG):promise_base(desc){}
|
2012-09-08 02:50:37 +00:00
|
|
|
promise( const T& val ){ set_value(val); }
|
|
|
|
|
promise( T&& val ){ set_value(fc::move(val) ); }
|
|
|
|
|
|
2013-06-05 19:19:00 +00:00
|
|
|
const T& wait(const microseconds& timeout = microseconds::maximum() ){
|
2012-09-08 02:50:37 +00:00
|
|
|
this->_wait( timeout );
|
|
|
|
|
return *result;
|
|
|
|
|
}
|
|
|
|
|
const T& wait_until(const time_point& tp ) {
|
|
|
|
|
this->_wait_until( tp );
|
|
|
|
|
return *result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void set_value( const T& v ) {
|
|
|
|
|
result = v;
|
|
|
|
|
_set_value(&*result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void set_value( T&& v ) {
|
|
|
|
|
result = fc::move(v);
|
|
|
|
|
_set_value(&*result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename CompletionHandler>
|
|
|
|
|
void on_complete( CompletionHandler&& c ) {
|
|
|
|
|
_on_complete( new detail::completion_handler_impl<CompletionHandler,T>(fc::forward<CompletionHandler>(c)) );
|
|
|
|
|
}
|
|
|
|
|
protected:
|
|
|
|
|
optional<T> result;
|
2012-09-09 23:44:49 +00:00
|
|
|
~promise(){}
|
2012-09-08 02:50:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<>
|
2012-09-09 23:44:49 +00:00
|
|
|
class promise<void> : virtual public promise_base {
|
2012-09-08 02:50:37 +00:00
|
|
|
public:
|
2013-06-05 19:19:00 +00:00
|
|
|
typedef fc::shared_ptr< promise<void> > ptr;
|
2014-07-27 21:37:21 +00:00
|
|
|
promise( const char* desc FC_TASK_NAME_DEFAULT_ARG):promise_base(desc){}
|
|
|
|
|
//promise( const void_t& ){ set_value(); }
|
2012-09-08 02:50:37 +00:00
|
|
|
|
2013-06-05 19:19:00 +00:00
|
|
|
void wait(const microseconds& timeout = microseconds::maximum() ){
|
2012-09-08 02:50:37 +00:00
|
|
|
this->_wait( timeout );
|
|
|
|
|
}
|
|
|
|
|
void wait_until(const time_point& tp ) {
|
|
|
|
|
this->_wait_until( tp );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void set_value(){ this->_set_value(nullptr); }
|
2013-06-05 19:19:00 +00:00
|
|
|
void set_value( const void_t& ) { this->_set_value(nullptr); }
|
2012-09-08 02:50:37 +00:00
|
|
|
|
|
|
|
|
template<typename CompletionHandler>
|
|
|
|
|
void on_complete( CompletionHandler&& c ) {
|
|
|
|
|
_on_complete( new detail::completion_handler_impl<CompletionHandler,void>(fc::forward<CompletionHandler>(c)) );
|
|
|
|
|
}
|
2012-09-09 23:44:49 +00:00
|
|
|
protected:
|
|
|
|
|
~promise(){}
|
2012-09-08 02:50:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief a placeholder for the result of an asynchronous operation.
|
|
|
|
|
*
|
|
|
|
|
* By calling future<T>::wait() you will block the current fiber until
|
|
|
|
|
* the asynchronous operation completes.
|
|
|
|
|
*
|
|
|
|
|
* If you would like to use an asynchronous interface instead of the synchronous
|
|
|
|
|
* 'wait' method you could specify a CompletionHandler which is a method that takes
|
|
|
|
|
* two parameters, a const reference to the value and an exception_ptr. If the
|
|
|
|
|
* exception_ptr is set, the value reference is invalid and accessing it is
|
|
|
|
|
* 'undefined'.
|
|
|
|
|
*
|
|
|
|
|
* Promises have pointer semantics, futures have reference semantics that
|
|
|
|
|
* contain a shared pointer to a promise.
|
|
|
|
|
*/
|
|
|
|
|
template<typename T>
|
|
|
|
|
class future {
|
|
|
|
|
public:
|
2013-06-05 19:19:00 +00:00
|
|
|
future( const fc::shared_ptr<promise<T>>& p ):m_prom(p){}
|
|
|
|
|
future( fc::shared_ptr<promise<T>>&& p ):m_prom(fc::move(p)){}
|
2013-12-13 03:18:09 +00:00
|
|
|
future(const future<T>& f ) : m_prom(f.m_prom){}
|
2012-09-08 02:50:37 +00:00
|
|
|
future(){}
|
2012-11-24 18:02:23 +00:00
|
|
|
|
2013-12-12 14:19:15 +00:00
|
|
|
future& operator=(future<T>&& f ) {
|
|
|
|
|
fc_swap(m_prom,f.m_prom);
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-11-24 18:02:23 +00:00
|
|
|
operator const T&()const { return wait(); }
|
2012-09-08 02:50:37 +00:00
|
|
|
|
|
|
|
|
/// @pre valid()
|
|
|
|
|
/// @post ready()
|
|
|
|
|
/// @throws timeout
|
2013-06-05 19:19:00 +00:00
|
|
|
const T& wait( const microseconds& timeout = microseconds::maximum() )const {
|
2014-06-29 05:38:46 +00:00
|
|
|
return m_prom->wait(timeout);
|
2012-09-08 02:50:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// @pre valid()
|
|
|
|
|
/// @post ready()
|
|
|
|
|
/// @throws timeout
|
2012-11-24 18:02:23 +00:00
|
|
|
const T& wait_until( const time_point& tp )const {
|
2014-06-29 05:38:46 +00:00
|
|
|
if( m_prom )
|
|
|
|
|
return m_prom->wait_until(tp);
|
2012-09-08 02:50:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool valid()const { return !!m_prom; }
|
|
|
|
|
|
|
|
|
|
/// @pre valid()
|
|
|
|
|
bool ready()const { return m_prom->ready(); }
|
|
|
|
|
|
|
|
|
|
/// @pre valid()
|
|
|
|
|
bool error()const { return m_prom->error(); }
|
|
|
|
|
|
2014-08-27 18:07:44 +00:00
|
|
|
void cancel(const char* reason FC_CANCELATION_REASON_DEFAULT_ARG) const { if( m_prom ) m_prom->cancel(reason); }
|
2014-07-17 21:03:25 +00:00
|
|
|
bool canceled()const { if( m_prom ) return m_prom->canceled(); else return true;}
|
2012-09-09 15:34:26 +00:00
|
|
|
|
2014-08-27 18:07:44 +00:00
|
|
|
void cancel_and_wait(const char* reason FC_CANCELATION_REASON_DEFAULT_ARG)
|
2014-06-29 05:38:46 +00:00
|
|
|
{
|
|
|
|
|
if( valid() )
|
|
|
|
|
{
|
2014-08-27 18:07:44 +00:00
|
|
|
cancel(reason);
|
2014-07-26 18:51:48 +00:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
wait();
|
|
|
|
|
}
|
|
|
|
|
catch (const canceled_exception&)
|
|
|
|
|
{
|
|
|
|
|
}
|
2014-06-29 05:38:46 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-08 02:50:37 +00:00
|
|
|
/**
|
|
|
|
|
* @pre valid()
|
|
|
|
|
*
|
|
|
|
|
* The given completion handler will be called from some
|
|
|
|
|
* arbitrary thread and should not 'block'. Generally
|
|
|
|
|
* it should post an event or start a new async operation.
|
|
|
|
|
*/
|
|
|
|
|
template<typename CompletionHandler>
|
|
|
|
|
void on_complete( CompletionHandler&& c ) {
|
|
|
|
|
m_prom->on_complete( fc::forward<CompletionHandler>(c) );
|
|
|
|
|
}
|
|
|
|
|
private:
|
2012-11-01 04:23:06 +00:00
|
|
|
friend class thread;
|
2013-06-05 19:19:00 +00:00
|
|
|
fc::shared_ptr<promise<T>> m_prom;
|
2012-09-08 02:50:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
class future<void> {
|
|
|
|
|
public:
|
2013-06-05 19:19:00 +00:00
|
|
|
future( const fc::shared_ptr<promise<void>>& p ):m_prom(p){}
|
|
|
|
|
future( fc::shared_ptr<promise<void>>&& p ):m_prom(fc::move(p)){}
|
2013-12-13 14:13:08 +00:00
|
|
|
future(const future<void>& f ) : m_prom(f.m_prom){}
|
2012-09-08 02:50:37 +00:00
|
|
|
future(){}
|
2013-12-12 14:19:15 +00:00
|
|
|
|
|
|
|
|
future& operator=(future<void>&& f ) {
|
|
|
|
|
fc_swap(m_prom,f.m_prom);
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-08 02:50:37 +00:00
|
|
|
|
|
|
|
|
/// @pre valid()
|
|
|
|
|
/// @post ready()
|
|
|
|
|
/// @throws timeout
|
2013-06-05 19:19:00 +00:00
|
|
|
void wait( const microseconds& timeout = microseconds::maximum() ){
|
2014-06-29 05:38:46 +00:00
|
|
|
if( m_prom )
|
|
|
|
|
m_prom->wait(timeout);
|
2012-09-08 02:50:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// @pre valid()
|
|
|
|
|
/// @post ready()
|
|
|
|
|
/// @throws timeout
|
|
|
|
|
void wait_until( const time_point& tp ) {
|
|
|
|
|
m_prom->wait_until(tp);
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-06 16:45:49 +00:00
|
|
|
bool valid()const { return !!m_prom; }
|
2014-07-17 21:03:25 +00:00
|
|
|
bool canceled()const { return m_prom ? m_prom->canceled() : true; }
|
2012-09-08 02:50:37 +00:00
|
|
|
|
2014-08-27 18:07:44 +00:00
|
|
|
void cancel_and_wait(const char* reason FC_CANCELATION_REASON_DEFAULT_ARG)
|
2014-06-29 05:38:46 +00:00
|
|
|
{
|
2014-08-27 18:07:44 +00:00
|
|
|
cancel(reason);
|
2014-07-26 18:51:48 +00:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
wait();
|
|
|
|
|
}
|
|
|
|
|
catch (const canceled_exception&)
|
|
|
|
|
{
|
|
|
|
|
}
|
2014-06-29 05:38:46 +00:00
|
|
|
}
|
|
|
|
|
|
2012-09-08 02:50:37 +00:00
|
|
|
/// @pre valid()
|
|
|
|
|
bool ready()const { return m_prom->ready(); }
|
|
|
|
|
|
|
|
|
|
/// @pre valid()
|
|
|
|
|
bool error()const { return m_prom->error(); }
|
|
|
|
|
|
2014-08-27 18:07:44 +00:00
|
|
|
void cancel(const char* reason FC_CANCELATION_REASON_DEFAULT_ARG) const { if( m_prom ) m_prom->cancel(reason); }
|
2012-09-09 15:34:26 +00:00
|
|
|
|
2012-09-08 02:50:37 +00:00
|
|
|
template<typename CompletionHandler>
|
|
|
|
|
void on_complete( CompletionHandler&& c ) {
|
|
|
|
|
m_prom->on_complete( fc::forward<CompletionHandler>(c) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2012-11-01 04:23:06 +00:00
|
|
|
friend class thread;
|
2013-06-05 19:19:00 +00:00
|
|
|
fc::shared_ptr<promise<void>> m_prom;
|
2012-09-08 02:50:37 +00:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|