BitShares-Core  4.0.0
BitShares blockchain implementation and command-line interface software
task.hpp
Go to the documentation of this file.
1 #pragma once
2 #include <fc/thread/future.hpp>
3 #include <fc/thread/priority.hpp>
4 #include <fc/fwd.hpp>
5 #include <type_traits>
6 
7 #include <boost/atomic.hpp>
8 
9 namespace fc {
10  struct context;
11  class spin_lock;
12 
13  namespace detail
14  {
16  {
17  void* value;
18  void (*cleanup)(void*);
20  value(0),
21  cleanup(0)
22  {}
23  specific_data_info(void* value, void (*cleanup)(void*)) :
24  value(value),
26  {}
27  };
28  void* get_task_specific_data(unsigned slot);
29  void set_task_specific_data(unsigned slot, void* new_value, void(*cleanup)(void*));
30  class idle_guard;
31  }
32 
33  class task_base : virtual public promise_base {
34  public:
35  void run();
36  virtual void cancel(const char* reason FC_CANCELATION_REASON_DEFAULT_ARG) override;
37  virtual ~task_base();
38 
39  /* HERE BE DRAGONS
40  *
41  * Tasks are handled by an fc::thread . To avoid concurrency issues, fc::thread keeps a reference to the
42  * task in the form of a simple pointer.
43  * At the same time, a task is also a promise that will be fulfilled with the task result, so typically the
44  * creator of the task also keeps a reference to the task (but not necessarily always).
45  *
46  * Because effectively neither fc::thread nor the task creator are responsible for releasing resources
47  * associated with a task, and neither can delete the task without knowing if the other still needs it,
48  * the task object is managed by a shared_ptr.
49  * However, fc::thread doesn't hold a shared_ptr but a native pointer. To work around this, the task can
50  * be made to contain a shared_ptr holding itself (by calling retain()), which happens before the task
51  * is handed to an fc::thread, e. g. in fc::async(). Once the thread has processed the task, it calls
52  * release() which deletes the self-referencing shared_ptr and deletes the task object if it's no longer
53  * in use anywhere.
54  */
55  void retain();
56  void release();
57 
58  protected:
60  uint64_t _posted_num;
63  void _set_active_context(context*);
66 
67  // support for task-specific data
68  std::vector<detail::specific_data_info> *_task_specific_data;
69 
70  friend void* detail::get_task_specific_data(unsigned slot);
71  friend void detail::set_task_specific_data(unsigned slot, void* new_value, void(*cleanup)(void*));
72 
73  task_base(void* func);
74  // opaque internal / private data used by
75  // thread/thread_private
76  friend class thread;
77  friend class thread_d;
78  friend class detail::idle_guard;
80 
81  // avoid rtti info for every possible functor...
83  void* _functor;
84  void (*_destroy_functor)(void*);
85  void (*_run_functor)(void*, void* );
86 
87  void run_impl();
88 
89  void cleanup_task_specific_data();
90  private:
91  std::shared_ptr<promise_base> _self;
92  boost::atomic<int32_t> _retain_count;
93  };
94 
95  namespace detail {
96  template<typename T>
98  static void destroy( void* v ) { ((T*)v)->~T(); }
99  };
100  template<typename T>
101  struct functor_run {
102  static void run( void* functor, void* prom ) {
103  ((promise<decltype((*((T*)functor))())>*)prom)->set_value( (*((T*)functor))() );
104  }
105  };
106  template<typename T>
108  static void run( void* functor, void* prom ) {
109  (*((T*)functor))();
110  ((promise<void>*)prom)->set_value();
111  }
112  };
113  }
114 
115  template<typename R,uint64_t FunctorSize=64>
116  class task : virtual public task_base, virtual public promise<R> {
117  public:
118  typedef std::shared_ptr<task<R,FunctorSize>> ptr;
119 
120  virtual ~task(){}
121 
122  template<typename Functor>
123  static ptr create( Functor&& f, const char* desc )
124  {
125  return ptr( new task<R,FunctorSize>( std::move(f), desc ) );
126  }
127  virtual void cancel(const char* reason FC_CANCELATION_REASON_DEFAULT_ARG) override { task_base::cancel(reason); }
128  private:
129  template<typename Functor>
130  task( Functor&& f, const char* desc ):promise_base(desc), task_base(&_functor), promise<R>(desc) {
131  typedef typename std::remove_const_t< std::remove_reference_t<Functor> > FunctorType;
132  static_assert( sizeof(f) <= sizeof(_functor), "sizeof(Functor) is larger than FunctorSize" );
133  new ((char*)&_functor) FunctorType( std::forward<Functor>(f) );
135 
136  _promise_impl = static_cast<promise<R>*>(this);
138  }
139 
140  alignas(double) char _functor[FunctorSize];
141  };
142 
143  template<uint64_t FunctorSize>
144  class task<void,FunctorSize> : public task_base, public promise<void> {
145  public:
146  typedef std::shared_ptr<task<void,FunctorSize>> ptr;
147 
148  virtual ~task(){}
149 
150  template<typename Functor>
151  static ptr create( Functor&& f, const char* desc )
152  {
153  return ptr( new task<void,FunctorSize>( std::move(f), desc ) );
154  }
155  virtual void cancel(const char* reason FC_CANCELATION_REASON_DEFAULT_ARG) override { task_base::cancel(reason); }
156  private:
157  template<typename Functor>
158  task( Functor&& f, const char* desc ):promise_base(desc), task_base(&_functor), promise<void>(desc) {
159  typedef typename std::remove_const_t< std::remove_reference_t<Functor> > FunctorType;
160  static_assert( sizeof(f) <= sizeof(_functor), "sizeof(Functor) is larger than FunctorSize" );
161  new ((char*)&_functor) FunctorType( std::forward<Functor>(f) );
163 
164  _promise_impl = static_cast<promise<void>*>(this);
166  }
167 
168  alignas(double) char _functor[FunctorSize];
169  };
170 
171 }
Used to forward declare value types.
Definition: fwd.hpp:10
time_point _when
Definition: task.hpp:62
void set_task_specific_data(unsigned slot, void *new_value, void(*cleanup)(void *))
static void destroy(void *v)
Definition: task.hpp:98
static ptr create(Functor &&f, const char *desc)
Definition: task.hpp:123
virtual void cancel(const char *reason FC_CANCELATION_REASON_DEFAULT_ARG) override
Definition: task.cpp:64
void * get_task_specific_data(unsigned slot)
#define FC_CANCELATION_REASON_DEFAULT_ARG
Definition: future.hpp:21
specific_data_info(void *value, void(*cleanup)(void *))
Definition: task.hpp:23
uint64_t _posted_num
Task priority looks like unsupported feature.
Definition: task.hpp:60
void * _promise_impl
Definition: task.hpp:82
static void run(void *functor, void *prom)
Definition: task.hpp:102
fwd< spin_lock, 8 > _spinlock
Definition: task.hpp:79
std::shared_ptr< task< R, FunctorSize > > ptr
Definition: task.hpp:118
static void run(void *functor, void *prom)
Definition: task.hpp:108
virtual void cancel(const char *reason FC_CANCELATION_REASON_DEFAULT_ARG) override
Definition: task.hpp:155
std::shared_ptr< task< void, FunctorSize > > ptr
Definition: task.hpp:146
task_base * _next
Definition: task.hpp:65
std::vector< detail::specific_data_info > * _task_specific_data
Definition: task.hpp:68
static ptr create(Functor &&f, const char *desc)
Definition: task.hpp:151
void(* cleanup)(void *)
Definition: task.hpp:18
Definition: api.hpp:15
virtual void cancel(const char *reason FC_CANCELATION_REASON_DEFAULT_ARG) override
Definition: task.hpp:127
virtual ~task()
Definition: task.hpp:120
void * _functor
Definition: task.hpp:83
context * _active_context
Definition: task.hpp:64
priority _prio
Definition: task.hpp:61