libcopp  1.1.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 <stdint.h>
17 
19 #include <libcopp/utils/errno.h>
20 #include <libcotask/task_macros.h>
21 #include <libcotask/this_task.h>
22 
23 
24 namespace cotask {
25 
26  template <typename TCO_MACRO = macro_coroutine, typename TTASK_MACRO = macro_task>
27  class task : public impl::task_impl {
28  public:
31  typedef TCO_MACRO macro_coroutine_t;
32  typedef TTASK_MACRO macro_task_t;
33 
34  typedef typename macro_coroutine_t::coroutine_t coroutine_t;
35  typedef typename macro_coroutine_t::stack_allocator_t stack_allocator_t;
36 
37  typedef typename macro_task_t::id_t id_t;
38  typedef typename macro_task_t::id_allocator_t id_allocator_t;
39 
40 
41  struct task_group {
42  std::list<std::pair<ptr_t, void *> > member_list_;
43  };
44 
45  private:
47 
48  public:
53  task(size_t stack_sz) : stack_size_(stack_sz), action_destroy_fn_(UTIL_CONFIG_NULLPTR) {
54  id_allocator_t id_alloc_;
55  id_ = id_alloc_.allocate();
56  ref_count_.store(0);
57  }
58 
59 
67 #if defined(UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES) && UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES
68  template <typename TAct, typename Ty>
69  static ptr_t create_with_delegate(Ty &&callable, typename coroutine_t::allocator_type &alloc, size_t stack_size = 0,
70  size_t private_buffer_size = 0) {
71 #else
72  template <typename TAct, typename Ty>
73  static ptr_t create_with_delegate(const Ty &callable, typename coroutine_t::allocator_type &alloc, size_t stack_size = 0,
74  size_t private_buffer_size = 0) {
75 #endif
76  typedef TAct a_t;
77 
78  if (0 == stack_size) {
79  stack_size = copp::stack_traits::default_size();
80  }
81 
82  size_t action_size = coroutine_t::align_address_size(sizeof(a_t));
83  size_t task_size = coroutine_t::align_address_size(sizeof(self_t));
84 
85  if (stack_size <= sizeof(impl::task_impl *) + private_buffer_size + action_size + task_size) {
86  return ptr_t();
87  }
88 
89  typename coroutine_t::ptr_t coroutine = coroutine_t::create(
90  (a_t *)(UTIL_CONFIG_NULLPTR), alloc, stack_size, sizeof(impl::task_impl *) + private_buffer_size, action_size + task_size);
91  if (!coroutine) {
92  return ptr_t();
93  }
94 
95  void *action_addr = sub_buffer_offset(coroutine.get(), action_size);
96  void *task_addr = sub_buffer_offset(action_addr, task_size);
97 
98  // placement new task
99  ptr_t ret(new (task_addr) self_t(stack_size));
100  if (!ret) {
101  return ret;
102  }
103 
104  *(reinterpret_cast<impl::task_impl **>(coroutine->get_private_buffer())) = ret.get();
105  ret->coroutine_obj_ = coroutine;
106  ret->coroutine_obj_->set_flags(impl::task_impl::ext_coroutine_flag_t::EN_ECFT_COTASK);
107 
108  // placement new action
109  a_t *action = new (action_addr) a_t(COPP_MACRO_STD_FORWARD(Ty, callable));
110  if (UTIL_CONFIG_NULLPTR == action) {
111  return ret;
112  }
113 
114  typedef int (a_t::*a_t_fn_t)(void *);
115  a_t_fn_t a_t_fn = &a_t::operator();
116 
117  // redirect runner
118  coroutine->set_runner(
119 #if defined(UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES) && UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES
120  std::move(std::bind(a_t_fn, action, std::placeholders::_1))
121 #else
122  std::bind(a_t_fn, action, std::placeholders::_1)
123 #endif
124  );
125 
126  ret->action_destroy_fn_ = get_placement_destroy(action);
127  ret->_set_action(action);
128 
129  return ret;
130  }
131 
132 
140 #if defined(UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES) && UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES
141  template <typename Ty>
142  static inline ptr_t create(Ty &&functor, size_t stack_size = 0, size_t private_buffer_size = 0) {
143  typename coroutine_t::allocator_type alloc;
144  return create(COPP_MACRO_STD_FORWARD(Ty, functor), alloc, stack_size, private_buffer_size);
145  }
146 
147  template <typename Ty>
148  static inline ptr_t create(Ty &&functor, typename coroutine_t::allocator_type &alloc, size_t stack_size = 0,
149  size_t private_buffer_size = 0) {
150  typedef typename std::conditional<std::is_base_of<impl::task_action_impl, Ty>::value, Ty, task_action_functor<Ty> >::type a_t;
151  return create_with_delegate<a_t>(COPP_MACRO_STD_FORWARD(Ty, functor), alloc, stack_size, private_buffer_size);
152  }
153 #else
154  template <typename Ty>
155  static inline ptr_t create(const Ty &functor, size_t stack_size = 0, size_t private_buffer_size = 0) {
156  typename coroutine_t::allocator_type alloc;
157  return create(functor, alloc, stack_size, private_buffer_size);
158  }
159 
160  template <typename Ty>
161  static ptr_t create(const Ty &functor, typename coroutine_t::allocator_type &alloc, size_t stack_size = 0,
162  size_t private_buffer_size = 0) {
163  typedef typename std::conditional<std::is_base_of<impl::task_action_impl, Ty>::value, Ty, task_action_functor<Ty> >::type a_t;
164  return create_with_delegate<a_t>(COPP_MACRO_STD_FORWARD(Ty, functor), alloc, stack_size, private_buffer_size);
165  }
166 #endif
167 
174  template <typename Ty>
175  static inline ptr_t create(Ty (*func)(void *), typename coroutine_t::allocator_type &alloc, size_t stack_size = 0,
176  size_t private_buffer_size = 0) {
177  typedef task_action_function<Ty> a_t;
178 
179  return create_with_delegate<a_t>(func, alloc, stack_size, private_buffer_size);
180  }
181 
182  template <typename Ty>
183  inline static ptr_t create(Ty (*func)(void *), size_t stack_size = 0, size_t private_buffer_size = 0) {
184  typename coroutine_t::allocator_type alloc;
185  return create(func, alloc, stack_size, private_buffer_size);
186  }
187 
194  template <typename Ty, typename TInst>
195  static ptr_t create(Ty(TInst::*func), TInst *instance, typename coroutine_t::allocator_type &alloc, size_t stack_size = 0,
196  size_t private_buffer_size = 0) {
198 
199  return create<a_t>(a_t(func, instance), alloc, stack_size, private_buffer_size);
200  }
201 
202  template <typename Ty, typename TInst>
203  inline static ptr_t create(Ty(TInst::*func), TInst *instance, size_t stack_size = 0, size_t private_buffer_size = 0) {
204  typename coroutine_t::allocator_type alloc;
205  return create(func, instance, alloc, stack_size, private_buffer_size);
206  }
207 
208 #if defined(UTIL_CONFIG_COMPILER_CXX_VARIADIC_TEMPLATES) && UTIL_CONFIG_COMPILER_CXX_VARIADIC_TEMPLATES
209 
215  template <typename Ty, typename... TParams>
216  static ptr_t create_with(typename coroutine_t::allocator_type &alloc, size_t stack_size, size_t private_buffer_size,
217  TParams &&... args) {
218  typedef Ty a_t;
219 
220  return create(COPP_MACRO_STD_MOVE(a_t(COPP_MACRO_STD_FORWARD(TParams, args)...)), alloc, stack_size, private_buffer_size);
221  }
222 #endif
223 
232  inline ptr_t next(ptr_t next_task, void *priv_data = UTIL_CONFIG_NULLPTR) {
233  // can not refers to self
234  if (this == next_task.get() || !next_task) {
235  return ptr_t(this);
236  }
237 
238  // can not add next task when finished
239  if (is_exiting() || is_completed()) {
240  // run next task immedialy
241  EN_TASK_STATUS next_task_status = next_task->get_status();
242  if (EN_TS_CREATED == next_task_status) {
243  next_task->start(priv_data);
244  } else if (EN_TS_WAITING == next_task_status) {
245  next_task->resume(priv_data);
246  }
247  return next_task;
248  }
249 
250 #if !defined(PROJECT_DISABLE_MT) || !(PROJECT_DISABLE_MT)
252 #endif
253 
254  next_list_.member_list_.push_back(std::make_pair(next_task, priv_data));
255  return next_task;
256  }
257 
266 #if defined(UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES) && UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES
267  template <typename Ty>
268  inline ptr_t next(Ty &&functor, void *priv_data = UTIL_CONFIG_NULLPTR, size_t stack_size = 0, size_t private_buffer_size = 0) {
269  return next(create(std::forward<Ty>(functor), stack_size, private_buffer_size), priv_data);
270  }
271 
272  template <typename Ty>
273  inline ptr_t next(Ty &&functor, typename coroutine_t::allocator_type &alloc, void *priv_data = UTIL_CONFIG_NULLPTR,
274  size_t stack_size = 0, size_t private_buffer_size = 0) {
275  return next(create(std::forward<Ty>(functor), alloc, stack_size, private_buffer_size), priv_data);
276  }
277 #else
278  template <typename Ty>
279  inline ptr_t next(const Ty &functor, void *priv_data = UTIL_CONFIG_NULLPTR, size_t stack_size = 0, size_t private_buffer_size = 0) {
280  return next(create(functor, stack_size, private_buffer_size), priv_data);
281  }
282 
283  template <typename Ty>
284  inline ptr_t next(const Ty &functor, typename coroutine_t::allocator_type &alloc, void *priv_data = UTIL_CONFIG_NULLPTR,
285  size_t stack_size = 0, size_t private_buffer_size = 0) {
286  return next(create(std::forward<Ty>(functor), alloc, stack_size, private_buffer_size), priv_data);
287  }
288 #endif
289 
298  template <typename Ty>
299  inline ptr_t next(Ty (*func)(void *), void *priv_data = UTIL_CONFIG_NULLPTR, size_t stack_size = 0,
300  size_t private_buffer_size = 0) {
301  return next(create(func, stack_size, private_buffer_size), priv_data);
302  }
303 
304  template <typename Ty>
305  inline ptr_t next(Ty (*func)(void *), typename coroutine_t::allocator_type &alloc, void *priv_data = UTIL_CONFIG_NULLPTR,
306  size_t stack_size = 0, size_t private_buffer_size = 0) {
307  return next(create(func, alloc, stack_size, private_buffer_size), priv_data);
308  }
309 
319  template <typename Ty, typename TInst>
320  inline ptr_t next(Ty(TInst::*func), TInst *instance, void *priv_data = UTIL_CONFIG_NULLPTR, size_t stack_size = 0,
321  size_t private_buffer_size = 0) {
322  return next(create(func, instance, stack_size, private_buffer_size), priv_data);
323  }
324 
325  template <typename Ty, typename TInst>
326  inline ptr_t next(Ty(TInst::*func), TInst *instance, typename coroutine_t::allocator_type &alloc,
327  void *priv_data = UTIL_CONFIG_NULLPTR, size_t stack_size = 0, size_t private_buffer_size = 0) {
328  return next(create(func, instance, alloc, stack_size, private_buffer_size), priv_data);
329  }
330 
338  inline int await(const ptr_t &wait_task) {
339  if (!wait_task) {
341  }
342 
343  if (this == wait_task.get()) {
345  }
346 
347  // if target is exiting or completed, just return
348  if (wait_task->is_exiting() || wait_task->is_completed()) {
350  }
351 
352  if (is_exiting()) {
354  }
355 
356  if (this_task() != this) {
358  }
359 
360  // add to next list failed
361  if (wait_task->next(ptr_t(this)).get() != this) {
363  }
364 
365  int ret = 0;
366  while (!(wait_task->is_exiting() || wait_task->is_completed())) {
367  if (is_exiting()) {
369  }
370 
371  ret = yield();
372  }
373 
374  return ret;
375  }
376 
377  template <typename TTask>
378  inline int await(TTask *wait_task) {
379  return await(ptr_t(wait_task));
380  }
381 
390  inline ptr_t then(ptr_t next_task, void *priv_data = UTIL_CONFIG_NULLPTR) { return next(next_task, priv_data); }
391 
399 #if defined(UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES) && UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES
400  template <typename Ty>
401  inline ptr_t then(Ty &&functor, void *priv_data = UTIL_CONFIG_NULLPTR) {
402  if (!coroutine_obj_) {
403  then(create(std::forward<Ty>(functor), stack_size_, get_private_buffer_size()), priv_data);
404  }
405 
406  return then(create(std::forward<Ty>(functor), coroutine_obj_->get_allocator(), stack_size_, get_private_buffer_size()),
407  priv_data);
408  }
409 #else
410  template <typename Ty>
411  inline ptr_t then(const Ty &functor, typename coroutine_t::allocator_type &alloc, void *priv_data = UTIL_CONFIG_NULLPTR,
412  size_t stack_size = 0, size_t private_buffer_size = 0) {
413  if (!coroutine_obj_) {
414  return then(create(std::forward<Ty>(functor), stack_size_, get_private_buffer_size()), priv_data);
415  }
416 
417  return then(create(std::forward<Ty>(functor), coroutine_obj_->get_allocator(), stack_size_, get_private_buffer_size()),
418  priv_data);
419  }
420 #endif
421 
422  template <typename Ty>
423  inline ptr_t then(Ty (*func)(void *), void *priv_data = UTIL_CONFIG_NULLPTR) {
424  if (!coroutine_obj_) {
425  return then(create(func, stack_size_, get_private_buffer_size()), priv_data);
426  }
427 
428  return then(create(func, coroutine_obj_->get_allocator(), stack_size_, get_private_buffer_size()), priv_data);
429  }
430 
431 
436  static self_t *this_task() { return dynamic_cast<self_t *>(impl::task_impl::this_task()); }
437 
438  public:
439  virtual ~task() {
440  EN_TASK_STATUS status = get_status();
441  // inited but not finished will trigger timeout or finish other actor
442  if (status < EN_TS_DONE && status > EN_TS_CREATED) {
444  }
445 
446  // free resource
447  id_allocator_t id_alloc_;
448  id_alloc_.deallocate(id_);
449  }
450 
451  inline typename coroutine_t::ptr_t & get_coroutine_context() UTIL_CONFIG_NOEXCEPT { return coroutine_obj_; }
452  inline const typename coroutine_t::ptr_t &get_coroutine_context() const UTIL_CONFIG_NOEXCEPT { return coroutine_obj_; }
453 
454  inline id_t get_id() const UTIL_CONFIG_NOEXCEPT { return id_; }
455 
456  public:
457  virtual int get_ret_code() const UTIL_CONFIG_OVERRIDE {
458  if (!coroutine_obj_) {
459  return 0;
460  }
461 
462  return coroutine_obj_->get_ret_code();
463  }
464 
465  virtual int start(void *priv_data, EN_TASK_STATUS expected_status = EN_TS_CREATED) UTIL_CONFIG_OVERRIDE {
466  if (!coroutine_obj_) {
468  }
469 
470  EN_TASK_STATUS from_status = expected_status;
471 
472  do {
473  if (unlikely(from_status >= EN_TS_DONE)) {
475  }
476 
477  if (unlikely(from_status == EN_TS_RUNNING)) {
479  }
480 
481  if (likely(_cas_status(from_status, EN_TS_RUNNING))) { // Atomic.CAS here
482  break;
483  }
484  } while (true);
485 
486  // use this smart ptr to avoid destroy of this
487  // ptr_t protect_from_destroy(this);
488 
489  int ret = coroutine_obj_->start(priv_data);
490 
491  from_status = EN_TS_RUNNING;
492  if (is_completed()) { // Atomic.CAS here
493  while (from_status < EN_TS_DONE) {
494  if (likely(_cas_status(from_status, EN_TS_DONE))) { // Atomic.CAS here
495  break;
496  }
497  }
498 
499  finish_priv_data_ = priv_data;
500  _notify_finished(priv_data);
501  return ret;
502  }
503 
504  while (true) {
505  if (from_status >= EN_TS_DONE) { // canceled or killed
507  break;
508  }
509 
510  if (likely(_cas_status(from_status, EN_TS_WAITING))) { // Atomic.CAS here
511  break;
512  // waiting
513  }
514  }
515 
516  return ret;
517  }
518 
519  virtual int resume(void *priv_data, EN_TASK_STATUS expected_status = EN_TS_WAITING) UTIL_CONFIG_OVERRIDE {
520  return start(priv_data, expected_status);
521  }
522 
523  virtual int yield(void **priv_data) UTIL_CONFIG_OVERRIDE {
524  if (!coroutine_obj_) {
526  }
527 
528  return coroutine_obj_->yield(priv_data);
529  }
530 
531  virtual int cancel(void *priv_data) UTIL_CONFIG_OVERRIDE {
532  EN_TASK_STATUS from_status = get_status();
533 
534  do {
535  if (EN_TS_RUNNING == from_status) {
537  }
538 
539  if (likely(_cas_status(from_status, EN_TS_CANCELED))) {
540  break;
541  }
542  } while (true);
543 
544  _notify_finished(priv_data);
545  return copp::COPP_EC_SUCCESS;
546  }
547 
548  virtual int kill(enum EN_TASK_STATUS status, void *priv_data) UTIL_CONFIG_OVERRIDE {
549  EN_TASK_STATUS from_status = get_status();
550 
551  do {
552  if (likely(_cas_status(from_status, status))) {
553  break;
554  }
555  } while (true);
556 
557  if (EN_TS_RUNNING != from_status) {
558  _notify_finished(priv_data);
559  } else {
560  finish_priv_data_ = priv_data;
561  }
562 
563  return copp::COPP_EC_SUCCESS;
564  }
565 
567  using impl::task_impl::kill;
571 
572  public:
573  virtual bool is_completed() const UTIL_CONFIG_NOEXCEPT UTIL_CONFIG_OVERRIDE {
574  if (!coroutine_obj_) {
575  return false;
576  }
577 
578  return coroutine_obj_->is_finished();
579  }
580 
581  static inline void *add_buffer_offset(void *in, size_t off) {
582  return reinterpret_cast<void *>(reinterpret_cast<unsigned char *>(in) + off);
583  }
584 
585  static inline void *sub_buffer_offset(void *in, size_t off) {
586  return reinterpret_cast<void *>(reinterpret_cast<unsigned char *>(in) - off);
587  }
588 
590  if (!coroutine_obj_) {
591  return UTIL_CONFIG_NULLPTR;
592  }
593 
594  return add_buffer_offset(coroutine_obj_->get_private_buffer(), sizeof(impl::task_impl *));
595  }
596 
598  if (!coroutine_obj_) {
599  return 0;
600  }
601 
602  return coroutine_obj_->get_private_buffer_size() - sizeof(impl::task_impl *);
603  }
604 
605 
606  inline size_t use_count() const { return ref_count_.load(); }
607 
608  private:
609  task(const task &) UTIL_CONFIG_DELETED_FUNCTION;
610 
612  std::list<std::pair<ptr_t, void *> > next_list;
613 
614  // first, lock and swap container
615  {
616 #if !defined(PROJECT_DISABLE_MT) || !(PROJECT_DISABLE_MT)
618 #endif
619  next_list.swap(next_list_.member_list_);
620  }
621 
622  // then, do all the pending tasks
623  for (typename std::list<std::pair<ptr_t, void *> >::iterator iter = next_list.begin(); iter != next_list.end(); ++iter) {
624  if (!iter->first || EN_TS_INVALID == iter->first->get_status()) {
625  continue;
626  }
627 
628  if (iter->first->get_status() < EN_TS_RUNNING) {
629  iter->first->start(iter->second);
630  } else {
631  iter->first->resume(iter->second);
632  }
633  }
634  }
635 
636  int _notify_finished(void *priv_data) {
637  // first, make sure coroutine finished.
638  if (coroutine_obj_ && false == coroutine_obj_->is_finished()) {
639  // make sure this task will not be destroyed when running
640  while (false == coroutine_obj_->is_finished()) {
641  coroutine_obj_->resume(priv_data);
642  }
643  }
644 
645  int ret = impl::task_impl::_notify_finished(priv_data);
646 
647  // next tasks
649  return ret;
650  }
651 
652 
653  friend void intrusive_ptr_add_ref(self_t *p) {
654  if (p == UTIL_CONFIG_NULLPTR) {
655  return;
656  }
657 
658  ++p->ref_count_;
659  }
660 
661  friend void intrusive_ptr_release(self_t *p) {
662  if (p == UTIL_CONFIG_NULLPTR) {
663  return;
664  }
665 
666  size_t left = --p->ref_count_;
667  if (0 == left) {
668  // save coroutine context first, make sure it's still available after destroy task
669  typename coroutine_t::ptr_t coro = p->coroutine_obj_;
670 
671  // then, find and destroy action
672  void *action_ptr = reinterpret_cast<void *>(p->_get_action());
673  if (UTIL_CONFIG_NULLPTR != p->action_destroy_fn_ && UTIL_CONFIG_NULLPTR != action_ptr) {
674  (*p->action_destroy_fn_)(action_ptr);
675  }
676 
677  // then, destruct task
678  p->~task();
679 
680  // at last, destroy the coroutine and maybe recycle the stack space
681  coro.reset();
682  }
683  }
684 
685  private:
686  id_t id_;
687  size_t stack_size_;
688  typename coroutine_t::ptr_t coroutine_obj_;
690 
691  // ============== action information ==============
692  void (*action_destroy_fn_)(void *);
693 
694 #if !defined(PROJECT_DISABLE_MT) || !(PROJECT_DISABLE_MT)
697 #else
699 #endif
700  };
701 } // namespace cotask
702 
703 
704 #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:465
ptr_t next(ptr_t next_task, void *priv_data=UTIL_CONFIG_NULLPTR)
add next task to run when task finished
Definition: task.h:232
#define unlikely(x)
virtual ~task()
Definition: task.h:439
void(* action_destroy_fn_)(void *)
Definition: task.h:692
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:34
static ptr_t create(Ty(*func)(void *), size_t stack_size=0, size_t private_buffer_size=0)
Definition: task.h:183
size_t get_private_buffer_size()
Definition: task.h:597
static void * sub_buffer_offset(void *in, size_t off)
Definition: task.h:585
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:411
std::list< std::pair< ptr_t, void * > > member_list_
Definition: task.h:42
int _notify_finished(void *priv_data)
Definition: task.h:636
virtual int cancel(void *priv_data) UTIL_CONFIG_OVERRIDE
Definition: task.h:531
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:284
virtual int resume(void *priv_data, EN_TASK_STATUS expected_status=EN_TS_WAITING) UTIL_CONFIG_OVERRIDE
Definition: task.h:519
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:53
COPP_EC_SUCCESS.
Definition: errno.h:12
#define COPP_MACRO_STD_FORWARD(t, x)
Definition: features.h:189
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:32
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:305
EN_TASK_STATUS get_status() const UTIL_CONFIG_NOEXCEPT
Definition: task_impl.h:64
const coroutine_t::ptr_t & get_coroutine_context() const UTIL_CONFIG_NOEXCEPT
Definition: task.h:452
size_t use_count() const
Definition: task.h:606
util::lock::spin_lock next_list_lock_
Definition: task.h:696
#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:73
sample endif() if(PROJECT_ENABLE_UNITTEST) add_custom_target(run_test) add_subdirectory("$
Definition: CMakeLists.txt:98
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:326
EN_TASK_STATUS
Definition: task_impl.h:28
virtual int yield(void **priv_data) UTIL_CONFIG_OVERRIDE
Definition: task.h:523
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:299
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:195
COPP_EC_IS_RUNNING.
Definition: errno.h:26
id_t id_
Definition: task.h:686
coroutine_t::ptr_t coroutine_obj_
Definition: task.h:688
task_group next_list_
Definition: task.h:689
#define COPP_MACRO_STD_MOVE(x)
Definition: features.h:185
size_t stack_size_
Definition: task.h:687
static ptr_t create(Ty(TInst::*func), TInst *instance, size_t stack_size=0, size_t private_buffer_size=0)
Definition: task.h:203
util::lock::atomic_int_type< size_t > ref_count_
Definition: task.h:695
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:457
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:155
virtual int kill(enum EN_TASK_STATUS status, void *priv_data) UTIL_CONFIG_OVERRIDE
Definition: task.h:548
macro_task_t::id_t id_t
Definition: task.h:37
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:279
virtual bool is_completed() const UTIL_CONFIG_NOEXCEPT UTIL_CONFIG_OVERRIDE
Definition: task.h:573
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:175
static void * add_buffer_offset(void *in, size_t off)
Definition: task.h:581
int await(TTask *wait_task)
Definition: task.h:378
coroutine_t::ptr_t & get_coroutine_context() UTIL_CONFIG_NOEXCEPT
Definition: task.h:451
id_t get_id() const UTIL_CONFIG_NOEXCEPT
Definition: task.h:454
friend void intrusive_ptr_add_ref(self_t *p)
Definition: task.h:653
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:320
task< TCO_MACRO, TTASK_MACRO > self_t
Definition: task.h:29
macro_task_t::id_allocator_t id_allocator_t
Definition: task.h:38
COPP_EC_TASK_NOT_IN_ACTION.
Definition: errno.h:38
static self_t * this_task()
Definition: task.h:436
ptr_t then(Ty(*func)(void *), void *priv_data=UTIL_CONFIG_NULLPTR)
Definition: task.h:423
impl::task_impl::action_ptr_t action_ptr_t
Definition: task.h:46
friend void intrusive_ptr_release(self_t *p)
Definition: task.h:661
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:589
TCO_MACRO macro_coroutine_t
Definition: task.h:31
std::intrusive_ptr< self_t > ptr_t
Definition: task.h:30
ptr_t then(ptr_t next_task, void *priv_data=UTIL_CONFIG_NULLPTR)
add task to run when task finished
Definition: task.h:390
static task_impl * this_task()
Definition: task_impl.cpp:38
macro_coroutine_t::stack_allocator_t stack_allocator_t
Definition: task.h:35
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:161
void active_next_tasks()
Definition: task.h:611
COPP_EC_ARGS_ERROR.
Definition: errno.h:30
int await(const ptr_t &wait_task)
await another cotask to finish
Definition: task.h:338