libcopp  1.2.0
task.h
Go to the documentation of this file.
1 /*
2  * task.h
3  *
4  * Created on: 2014年4月1日
5  * Author: owent
6  *
7  * Released under the MIT license
8  */
9 
10 #ifndef COTASK_TASK_H
11 #define COTASK_TASK_H
12 
13 #pragma once
14 
15 #include <algorithm>
16 #include <cstddef>
17 #include <stdint.h>
18 
20 #include <libcopp/utils/errno.h>
21 #include <libcotask/task_macros.h>
22 #include <libcotask/this_task.h>
23 
24 
25 namespace cotask {
26 
27  template <typename TCO_MACRO = macro_coroutine, typename TTASK_MACRO = macro_task>
28  class task : public impl::task_impl {
29  public:
32  typedef TCO_MACRO macro_coroutine_t;
33  typedef TTASK_MACRO macro_task_t;
34 
35  typedef typename macro_coroutine_t::coroutine_t coroutine_t;
36  typedef typename macro_coroutine_t::stack_allocator_t stack_allocator_t;
37 
38  typedef typename macro_task_t::id_t id_t;
39  typedef typename macro_task_t::id_allocator_t id_allocator_t;
40 
41 
42  struct task_group {
43  std::list<std::pair<ptr_t, void *> > member_list_;
44  };
45 
46  private:
48 
49  public:
54  task(size_t stack_sz)
55  : id_(0), stack_size_(stack_sz), action_destroy_fn_(UTIL_CONFIG_NULLPTR)
57  ,
58  binding_manager_ptr_(UTIL_CONFIG_NULLPTR), binding_manager_fn_(UTIL_CONFIG_NULLPTR)
59 #endif
60  {
61  id_allocator_t id_alloc_;
62  id_ = id_alloc_.allocate();
63  ref_count_.store(0);
64  }
65 
66 
74 #if defined(UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES) && UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES
75  template <typename TAct, typename Ty>
76  static ptr_t create_with_delegate(Ty &&callable, typename coroutine_t::allocator_type &alloc, size_t stack_size = 0,
77  size_t private_buffer_size = 0) {
78 #else
79  template <typename TAct, typename Ty>
80  static ptr_t create_with_delegate(const Ty &callable, typename coroutine_t::allocator_type &alloc, size_t stack_size = 0,
81  size_t private_buffer_size = 0) {
82 #endif
83  typedef TAct a_t;
84 
85  if (0 == stack_size) {
86  stack_size = copp::stack_traits::default_size();
87  }
88 
89  size_t action_size = coroutine_t::align_address_size(sizeof(a_t));
90  size_t task_size = coroutine_t::align_address_size(sizeof(self_t));
91 
92  if (stack_size <= sizeof(impl::task_impl *) + private_buffer_size + action_size + task_size) {
93  return ptr_t();
94  }
95 
96  typename coroutine_t::ptr_t coroutine = coroutine_t::create(
97  (a_t *)(UTIL_CONFIG_NULLPTR), alloc, stack_size, sizeof(impl::task_impl *) + private_buffer_size, action_size + task_size);
98  if (!coroutine) {
99  return ptr_t();
100  }
101 
102  void *action_addr = sub_buffer_offset(coroutine.get(), action_size);
103  void *task_addr = sub_buffer_offset(action_addr, task_size);
104 
105  // placement new task
106  ptr_t ret(new (task_addr) self_t(stack_size));
107  if (!ret) {
108  return ret;
109  }
110 
111  *(reinterpret_cast<impl::task_impl **>(coroutine->get_private_buffer())) = ret.get();
112  ret->coroutine_obj_ = coroutine;
113  ret->coroutine_obj_->set_flags(impl::task_impl::ext_coroutine_flag_t::EN_ECFT_COTASK);
114 
115  // placement new action
116  a_t *action = new (action_addr) a_t(COPP_MACRO_STD_FORWARD(Ty, callable));
117  if (UTIL_CONFIG_NULLPTR == action) {
118  return ret;
119  }
120 
121  typedef int (a_t::*a_t_fn_t)(void *);
122  a_t_fn_t a_t_fn = &a_t::operator();
123 
124  // redirect runner
125  coroutine->set_runner(
126 #if defined(UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES) && UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES
127  std::move(std::bind(a_t_fn, action, std::placeholders::_1))
128 #else
129  std::bind(a_t_fn, action, std::placeholders::_1)
130 #endif
131  );
132 
133  ret->action_destroy_fn_ = get_placement_destroy(action);
134  ret->_set_action(action);
135 
136  return ret;
137  }
138 
139 
147 #if defined(UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES) && UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES
148  template <typename Ty>
149  static inline ptr_t create(Ty &&functor, size_t stack_size = 0, size_t private_buffer_size = 0) {
150  typename coroutine_t::allocator_type alloc;
151  return create(COPP_MACRO_STD_FORWARD(Ty, functor), alloc, stack_size, private_buffer_size);
152  }
153 
154  template <typename Ty>
155  static inline ptr_t create(Ty &&functor, typename coroutine_t::allocator_type &alloc, size_t stack_size = 0,
156  size_t private_buffer_size = 0) {
157  typedef typename std::conditional<std::is_base_of<impl::task_action_impl, Ty>::value, Ty, task_action_functor<Ty> >::type a_t;
158  return create_with_delegate<a_t>(COPP_MACRO_STD_FORWARD(Ty, functor), alloc, stack_size, private_buffer_size);
159  }
160 #else
161  template <typename Ty>
162  static inline ptr_t create(const Ty &functor, size_t stack_size = 0, size_t private_buffer_size = 0) {
163  typename coroutine_t::allocator_type alloc;
164  return create(functor, alloc, stack_size, private_buffer_size);
165  }
166 
167  template <typename Ty>
168  static ptr_t create(const Ty &functor, typename coroutine_t::allocator_type &alloc, size_t stack_size = 0,
169  size_t private_buffer_size = 0) {
170  typedef typename std::conditional<std::is_base_of<impl::task_action_impl, Ty>::value, Ty, task_action_functor<Ty> >::type a_t;
171  return create_with_delegate<a_t>(COPP_MACRO_STD_FORWARD(Ty, functor), alloc, stack_size, private_buffer_size);
172  }
173 #endif
174 
181  template <typename Ty>
182  static inline ptr_t create(Ty (*func)(void *), typename coroutine_t::allocator_type &alloc, size_t stack_size = 0,
183  size_t private_buffer_size = 0) {
184  typedef task_action_function<Ty> a_t;
185 
186  return create_with_delegate<a_t>(func, alloc, stack_size, private_buffer_size);
187  }
188 
189  template <typename Ty>
190  inline static ptr_t create(Ty (*func)(void *), size_t stack_size = 0, size_t private_buffer_size = 0) {
191  typename coroutine_t::allocator_type alloc;
192  return create(func, alloc, stack_size, private_buffer_size);
193  }
194 
201  template <typename Ty, typename TInst>
202  static ptr_t create(Ty(TInst::*func), TInst *instance, typename coroutine_t::allocator_type &alloc, size_t stack_size = 0,
203  size_t private_buffer_size = 0) {
205 
206  return create<a_t>(a_t(func, instance), alloc, stack_size, private_buffer_size);
207  }
208 
209  template <typename Ty, typename TInst>
210  inline static ptr_t create(Ty(TInst::*func), TInst *instance, size_t stack_size = 0, size_t private_buffer_size = 0) {
211  typename coroutine_t::allocator_type alloc;
212  return create(func, instance, alloc, stack_size, private_buffer_size);
213  }
214 
215 #if defined(UTIL_CONFIG_COMPILER_CXX_VARIADIC_TEMPLATES) && UTIL_CONFIG_COMPILER_CXX_VARIADIC_TEMPLATES
216 
222  template <typename Ty, typename... TParams>
223  static ptr_t create_with(typename coroutine_t::allocator_type &alloc, size_t stack_size, size_t private_buffer_size,
224  TParams &&... args) {
225  typedef Ty a_t;
226 
227  return create(COPP_MACRO_STD_MOVE(a_t(COPP_MACRO_STD_FORWARD(TParams, args)...)), alloc, stack_size, private_buffer_size);
228  }
229 #endif
230 
239  inline ptr_t next(ptr_t next_task, void *priv_data = UTIL_CONFIG_NULLPTR) {
240  // can not refers to self
241  if (this == next_task.get() || !next_task) {
242  return ptr_t(this);
243  }
244 
245  // can not add next task when finished
246  if (is_exiting() || is_completed()) {
247  // run next task immedialy
248  EN_TASK_STATUS next_task_status = next_task->get_status();
249  if (EN_TS_CREATED == next_task_status) {
250  next_task->start(priv_data);
251  } else if (EN_TS_WAITING == next_task_status) {
252  next_task->resume(priv_data);
253  }
254  return next_task;
255  }
256 
257 #if !defined(PROJECT_DISABLE_MT) || !(PROJECT_DISABLE_MT)
259 #endif
260 
261  next_list_.member_list_.push_back(std::make_pair(next_task, priv_data));
262  return next_task;
263  }
264 
273 #if defined(UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES) && UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES
274  template <typename Ty>
275  inline ptr_t next(Ty &&functor, void *priv_data = UTIL_CONFIG_NULLPTR, size_t stack_size = 0, size_t private_buffer_size = 0) {
276  return next(create(std::forward<Ty>(functor), stack_size, private_buffer_size), priv_data);
277  }
278 
279  template <typename Ty>
280  inline ptr_t next(Ty &&functor, typename coroutine_t::allocator_type &alloc, void *priv_data = UTIL_CONFIG_NULLPTR,
281  size_t stack_size = 0, size_t private_buffer_size = 0) {
282  return next(create(std::forward<Ty>(functor), alloc, stack_size, private_buffer_size), priv_data);
283  }
284 #else
285  template <typename Ty>
286  inline ptr_t next(const Ty &functor, void *priv_data = UTIL_CONFIG_NULLPTR, size_t stack_size = 0, size_t private_buffer_size = 0) {
287  return next(create(functor, stack_size, private_buffer_size), priv_data);
288  }
289 
290  template <typename Ty>
291  inline ptr_t next(const Ty &functor, typename coroutine_t::allocator_type &alloc, void *priv_data = UTIL_CONFIG_NULLPTR,
292  size_t stack_size = 0, size_t private_buffer_size = 0) {
293  return next(create(std::forward<Ty>(functor), alloc, stack_size, private_buffer_size), priv_data);
294  }
295 #endif
296 
305  template <typename Ty>
306  inline ptr_t next(Ty (*func)(void *), void *priv_data = UTIL_CONFIG_NULLPTR, size_t stack_size = 0,
307  size_t private_buffer_size = 0) {
308  return next(create(func, stack_size, private_buffer_size), priv_data);
309  }
310 
311  template <typename Ty>
312  inline ptr_t next(Ty (*func)(void *), typename coroutine_t::allocator_type &alloc, void *priv_data = UTIL_CONFIG_NULLPTR,
313  size_t stack_size = 0, size_t private_buffer_size = 0) {
314  return next(create(func, alloc, stack_size, private_buffer_size), priv_data);
315  }
316 
326  template <typename Ty, typename TInst>
327  inline ptr_t next(Ty(TInst::*func), TInst *instance, void *priv_data = UTIL_CONFIG_NULLPTR, size_t stack_size = 0,
328  size_t private_buffer_size = 0) {
329  return next(create(func, instance, stack_size, private_buffer_size), priv_data);
330  }
331 
332  template <typename Ty, typename TInst>
333  inline ptr_t next(Ty(TInst::*func), TInst *instance, typename coroutine_t::allocator_type &alloc,
334  void *priv_data = UTIL_CONFIG_NULLPTR, size_t stack_size = 0, size_t private_buffer_size = 0) {
335  return next(create(func, instance, alloc, stack_size, private_buffer_size), priv_data);
336  }
337 
346  inline int await(ptr_t wait_task) {
347  if (!wait_task) {
349  }
350 
351  if (this == wait_task.get()) {
353  }
354 
355  // if target is exiting or completed, just return
356  if (wait_task->is_exiting() || wait_task->is_completed()) {
358  }
359 
360  if (is_exiting()) {
362  }
363 
364  if (this_task() != this) {
366  }
367 
368  // add to next list failed
369  if (wait_task->next(ptr_t(this)).get() != this) {
371  }
372 
373  int ret = 0;
374  while (!(wait_task->is_exiting() || wait_task->is_completed())) {
375  if (is_exiting()) {
377  }
378 
379  ret = yield();
380  }
381 
382  return ret;
383  }
384 
385  template <typename TTask>
386  inline int await(TTask *wait_task) {
387  return await(ptr_t(wait_task));
388  }
389 
398  inline ptr_t then(ptr_t next_task, void *priv_data = UTIL_CONFIG_NULLPTR) { return next(next_task, priv_data); }
399 
407 #if defined(UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES) && UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES
408  template <typename Ty>
409  inline ptr_t then(Ty &&functor, void *priv_data = UTIL_CONFIG_NULLPTR) {
410  if (!coroutine_obj_) {
411  then(create(std::forward<Ty>(functor), stack_size_, get_private_buffer_size()), priv_data);
412  }
413 
414  return then(create(std::forward<Ty>(functor), coroutine_obj_->get_allocator(), stack_size_, get_private_buffer_size()),
415  priv_data);
416  }
417 #else
418  template <typename Ty>
419  inline ptr_t then(const Ty &functor, typename coroutine_t::allocator_type &alloc, void *priv_data = UTIL_CONFIG_NULLPTR,
420  size_t stack_size = 0, size_t private_buffer_size = 0) {
421  if (!coroutine_obj_) {
422  return then(create(std::forward<Ty>(functor), stack_size_, get_private_buffer_size()), priv_data);
423  }
424 
425  return then(create(std::forward<Ty>(functor), coroutine_obj_->get_allocator(), stack_size_, get_private_buffer_size()),
426  priv_data);
427  }
428 #endif
429 
430  template <typename Ty>
431  inline ptr_t then(Ty (*func)(void *), void *priv_data = UTIL_CONFIG_NULLPTR) {
432  if (!coroutine_obj_) {
433  return then(create(func, stack_size_, get_private_buffer_size()), priv_data);
434  }
435 
436  return then(create(func, coroutine_obj_->get_allocator(), stack_size_, get_private_buffer_size()), priv_data);
437  }
438 
439 
444  static self_t *this_task() { return dynamic_cast<self_t *>(impl::task_impl::this_task()); }
445 
446  public:
447  virtual ~task() {
448  EN_TASK_STATUS status = get_status();
449  // inited but not finished will trigger timeout or finish other actor
450  if (status < EN_TS_DONE && status > EN_TS_CREATED) {
452  }
453 
454  // free resource
455  id_allocator_t id_alloc_;
456  id_alloc_.deallocate(id_);
457  }
458 
459  inline typename coroutine_t::ptr_t & get_coroutine_context() UTIL_CONFIG_NOEXCEPT { return coroutine_obj_; }
460  inline const typename coroutine_t::ptr_t &get_coroutine_context() const UTIL_CONFIG_NOEXCEPT { return coroutine_obj_; }
461 
462  inline id_t get_id() const UTIL_CONFIG_NOEXCEPT { return id_; }
463 
464  public:
465  virtual int get_ret_code() const UTIL_CONFIG_OVERRIDE {
466  if (!coroutine_obj_) {
467  return 0;
468  }
469 
470  return coroutine_obj_->get_ret_code();
471  }
472 
473  virtual int start(void *priv_data, EN_TASK_STATUS expected_status = EN_TS_CREATED) UTIL_CONFIG_OVERRIDE {
474  if (!coroutine_obj_) {
476  }
477 
478  EN_TASK_STATUS from_status = expected_status;
479 
480  do {
481  if (unlikely(from_status >= EN_TS_DONE)) {
483  }
484 
485  if (unlikely(from_status == EN_TS_RUNNING)) {
487  }
488 
489  if (likely(_cas_status(from_status, EN_TS_RUNNING))) { // Atomic.CAS here
490  break;
491  }
492  } while (true);
493 
494  // use this smart ptr to avoid destroy of this
495  // ptr_t protect_from_destroy(this);
496 
497  int ret = coroutine_obj_->start(priv_data);
498 
499  from_status = EN_TS_RUNNING;
500  if (is_completed()) { // Atomic.CAS here
501  while (from_status < EN_TS_DONE) {
502  if (likely(_cas_status(from_status, EN_TS_DONE))) { // Atomic.CAS here
503  break;
504  }
505  }
506 
507  finish_priv_data_ = priv_data;
508  _notify_finished(priv_data);
509  return ret;
510  }
511 
512  while (true) {
513  if (from_status >= EN_TS_DONE) { // canceled or killed
515  break;
516  }
517 
518  if (likely(_cas_status(from_status, EN_TS_WAITING))) { // Atomic.CAS here
519  break;
520  // waiting
521  }
522  }
523 
524  return ret;
525  }
526 
527  virtual int resume(void *priv_data, EN_TASK_STATUS expected_status = EN_TS_WAITING) UTIL_CONFIG_OVERRIDE {
528  return start(priv_data, expected_status);
529  }
530 
531  virtual int yield(void **priv_data) UTIL_CONFIG_OVERRIDE {
532  if (!coroutine_obj_) {
534  }
535 
536  return coroutine_obj_->yield(priv_data);
537  }
538 
539  virtual int cancel(void *priv_data) UTIL_CONFIG_OVERRIDE {
540  EN_TASK_STATUS from_status = get_status();
541 
542  do {
543  if (EN_TS_RUNNING == from_status) {
545  }
546 
547  if (likely(_cas_status(from_status, EN_TS_CANCELED))) {
548  break;
549  }
550  } while (true);
551 
552  _notify_finished(priv_data);
553  return copp::COPP_EC_SUCCESS;
554  }
555 
556  virtual int kill(enum EN_TASK_STATUS status, void *priv_data) UTIL_CONFIG_OVERRIDE {
557  EN_TASK_STATUS from_status = get_status();
558 
559  do {
560  if (likely(_cas_status(from_status, status))) {
561  break;
562  }
563  } while (true);
564 
565  if (EN_TS_RUNNING != from_status) {
566  _notify_finished(priv_data);
567  } else {
568  finish_priv_data_ = priv_data;
569  }
570 
571  return copp::COPP_EC_SUCCESS;
572  }
573 
575  using impl::task_impl::kill;
579 
580  public:
581  virtual bool is_completed() const UTIL_CONFIG_NOEXCEPT UTIL_CONFIG_OVERRIDE {
582  if (!coroutine_obj_) {
583  return false;
584  }
585 
586  return coroutine_obj_->is_finished();
587  }
588 
589  static inline void *add_buffer_offset(void *in, size_t off) {
590  return reinterpret_cast<void *>(reinterpret_cast<unsigned char *>(in) + off);
591  }
592 
593  static inline void *sub_buffer_offset(void *in, size_t off) {
594  return reinterpret_cast<void *>(reinterpret_cast<unsigned char *>(in) - off);
595  }
596 
598  if (!coroutine_obj_) {
599  return UTIL_CONFIG_NULLPTR;
600  }
601 
602  return add_buffer_offset(coroutine_obj_->get_private_buffer(), sizeof(impl::task_impl *));
603  }
604 
606  if (!coroutine_obj_) {
607  return 0;
608  }
609 
610  return coroutine_obj_->get_private_buffer_size() - sizeof(impl::task_impl *);
611  }
612 
613 
614  inline size_t use_count() const { return ref_count_.load(); }
615 
616  private:
617  task(const task &) UTIL_CONFIG_DELETED_FUNCTION;
618 
620  std::list<std::pair<ptr_t, void *> > next_list;
621 #if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
622  void *manager_ptr;
623  void (*manager_fn)(void *, self_t &);
624 #endif
625  // first, lock and swap container
626  {
627 #if !defined(PROJECT_DISABLE_MT) || !(PROJECT_DISABLE_MT)
629 #endif
630  next_list.swap(next_list_.member_list_);
631 #if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
632  manager_ptr = binding_manager_ptr_;
633  manager_fn = binding_manager_fn_;
634  binding_manager_ptr_ = UTIL_CONFIG_NULLPTR;
635  binding_manager_fn_ = UTIL_CONFIG_NULLPTR;
636 #endif
637  }
638 
639  // then, do all the pending tasks
640  for (typename std::list<std::pair<ptr_t, void *> >::iterator iter = next_list.begin(); iter != next_list.end(); ++iter) {
641  if (!iter->first || EN_TS_INVALID == iter->first->get_status()) {
642  continue;
643  }
644 
645  if (iter->first->get_status() < EN_TS_RUNNING) {
646  iter->first->start(iter->second);
647  } else {
648  iter->first->resume(iter->second);
649  }
650  }
651 
652  // finally, notify manager to cleanup(maybe start or resume with task's API but not task_manager's)
653 #if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
654  if (UTIL_CONFIG_NULLPTR != manager_ptr && UTIL_CONFIG_NULLPTR != manager_fn) {
655  (*manager_fn)(manager_ptr, *this);
656  }
657 #endif
658  }
659 
660  int _notify_finished(void *priv_data) {
661  // first, make sure coroutine finished.
662  if (coroutine_obj_ && false == coroutine_obj_->is_finished()) {
663  // make sure this task will not be destroyed when running
664  while (false == coroutine_obj_->is_finished()) {
665  coroutine_obj_->resume(priv_data);
666  }
667  }
668 
669  int ret = impl::task_impl::_notify_finished(priv_data);
670 
671  // next tasks
673  return ret;
674  }
675 
676 
677  friend void intrusive_ptr_add_ref(self_t *p) {
678  if (p == UTIL_CONFIG_NULLPTR) {
679  return;
680  }
681 
682  ++p->ref_count_;
683  }
684 
685  friend void intrusive_ptr_release(self_t *p) {
686  if (p == UTIL_CONFIG_NULLPTR) {
687  return;
688  }
689 
690  size_t left = --p->ref_count_;
691  if (0 == left) {
692  // save coroutine context first, make sure it's still available after destroy task
693  typename coroutine_t::ptr_t coro = p->coroutine_obj_;
694 
695  // then, find and destroy action
696  void *action_ptr = reinterpret_cast<void *>(p->_get_action());
697  if (UTIL_CONFIG_NULLPTR != p->action_destroy_fn_ && UTIL_CONFIG_NULLPTR != action_ptr) {
698  (*p->action_destroy_fn_)(action_ptr);
699  }
700 
701  // then, destruct task
702  p->~task();
703 
704  // at last, destroy the coroutine and maybe recycle the stack space
705  coro.reset();
706  }
707  }
708 
709 #if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
710  public:
711  class task_manager_helper {
712  private:
713  template <typename, typename>
714  friend class task_manager;
715  static bool setup_task_manager(self_t &task_inst, void *manager_ptr, void (*fn)(void *, self_t &)) {
716 #if !defined(PROJECT_DISABLE_MT) || !(PROJECT_DISABLE_MT)
718 #endif
719  if (task_inst.binding_manager_ptr_ != UTIL_CONFIG_NULLPTR) {
720  return false;
721  }
722 
723  task_inst.binding_manager_ptr_ = manager_ptr;
724  task_inst.binding_manager_fn_ = fn;
725  return true;
726  }
727 
728  static bool cleanup_task_manager(self_t &task_inst, void *manager_ptr) {
729 #if !defined(PROJECT_DISABLE_MT) || !(PROJECT_DISABLE_MT)
731 #endif
732  if (task_inst.binding_manager_ptr_ != manager_ptr) {
733  return false;
734  }
735 
736  task_inst.binding_manager_ptr_ = UTIL_CONFIG_NULLPTR;
737  task_inst.binding_manager_fn_ = UTIL_CONFIG_NULLPTR;
738  return true;
739  }
740  };
741 #endif
742 
743  private:
744  id_t id_;
745  size_t stack_size_;
746  typename coroutine_t::ptr_t coroutine_obj_;
748 
749  // ============== action information ==============
750  void (*action_destroy_fn_)(void *);
751 
752 #if !defined(PROJECT_DISABLE_MT) || !(PROJECT_DISABLE_MT)
755 #else
757 #endif
758 
759  // ============== binding to task manager ==============
760 #if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
761  void *binding_manager_ptr_;
762  void (*binding_manager_fn_)(void *, self_t &);
763 #endif
764  };
765 } // namespace cotask
766 
767 
768 #endif /* _COTASK_TASK_H_ */
static std::size_t default_size() COPP_MACRO_NOEXCEPT
virtual int start(void *priv_data, EN_TASK_STATUS expected_status=EN_TS_CREATED) UTIL_CONFIG_OVERRIDE
Definition: task.h:473
ptr_t next(ptr_t next_task, void *priv_data=UTIL_CONFIG_NULLPTR)
add next task to run when task finished
Definition: task.h:239
#define unlikely(x)
virtual ~task()
Definition: task.h:447
void(* action_destroy_fn_)(void *)
Definition: task.h:750
int _notify_finished(void *priv_data)
Definition: task_impl.cpp:63
COPP_EC_TASK_IS_EXITING.
Definition: errno.h:36
COPP_EC_TASK_CAN_NOT_WAIT_SELF.
Definition: errno.h:35
void store(value_type desired, EXPLICIT_UNUSED_ATTR::util::lock::memory_order order=::util::lock::memory_order_seq_cst) UTIL_CONFIG_NOEXCEPT
macro_coroutine_t::coroutine_t coroutine_t
Definition: task.h:35
static ptr_t create(Ty(*func)(void *), size_t stack_size=0, size_t private_buffer_size=0)
Definition: task.h:190
size_t get_private_buffer_size()
Definition: task.h:605
static void * sub_buffer_offset(void *in, size_t off)
Definition: task.h:593
ptr_t then(const Ty &functor, typename coroutine_t::allocator_type &alloc, void *priv_data=UTIL_CONFIG_NULLPTR, size_t stack_size=0, size_t private_buffer_size=0)
create next task with functor using the same allocator and private buffer size as this task ...
Definition: task.h:419
std::list< std::pair< ptr_t, void * > > member_list_
Definition: task.h:43
int _notify_finished(void *priv_data)
Definition: task.h:660
virtual int cancel(void *priv_data) UTIL_CONFIG_OVERRIDE
Definition: task.h:539
COPP_EC_NOT_INITED.
Definition: errno.h:21
COPP_EC_ALREADY_FINISHED.
Definition: errno.h:27
ptr_t next(const Ty &functor, typename coroutine_t::allocator_type &alloc, void *priv_data=UTIL_CONFIG_NULLPTR, size_t stack_size=0, size_t private_buffer_size=0)
Definition: task.h:291
virtual int resume(void *priv_data, EN_TASK_STATUS expected_status=EN_TS_WAITING) UTIL_CONFIG_OVERRIDE
Definition: task.h:527
bool is_exiting() const UTIL_CONFIG_NOEXCEPT
check if a cotask is exiting
Definition: task_impl.cpp:34
task(size_t stack_sz)
constuctor
Definition: task.h:54
COPP_EC_SUCCESS.
Definition: errno.h:12
#define COPP_MACRO_STD_FORWARD(t, x)
Definition: features.h:175
bool _cas_status(EN_TASK_STATUS &expected, EN_TASK_STATUS desired)
Definition: task_impl.cpp:55
action_ptr_t _get_action()
Definition: task_impl.cpp:53
TTASK_MACRO macro_task_t
Definition: task.h:33
ptr_t next(Ty(*func)(void *), typename coroutine_t::allocator_type &alloc, void *priv_data=UTIL_CONFIG_NULLPTR, size_t stack_size=0, size_t private_buffer_size=0)
Definition: task.h:312
EN_TASK_STATUS get_status() const UTIL_CONFIG_NOEXCEPT
Definition: task_impl.h:64
int await(ptr_t wait_task)
await another cotask to finish
Definition: task.h:346
const coroutine_t::ptr_t & get_coroutine_context() const UTIL_CONFIG_NOEXCEPT
Definition: task.h:460
size_t use_count() const
Definition: task.h:614
#define likely(x)
static ptr_t create_with_delegate(const Ty &callable, typename coroutine_t::allocator_type &alloc, size_t stack_size=0, size_t private_buffer_size=0)
create task with functor
Definition: task.h:80
sample endif() if(PROJECT_ENABLE_UNITTEST) add_custom_target(run_test) add_subdirectory("$
Definition: CMakeLists.txt:116
ptr_t next(Ty(TInst::*func), TInst *instance, typename coroutine_t::allocator_type &alloc, void *priv_data=UTIL_CONFIG_NULLPTR, size_t stack_size=0, size_t private_buffer_size=0)
Definition: task.h:333
EN_TASK_STATUS
Definition: task_impl.h:28
#define LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
Definition: build_feature.h:35
virtual int yield(void **priv_data) UTIL_CONFIG_OVERRIDE
Definition: task.h:531
ptr_t next(Ty(*func)(void *), void *priv_data=UTIL_CONFIG_NULLPTR, size_t stack_size=0, size_t private_buffer_size=0)
create next task with function
Definition: task.h:306
static ptr_t create(Ty(TInst::*func), TInst *instance, typename coroutine_t::allocator_type &alloc, size_t stack_size=0, size_t private_buffer_size=0)
create task with function
Definition: task.h:202
COPP_EC_IS_RUNNING.
Definition: errno.h:26
id_t id_
Definition: task.h:744
coroutine_t::ptr_t coroutine_obj_
Definition: task.h:746
task_group next_list_
Definition: task.h:747
#define COPP_MACRO_STD_MOVE(x)
Definition: features.h:171
size_t stack_size_
Definition: task.h:745
static ptr_t create(Ty(TInst::*func), TInst *instance, size_t stack_size=0, size_t private_buffer_size=0)
Definition: task.h:210
util::lock::atomic_int_type< size_t > ref_count_
Definition: task.h:753
placement_destroy_fn_t get_placement_destroy(task_action_functor< Ty > *)
Definition: task_actions.h:226
virtual int get_ret_code() const UTIL_CONFIG_OVERRIDE
Definition: task.h:465
static ptr_t create(const Ty &functor, size_t stack_size=0, size_t private_buffer_size=0)
create task with functor
Definition: task.h:162
virtual int kill(enum EN_TASK_STATUS status, void *priv_data) UTIL_CONFIG_OVERRIDE
Definition: task.h:556
macro_task_t::id_t id_t
Definition: task.h:38
ptr_t next(const Ty &functor, void *priv_data=UTIL_CONFIG_NULLPTR, size_t stack_size=0, size_t private_buffer_size=0)
create next task with functor
Definition: task.h:286
util::lock::spin_lock inner_action_lock_
Definition: task.h:754
virtual bool is_completed() const UTIL_CONFIG_NOEXCEPT UTIL_CONFIG_OVERRIDE
Definition: task.h:581
static ptr_t create(Ty(*func)(void *), typename coroutine_t::allocator_type &alloc, size_t stack_size=0, size_t private_buffer_size=0)
create task with function
Definition: task.h:182
static void * add_buffer_offset(void *in, size_t off)
Definition: task.h:589
int await(TTask *wait_task)
Definition: task.h:386
libcopp if(LIBCOTASK_MACRO_ENABLED) add_subdirectory("$
Definition: CMakeLists.txt:8
coroutine_t::ptr_t & get_coroutine_context() UTIL_CONFIG_NOEXCEPT
Definition: task.h:459
id_t get_id() const UTIL_CONFIG_NOEXCEPT
Definition: task.h:462
friend void intrusive_ptr_add_ref(self_t *p)
Definition: task.h:677
ptr_t next(Ty(TInst::*func), TInst *instance, void *priv_data=UTIL_CONFIG_NULLPTR, size_t stack_size=0, size_t private_buffer_size=0)
create next task with function
Definition: task.h:327
task< TCO_MACRO, TTASK_MACRO > self_t
Definition: task.h:30
macro_task_t::id_allocator_t id_allocator_t
Definition: task.h:39
COPP_EC_TASK_NOT_IN_ACTION.
Definition: errno.h:38
static self_t * this_task()
Definition: task.h:444
ptr_t then(Ty(*func)(void *), void *priv_data=UTIL_CONFIG_NULLPTR)
Definition: task.h:431
impl::task_impl::action_ptr_t action_ptr_t
Definition: task.h:47
friend void intrusive_ptr_release(self_t *p)
Definition: task.h:685
value_type load(EXPLICIT_UNUSED_ATTR::util::lock::memory_order order=::util::lock::memory_order_seq_cst) const UTIL_CONFIG_NOEXCEPT
element_type * get() const UTIL_CONFIG_NOEXCEPT
COPP_EC_TASK_ADD_NEXT_FAILED.
Definition: errno.h:37
void * get_private_buffer()
Definition: task.h:597
TCO_MACRO macro_coroutine_t
Definition: task.h:32
std::intrusive_ptr< self_t > ptr_t
Definition: task.h:31
ptr_t then(ptr_t next_task, void *priv_data=UTIL_CONFIG_NULLPTR)
add task to run when task finished
Definition: task.h:398
static task_impl * this_task()
Definition: task_impl.cpp:38
macro_coroutine_t::stack_allocator_t stack_allocator_t
Definition: task.h:36
static ptr_t create(const Ty &functor, typename coroutine_t::allocator_type &alloc, size_t stack_size=0, size_t private_buffer_size=0)
Definition: task.h:168
void active_next_tasks()
Definition: task.h:619
COPP_EC_ARGS_ERROR.
Definition: errno.h:30