5#include <libcopp/utils/config/libcopp_build_features.h>
10#include <libcopp/utils/config/libcopp_build_features.h>
20#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
24#if defined(LIBCOPP_MACRO_ENABLE_WIN_FIBER) && LIBCOPP_MACRO_ENABLE_WIN_FIBER
25# include <type_traits>
35LIBCOPP_COTASK_NAMESPACE_BEGIN
37template <
class TCO_MACRO = macro_coroutine>
42 using ptr_type = LIBCOPP_COPP_NAMESPACE_ID::memory::intrusive_ptr<self_type>;
74 : stack_size_(stack_sz),
75 action_destroy_fn_(nullptr)
76#if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
78 binding_manager_ptr_(nullptr),
79 binding_manager_fn_(nullptr)
91 template <
typename TAct,
typename Ty>
93 typename coroutine_type::allocator_type &alloc,
94 size_t stack_size = 0,
95 size_t private_buffer_size = 0) {
98 if (0 == stack_size) {
99 stack_size = LIBCOPP_COPP_NAMESPACE_ID::stack_traits::default_size();
102 size_t action_size = coroutine_type::align_address_size(
sizeof(a_t));
103 size_t task_size = coroutine_type::align_address_size(
sizeof(
self_type));
105 if (stack_size <=
sizeof(
impl::task_impl *) + private_buffer_size + action_size + task_size) {
109 typename coroutine_type::ptr_type coroutine =
110 coroutine_type::create(
typename coroutine_type::callback_t(), alloc, stack_size,
111 sizeof(
impl::task_impl *) + private_buffer_size, action_size + task_size);
116 void *action_addr = sub_buffer_offset(coroutine.get(), action_size);
117 void *task_addr = sub_buffer_offset(action_addr, task_size);
125 *(
reinterpret_cast<impl::task_impl **
>(coroutine->get_private_buffer())) = ret.get();
126 ret->coroutine_obj_ = coroutine;
130 a_t *action =
new (action_addr) a_t(std::forward<Ty>(callable));
131 if (
nullptr == action) {
136 coroutine->set_runner([action](
void *private_data) {
return (*action)(private_data); });
139 ret->_set_action(action);
151 template <
typename Ty>
152 static inline ptr_type create(Ty &&functor,
size_t stack_size = 0,
size_t private_buffer_size = 0) {
153 typename coroutine_type::allocator_type alloc;
154 return create(std::forward<Ty>(functor), alloc, stack_size, private_buffer_size);
152 static inline ptr_type create(Ty &&functor,
size_t stack_size = 0,
size_t private_buffer_size = 0) {
…}
157 template <
typename Ty>
158 static inline ptr_type create(Ty &&functor,
typename coroutine_type::allocator_type &alloc,
size_t stack_size = 0,
159 size_t private_buffer_size = 0) {
160 using decay_type =
typename std::decay<Ty>::type;
161 using a_t =
typename std::conditional<std::is_base_of<impl::task_action_impl, decay_type>::value, decay_type,
164 return create_with_delegate<a_t>(std::forward<Ty>(functor), alloc, stack_size, private_buffer_size);
158 static inline ptr_type create(Ty &&functor,
typename coroutine_type::allocator_type &alloc,
size_t stack_size = 0, {
…}
173 template <
typename Ty>
174 static inline ptr_type create(Ty (*func)(
void *),
typename coroutine_type::allocator_type &alloc,
175 size_t stack_size = 0,
size_t private_buffer_size = 0) {
178 return create_with_delegate<a_t>(func, alloc, stack_size, private_buffer_size);
174 static inline ptr_type create(Ty (*func)(
void *),
typename coroutine_type::allocator_type &alloc, {
…}
181 template <
typename Ty>
182 static inline ptr_type create(Ty (*func)(
void *),
size_t stack_size = 0,
size_t private_buffer_size = 0) {
183 typename coroutine_type::allocator_type alloc;
184 return create(func, alloc, stack_size, private_buffer_size);
182 static inline ptr_type create(Ty (*func)(
void *),
size_t stack_size = 0,
size_t private_buffer_size = 0) {
…}
193 template <
typename Ty,
typename TInst>
194 static LIBCOPP_COTASK_API_HEAD_ONLY
ptr_type create(Ty(TInst::*func), TInst *instance,
196 size_t stack_size = 0, size_t private_buffer_size = 0) {
199 return create<a_t>(a_t(func, instance), alloc, stack_size, private_buffer_size);
194 static LIBCOPP_COTASK_API_HEAD_ONLY
ptr_type create(Ty(TInst::*func), TInst *instance, {
…}
202 template <
typename Ty,
typename TInst>
203 static inline ptr_type create(Ty(TInst::*func), TInst *instance, size_t stack_size = 0,
204 size_t private_buffer_size = 0) {
205 typename coroutine_type::allocator_type alloc;
206 return create(func, instance, alloc, stack_size, private_buffer_size);
203 static inline ptr_type create(Ty(TInst::*func), TInst *instance, size_t stack_size = 0, {
…}
215 template <
typename Ty,
typename... TParams>
217 size_t stack_size,
size_t private_buffer_size,
221 return create(a_t(std::forward<TParams>(args)...), alloc, stack_size, private_buffer_size);
234 if (
this == next_task.get() || !next_task) {
243 next_task->start(priv_data);
245 next_task->resume(priv_data);
250#if LIBCOPP_MACRO_ENABLE_MULTI_THREAD
251 LIBCOPP_COPP_NAMESPACE_ID::util::lock::lock_holder<LIBCOPP_COPP_NAMESPACE_ID::util::lock::spin_lock> lock_guard(
255 next_list_.member_list_.push_back(std::make_pair(next_task, priv_data));
267 template <
typename Ty>
268 inline ptr_type next(Ty &&functor,
void *priv_data =
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);
268 inline ptr_type next(Ty &&functor,
void *priv_data =
nullptr,
size_t stack_size = 0,
size_t private_buffer_size = 0) {
…}
272 template <
typename Ty>
273 inline ptr_type next(Ty &&functor,
typename coroutine_type::allocator_type &alloc,
void *priv_data =
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);
273 inline ptr_type next(Ty &&functor,
typename coroutine_type::allocator_type &alloc,
void *priv_data =
nullptr, {
…}
286 template <
typename Ty>
287 inline ptr_type next(Ty (*func)(
void *),
void *priv_data =
nullptr,
size_t stack_size = 0,
288 size_t private_buffer_size = 0) {
289 return next(create(func, stack_size, private_buffer_size), priv_data);
287 inline ptr_type next(Ty (*func)(
void *),
void *priv_data =
nullptr,
size_t stack_size = 0, {
…}
292 template <
typename Ty>
293 inline ptr_type next(Ty (*func)(
void *),
typename coroutine_type::allocator_type &alloc,
void *priv_data =
nullptr,
294 size_t stack_size = 0,
size_t private_buffer_size = 0) {
295 return next(create(func, alloc, stack_size, private_buffer_size), priv_data);
293 inline ptr_type next(Ty (*func)(
void *),
typename coroutine_type::allocator_type &alloc,
void *priv_data =
nullptr, {
…}
307 template <
typename Ty,
typename TInst>
308 inline ptr_type next(Ty(TInst::*func), TInst *instance, void *priv_data = nullptr, size_t stack_size = 0,
309 size_t private_buffer_size = 0) {
310 return next(create(func, instance, stack_size, private_buffer_size), priv_data);
308 inline ptr_type next(Ty(TInst::*func), TInst *instance, void *priv_data = nullptr, size_t stack_size = 0, {
…}
313 template <
typename Ty,
typename TInst>
315 void *priv_data = nullptr, size_t stack_size = 0, size_t private_buffer_size = 0) {
316 return next(create(func, instance, alloc, stack_size, private_buffer_size), priv_data);
329 return LIBCOPP_COPP_NAMESPACE_ID::COPP_EC_ARGS_ERROR;
332 if (
this == wait_task.get()) {
333 return LIBCOPP_COPP_NAMESPACE_ID::COPP_EC_TASK_CAN_NOT_WAIT_SELF;
337 if (wait_task->is_exiting() || wait_task->is_completed()) {
338 return LIBCOPP_COPP_NAMESPACE_ID::COPP_EC_TASK_IS_EXITING;
342 return LIBCOPP_COPP_NAMESPACE_ID::COPP_EC_TASK_IS_EXITING;
346 return LIBCOPP_COPP_NAMESPACE_ID::COPP_EC_TASK_NOT_IN_ACTION;
350 if (wait_task->next(
ptr_type(
this)).get() !=
this) {
351 return LIBCOPP_COPP_NAMESPACE_ID::COPP_EC_TASK_ADD_NEXT_FAILED;
355 while (!(wait_task->is_exiting() || wait_task->is_completed())) {
357 return LIBCOPP_COPP_NAMESPACE_ID::COPP_EC_TASK_IS_EXITING;
374 template <
class TAWAITABLE,
class TERROR_TRANSFORM,
375 class = LIBCOPP_COPP_NAMESPACE_ID::nostd::enable_if_t<LIBCOPP_COPP_NAMESPACE_ID::stackful_inject_awaitable<
376 LIBCOPP_COPP_NAMESPACE_ID::nostd::remove_cvref_t<TAWAITABLE>>::value>>
377 inline LIBCOPP_COPP_NAMESPACE_ID::container_value_type<TAWAITABLE>
378 await_value(TAWAITABLE &&awaitable, TERROR_TRANSFORM &&error_transform)
noexcept(
379 std::is_nothrow_copy_constructible<LIBCOPP_COPP_NAMESPACE_ID::container_value_type<TAWAITABLE>>::value &&
380 noexcept(error_transform(LIBCOPP_COPP_NAMESPACE_ID::COPP_EC_ARGS_ERROR))) {
381 if (!coroutine_obj_) {
382 return error_transform(LIBCOPP_COPP_NAMESPACE_ID::COPP_EC_NOT_INITED);
385 return awaitable.inject_await(
this, std::forward<TERROR_TRANSFORM>(error_transform));
378 await_value(TAWAITABLE &&awaitable, TERROR_TRANSFORM &&error_transform)
noexcept( {
…}
396 template <
class TAWAITABLE,
397 class = LIBCOPP_COPP_NAMESPACE_ID::nostd::enable_if_t<LIBCOPP_COPP_NAMESPACE_ID::stackful_inject_awaitable<
398 LIBCOPP_COPP_NAMESPACE_ID::nostd::remove_cvref_t<TAWAITABLE>>::value>>
399 inline LIBCOPP_COPP_NAMESPACE_ID::container_value_type<TAWAITABLE>
await_value(TAWAITABLE &&awaitable)
noexcept(
400 std::is_nothrow_copy_constructible<LIBCOPP_COPP_NAMESPACE_ID::container_value_type<TAWAITABLE>>::value &&
401 noexcept(LIBCOPP_COPP_NAMESPACE_ID::stackful_channel_error_transform<
402 LIBCOPP_COPP_NAMESPACE_ID::container_value_type<TAWAITABLE>>()(
403 LIBCOPP_COPP_NAMESPACE_ID::COPP_EC_ARGS_ERROR))) {
404 if (!coroutine_obj_) {
405 return LIBCOPP_COPP_NAMESPACE_ID::stackful_channel_error_transform<
406 LIBCOPP_COPP_NAMESPACE_ID::container_value_type<TAWAITABLE>>()(LIBCOPP_COPP_NAMESPACE_ID::COPP_EC_NOT_INITED);
409 return awaitable.inject_await(
this, LIBCOPP_COPP_NAMESPACE_ID::stackful_channel_error_transform<
410 LIBCOPP_COPP_NAMESPACE_ID::container_value_type<TAWAITABLE>>());
399 inline LIBCOPP_COPP_NAMESPACE_ID::container_value_type<TAWAITABLE>
await_value(TAWAITABLE &&awaitable)
noexcept( {
…}
417 template <
typename TTask>
419 return await_task(
ptr_type(wait_task));
439 template <
typename Ty>
441 if (!coroutine_obj_) {
442 then(create(std::forward<Ty>(functor), stack_size_, get_private_buffer_size()), priv_data);
446 create(std::forward<Ty>(functor), coroutine_obj_->get_allocator(), stack_size_, get_private_buffer_size()),
450 template <
typename Ty>
452 if (!coroutine_obj_) {
453 return then(create(func, stack_size_, get_private_buffer_size()), priv_data);
456 return then(create(func, coroutine_obj_->get_allocator(), stack_size_, get_private_buffer_size()), priv_data);
464#if defined(LIBCOPP_MACRO_ENABLE_RTTI) && LIBCOPP_MACRO_ENABLE_RTTI
478#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
479 std::list<std::exception_ptr> eptrs;
480 active_next_tasks(eptrs);
482 maybe_rethrow(eptrs);
489 void *action_ptr =
reinterpret_cast<void *
>(
_get_action());
490 if (
nullptr != action_destroy_fn_ &&
nullptr != action_ptr) {
491 (*action_destroy_fn_)(action_ptr);
493 action_destroy_fn_ =
nullptr;
500 return coroutine_obj_;
505 if (!coroutine_obj_) {
509 return coroutine_obj_->get_ret_code();
512#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
514 std::list<std::exception_ptr> eptrs;
515 int ret =
start(eptrs, priv_data, expected_status);
516 maybe_rethrow(eptrs);
520 virtual int start(std::list<std::exception_ptr> &unhandled,
void *priv_data,
525 if (!coroutine_obj_) {
526 return LIBCOPP_COPP_NAMESPACE_ID::COPP_EC_NOT_INITED;
533 return LIBCOPP_COPP_NAMESPACE_ID::COPP_EC_ALREADY_FINISHED;
537 return LIBCOPP_COPP_NAMESPACE_ID::COPP_EC_IS_RUNNING;
548#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
549 std::exception_ptr eptr;
550 int ret = coroutine_obj_->start(eptr, priv_data);
552 unhandled.emplace_back(std::move(eptr));
555 int ret = coroutine_obj_->start(priv_data);
566 finish_priv_data_ = priv_data;
567#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
577#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
594#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
596 return start(priv_data, expected_status);
599 virtual int resume(std::list<std::exception_ptr> &unhandled,
void *priv_data,
601 return start(unhandled, priv_data, expected_status);
605 return start(priv_data, expected_status);
609 int yield(
void **priv_data)
override {
610 if (!coroutine_obj_) {
611 return LIBCOPP_COPP_NAMESPACE_ID::COPP_EC_NOT_INITED;
614 return coroutine_obj_->yield(priv_data);
617#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
618 int cancel(
void *priv_data)
override {
619 std::list<std::exception_ptr> eptrs;
620 int ret =
cancel(eptrs, priv_data);
621 maybe_rethrow(eptrs);
625 virtual int cancel(std::list<std::exception_ptr> &unhandled,
void *priv_data) LIBCOPP_MACRO_NOEXCEPT {
634 return LIBCOPP_COPP_NAMESPACE_ID::COPP_EC_IS_RUNNING;
642#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
647 return LIBCOPP_COPP_NAMESPACE_ID::COPP_EC_SUCCESS;
650#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
652 std::list<std::exception_ptr> eptrs;
653 int ret =
kill(eptrs, status, priv_data);
654 maybe_rethrow(eptrs);
658 virtual int kill(std::list<std::exception_ptr> &unhandled,
enum EN_TASK_STATUS status,
659 void *priv_data) LIBCOPP_MACRO_NOEXCEPT {
672#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
678 finish_priv_data_ = priv_data;
681 return LIBCOPP_COPP_NAMESPACE_ID::COPP_EC_SUCCESS;
692 if (!coroutine_obj_) {
696 return coroutine_obj_->is_finished();
699#if defined(LIBCOPP_MACRO_ENABLE_WIN_FIBER) && LIBCOPP_MACRO_ENABLE_WIN_FIBER
700 bool is_fiber() const LIBCOPP_MACRO_NOEXCEPT
override {
701 return std::is_base_of<LIBCOPP_COPP_NAMESPACE_ID::coroutine_context_fiber, coroutine_type>::value;
706 return reinterpret_cast<void *
>(
reinterpret_cast<unsigned char *
>(in) + off);
710 return reinterpret_cast<void *
>(
reinterpret_cast<unsigned char *
>(in) - off);
714 if (!coroutine_obj_) {
718 return add_buffer_offset(coroutine_obj_->get_private_buffer(),
sizeof(
impl::task_impl *));
722 if (!coroutine_obj_) {
726 return coroutine_obj_->get_private_buffer_size() -
sizeof(
impl::task_impl *);
729 inline size_t use_count()
const {
return ref_count_.load(); }
731#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
733 for (std::list<std::exception_ptr>::iterator iter = eptrs.begin(); iter != eptrs.end(); ++iter) {
734 coroutine_type::maybe_rethrow(*iter);
741#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
742 void active_next_tasks(std::list<std::exception_ptr> &unhandled) LIBCOPP_MACRO_NOEXCEPT {
746 std::list<std::pair<ptr_type, void *>> next_list;
747#if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
753#if LIBCOPP_MACRO_ENABLE_MULTI_THREAD
754 LIBCOPP_COPP_NAMESPACE_ID::util::lock::lock_holder<LIBCOPP_COPP_NAMESPACE_ID::util::lock::spin_lock> lock_guard(
757 next_list.swap(next_list_.member_list_);
758#if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
759 manager_ptr = binding_manager_ptr_;
760 manager_fn = binding_manager_fn_;
761 binding_manager_ptr_ =
nullptr;
762 binding_manager_fn_ =
nullptr;
767 for (
typename std::list<std::pair<ptr_type, void *>>::iterator iter = next_list.begin(); iter != next_list.end();
769 if (!iter->first ||
EN_TS_INVALID == iter->first->get_status()) {
773#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
775 iter->first->start(unhandled, iter->second);
777 iter->first->resume(unhandled, iter->second);
781 iter->first->start(iter->second);
783 iter->first->resume(iter->second);
788#if defined(LIBCOPP_MACRO_ENABLE_STD_COROUTINE) && LIBCOPP_MACRO_ENABLE_STD_COROUTINE
789 caller_manager_.resume_callers();
793#if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
794 if (
nullptr != manager_ptr &&
nullptr != manager_fn) {
795 (*manager_fn)(manager_ptr, *
this);
801#
if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
802 std::list<std::exception_ptr> &unhandled,
804 void *priv_data) LIBCOPP_MACRO_NOEXCEPT {
806 if (coroutine_obj_ &&
false == coroutine_obj_->is_finished()) {
808 while (
false == coroutine_obj_->is_finished()) {
809#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
810 std::exception_ptr eptr;
811 coroutine_obj_->resume(eptr, priv_data);
813 unhandled.emplace_back(std::move(eptr));
816 coroutine_obj_->resume(priv_data);
821#if defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
824 active_next_tasks(unhandled);
850 using this_coroutine_ptr_type =
typename this_coroutine_type::ptr_type;
861#if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
863 class LIBCOPP_COTASK_API_HEAD_ONLY task_manager_helper {
867 static bool setup_task_manager(self_type &task_inst,
void *manager_ptr,
void (*fn)(
void *, self_type &)) {
868# if LIBCOPP_MACRO_ENABLE_MULTI_THREAD
869 LIBCOPP_COPP_NAMESPACE_ID::util::lock::lock_holder<LIBCOPP_COPP_NAMESPACE_ID::util::lock::spin_lock> lock_guard(
870 task_inst.inner_action_lock_);
872 if (task_inst.binding_manager_ptr_ !=
nullptr) {
876 task_inst.binding_manager_ptr_ = manager_ptr;
877 task_inst.binding_manager_fn_ = fn;
881 static bool cleanup_task_manager(self_type &task_inst,
void *manager_ptr) {
882# if LIBCOPP_MACRO_ENABLE_MULTI_THREAD
883 LIBCOPP_COPP_NAMESPACE_ID::util::lock::lock_holder<LIBCOPP_COPP_NAMESPACE_ID::util::lock::spin_lock> lock_guard(
884 task_inst.inner_action_lock_);
886 if (task_inst.binding_manager_ptr_ != manager_ptr) {
890 task_inst.binding_manager_ptr_ =
nullptr;
891 task_inst.binding_manager_fn_ =
nullptr;
897#if defined(LIBCOPP_MACRO_ENABLE_STD_COROUTINE) && LIBCOPP_MACRO_ENABLE_STD_COROUTINE
899 class LIBCOPP_COPP_API_HEAD_ONLY stackful_task_awaitable :
public LIBCOPP_COPP_NAMESPACE_ID::awaitable_base_type {
901 using value_type =
typename macro_coroutine_type::value_type;
904 explicit stackful_task_awaitable(self_type *waiting_task) : waiting_task_(waiting_task) {}
906 inline bool await_ready() const noexcept {
907 if (!waiting_task_) {
911 return waiting_task_->is_exiting();
914# if defined(LIBCOPP_MACRO_ENABLE_CONCEPTS) && LIBCOPP_MACRO_ENABLE_CONCEPTS
915 template <LIBCOPP_COPP_NAMESPACE_ID::DerivedPromiseBaseType TCPROMISE>
917 template <
class TCPROMISE,
typename = std::enable_if_t<
918 std::is_base_of<LIBCOPP_COPP_NAMESPACE_ID::promise_base_type, TCPROMISE>::value>>
921 if (waiting_task_ && !waiting_task_->is_exiting() &&
922 caller.promise().get_status() < LIBCOPP_COPP_NAMESPACE_ID::promise_status::kDone) {
924 waiting_task_->caller_manager_.add_caller(
925 LIBCOPP_COPP_NAMESPACE_ID::promise_caller_manager::handle_delegate{caller});
928 caller.promise().set_flag(LIBCOPP_COPP_NAMESPACE_ID::promise_flag::kInternalWaitting,
true);
936 if (!waiting_task_) {
937 return LIBCOPP_COPP_NAMESPACE_ID::COPP_EC_NOT_INITED;
941 if (waiting_task_->is_exiting()) {
942 switch (waiting_task_->get_status()) {
946 ret = LIBCOPP_COPP_NAMESPACE_ID::COPP_EC_TASK_IS_EXITING;
949 ret = waiting_task_->get_ret_code();
953 ret = LIBCOPP_COPP_NAMESPACE_ID::COPP_EC_TASK_IS_KILLED;
957 auto caller = get_caller();
960 if (
nullptr != caller.promise) {
961 caller.promise->set_flag(LIBCOPP_COPP_NAMESPACE_ID::promise_flag::kInternalWaitting,
false);
964 waiting_task_->caller_manager_.remove_caller(caller);
973 self_type *waiting_task_;
976 auto operator co_await() & LIBCOPP_MACRO_NOEXCEPT {
return stackful_task_awaitable{
this}; }
984 void (*action_destroy_fn_)(
void *);
986#if LIBCOPP_MACRO_ENABLE_MULTI_THREAD
987 LIBCOPP_COPP_NAMESPACE_ID::util::lock::atomic_int_type<size_t> ref_count_;
988 LIBCOPP_COPP_NAMESPACE_ID::util::lock::spin_lock inner_action_lock_;
990 LIBCOPP_COPP_NAMESPACE_ID::util::lock::atomic_int_type<LIBCOPP_COPP_NAMESPACE_ID::util::lock::unsafe_int_type<size_t>>
995#if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
996 void *binding_manager_ptr_;
997 void (*binding_manager_fn_)(
void *,
self_type &);
1000#if defined(LIBCOPP_MACRO_ENABLE_STD_COROUTINE) && LIBCOPP_MACRO_ENABLE_STD_COROUTINE
1001 LIBCOPP_COPP_NAMESPACE_ID::promise_caller_manager caller_manager_;
1005#if defined(LIBCOPP_MACRO_ENABLE_STD_COROUTINE) && LIBCOPP_MACRO_ENABLE_STD_COROUTINE
1006template <
typename TCO_MACRO>
1007auto operator co_await(
const LIBCOPP_COPP_NAMESPACE_ID::memory::intrusive_ptr<task<TCO_MACRO>> &t)
1008 LIBCOPP_MACRO_NOEXCEPT {
1010 return awaitable{t.get()};
1013LIBCOPP_COTASK_NAMESPACE_END
1015LIBCOPP_COPP_NAMESPACE_BEGIN
1016template <
class TCO_MACRO>
1019 if (
nullptr != invoke_task) {
1020 return reinterpret_cast<LIBCOPP_COTASK_NAMESPACE_ID::task<TCO_MACRO> *
>(invoke_task)
1021 ->resume(
reinterpret_cast<void *
>(priv_data));
1027LIBCOPP_COPP_NAMESPACE_END
LIBCOPP_COTASK_API bool is_exiting() const LIBCOPP_MACRO_NOEXCEPT
check if a cotask is exiting
LIBCOPP_UTIL_FORCEINLINE int cancel()
LIBCOPP_UTIL_FORCEINLINE EN_TASK_STATUS get_status() const LIBCOPP_MACRO_NOEXCEPT
LIBCOPP_COPP_NAMESPACE_ID::util::uint64_id_allocator id_allocator_type
LIBCOPP_COTASK_API void _set_action(action_ptr_type action)
task_action_impl * action_ptr_type
LIBCOPP_UTIL_FORCEINLINE int yield()
LIBCOPP_COPP_NAMESPACE_ID::util::uint64_id_allocator::value_type id_type
LIBCOPP_UTIL_FORCEINLINE int start()
LIBCOPP_UTIL_FORCEINLINE int resume()
LIBCOPP_COTASK_API action_ptr_type _get_action()
LIBCOPP_UTIL_FORCEINLINE int kill()
virtual LIBCOPP_COTASK_API bool is_completed() const LIBCOPP_MACRO_NOEXCEPT
LIBCOPP_COTASK_API bool _cas_status(EN_TASK_STATUS &expected, EN_TASK_STATUS desired)
static LIBCOPP_COTASK_API task_impl * this_task()
LIBCOPP_COTASK_API int _notify_finished(void *priv_data)
ptr_type next(Ty &&functor, typename coroutine_type::allocator_type &alloc, void *priv_data=nullptr, size_t stack_size=0, size_t private_buffer_size=0)
size_t get_private_buffer_size()
ptr_type next(Ty(TInst::*func), TInst *instance, void *priv_data=nullptr, size_t stack_size=0, size_t private_buffer_size=0)
create next task with function
static ptr_type create(Ty &&functor, size_t stack_size=0, size_t private_buffer_size=0)
create task with functor
typename impl::task_impl::id_type id_type
int yield(void **priv_data) override
int _notify_finished(void *priv_data) LIBCOPP_MACRO_NOEXCEPT
stack_allocator_type stack_allocator_t
static ptr_type create(Ty(*func)(void *), size_t stack_size=0, size_t private_buffer_size=0)
ptr_type next(ptr_type next_task, void *priv_data=nullptr)
add next task to run when task finished
const coroutine_type::ptr_type & get_coroutine_context() const LIBCOPP_MACRO_NOEXCEPT
static ptr_type create(Ty &&functor, typename coroutine_type::allocator_type &alloc, size_t stack_size=0, size_t private_buffer_size=0)
task(size_t stack_sz)
constuctor
int get_ret_code() const override
void * get_private_buffer()
macro_coroutine_type macro_coroutine_t
friend void intrusive_ptr_release(self_type *p)
int await_task(TTask *wait_task)
await another task
ptr_type then(Ty(*func)(void *), void *priv_data=nullptr)
ptr_type next(Ty(*func)(void *), void *priv_data=nullptr, size_t stack_size=0, size_t private_buffer_size=0)
create next task with function
static LIBCOPP_COTASK_API_HEAD_ONLY ptr_type create_with(typename coroutine_type::allocator_type &alloc, size_t stack_size, size_t private_buffer_size, TParams &&...args)
create task with functor type and parameters
int kill(enum EN_TASK_STATUS status, void *priv_data) override
static void * sub_buffer_offset(void *in, size_t off)
coroutine_type coroutine_t
coroutine_type::ptr_type & get_coroutine_context() LIBCOPP_MACRO_NOEXCEPT
bool is_completed() const LIBCOPP_MACRO_NOEXCEPT override
static ptr_type create(Ty(TInst::*func), TInst *instance, size_t stack_size=0, size_t private_buffer_size=0)
LIBCOPP_COPP_NAMESPACE_ID::util::lock::atomic_int_type< LIBCOPP_COPP_NAMESPACE_ID::util::lock::unsafe_int_type< size_t > > ref_count_
LIBCOPP_COPP_NAMESPACE_ID::container_value_type< TAWAITABLE > await_value(TAWAITABLE &&awaitable) noexcept(std::is_nothrow_copy_constructible< LIBCOPP_COPP_NAMESPACE_ID::container_value_type< TAWAITABLE > >::value &&noexcept(LIBCOPP_COPP_NAMESPACE_ID::stackful_channel_error_transform< LIBCOPP_COPP_NAMESPACE_ID::container_value_type< TAWAITABLE > >()(LIBCOPP_COPP_NAMESPACE_ID::COPP_EC_ARGS_ERROR)))
Waits for the specified awaitable object to finish and retrieves its result.
ptr_type then(Ty &&functor, void *priv_data=nullptr)
create next task with functor using the same allocator and private buffer size as this task
static LIBCOPP_COTASK_API_HEAD_ONLY ptr_type create_with_delegate(Ty &&callable, typename coroutine_type::allocator_type &alloc, size_t stack_size=0, size_t private_buffer_size=0)
create task with functor
TCO_MACRO macro_coroutine_type
LIBCOPP_COPP_NAMESPACE_ID::container_value_type< TAWAITABLE > await_value(TAWAITABLE &&awaitable, TERROR_TRANSFORM &&error_transform) noexcept(std::is_nothrow_copy_constructible< LIBCOPP_COPP_NAMESPACE_ID::container_value_type< TAWAITABLE > >::value &&noexcept(error_transform(LIBCOPP_COPP_NAMESPACE_ID::COPP_EC_ARGS_ERROR)))
Waits for the specified awaitable object to finish and retrieves its result.
LIBCOPP_COPP_NAMESPACE_ID::memory::intrusive_ptr< self_type > ptr_type
ptr_type then(ptr_type next_task, void *priv_data=nullptr)
add task to run when task finished
static self_type * this_task()
static ptr_type create(Ty(*func)(void *), typename coroutine_type::allocator_type &alloc, size_t stack_size=0, size_t private_buffer_size=0)
create task with function
ptr_type next(Ty(TInst::*func), TInst *instance, typename coroutine_type::allocator_type &alloc, void *priv_data=nullptr, size_t stack_size=0, size_t private_buffer_size=0)
typename macro_coroutine_type::coroutine_type coroutine_type
task(const task &)=delete
int await_task(ptr_type wait_task)
await_task another cotask to finish
static void * add_buffer_offset(void *in, size_t off)
int start(void *priv_data, EN_TASK_STATUS expected_status=EN_TS_CREATED) override
coroutine_type::ptr_type coroutine_obj_
friend void intrusive_ptr_add_ref(self_type *p)
ptr_type next(Ty &&functor, void *priv_data=nullptr, size_t stack_size=0, size_t private_buffer_size=0)
create next task with functor
int cancel(void *priv_data) override
typename impl::task_impl::id_allocator_type id_allocator_type
typename macro_coroutine_type::stack_allocator_type stack_allocator_type
ptr_type next(Ty(*func)(void *), typename coroutine_type::allocator_type &alloc, void *priv_data=nullptr, size_t stack_size=0, size_t private_buffer_size=0)
int resume(void *priv_data, EN_TASK_STATUS expected_status=EN_TS_WAITING) override
id_allocator_type id_allocator_t
static LIBCOPP_COTASK_API_HEAD_ONLY ptr_type create(Ty(TInst::*func), TInst *instance, typename coroutine_type::allocator_type &alloc, size_t stack_size=0, size_t private_buffer_size=0)
create task with function
#define LIBCOPP_UTIL_FORCEINLINE
#define LIBCOPP_UTIL_LIKELY_CONDITION(__C)
#define LIBCOPP_UTIL_UNLIKELY_CONDITION(__C)
#define LIBCOPP_MACRO_STD_COROUTINE_NAMESPACE
std::shared_ptr< cli::cmd_option_value > value_type
static LIBCOPP_COPP_API_HEAD_ONLY int resume(void *invoke_task, stackful_channel_context_base *priv_data)
std::list< std::pair< ptr_type, void * > > member_list_
LIBCOPP_COTASK_API_HEAD_ONLY placement_destroy_fn_t get_placement_destroy(task_action_functor< Ty > *)
class LIBCOPP_COTASK_API_HEAD_ONLY task_manager