16 #ifdef LIBCOTASK_MACRO_ENABLED
17 static int g_test_coroutine_task_status = 0;
18 static int g_test_coroutine_task_on_finished = 0;
19 class test_context_task_action_base :
public cotask::impl::task_action_impl {
22 virtual int operator()() = 0;
24 int operator()(
void *priv_data) {
25 ++g_test_coroutine_task_status;
35 ++g_test_coroutine_task_status;
40 virtual int on_finished(cotask::impl::task_impl &) {
41 ++g_test_coroutine_task_on_finished;
46 class test_context_task_action :
public test_context_task_action_base {
48 using test_context_task_action_base::operator();
51 virtual int operator()() {
return 0; }
54 CASE_TEST(coroutine_task, custom_action) {
56 g_test_coroutine_task_status = 0;
57 g_test_coroutine_task_on_finished = 0;
60 task_ptr_type co_task = cotask::task<>::create(test_context_task_action());
61 task_ptr_type co_another_task = cotask::task<>::create(test_context_task_action());
73 CASE_EXPECT_EQ(0, co_another_task->start(&g_test_coroutine_task_status));
93 ++g_test_coroutine_task_status;
102 struct test_context_task_functor {
104 int operator()(
void *)
const {
105 ++g_test_coroutine_task_status;
110 ++g_test_coroutine_task_status;
117 CASE_TEST(coroutine_task, functor_action) {
119 task_ptr_type co_task = cotask::task<>::create(test_context_task_functor());
120 g_test_coroutine_task_status = 0;
124 ++g_test_coroutine_task_status;
132 ++g_test_coroutine_task_status;
138 static int test_context_task_function_1(
void *) {
139 ++g_test_coroutine_task_status;
144 ++g_test_coroutine_task_status;
150 static void test_context_task_function_2(
void *) {
151 ++g_test_coroutine_task_status;
156 ++g_test_coroutine_task_status;
160 CASE_TEST(coroutine_task, function_action) {
163 task_ptr_type co_task = cotask::task<>::create(test_context_task_function_1);
164 g_test_coroutine_task_status = 0;
168 ++g_test_coroutine_task_status;
176 ++g_test_coroutine_task_status;
178 CASE_EXPECT_EQ(co_task->get_coroutine_context()->get_ret_code(), 100);
183 task_ptr_type co_task = cotask::task<>::create(test_context_task_function_2);
184 g_test_coroutine_task_status = 0;
188 ++g_test_coroutine_task_status;
196 ++g_test_coroutine_task_status;
203 task_ptr_type co_task = cotask::task<>::create(test_context_task_function_1);
204 g_test_coroutine_task_status = 0;
208 ++g_test_coroutine_task_status;
218 static void test_context_task_function_3(
void *) {
219 ++g_test_coroutine_task_status;
228 ++g_test_coroutine_task_status;
232 CASE_TEST(coroutine_task, coroutine_context_yield) {
234 task_ptr_type co_task = cotask::task<>::create(test_context_task_function_3);
235 g_test_coroutine_task_status = 0;
239 ++g_test_coroutine_task_status;
248 ++g_test_coroutine_task_status;
254 struct test_context_task_mem_function {
255 cotask::task<>::id_t task_id_;
257 int real_run(
void *) {
258 ++g_test_coroutine_task_status;
262 cotask::task<>::this_task()->yield();
265 ++g_test_coroutine_task_status;
272 CASE_TEST(coroutine_task, mem_function_action) {
274 test_context_task_mem_function obj;
275 task_ptr_type co_task = cotask::task<>::create(&test_context_task_mem_function::real_run, &obj);
276 g_test_coroutine_task_status = 0;
277 obj.task_id_ = co_task->get_id();
281 ++g_test_coroutine_task_status;
289 ++g_test_coroutine_task_status;
292 CASE_EXPECT_NE(co_task->get_coroutine_context()->get_ret_code(), -1);
298 test_context_task_mem_function obj;
299 task_ptr_type co_task = cotask::task<>::create(&test_context_task_mem_function::real_run, &obj);
300 g_test_coroutine_task_status = 0;
301 obj.task_id_ = co_task->get_id();
306 test_context_task_mem_function obj;
307 task_ptr_type co_task = cotask::task<>::create(&test_context_task_mem_function::real_run, &obj);
308 g_test_coroutine_task_status = 0;
309 obj.task_id_ = co_task->get_id();
313 ++g_test_coroutine_task_status;
319 ++g_test_coroutine_task_status;
323 struct test_context_task_next_action :
public cotask::impl::task_action_impl {
326 test_context_task_next_action(
int s,
int c) : cotask::
impl::task_action_impl(), set_(s), check_(c) {}
328 int operator()(
void *) {
330 g_test_coroutine_task_status = set_;
334 ++g_test_coroutine_task_on_finished;
343 g_test_coroutine_task_status = 0;
345 task_ptr_type co_task = cotask::task<>::create(test_context_task_next_action(15, 0));
346 co_task->next(test_context_task_next_action(7, 15))
347 ->next(test_context_task_next_action(99, 7))
348 ->next(test_context_task_next_action(1023, 99))
349 ->next(test_context_task_next_action(5, 1023));
359 g_test_coroutine_task_status = 0;
360 task_ptr_type co_task_a = cotask::task<>::create(test_context_task_next_action(2, 1));
361 task_ptr_type co_task_b = cotask::task<>::create(test_context_task_function_1);
364 co_task_a->next(co_task_b);
372 struct test_context_task_functor_drived :
public cotask::impl::task_action_impl {
376 test_context_task_functor_drived(
int a,
int b) : a_(a), b_(b) {}
378 virtual int operator()(
void *) {
386 CASE_TEST(coroutine_task, functor_drived_action) {
388 cotask::task<>::coroutine_type::allocator_type alloc;
389 task_ptr_type co_task = cotask::task<>::create_with<test_context_task_functor_drived>(alloc, 0, 0, 1, 3);
393 static int test_context_task_priavte_buffer(
void *) {
394 void *priv_data = cotask::task<>::this_task()->get_private_buffer();
395 size_t priv_sz = cotask::task<>::this_task()->get_private_buffer_size();
399 if (priv_sz >= 256) {
400 char checked_data[256];
401 memset(checked_data, 0x5e, 256);
409 CASE_TEST(coroutine_task, priavte_buffer) {
411 task_ptr_type co_task = cotask::task<>::create(test_context_task_priavte_buffer, 16384, 256);
413 void *priv_data = co_task->get_private_buffer();
414 memset(priv_data, 0x5e, 256);
419 static int test_context_task_timeout(
void *) {
420 cotask::task<>::this_task()->yield();
430 CASE_TEST(coroutine_task, kill_and_timeout) {
432 task_ptr_type co_task = cotask::task<>::create(test_context_task_timeout, 16384, 256);
434 void *priv_data = co_task->get_private_buffer();
435 memset(priv_data, 0x5e, 256);
451 static int test_context_task_await_1(
void *) {
459 void *priv_data =
self->get_private_buffer();
460 cotask::task<>::self_t *other_task = *
reinterpret_cast<cotask::task<>::self_t **
>(priv_data);
462 if (other_task->is_exiting()) {
465 if (self->is_exiting()) {
475 static int test_context_task_await_2(
void *) {
return 0; }
483 cotask::task<>::create(test_context_task_await_1, 16384,
sizeof(cotask::task<>::self_t *));
484 task_ptr_type co_task_2 = cotask::task<>::create(test_context_task_await_2, 16384);
486 void *priv_data = co_task_1->get_private_buffer();
488 *
reinterpret_cast<cotask::task<>::self_t **
>(priv_data) = co_task_2.get();
506 cotask::task<>::create(test_context_task_await_1, 16384,
sizeof(cotask::task<>::self_t *));
507 task_ptr_type co_task_2 = cotask::task<>::create(test_context_task_await_2, 16384);
509 void *priv_data = co_task_1->get_private_buffer();
514 *
reinterpret_cast<cotask::task<>::self_t **
>(priv_data) = co_task_2.get();
534 cotask::task<>::create(test_context_task_await_1, 16384,
sizeof(cotask::task<>::self_t *));
535 task_ptr_type co_task_2 = cotask::task<>::create(test_context_task_await_2, 16384);
537 void *priv_data = co_task_1->get_private_buffer();
539 *
reinterpret_cast<cotask::task<>::self_t **
>(priv_data) = co_task_2.get();
555 static int test_context_task_then_action_func(
void *priv_data) {
557 ++g_test_coroutine_task_on_finished;
563 g_test_coroutine_task_status = 0;
564 g_test_coroutine_task_on_finished = 0;
566 task_ptr_type co_task = cotask::task<>::create(test_context_task_next_action(15, 0));
567 co_task->then(test_context_task_next_action(7, 15))
568 ->then(test_context_task_next_action(99, 7))
569 ->then(test_context_task_next_action(1023, 99))
570 ->then(test_context_task_next_action(5, 1023));
580 co_task->then(test_context_task_next_action(127, 5))
581 ->then(test_context_task_then_action_func, &g_test_coroutine_task_status);
586 typedef copp::stack_pool<copp::allocator::stack_allocator_malloc> test_context_task_stack_pool_t;
587 struct test_context_task_stack_pool_test_macro_coroutine {
588 using stack_allocator_type = copp::allocator::stack_allocator_pool<test_context_task_stack_pool_t>;
589 using coroutine_type = copp::coroutine_context_container<stack_allocator_type>;
593 typedef cotask::task<test_context_task_stack_pool_test_macro_coroutine> test_context_task_stack_pool_test_task_t;
595 CASE_TEST(coroutine_task, then_with_stack_pool) {
596 typedef test_context_task_stack_pool_test_task_t::ptr_t
task_ptr_type;
597 test_context_task_stack_pool_t::ptr_t
stack_pool = test_context_task_stack_pool_t::create();
599 g_test_coroutine_task_on_finished = 0;
600 g_test_coroutine_task_status = 0;
602 copp::allocator::stack_allocator_pool<test_context_task_stack_pool_t> base_alloc(
stack_pool);
603 task_ptr_type tp = test_context_task_stack_pool_test_task_t::create(test_context_task_next_action(15, 0), base_alloc);
604 tp->then(test_context_task_next_action(127, 15))
605 ->then(test_context_task_then_action_func, &g_test_coroutine_task_status);
611 tp->then(test_context_task_next_action(255, 127))
612 ->then(test_context_task_then_action_func, &g_test_coroutine_task_status);
621 class task_action_of_issue18 {
623 task_action_of_issue18() {}
624 int operator()(
void *) {
return 0; }
627 CASE_TEST(coroutine_task, github_issues_18) {
628 using simple_task_t = cotask::task<>;
631 simple_task_t::ptr_t co_task = simple_task_t::create(task_action_of_issue18());
633 co_task->then(task_action_of_issue18());
638 task_action_of_issue18 copy_action;
639 simple_task_t::ptr_t co_task = simple_task_t::create(copy_action);
641 co_task->then(copy_action);
646 static LIBCOPP_COPP_NAMESPACE_ID::util::lock::atomic_int_type<int> g_test_context_task_test_atomic;
647 static constexpr
const int g_test_context_task_test_mt_run_times = 10000;
648 static size_t g_test_context_task_test_mt_max_run_thread_number = 0;
650 test_context_task_test_mt_thread_num = 100,
651 test_context_task_test_mt_task_num = 1000,
654 struct test_context_task_test_action_mt_thread :
public cotask::impl::task_action_impl {
658 test_context_task_test_action_mt_thread() : run_count(0) {}
660 int operator()(
void *thread_func_address) {
661 std::set<void *> thread_counter;
663 while (run_count < g_test_context_task_test_mt_run_times) {
665 ++g_test_context_task_test_atomic;
667 thread_counter.insert(thread_func_address);
672 if (g_test_context_task_test_mt_max_run_thread_number < thread_counter.size()) {
673 g_test_context_task_test_mt_max_run_thread_number = thread_counter.size();
679 struct test_context_task_test_mt_thread_runner {
682 std::vector<task_ptr_type> *task_pool;
683 test_context_task_test_mt_thread_runner(std::vector<task_ptr_type> *pool) : task_pool(pool) {}
686 bool need_continue =
true;
687 while (need_continue) {
688 need_continue =
false;
690 for (
size_t i = 0; i < task_pool->size(); ++i) {
691 if (
false == (*task_pool)[i]->is_completed()) {
692 need_continue =
true;
693 (*task_pool)[i]->resume(
this);
701 CASE_TEST(coroutine_task, mt_run_competition) {
703 std::vector<task_ptr_type> task_pool;
704 task_pool.reserve(test_context_task_test_mt_task_num);
705 for (
int i = 0; i < test_context_task_test_mt_task_num; ++i) {
707 cotask::task<>::create(test_context_task_test_action_mt_thread(), 16 * 1024));
710 g_test_context_task_test_atomic.store(0);
711 g_test_context_task_test_mt_max_run_thread_number = 0;
713 std::unique_ptr<std::thread> thds[test_context_task_test_mt_thread_num];
714 for (
int i = 0; i < test_context_task_test_mt_thread_num; ++i) {
715 thds[i].reset(
new std::thread(test_context_task_test_mt_thread_runner(&task_pool)));
718 for (
int i = 0; i < test_context_task_test_mt_thread_num; ++i) {
722 CASE_EXPECT_EQ(g_test_context_task_test_mt_run_times * test_context_task_test_mt_task_num,
723 g_test_context_task_test_atomic.load());
724 CASE_MSG_INFO() <<
"Coroutine tasks are run on " << g_test_context_task_test_mt_max_run_thread_number
725 <<
" threads at most." << std::endl;
728 # if defined(LIBCOPP_MACRO_ENABLE_STD_COROUTINE) && LIBCOPP_MACRO_ENABLE_STD_COROUTINE
729 static copp::callable_future<int> call_for_await_cotask(
const cotask::task<>::ptr_t &t) {
731 co_return co_await t;
737 static int cotask_action_callback(
void *) {
741 if (ptr !=
nullptr) {
742 ret = *
reinterpret_cast<int *
>(ptr);
747 CASE_TEST(coroutine_task, callable_future_co_await) {
748 cotask::task<>::ptr_t co_task = cotask::task<>::create(cotask_action_callback);
750 auto t = call_for_await_cotask(co_task);
755 co_task->resume(
reinterpret_cast<void *
>(&res));
762 CASE_TEST(coroutine_task, callable_future_co_await_do_not_start) {
763 cotask::task<>::ptr_t co_task = cotask::task<>::create(cotask_action_callback);
765 auto t = call_for_await_cotask(co_task);
virtual int yield(void **priv_data)=0
const limit_t & get_limit() const
@ COPP_EC_IS_RUNNING
COPP_EC_IS_RUNNING.
@ COPP_EC_TASK_NOT_IN_ACTION
COPP_EC_TASK_NOT_IN_ACTION.
@ COPP_EC_ALREADY_FINISHED
COPP_EC_ALREADY_FINISHED.
@ COPP_EC_TASK_IS_KILLED
COPP_EC_TASK_IS_KILLED.
@ COPP_EC_TASK_IS_EXITING
COPP_EC_TASK_IS_EXITING.
@ COPP_EC_TASK_CAN_NOT_WAIT_SELF
COPP_EC_TASK_CAN_NOT_WAIT_SELF.
@ COPP_EC_ARGS_ERROR
COPP_EC_ARGS_ERROR.
LIBCOPP_COPP_API_HEAD_ONLY Tc * get()
get current coroutine and try to convert type
LIBCOPP_COPP_API int yield(void **priv_data=nullptr) LIBCOPP_MACRO_NOEXCEPT
yield current coroutine
LIBCOPP_COTASK_API impl::task_impl * get_task() LIBCOPP_MACRO_NOEXCEPT
get current running task
std::shared_ptr< cli::cmd_option_value > value_type
my_task_t::ptr_t task_ptr_type
#define CASE_EXPECT_FALSE(c)
#define CASE_EXPECT_EQ(l, r)
#define CASE_EXPECT_GT(l, r)
#define CASE_EXPECT_NE(l, r)
#define CASE_TEST(test_name, case_name)
#define CASE_EXPECT_TRUE(c)
#define CASE_EXPECT_GE(l, r)