2013-06-05 19:19:00 +00:00
|
|
|
#pragma once
|
|
|
|
|
#include <fc/thread/future.hpp>
|
|
|
|
|
#include <fc/thread/priority.hpp>
|
2012-09-09 23:44:49 +00:00
|
|
|
#include <fc/fwd.hpp>
|
2019-06-03 10:21:50 +00:00
|
|
|
#include <type_traits>
|
2012-09-08 02:50:37 +00:00
|
|
|
|
|
|
|
|
namespace fc {
|
|
|
|
|
struct context;
|
2012-09-09 23:44:49 +00:00
|
|
|
class spin_lock;
|
2012-09-08 02:50:37 +00:00
|
|
|
|
2014-08-27 16:20:19 +00:00
|
|
|
namespace detail
|
|
|
|
|
{
|
|
|
|
|
struct specific_data_info
|
|
|
|
|
{
|
|
|
|
|
void* value;
|
|
|
|
|
void (*cleanup)(void*);
|
|
|
|
|
specific_data_info() :
|
|
|
|
|
value(0),
|
|
|
|
|
cleanup(0)
|
|
|
|
|
{}
|
|
|
|
|
specific_data_info(void* value, void (*cleanup)(void*)) :
|
|
|
|
|
value(value),
|
|
|
|
|
cleanup(cleanup)
|
|
|
|
|
{}
|
|
|
|
|
};
|
|
|
|
|
void* get_task_specific_data(unsigned slot);
|
|
|
|
|
void set_task_specific_data(unsigned slot, void* new_value, void(*cleanup)(void*));
|
2018-10-03 08:47:02 +00:00
|
|
|
class idle_guard;
|
2014-08-27 16:20:19 +00:00
|
|
|
}
|
|
|
|
|
|
2012-09-08 02:50:37 +00:00
|
|
|
class task_base : virtual public promise_base {
|
|
|
|
|
public:
|
2014-08-01 15:31:36 +00:00
|
|
|
void run();
|
2014-08-27 18:07:44 +00:00
|
|
|
virtual void cancel(const char* reason FC_CANCELATION_REASON_DEFAULT_ARG) override;
|
2019-06-10 21:25:56 +00:00
|
|
|
virtual ~task_base();
|
2014-08-01 15:31:36 +00:00
|
|
|
|
2019-05-02 14:25:23 +00:00
|
|
|
/* HERE BE DRAGONS
|
|
|
|
|
*
|
2019-06-19 15:31:54 +00:00
|
|
|
* Tasks are handled by an fc::thread . To avoid concurrency issues, fc::thread keeps a reference to the
|
2019-05-02 14:25:23 +00:00
|
|
|
* task in the form of a simple pointer.
|
|
|
|
|
* At the same time, a task is also a promise that will be fulfilled with the task result, so typically the
|
|
|
|
|
* creator of the task also keeps a reference to the task (but not necessarily always).
|
|
|
|
|
*
|
|
|
|
|
* Because effectively neither fc::thread nor the task creator are responsible for releasing resources
|
|
|
|
|
* associated with a task, and neither can delete the task without knowing if the other still needs it,
|
|
|
|
|
* the task object is managed by a shared_ptr.
|
|
|
|
|
* However, fc::thread doesn't hold a shared_ptr but a native pointer. To work around this, the task can
|
|
|
|
|
* be made to contain a shared_ptr holding itself (by calling retain()), which happens before the task
|
|
|
|
|
* is handed to an fc::thread, e. g. in fc::async(). Once the thread has processed the task, it calls
|
|
|
|
|
* release() which deletes the self-referencing shared_ptr and deletes the task object if it's no longer
|
|
|
|
|
* in use anywhere.
|
|
|
|
|
*/
|
|
|
|
|
void retain();
|
|
|
|
|
void release();
|
|
|
|
|
|
2012-09-08 02:50:37 +00:00
|
|
|
protected:
|
2014-01-06 22:58:38 +00:00
|
|
|
/// Task priority looks like unsupported feature.
|
2012-09-08 02:50:37 +00:00
|
|
|
uint64_t _posted_num;
|
|
|
|
|
priority _prio;
|
|
|
|
|
time_point _when;
|
|
|
|
|
void _set_active_context(context*);
|
|
|
|
|
context* _active_context;
|
|
|
|
|
task_base* _next;
|
|
|
|
|
|
2014-08-27 16:20:19 +00:00
|
|
|
// support for task-specific data
|
|
|
|
|
std::vector<detail::specific_data_info> *_task_specific_data;
|
|
|
|
|
|
|
|
|
|
friend void* detail::get_task_specific_data(unsigned slot);
|
|
|
|
|
friend void detail::set_task_specific_data(unsigned slot, void* new_value, void(*cleanup)(void*));
|
|
|
|
|
|
2012-09-08 02:50:37 +00:00
|
|
|
task_base(void* func);
|
|
|
|
|
// opaque internal / private data used by
|
|
|
|
|
// thread/thread_private
|
|
|
|
|
friend class thread;
|
|
|
|
|
friend class thread_d;
|
2018-10-03 08:47:02 +00:00
|
|
|
friend class detail::idle_guard;
|
2012-09-09 23:44:49 +00:00
|
|
|
fwd<spin_lock,8> _spinlock;
|
2012-09-08 02:50:37 +00:00
|
|
|
|
|
|
|
|
// avoid rtti info for every possible functor...
|
2012-09-09 23:44:49 +00:00
|
|
|
void* _promise_impl;
|
2012-09-08 02:50:37 +00:00
|
|
|
void* _functor;
|
|
|
|
|
void (*_destroy_functor)(void*);
|
|
|
|
|
void (*_run_functor)(void*, void* );
|
2014-03-08 23:48:19 +00:00
|
|
|
|
|
|
|
|
void run_impl();
|
2014-08-27 16:20:19 +00:00
|
|
|
|
|
|
|
|
void cleanup_task_specific_data();
|
2019-05-02 14:25:23 +00:00
|
|
|
private:
|
|
|
|
|
std::shared_ptr<promise_base> _self;
|
|
|
|
|
boost::atomic<int32_t> _retain_count;
|
2012-09-08 02:50:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
namespace detail {
|
|
|
|
|
template<typename T>
|
|
|
|
|
struct functor_destructor {
|
|
|
|
|
static void destroy( void* v ) { ((T*)v)->~T(); }
|
|
|
|
|
};
|
|
|
|
|
template<typename T>
|
|
|
|
|
struct functor_run {
|
|
|
|
|
static void run( void* functor, void* prom ) {
|
|
|
|
|
((promise<decltype((*((T*)functor))())>*)prom)->set_value( (*((T*)functor))() );
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
template<typename T>
|
|
|
|
|
struct void_functor_run {
|
|
|
|
|
static void run( void* functor, void* prom ) {
|
|
|
|
|
(*((T*)functor))();
|
|
|
|
|
((promise<void>*)prom)->set_value();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename R,uint64_t FunctorSize=64>
|
|
|
|
|
class task : virtual public task_base, virtual public promise<R> {
|
|
|
|
|
public:
|
2019-04-26 12:21:11 +00:00
|
|
|
typedef std::shared_ptr<task<R,FunctorSize>> ptr;
|
|
|
|
|
|
|
|
|
|
virtual ~task(){}
|
|
|
|
|
|
|
|
|
|
template<typename Functor>
|
|
|
|
|
static ptr create( Functor&& f, const char* desc )
|
|
|
|
|
{
|
|
|
|
|
return ptr( new task<R,FunctorSize>( std::move(f), desc ) );
|
|
|
|
|
}
|
|
|
|
|
virtual void cancel(const char* reason FC_CANCELATION_REASON_DEFAULT_ARG) override { task_base::cancel(reason); }
|
|
|
|
|
private:
|
2012-09-08 02:50:37 +00:00
|
|
|
template<typename Functor>
|
2014-07-28 00:46:39 +00:00
|
|
|
task( Functor&& f, const char* desc ):promise_base(desc), task_base(&_functor), promise<R>(desc) {
|
2019-06-03 10:21:50 +00:00
|
|
|
typedef typename std::remove_const_t< std::remove_reference_t<Functor> > FunctorType;
|
2012-09-08 02:50:37 +00:00
|
|
|
static_assert( sizeof(f) <= sizeof(_functor), "sizeof(Functor) is larger than FunctorSize" );
|
2019-06-03 10:06:55 +00:00
|
|
|
new ((char*)&_functor) FunctorType( std::forward<Functor>(f) );
|
2012-12-15 15:26:03 +00:00
|
|
|
_destroy_functor = &detail::functor_destructor<FunctorType>::destroy;
|
2012-09-08 02:50:37 +00:00
|
|
|
|
|
|
|
|
_promise_impl = static_cast<promise<R>*>(this);
|
2012-12-15 15:26:03 +00:00
|
|
|
_run_functor = &detail::functor_run<FunctorType>::run;
|
2012-09-08 02:50:37 +00:00
|
|
|
}
|
2019-06-19 15:40:22 +00:00
|
|
|
|
|
|
|
|
alignas(double) char _functor[FunctorSize];
|
2012-09-08 02:50:37 +00:00
|
|
|
};
|
2014-07-28 00:46:39 +00:00
|
|
|
|
2012-09-08 02:50:37 +00:00
|
|
|
template<uint64_t FunctorSize>
|
2019-04-26 12:21:11 +00:00
|
|
|
class task<void,FunctorSize> : public task_base, public promise<void> {
|
2012-09-08 02:50:37 +00:00
|
|
|
public:
|
2019-04-26 12:21:11 +00:00
|
|
|
typedef std::shared_ptr<task<void,FunctorSize>> ptr;
|
|
|
|
|
|
|
|
|
|
virtual ~task(){}
|
|
|
|
|
|
|
|
|
|
template<typename Functor>
|
|
|
|
|
static ptr create( Functor&& f, const char* desc )
|
|
|
|
|
{
|
|
|
|
|
return ptr( new task<void,FunctorSize>( std::move(f), desc ) );
|
|
|
|
|
}
|
|
|
|
|
virtual void cancel(const char* reason FC_CANCELATION_REASON_DEFAULT_ARG) override { task_base::cancel(reason); }
|
|
|
|
|
private:
|
2012-09-08 02:50:37 +00:00
|
|
|
template<typename Functor>
|
2014-07-28 00:46:39 +00:00
|
|
|
task( Functor&& f, const char* desc ):promise_base(desc), task_base(&_functor), promise<void>(desc) {
|
2019-06-03 10:21:50 +00:00
|
|
|
typedef typename std::remove_const_t< std::remove_reference_t<Functor> > FunctorType;
|
2012-09-08 02:50:37 +00:00
|
|
|
static_assert( sizeof(f) <= sizeof(_functor), "sizeof(Functor) is larger than FunctorSize" );
|
2019-06-03 10:06:55 +00:00
|
|
|
new ((char*)&_functor) FunctorType( std::forward<Functor>(f) );
|
2012-12-15 15:26:03 +00:00
|
|
|
_destroy_functor = &detail::functor_destructor<FunctorType>::destroy;
|
2012-09-08 02:50:37 +00:00
|
|
|
|
|
|
|
|
_promise_impl = static_cast<promise<void>*>(this);
|
2012-12-15 15:26:03 +00:00
|
|
|
_run_functor = &detail::void_functor_run<FunctorType>::run;
|
2012-09-08 02:50:37 +00:00
|
|
|
}
|
2019-06-19 15:40:22 +00:00
|
|
|
|
|
|
|
|
alignas(double) char _functor[FunctorSize];
|
2012-09-08 02:50:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
}
|