libcopp  2.2.0
coroutine_task_test.cpp
Go to the documentation of this file.
1 // Copyright 2023 owent
2 
5 #include <libcotask/task.h>
6 
7 #include <cstdio>
8 #include <cstring>
9 #include <iostream>
10 #include <memory>
11 #include <set>
12 #include <vector>
13 
14 #include "frame/test_macros.h"
15 
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 {
20  public:
21  // add a same name function to find the type detection error
22  virtual int operator()() = 0;
23 
24  int operator()(void *priv_data) {
25  ++g_test_coroutine_task_status;
26 
27  CASE_EXPECT_EQ(&g_test_coroutine_task_status, priv_data);
28 
30  cotask::this_task::get_task()->yield(&priv_data);
32 
34 
35  ++g_test_coroutine_task_status;
36 
37  return 0;
38  }
39 
40  virtual int on_finished(cotask::impl::task_impl &) {
41  ++g_test_coroutine_task_on_finished;
42  return 0;
43  }
44 };
45 
46 class test_context_task_action : public test_context_task_action_base {
47  public:
48  using test_context_task_action_base::operator();
49 
50  // add a same name function to find the type detection error
51  virtual int operator()() { return 0; }
52 };
53 
54 CASE_TEST(coroutine_task, custom_action) {
55  typedef cotask::task<>::ptr_t task_ptr_type;
56  g_test_coroutine_task_status = 0;
57  g_test_coroutine_task_on_finished = 0;
58 
59  {
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()); // share action
62 
63  CASE_EXPECT_EQ(cotask::EN_TS_CREATED, co_task->get_status());
64  CASE_EXPECT_EQ(cotask::EN_TS_CREATED, co_another_task->get_status());
65 
66  CASE_EXPECT_EQ(0, co_task->start(&g_test_coroutine_task_status));
67 
68  CASE_EXPECT_EQ(g_test_coroutine_task_status, 1);
69  CASE_EXPECT_FALSE(co_task->is_completed());
70  CASE_EXPECT_FALSE(co_task->is_canceled());
71  CASE_EXPECT_FALSE(co_task->is_faulted());
72 
73  CASE_EXPECT_EQ(0, co_another_task->start(&g_test_coroutine_task_status));
74  CASE_EXPECT_EQ(g_test_coroutine_task_status, 2);
75 
76  CASE_EXPECT_EQ(cotask::EN_TS_WAITING, co_task->get_status());
77  CASE_EXPECT_EQ(cotask::EN_TS_WAITING, co_another_task->get_status());
78 
79  CASE_EXPECT_EQ(0, co_task->resume(co_task.get()));
80  CASE_EXPECT_EQ(g_test_coroutine_task_status, 3);
81 
82  CASE_EXPECT_EQ(0, co_another_task->resume(co_another_task.get()));
83  CASE_EXPECT_EQ(g_test_coroutine_task_status, 4);
84 
85  CASE_EXPECT_TRUE(co_task->is_completed());
86  CASE_EXPECT_TRUE(co_another_task->is_completed());
87  CASE_EXPECT_FALSE(co_task->is_canceled());
88  CASE_EXPECT_FALSE(co_task->is_faulted());
89 
90  CASE_EXPECT_GT(0, co_another_task->resume(co_another_task.get()));
91  CASE_EXPECT_EQ(g_test_coroutine_task_status, 4);
92 
93  ++g_test_coroutine_task_status;
94  CASE_EXPECT_EQ(g_test_coroutine_task_status, 5);
95 
96  CASE_EXPECT_NE(co_task->get_id(), 0);
97  }
98 
99  CASE_EXPECT_EQ(g_test_coroutine_task_on_finished, 2);
100 }
101 
102 struct test_context_task_functor {
103  public:
104  int operator()(void *) const {
105  ++g_test_coroutine_task_status;
106  CASE_EXPECT_EQ(g_test_coroutine_task_status, 1);
107 
109 
110  ++g_test_coroutine_task_status;
111  CASE_EXPECT_EQ(g_test_coroutine_task_status, 3);
112 
113  return 0;
114  }
115 };
116 
117 CASE_TEST(coroutine_task, functor_action) {
118  typedef cotask::task<>::ptr_t task_ptr_type;
119  task_ptr_type co_task = cotask::task<>::create(test_context_task_functor());
120  g_test_coroutine_task_status = 0;
121 
122  CASE_EXPECT_EQ(0, co_task->start());
123 
124  ++g_test_coroutine_task_status;
125  CASE_EXPECT_EQ(g_test_coroutine_task_status, 2);
126 
127  CASE_EXPECT_FALSE(co_task->is_completed());
128  CASE_EXPECT_EQ(0, co_task->resume());
129 
130  CASE_EXPECT_TRUE(co_task->is_completed());
131 
132  ++g_test_coroutine_task_status;
133  CASE_EXPECT_EQ(g_test_coroutine_task_status, 4);
134 
135  CASE_EXPECT_NE(co_task->get_id(), 0);
136 }
137 
138 static int test_context_task_function_1(void *) {
139  ++g_test_coroutine_task_status;
140  CASE_EXPECT_EQ(g_test_coroutine_task_status, 1);
141 
143 
144  ++g_test_coroutine_task_status;
145  CASE_EXPECT_EQ(g_test_coroutine_task_status, 3);
146 
147  return 100;
148 }
149 
150 static void test_context_task_function_2(void *) {
151  ++g_test_coroutine_task_status;
152  CASE_EXPECT_EQ(g_test_coroutine_task_status, 1);
153 
155 
156  ++g_test_coroutine_task_status;
157  CASE_EXPECT_EQ(g_test_coroutine_task_status, 3);
158 }
159 
160 CASE_TEST(coroutine_task, function_action) {
161  {
162  typedef cotask::task<>::ptr_t task_ptr_type;
163  task_ptr_type co_task = cotask::task<>::create(test_context_task_function_1);
164  g_test_coroutine_task_status = 0;
165 
166  CASE_EXPECT_EQ(0, co_task->start());
167 
168  ++g_test_coroutine_task_status;
169  CASE_EXPECT_EQ(g_test_coroutine_task_status, 2);
170 
171  CASE_EXPECT_FALSE(co_task->is_completed());
172  CASE_EXPECT_EQ(0, co_task->resume());
173 
174  CASE_EXPECT_TRUE(co_task->is_completed());
175 
176  ++g_test_coroutine_task_status;
177  CASE_EXPECT_EQ(g_test_coroutine_task_status, 4);
178  CASE_EXPECT_EQ(co_task->get_coroutine_context()->get_ret_code(), 100);
179  }
180 
181  {
182  typedef cotask::task<>::ptr_t task_ptr_type;
183  task_ptr_type co_task = cotask::task<>::create(test_context_task_function_2);
184  g_test_coroutine_task_status = 0;
185 
186  CASE_EXPECT_EQ(0, co_task->start());
187 
188  ++g_test_coroutine_task_status;
189  CASE_EXPECT_EQ(g_test_coroutine_task_status, 2);
190 
191  CASE_EXPECT_FALSE(co_task->is_completed());
192  CASE_EXPECT_EQ(0, co_task->resume());
193 
194  CASE_EXPECT_TRUE(co_task->is_completed());
195 
196  ++g_test_coroutine_task_status;
197  CASE_EXPECT_EQ(g_test_coroutine_task_status, 4);
198  }
199 }
200 
201 CASE_TEST(coroutine_task, cancel) {
202  typedef cotask::task<>::ptr_t task_ptr_type;
203  task_ptr_type co_task = cotask::task<>::create(test_context_task_function_1);
204  g_test_coroutine_task_status = 0;
205 
206  CASE_EXPECT_EQ(0, co_task->start());
207 
208  ++g_test_coroutine_task_status;
209  CASE_EXPECT_EQ(g_test_coroutine_task_status, 2);
210 
211  CASE_EXPECT_FALSE(co_task->is_completed());
212  CASE_EXPECT_EQ(0, co_task->cancel(nullptr));
213 
214  CASE_EXPECT_TRUE(co_task->is_completed());
215 }
216 
217 // task start and coroutine context yield
218 static void test_context_task_function_3(void *) {
219  ++g_test_coroutine_task_status;
220  CASE_EXPECT_EQ(g_test_coroutine_task_status, 1);
221 
223 
225 
226  CASE_EXPECT_EQ(cotask::EN_TS_RUNNING, cotask::this_task::get<cotask::task<> >()->get_status());
227 
228  ++g_test_coroutine_task_status;
229  CASE_EXPECT_EQ(g_test_coroutine_task_status, 3);
230 }
231 
232 CASE_TEST(coroutine_task, coroutine_context_yield) {
233  typedef cotask::task<>::ptr_t task_ptr_type;
234  task_ptr_type co_task = cotask::task<>::create(test_context_task_function_3);
235  g_test_coroutine_task_status = 0;
236 
237  CASE_EXPECT_EQ(0, co_task->start());
238 
239  ++g_test_coroutine_task_status;
240  CASE_EXPECT_EQ(g_test_coroutine_task_status, 2);
241 
242  CASE_EXPECT_FALSE(co_task->is_completed());
243  CASE_EXPECT_EQ(cotask::EN_TS_WAITING, co_task->get_status());
244  CASE_EXPECT_EQ(0, co_task->resume());
245 
246  CASE_EXPECT_TRUE(co_task->is_completed());
247 
248  ++g_test_coroutine_task_status;
249  CASE_EXPECT_EQ(g_test_coroutine_task_status, 4);
250 
251  CASE_EXPECT_NE(co_task->get_id(), 0);
252 }
253 
254 struct test_context_task_mem_function {
255  cotask::task<>::id_t task_id_;
256 
257  int real_run(void *) {
258  ++g_test_coroutine_task_status;
259  CASE_EXPECT_EQ(g_test_coroutine_task_status, 1);
260 
261  CASE_EXPECT_EQ(task_id_, cotask::task<>::this_task()->get_id());
262  cotask::task<>::this_task()->yield();
263  CASE_EXPECT_EQ(task_id_, cotask::task<>::this_task()->get_id());
264 
265  ++g_test_coroutine_task_status;
266  CASE_EXPECT_EQ(g_test_coroutine_task_status, 3);
267 
268  return -1;
269  }
270 };
271 
272 CASE_TEST(coroutine_task, mem_function_action) {
273  typedef cotask::task<>::ptr_t task_ptr_type;
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();
278 
279  CASE_EXPECT_EQ(0, co_task->start());
280 
281  ++g_test_coroutine_task_status;
282  CASE_EXPECT_EQ(g_test_coroutine_task_status, 2);
283 
284  CASE_EXPECT_FALSE(co_task->is_completed());
285  CASE_EXPECT_EQ(0, co_task->resume());
286 
287  CASE_EXPECT_TRUE(co_task->is_completed());
288 
289  ++g_test_coroutine_task_status;
290  CASE_EXPECT_EQ(g_test_coroutine_task_status, 4);
291 
292  CASE_EXPECT_NE(co_task->get_coroutine_context()->get_ret_code(), -1);
293 }
294 
295 CASE_TEST(coroutine_task, auto_finish) {
296  typedef cotask::task<>::ptr_t task_ptr_type;
297  {
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();
302  }
303  CASE_EXPECT_EQ(0, g_test_coroutine_task_status);
304 
305  {
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();
310 
311  CASE_EXPECT_EQ(0, co_task->start());
312 
313  ++g_test_coroutine_task_status;
314  CASE_EXPECT_EQ(g_test_coroutine_task_status, 2);
315 
316  CASE_EXPECT_FALSE(co_task->is_completed());
317  }
318 
319  ++g_test_coroutine_task_status;
320  CASE_EXPECT_EQ(g_test_coroutine_task_status, 4);
321 }
322 
323 struct test_context_task_next_action : public cotask::impl::task_action_impl {
324  int set_;
325  int check_;
326  test_context_task_next_action(int s, int c) : cotask::impl::task_action_impl(), set_(s), check_(c) {}
327 
328  int operator()(void *) {
329  CASE_EXPECT_EQ(g_test_coroutine_task_status, check_);
330  g_test_coroutine_task_status = set_;
331 
333 
334  ++g_test_coroutine_task_on_finished;
335  return 0;
336  }
337 };
338 
339 CASE_TEST(coroutine_task, next) {
340  typedef cotask::task<>::ptr_t task_ptr_type;
341 
342  {
343  g_test_coroutine_task_status = 0;
344 
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));
350 
351  CASE_EXPECT_EQ(co_task->next(co_task), co_task);
352  CASE_EXPECT_EQ(0, co_task->start());
353  CASE_EXPECT_EQ(g_test_coroutine_task_status, 5);
354 
356  }
357 
358  {
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);
362 
363  CASE_EXPECT_EQ(0, co_task_b->start());
364  co_task_a->next(co_task_b);
365  CASE_EXPECT_EQ(0, co_task_a->start());
366  CASE_EXPECT_TRUE(co_task_a->is_completed());
367  CASE_EXPECT_TRUE(co_task_b->is_completed());
368  CASE_EXPECT_TRUE(co_task_b->::cotask::impl::task_impl::is_completed());
369  }
370 }
371 
372 struct test_context_task_functor_drived : public cotask::impl::task_action_impl {
373  public:
374  int a_;
375  int b_;
376  test_context_task_functor_drived(int a, int b) : a_(a), b_(b) {}
377 
378  virtual int operator()(void *) {
379  CASE_EXPECT_EQ(a_, 1);
380  CASE_EXPECT_EQ(3, b_);
381 
382  return 0;
383  }
384 };
385 
386 CASE_TEST(coroutine_task, functor_drived_action) {
387  typedef cotask::task<>::ptr_t task_ptr_type;
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);
390  CASE_EXPECT_EQ(0, co_task->start());
391 }
392 
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();
396 
397  CASE_EXPECT_GE(priv_sz, 256);
398 
399  if (priv_sz >= 256) {
400  char checked_data[256];
401  memset(checked_data, 0x5e, 256);
402 
403  CASE_EXPECT_EQ(0, memcmp(priv_data, checked_data, 256));
404  }
405 
406  return 0;
407 }
408 
409 CASE_TEST(coroutine_task, priavte_buffer) {
410  typedef cotask::task<>::ptr_t task_ptr_type;
411  task_ptr_type co_task = cotask::task<>::create(test_context_task_priavte_buffer, 16384, 256);
412 
413  void *priv_data = co_task->get_private_buffer();
414  memset(priv_data, 0x5e, 256);
415 
416  CASE_EXPECT_EQ(0, co_task->start());
417 }
418 
419 static int test_context_task_timeout(void *) {
420  cotask::task<>::this_task()->yield();
421 
422  CASE_EXPECT_TRUE(cotask::task<>::this_task()->is_timeout());
423  CASE_EXPECT_TRUE(cotask::task<>::this_task()->is_faulted());
424  CASE_EXPECT_FALSE(cotask::task<>::this_task()->is_completed());
425  CASE_EXPECT_TRUE(cotask::task<>::this_task()->is_exiting());
426 
427  return 0;
428 }
429 
430 CASE_TEST(coroutine_task, kill_and_timeout) {
431  typedef cotask::task<>::ptr_t task_ptr_type;
432  task_ptr_type co_task = cotask::task<>::create(test_context_task_timeout, 16384, 256);
433 
434  void *priv_data = co_task->get_private_buffer();
435  memset(priv_data, 0x5e, 256);
436 
437  CASE_EXPECT_EQ(0, co_task->start());
438 
439  CASE_EXPECT_FALSE(co_task->is_timeout());
440  CASE_EXPECT_FALSE(co_task->is_faulted());
441  CASE_EXPECT_FALSE(co_task->is_completed());
442  CASE_EXPECT_FALSE(co_task->is_exiting());
443 
444  CASE_EXPECT_EQ(0, co_task->kill(cotask::EN_TS_TIMEOUT, nullptr));
445 
446  CASE_EXPECT_TRUE(co_task->is_completed());
447 
448  CASE_EXPECT_NE(nullptr, co_task->get_raw_action());
449 }
450 
451 static int test_context_task_await_1(void *) {
452  typedef cotask::task<>::ptr_t task_ptr_type;
453 
454  task_ptr_type self = cotask::task<>::this_task();
455 
456  CASE_EXPECT_EQ(copp::COPP_EC_ARGS_ERROR, self->await_task(nullptr));
457  CASE_EXPECT_EQ(copp::COPP_EC_TASK_CAN_NOT_WAIT_SELF, self->await_task(self));
458 
459  void *priv_data = self->get_private_buffer();
460  cotask::task<>::self_t *other_task = *reinterpret_cast<cotask::task<>::self_t **>(priv_data);
461 
462  if (other_task->is_exiting()) {
463  CASE_EXPECT_EQ(copp::COPP_EC_TASK_IS_EXITING, self->await_task(other_task));
464  } else {
465  if (self->is_exiting()) {
466  CASE_EXPECT_EQ(copp::COPP_EC_TASK_IS_EXITING, self->await_task(other_task));
467  } else {
468  CASE_EXPECT_EQ(0, self->await_task(other_task));
469  }
470  }
471 
472  return 0;
473 }
474 
475 static int test_context_task_await_2(void *) { return 0; }
476 
477 CASE_TEST(coroutine_task, await_task) {
478  typedef cotask::task<>::ptr_t task_ptr_type;
479 
480  // normal
481  {
482  task_ptr_type co_task_1 =
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);
485 
486  void *priv_data = co_task_1->get_private_buffer();
487 
488  *reinterpret_cast<cotask::task<>::self_t **>(priv_data) = co_task_2.get();
489  CASE_EXPECT_EQ(copp::COPP_EC_TASK_NOT_IN_ACTION, co_task_1->await_task(co_task_2));
490 
491  CASE_EXPECT_FALSE(co_task_1->is_exiting());
492  CASE_EXPECT_FALSE(co_task_2->is_exiting());
493 
494  co_task_1->start();
495  CASE_EXPECT_FALSE(co_task_1->is_exiting());
496  CASE_EXPECT_FALSE(co_task_2->is_exiting());
497 
498  co_task_2->start();
499  CASE_EXPECT_TRUE(co_task_1->is_exiting());
500  CASE_EXPECT_TRUE(co_task_2->is_exiting());
501  }
502 
503  // co_task_1 exiting
504  {
505  task_ptr_type co_task_1 =
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);
508 
509  void *priv_data = co_task_1->get_private_buffer();
510 
511  CASE_EXPECT_EQ(copp::COPP_EC_ARGS_ERROR, co_task_1->await_task(nullptr));
512  CASE_EXPECT_EQ(copp::COPP_EC_TASK_CAN_NOT_WAIT_SELF, co_task_1->await_task(co_task_1));
513 
514  *reinterpret_cast<cotask::task<>::self_t **>(priv_data) = co_task_2.get();
515  CASE_EXPECT_EQ(copp::COPP_EC_TASK_NOT_IN_ACTION, co_task_1->await_task(co_task_2));
516 
517  CASE_EXPECT_FALSE(co_task_1->is_exiting());
518  CASE_EXPECT_FALSE(co_task_2->is_exiting());
519 
520  co_task_1->kill(cotask::EN_TS_TIMEOUT);
521  CASE_EXPECT_TRUE(co_task_1->is_exiting());
522  co_task_1->start();
523  CASE_EXPECT_TRUE(co_task_1->is_exiting());
524  CASE_EXPECT_FALSE(co_task_2->is_exiting());
525 
526  co_task_2->start();
527  CASE_EXPECT_TRUE(co_task_1->is_exiting());
528  CASE_EXPECT_TRUE(co_task_2->is_exiting());
529  }
530 
531  // co_task_2 exiting
532  {
533  task_ptr_type co_task_1 =
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);
536 
537  void *priv_data = co_task_1->get_private_buffer();
538 
539  *reinterpret_cast<cotask::task<>::self_t **>(priv_data) = co_task_2.get();
540  CASE_EXPECT_EQ(copp::COPP_EC_TASK_NOT_IN_ACTION, co_task_1->await_task(co_task_2));
541 
542  CASE_EXPECT_FALSE(co_task_1->is_exiting());
543  CASE_EXPECT_FALSE(co_task_2->is_exiting());
544 
545  co_task_2->start();
546  CASE_EXPECT_FALSE(co_task_1->is_exiting());
547  CASE_EXPECT_TRUE(co_task_2->is_exiting());
548 
549  co_task_1->start();
550  CASE_EXPECT_TRUE(co_task_1->is_exiting());
551  CASE_EXPECT_TRUE(co_task_2->is_exiting());
552  }
553 }
554 
555 static int test_context_task_then_action_func(void *priv_data) {
556  CASE_EXPECT_EQ(&g_test_coroutine_task_status, priv_data);
557  ++g_test_coroutine_task_on_finished;
558  return 0;
559 }
560 
561 CASE_TEST(coroutine_task, then) {
562  typedef cotask::task<>::ptr_t task_ptr_type;
563  g_test_coroutine_task_status = 0;
564  g_test_coroutine_task_on_finished = 0;
565 
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));
571 
572  CASE_EXPECT_EQ(0, co_task->start());
573  CASE_EXPECT_EQ(g_test_coroutine_task_status, 5);
574 
576 
577  CASE_EXPECT_TRUE(co_task->is_exiting());
578  CASE_EXPECT_TRUE(co_task->is_completed());
579 
580  co_task->then(test_context_task_next_action(127, 5))
581  ->then(test_context_task_then_action_func, &g_test_coroutine_task_status);
582  CASE_EXPECT_EQ(g_test_coroutine_task_status, 127);
583  CASE_EXPECT_EQ(g_test_coroutine_task_on_finished, 7);
584 }
585 
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>;
590  using value_type = int;
591 };
592 
593 typedef cotask::task<test_context_task_stack_pool_test_macro_coroutine> test_context_task_stack_pool_test_task_t;
594 
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();
598 
599  g_test_coroutine_task_on_finished = 0;
600  g_test_coroutine_task_status = 0;
601 
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);
606 
608  tp->start();
610 
611  tp->then(test_context_task_next_action(255, 127))
612  ->then(test_context_task_then_action_func, &g_test_coroutine_task_status);
613 
615  CASE_EXPECT_EQ(g_test_coroutine_task_status, 255);
616  CASE_EXPECT_EQ(g_test_coroutine_task_on_finished, 5);
617 }
618 
619 // Issue #18: https://github.com/owent/libcopp/issues/18
620 
621 class task_action_of_issue18 {
622  public:
623  task_action_of_issue18() {}
624  int operator()(void *) { return 0; }
625 };
626 
627 CASE_TEST(coroutine_task, github_issues_18) {
628  using simple_task_t = cotask::task<>;
629 
630  {
631  simple_task_t::ptr_t co_task = simple_task_t::create(task_action_of_issue18());
632  if (co_task) {
633  co_task->then(task_action_of_issue18());
634  }
635  }
636 
637  {
638  task_action_of_issue18 copy_action;
639  simple_task_t::ptr_t co_task = simple_task_t::create(copy_action);
640  if (co_task) {
641  co_task->then(copy_action);
642  }
643  }
644 }
645 
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;
649 enum {
650  test_context_task_test_mt_thread_num = 100,
651  test_context_task_test_mt_task_num = 1000,
652 };
653 
654 struct test_context_task_test_action_mt_thread : public cotask::impl::task_action_impl {
655  int run_count;
656 
657  public:
658  test_context_task_test_action_mt_thread() : run_count(0) {}
659 
660  int operator()(void *thread_func_address) {
661  std::set<void *> thread_counter;
662 
663  while (run_count < g_test_context_task_test_mt_run_times) {
664  ++run_count;
665  ++g_test_context_task_test_atomic;
666 
667  thread_counter.insert(thread_func_address);
668 
669  cotask::this_task::get_task()->yield(&thread_func_address);
670  }
671 
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();
674  }
675  return 0;
676  }
677 };
678 
679 struct test_context_task_test_mt_thread_runner {
680  typedef cotask::task<>::ptr_t task_ptr_type;
681 
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) {}
684 
685  int operator()() {
686  bool need_continue = true;
687  while (need_continue) {
688  need_continue = false;
689 
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);
694  }
695  }
696  }
697  return 0;
698  }
699 };
700 
701 CASE_TEST(coroutine_task, mt_run_competition) {
702  typedef cotask::task<>::ptr_t task_ptr_type;
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) {
706  task_pool.push_back(
707  cotask::task<>::create(test_context_task_test_action_mt_thread(), 16 * 1024)); // use 16KB for stack
708  }
709 
710  g_test_context_task_test_atomic.store(0);
711  g_test_context_task_test_mt_max_run_thread_number = 0;
712 
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)));
716  }
717 
718  for (int i = 0; i < test_context_task_test_mt_thread_num; ++i) {
719  thds[i]->join();
720  }
721 
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;
726 }
727 
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) {
730  if (t) {
731  co_return co_await t;
732  }
733 
734  co_return 0;
735 }
736 
737 static int cotask_action_callback(void *) {
738  int ret = 234;
739  void *ptr = nullptr;
741  if (ptr != nullptr) {
742  ret = *reinterpret_cast<int *>(ptr);
743  }
744  return ret;
745 }
746 
747 CASE_TEST(coroutine_task, callable_future_co_await) {
748  cotask::task<>::ptr_t co_task = cotask::task<>::create(cotask_action_callback);
749 
750  auto t = call_for_await_cotask(co_task);
751  co_task->start();
752  CASE_EXPECT_FALSE(t.is_ready());
753 
754  int res = 345;
755  co_task->resume(reinterpret_cast<void *>(&res));
756 
757  CASE_EXPECT_TRUE(t.is_ready());
758 
759  CASE_EXPECT_EQ(res, t.get_internal_promise().data());
760 }
761 
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);
764 
765  auto t = call_for_await_cotask(co_task);
766  CASE_EXPECT_FALSE(t.is_ready());
767 
768  co_task.reset();
769 
770  CASE_EXPECT_TRUE(t.is_ready());
771 
772  CASE_EXPECT_EQ(LIBCOPP_COPP_NAMESPACE_ID::COPP_EC_TASK_IS_KILLED, t.get_internal_promise().data());
773 }
774 
775 # endif
776 
777 #endif
virtual int yield(void **priv_data)=0
const limit_t & get_limit() const
Definition: stack_pool.h:71
@ COPP_EC_IS_RUNNING
COPP_EC_IS_RUNNING.
Definition: errno.h:26
@ COPP_EC_TASK_NOT_IN_ACTION
COPP_EC_TASK_NOT_IN_ACTION.
Definition: errno.h:40
@ COPP_EC_ALREADY_FINISHED
COPP_EC_ALREADY_FINISHED.
Definition: errno.h:27
@ COPP_EC_TASK_IS_KILLED
COPP_EC_TASK_IS_KILLED.
Definition: errno.h:42
@ COPP_EC_TASK_IS_EXITING
COPP_EC_TASK_IS_EXITING.
Definition: errno.h:38
@ COPP_EC_TASK_CAN_NOT_WAIT_SELF
COPP_EC_TASK_CAN_NOT_WAIT_SELF.
Definition: errno.h:37
@ COPP_EC_ARGS_ERROR
COPP_EC_ARGS_ERROR.
Definition: errno.h:30
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
Definition: this_task.cpp:9
std::shared_ptr< cli::cmd_option_value > value_type
Definition: cmd_option.h:50
my_task_t::ptr_t task_ptr_type
size_t used_stack_number
Definition: stack_pool.h:37
@ EN_TS_CREATED
Definition: task_impl.h:29
@ EN_TS_TIMEOUT
Definition: task_impl.h:35
@ EN_TS_WAITING
Definition: task_impl.h:31
@ EN_TS_RUNNING
Definition: task_impl.h:30
#define CASE_MSG_INFO()
Definition: test_macros.h:114
#define CASE_EXPECT_FALSE(c)
Definition: test_macros.h:95
#define CASE_EXPECT_EQ(l, r)
Definition: test_macros.h:96
#define CASE_EXPECT_GT(l, r)
Definition: test_macros.h:100
#define CASE_EXPECT_NE(l, r)
Definition: test_macros.h:97
#define CASE_TEST(test_name, case_name)
Definition: test_macros.h:46
#define CASE_EXPECT_TRUE(c)
Definition: test_macros.h:94
#define CASE_EXPECT_GE(l, r)
Definition: test_macros.h:101