libcopp  2.2.0
coroutine_task_fiber_test.cpp
Go to the documentation of this file.
1 // Copyright 2023 owent
2 
4 #include <libcotask/task.h>
5 
6 #include <cstdio>
7 #include <cstring>
8 #include <iostream>
9 #include <memory>
10 #include <set>
11 #include <vector>
12 
13 #include "frame/test_macros.h"
14 
15 #if defined(LIBCOTASK_MACRO_ENABLED) && defined(LIBCOPP_MACRO_ENABLE_WIN_FIBER) && LIBCOPP_MACRO_ENABLE_WIN_FIBER
16 struct test_context_task_fiber_default_test_macro {
17  using stack_allocator_type = copp::allocator::stack_allocator_malloc;
18  using coroutine_type = copp::coroutine_context_fiber_container<stack_allocator_type>;
19  using value_type = int;
20 };
21 
22 static int g_test_coroutine_task_fiber_status = 0;
23 static int g_test_coroutine_task_fiber_on_finished = 0;
24 class test_context_task_fiber_action_base : public cotask::impl::task_action_impl {
25  public:
26  // add a same name function to find the type detection error
27  virtual int operator()() = 0;
28 
29  int operator()(void *priv_data) {
30  ++g_test_coroutine_task_fiber_status;
31 
32  CASE_EXPECT_EQ(&g_test_coroutine_task_fiber_status, priv_data);
33 
35  cotask::this_task::get_task()->yield(&priv_data);
37 
39 
40  ++g_test_coroutine_task_fiber_status;
41 
42  return 0;
43  }
44 
45  virtual int on_finished(cotask::impl::task_impl &) {
46  ++g_test_coroutine_task_fiber_on_finished;
47  return 0;
48  }
49 };
50 
51 class test_context_task_fiber_action : public test_context_task_fiber_action_base {
52  public:
53  using test_context_task_fiber_action_base::operator();
54 
55  // add a same name function to find the type detection error
56  virtual int operator()() { return 0; }
57 };
58 
59 CASE_TEST(coroutine_task_fiber, custom_action) {
60  typedef cotask::task<test_context_task_fiber_default_test_macro>::ptr_t task_ptr_type;
61  g_test_coroutine_task_fiber_status = 0;
62  g_test_coroutine_task_fiber_on_finished = 0;
63 
64  {
65  task_ptr_type co_task =
66  cotask::task<test_context_task_fiber_default_test_macro>::create(test_context_task_fiber_action());
67  task_ptr_type co_another_task = cotask::task<test_context_task_fiber_default_test_macro>::create(
68  test_context_task_fiber_action()); // share action
69 
70  CASE_EXPECT_EQ(cotask::EN_TS_CREATED, co_task->get_status());
71  CASE_EXPECT_EQ(cotask::EN_TS_CREATED, co_another_task->get_status());
72 
73  CASE_EXPECT_EQ(0, co_task->start(&g_test_coroutine_task_fiber_status));
74 
75  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 1);
76  CASE_EXPECT_FALSE(co_task->is_completed());
77  CASE_EXPECT_FALSE(co_task->is_canceled());
78  CASE_EXPECT_FALSE(co_task->is_faulted());
79 
80  CASE_EXPECT_EQ(0, co_another_task->start(&g_test_coroutine_task_fiber_status));
81  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 2);
82 
83  CASE_EXPECT_EQ(cotask::EN_TS_WAITING, co_task->get_status());
84  CASE_EXPECT_EQ(cotask::EN_TS_WAITING, co_another_task->get_status());
85 
86  CASE_EXPECT_EQ(0, co_task->resume(co_task.get()));
87  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 3);
88 
89  CASE_EXPECT_EQ(0, co_another_task->resume(co_another_task.get()));
90  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 4);
91 
92  CASE_EXPECT_TRUE(co_task->is_completed());
93  CASE_EXPECT_TRUE(co_another_task->is_completed());
94  CASE_EXPECT_FALSE(co_task->is_canceled());
95  CASE_EXPECT_FALSE(co_task->is_faulted());
96 
97  CASE_EXPECT_GT(0, co_another_task->resume(co_another_task.get()));
98  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 4);
99 
100  ++g_test_coroutine_task_fiber_status;
101  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 5);
102 
103  CASE_EXPECT_NE(co_task->get_id(), 0);
104  }
105 
106  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_on_finished, 2);
107 }
108 
109 struct test_context_task_fiber_functor {
110  public:
111  int operator()(void *) const {
112  ++g_test_coroutine_task_fiber_status;
113  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 1);
114 
116 
117  ++g_test_coroutine_task_fiber_status;
118  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 3);
119 
120  return 0;
121  }
122 };
123 
124 CASE_TEST(coroutine_task_fiber, functor_action) {
125  typedef cotask::task<test_context_task_fiber_default_test_macro>::ptr_t task_ptr_type;
126  task_ptr_type co_task =
127  cotask::task<test_context_task_fiber_default_test_macro>::create(test_context_task_fiber_functor());
128  g_test_coroutine_task_fiber_status = 0;
129 
130  CASE_EXPECT_EQ(0, co_task->start());
131 
132  ++g_test_coroutine_task_fiber_status;
133  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 2);
134 
135  CASE_EXPECT_FALSE(co_task->is_completed());
136  CASE_EXPECT_EQ(0, co_task->resume());
137 
138  CASE_EXPECT_TRUE(co_task->is_completed());
139 
140  ++g_test_coroutine_task_fiber_status;
141  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 4);
142 
143  CASE_EXPECT_NE(co_task->get_id(), 0);
144 }
145 
146 static int test_context_task_fiber_function_1(void *) {
147  ++g_test_coroutine_task_fiber_status;
148  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 1);
149 
151 
152  ++g_test_coroutine_task_fiber_status;
153  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 3);
154 
155  return 100;
156 }
157 
158 static void test_context_task_fiber_function_2(void *) {
159  ++g_test_coroutine_task_fiber_status;
160  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 1);
161 
163 
164  ++g_test_coroutine_task_fiber_status;
165  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 3);
166 }
167 
168 CASE_TEST(coroutine_task_fiber, function_action) {
169  {
170  typedef cotask::task<test_context_task_fiber_default_test_macro>::ptr_t task_ptr_type;
171  task_ptr_type co_task =
172  cotask::task<test_context_task_fiber_default_test_macro>::create(test_context_task_fiber_function_1);
173  g_test_coroutine_task_fiber_status = 0;
174 
175  CASE_EXPECT_EQ(0, co_task->start());
176 
177  ++g_test_coroutine_task_fiber_status;
178  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 2);
179 
180  CASE_EXPECT_FALSE(co_task->is_completed());
181  CASE_EXPECT_EQ(0, co_task->resume());
182 
183  CASE_EXPECT_TRUE(co_task->is_completed());
184 
185  ++g_test_coroutine_task_fiber_status;
186  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 4);
187  CASE_EXPECT_EQ(co_task->get_coroutine_context()->get_ret_code(), 100);
188  }
189 
190  {
191  typedef cotask::task<test_context_task_fiber_default_test_macro>::ptr_t task_ptr_type;
192  task_ptr_type co_task =
193  cotask::task<test_context_task_fiber_default_test_macro>::create(test_context_task_fiber_function_2);
194  g_test_coroutine_task_fiber_status = 0;
195 
196  CASE_EXPECT_EQ(0, co_task->start());
197 
198  ++g_test_coroutine_task_fiber_status;
199  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 2);
200 
201  CASE_EXPECT_FALSE(co_task->is_completed());
202  CASE_EXPECT_EQ(0, co_task->resume());
203 
204  CASE_EXPECT_TRUE(co_task->is_completed());
205 
206  ++g_test_coroutine_task_fiber_status;
207  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 4);
208  }
209 }
210 
211 CASE_TEST(coroutine_task_fiber, cancel) {
212  typedef cotask::task<test_context_task_fiber_default_test_macro>::ptr_t task_ptr_type;
213  task_ptr_type co_task =
214  cotask::task<test_context_task_fiber_default_test_macro>::create(test_context_task_fiber_function_1);
215  g_test_coroutine_task_fiber_status = 0;
216 
217  CASE_EXPECT_EQ(0, co_task->start());
218 
219  ++g_test_coroutine_task_fiber_status;
220  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 2);
221 
222  CASE_EXPECT_FALSE(co_task->is_completed());
223  CASE_EXPECT_EQ(0, co_task->cancel(nullptr));
224 
225  CASE_EXPECT_TRUE(co_task->is_completed());
226 }
227 
228 // task start and coroutine context yield
229 static void test_context_task_fiber_function_3(void *) {
230  ++g_test_coroutine_task_fiber_status;
231  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 1);
232 
234 
236 
238  cotask::this_task::get<cotask::task<test_context_task_fiber_default_test_macro> >()->get_status());
239 
240  ++g_test_coroutine_task_fiber_status;
241  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 3);
242 }
243 
244 CASE_TEST(coroutine_task_fiber, coroutine_context_yield) {
245  typedef cotask::task<test_context_task_fiber_default_test_macro>::ptr_t task_ptr_type;
246  task_ptr_type co_task =
247  cotask::task<test_context_task_fiber_default_test_macro>::create(test_context_task_fiber_function_3);
248  g_test_coroutine_task_fiber_status = 0;
249 
250  CASE_EXPECT_EQ(0, co_task->start());
251 
252  ++g_test_coroutine_task_fiber_status;
253  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 2);
254 
255  CASE_EXPECT_FALSE(co_task->is_completed());
256  CASE_EXPECT_EQ(cotask::EN_TS_WAITING, co_task->get_status());
257  CASE_EXPECT_EQ(0, co_task->resume());
258 
259  CASE_EXPECT_TRUE(co_task->is_completed());
260 
261  ++g_test_coroutine_task_fiber_status;
262  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 4);
263 
264  CASE_EXPECT_NE(co_task->get_id(), 0);
265 }
266 
267 struct test_context_task_fiber_mem_function {
268  cotask::task<test_context_task_fiber_default_test_macro>::id_t task_id_;
269 
270  int real_run(void *) {
271  ++g_test_coroutine_task_fiber_status;
272  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 1);
273 
274  CASE_EXPECT_EQ(task_id_, cotask::task<test_context_task_fiber_default_test_macro>::this_task()->get_id());
275  cotask::task<test_context_task_fiber_default_test_macro>::this_task()->yield();
276  CASE_EXPECT_EQ(task_id_, cotask::task<test_context_task_fiber_default_test_macro>::this_task()->get_id());
277 
278  ++g_test_coroutine_task_fiber_status;
279  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 3);
280 
281  return -1;
282  }
283 };
284 
285 CASE_TEST(coroutine_task_fiber, mem_function_action) {
286  typedef cotask::task<test_context_task_fiber_default_test_macro>::ptr_t task_ptr_type;
287  test_context_task_fiber_mem_function obj;
288  task_ptr_type co_task = cotask::task<test_context_task_fiber_default_test_macro>::create(
289  &test_context_task_fiber_mem_function::real_run, &obj);
290  g_test_coroutine_task_fiber_status = 0;
291  obj.task_id_ = co_task->get_id();
292 
293  CASE_EXPECT_EQ(0, co_task->start());
294 
295  ++g_test_coroutine_task_fiber_status;
296  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 2);
297 
298  CASE_EXPECT_FALSE(co_task->is_completed());
299  CASE_EXPECT_EQ(0, co_task->resume());
300 
301  CASE_EXPECT_TRUE(co_task->is_completed());
302 
303  ++g_test_coroutine_task_fiber_status;
304  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 4);
305 
306  CASE_EXPECT_NE(co_task->get_coroutine_context()->get_ret_code(), -1);
307 }
308 
309 CASE_TEST(coroutine_task_fiber, auto_finish) {
310  typedef cotask::task<test_context_task_fiber_default_test_macro>::ptr_t task_ptr_type;
311  {
312  test_context_task_fiber_mem_function obj;
313  task_ptr_type co_task = cotask::task<test_context_task_fiber_default_test_macro>::create(
314  &test_context_task_fiber_mem_function::real_run, &obj);
315  g_test_coroutine_task_fiber_status = 0;
316  obj.task_id_ = co_task->get_id();
317  }
318  CASE_EXPECT_EQ(0, g_test_coroutine_task_fiber_status);
319 
320  {
321  test_context_task_fiber_mem_function obj;
322  task_ptr_type co_task = cotask::task<test_context_task_fiber_default_test_macro>::create(
323  &test_context_task_fiber_mem_function::real_run, &obj);
324  g_test_coroutine_task_fiber_status = 0;
325  obj.task_id_ = co_task->get_id();
326 
327  CASE_EXPECT_EQ(0, co_task->start());
328 
329  ++g_test_coroutine_task_fiber_status;
330  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 2);
331 
332  CASE_EXPECT_FALSE(co_task->is_completed());
333  }
334 
335  ++g_test_coroutine_task_fiber_status;
336  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 4);
337 }
338 
339 struct test_context_task_fiber_next_action : public cotask::impl::task_action_impl {
340  int set_;
341  int check_;
342  test_context_task_fiber_next_action(int s, int c) : cotask::impl::task_action_impl(), set_(s), check_(c) {}
343 
344  int operator()(void *) {
345  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, check_);
346  g_test_coroutine_task_fiber_status = set_;
347 
349 
350  ++g_test_coroutine_task_fiber_on_finished;
351  return 0;
352  }
353 };
354 
355 CASE_TEST(coroutine_task_fiber, next) {
356  typedef cotask::task<test_context_task_fiber_default_test_macro>::ptr_t task_ptr_type;
357 
358  {
359  g_test_coroutine_task_fiber_status = 0;
360 
361  task_ptr_type co_task =
362  cotask::task<test_context_task_fiber_default_test_macro>::create(test_context_task_fiber_next_action(15, 0));
363  co_task->next(test_context_task_fiber_next_action(7, 15))
364  ->next(test_context_task_fiber_next_action(99, 7))
365  ->next(test_context_task_fiber_next_action(1023, 99))
366  ->next(test_context_task_fiber_next_action(5, 1023));
367 
368  CASE_EXPECT_EQ(co_task->next(co_task), co_task);
369  CASE_EXPECT_EQ(0, co_task->start());
370  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 5);
371 
373  }
374 
375  {
376  g_test_coroutine_task_fiber_status = 0;
377  task_ptr_type co_task_a =
378  cotask::task<test_context_task_fiber_default_test_macro>::create(test_context_task_fiber_next_action(2, 1));
379  task_ptr_type co_task_b =
380  cotask::task<test_context_task_fiber_default_test_macro>::create(test_context_task_fiber_function_1);
381 
382  CASE_EXPECT_EQ(0, co_task_b->start());
383  co_task_a->next(co_task_b);
384  CASE_EXPECT_EQ(0, co_task_a->start());
385  CASE_EXPECT_TRUE(co_task_a->is_completed());
386  CASE_EXPECT_TRUE(co_task_b->is_completed());
387  CASE_EXPECT_TRUE(co_task_b->::cotask::impl::task_impl::is_completed());
388  }
389 }
390 
391 struct test_context_task_fiber_functor_drived : public cotask::impl::task_action_impl {
392  public:
393  int a_;
394  int b_;
395  test_context_task_fiber_functor_drived(int a, int b) : a_(a), b_(b) {}
396 
397  virtual int operator()(void *) {
398  CASE_EXPECT_EQ(a_, 1);
399  CASE_EXPECT_EQ(3, b_);
400 
401  return 0;
402  }
403 };
404 
405 CASE_TEST(coroutine_task_fiber, functor_drived_action) {
406  typedef cotask::task<test_context_task_fiber_default_test_macro>::ptr_t task_ptr_type;
407  cotask::task<test_context_task_fiber_default_test_macro>::coroutine_type::allocator_type alloc;
408  task_ptr_type co_task =
409  cotask::task<test_context_task_fiber_default_test_macro>::create_with<test_context_task_fiber_functor_drived>(
410  alloc, 0, 0, 1, 3);
411  CASE_EXPECT_EQ(0, co_task->start());
412 }
413 
414 static int test_context_task_fiber_priavte_buffer(void *) {
415  void *priv_data = cotask::task<test_context_task_fiber_default_test_macro>::this_task()->get_private_buffer();
416  size_t priv_sz = cotask::task<test_context_task_fiber_default_test_macro>::this_task()->get_private_buffer_size();
417 
418  CASE_EXPECT_GE(priv_sz, 256);
419 
420  if (priv_sz >= 256) {
421  char checked_data[256];
422  memset(checked_data, 0x5e, 256);
423 
424  CASE_EXPECT_EQ(0, memcmp(priv_data, checked_data, 256));
425  }
426 
427  return 0;
428 }
429 
430 CASE_TEST(coroutine_task_fiber, priavte_buffer) {
431  typedef cotask::task<test_context_task_fiber_default_test_macro>::ptr_t task_ptr_type;
432  task_ptr_type co_task = cotask::task<test_context_task_fiber_default_test_macro>::create(
433  test_context_task_fiber_priavte_buffer, 16384, 256);
434 
435  void *priv_data = co_task->get_private_buffer();
436  memset(priv_data, 0x5e, 256);
437 
438  CASE_EXPECT_EQ(0, co_task->start());
439 }
440 
441 static int test_context_task_fiber_timeout(void *) {
442  cotask::task<test_context_task_fiber_default_test_macro>::this_task()->yield();
443 
444  CASE_EXPECT_TRUE(cotask::task<test_context_task_fiber_default_test_macro>::this_task()->is_timeout());
445  CASE_EXPECT_TRUE(cotask::task<test_context_task_fiber_default_test_macro>::this_task()->is_faulted());
446  CASE_EXPECT_FALSE(cotask::task<test_context_task_fiber_default_test_macro>::this_task()->is_completed());
447  CASE_EXPECT_TRUE(cotask::task<test_context_task_fiber_default_test_macro>::this_task()->is_exiting());
448 
449  return 0;
450 }
451 
452 CASE_TEST(coroutine_task_fiber, kill_and_timeout) {
453  typedef cotask::task<test_context_task_fiber_default_test_macro>::ptr_t task_ptr_type;
454  task_ptr_type co_task =
455  cotask::task<test_context_task_fiber_default_test_macro>::create(test_context_task_fiber_timeout, 16384, 256);
456 
457  void *priv_data = co_task->get_private_buffer();
458  memset(priv_data, 0x5e, 256);
459 
460  CASE_EXPECT_EQ(0, co_task->start());
461 
462  CASE_EXPECT_FALSE(co_task->is_timeout());
463  CASE_EXPECT_FALSE(co_task->is_faulted());
464  CASE_EXPECT_FALSE(co_task->is_completed());
465  CASE_EXPECT_FALSE(co_task->is_exiting());
466 
467  CASE_EXPECT_EQ(0, co_task->kill(cotask::EN_TS_TIMEOUT, nullptr));
468 
469  CASE_EXPECT_TRUE(co_task->is_completed());
470 
471  CASE_EXPECT_NE(nullptr, co_task->get_raw_action());
472 }
473 
474 static int test_context_task_fiber_await_1(void *) {
475  typedef cotask::task<test_context_task_fiber_default_test_macro>::ptr_t task_ptr_type;
476 
477  task_ptr_type self = cotask::task<test_context_task_fiber_default_test_macro>::this_task();
478 
479  CASE_EXPECT_EQ(copp::COPP_EC_ARGS_ERROR, self->await_task(nullptr));
480  CASE_EXPECT_EQ(copp::COPP_EC_TASK_CAN_NOT_WAIT_SELF, self->await_task(self));
481 
482  void *priv_data = self->get_private_buffer();
483  cotask::task<test_context_task_fiber_default_test_macro>::self_t *other_task =
484  *reinterpret_cast<cotask::task<test_context_task_fiber_default_test_macro>::self_t **>(priv_data);
485 
486  if (other_task->is_exiting()) {
487  CASE_EXPECT_EQ(copp::COPP_EC_TASK_IS_EXITING, self->await_task(other_task));
488  } else {
489  if (self->is_exiting()) {
490  CASE_EXPECT_EQ(copp::COPP_EC_TASK_IS_EXITING, self->await_task(other_task));
491  } else {
492  CASE_EXPECT_EQ(0, self->await_task(other_task));
493  }
494  }
495 
496  return 0;
497 }
498 
499 static int test_context_task_fiber_await_2(void *) { return 0; }
500 
501 CASE_TEST(coroutine_task_fiber, await_task) {
502  typedef cotask::task<test_context_task_fiber_default_test_macro>::ptr_t task_ptr_type;
503 
504  // normal
505  {
506  task_ptr_type co_task_1 = cotask::task<test_context_task_fiber_default_test_macro>::create(
507  test_context_task_fiber_await_1, 16384,
508  sizeof(cotask::task<test_context_task_fiber_default_test_macro>::self_t *));
509  task_ptr_type co_task_2 =
510  cotask::task<test_context_task_fiber_default_test_macro>::create(test_context_task_fiber_await_2, 16384);
511 
512  void *priv_data = co_task_1->get_private_buffer();
513 
514  *reinterpret_cast<cotask::task<test_context_task_fiber_default_test_macro>::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->start();
521  CASE_EXPECT_FALSE(co_task_1->is_exiting());
522  CASE_EXPECT_FALSE(co_task_2->is_exiting());
523 
524  co_task_2->start();
525  CASE_EXPECT_TRUE(co_task_1->is_exiting());
526  CASE_EXPECT_TRUE(co_task_2->is_exiting());
527  }
528 
529  // co_task_1 exiting
530  {
531  task_ptr_type co_task_1 = cotask::task<test_context_task_fiber_default_test_macro>::create(
532  test_context_task_fiber_await_1, 16384,
533  sizeof(cotask::task<test_context_task_fiber_default_test_macro>::self_t *));
534  task_ptr_type co_task_2 =
535  cotask::task<test_context_task_fiber_default_test_macro>::create(test_context_task_fiber_await_2, 16384);
536 
537  void *priv_data = co_task_1->get_private_buffer();
538 
539  CASE_EXPECT_EQ(copp::COPP_EC_ARGS_ERROR, co_task_1->await_task(nullptr));
540  CASE_EXPECT_EQ(copp::COPP_EC_TASK_CAN_NOT_WAIT_SELF, co_task_1->await_task(co_task_1));
541 
542  *reinterpret_cast<cotask::task<test_context_task_fiber_default_test_macro>::self_t **>(priv_data) = co_task_2.get();
543  CASE_EXPECT_EQ(copp::COPP_EC_TASK_NOT_IN_ACTION, co_task_1->await_task(co_task_2));
544 
545  CASE_EXPECT_FALSE(co_task_1->is_exiting());
546  CASE_EXPECT_FALSE(co_task_2->is_exiting());
547 
548  co_task_1->kill(cotask::EN_TS_TIMEOUT);
549  CASE_EXPECT_TRUE(co_task_1->is_exiting());
550  co_task_1->start();
551  CASE_EXPECT_TRUE(co_task_1->is_exiting());
552  CASE_EXPECT_FALSE(co_task_2->is_exiting());
553 
554  co_task_2->start();
555  CASE_EXPECT_TRUE(co_task_1->is_exiting());
556  CASE_EXPECT_TRUE(co_task_2->is_exiting());
557  }
558 
559  // co_task_2 exiting
560  {
561  task_ptr_type co_task_1 = cotask::task<test_context_task_fiber_default_test_macro>::create(
562  test_context_task_fiber_await_1, 16384,
563  sizeof(cotask::task<test_context_task_fiber_default_test_macro>::self_t *));
564  task_ptr_type co_task_2 =
565  cotask::task<test_context_task_fiber_default_test_macro>::create(test_context_task_fiber_await_2, 16384);
566 
567  void *priv_data = co_task_1->get_private_buffer();
568 
569  *reinterpret_cast<cotask::task<test_context_task_fiber_default_test_macro>::self_t **>(priv_data) = co_task_2.get();
570  CASE_EXPECT_EQ(copp::COPP_EC_TASK_NOT_IN_ACTION, co_task_1->await_task(co_task_2));
571 
572  CASE_EXPECT_FALSE(co_task_1->is_exiting());
573  CASE_EXPECT_FALSE(co_task_2->is_exiting());
574 
575  co_task_2->start();
576  CASE_EXPECT_FALSE(co_task_1->is_exiting());
577  CASE_EXPECT_TRUE(co_task_2->is_exiting());
578 
579  co_task_1->start();
580  CASE_EXPECT_TRUE(co_task_1->is_exiting());
581  CASE_EXPECT_TRUE(co_task_2->is_exiting());
582  }
583 }
584 
585 static int test_context_task_fiber_then_action_func(void *priv_data) {
586  CASE_EXPECT_EQ(&g_test_coroutine_task_fiber_status, priv_data);
587  ++g_test_coroutine_task_fiber_on_finished;
588  return 0;
589 }
590 
591 CASE_TEST(coroutine_task_fiber, then) {
592  typedef cotask::task<test_context_task_fiber_default_test_macro>::ptr_t task_ptr_type;
593  g_test_coroutine_task_fiber_status = 0;
594  g_test_coroutine_task_fiber_on_finished = 0;
595 
596  task_ptr_type co_task =
597  cotask::task<test_context_task_fiber_default_test_macro>::create(test_context_task_fiber_next_action(15, 0));
598  co_task->then(test_context_task_fiber_next_action(7, 15))
599  ->then(test_context_task_fiber_next_action(99, 7))
600  ->then(test_context_task_fiber_next_action(1023, 99))
601  ->then(test_context_task_fiber_next_action(5, 1023));
602 
603  CASE_EXPECT_EQ(0, co_task->start());
604  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 5);
605 
607 
608  CASE_EXPECT_TRUE(co_task->is_exiting());
609  CASE_EXPECT_TRUE(co_task->is_completed());
610 
611  co_task->then(test_context_task_fiber_next_action(127, 5))
612  ->then(test_context_task_fiber_then_action_func, &g_test_coroutine_task_fiber_status);
613  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 127);
614  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_on_finished, 7);
615 }
616 
617 typedef copp::stack_pool<copp::allocator::stack_allocator_malloc> test_context_task_fiber_stack_pool_t;
618 struct test_context_task_fiber_stack_pool_test_macro_coroutine {
619  using stack_allocator_type = copp::allocator::stack_allocator_pool<test_context_task_fiber_stack_pool_t>;
620  using coroutine_type = copp::coroutine_context_fiber_container<stack_allocator_type>;
621  using value_type = int;
622 };
623 
624 typedef cotask::task<test_context_task_fiber_stack_pool_test_macro_coroutine>
625  test_context_task_fiber_stack_pool_test_task_t;
626 
627 CASE_TEST(coroutine_task_fiber, then_with_stack_pool) {
628  typedef test_context_task_fiber_stack_pool_test_task_t::ptr_t task_ptr_type;
629  test_context_task_fiber_stack_pool_t::ptr_t stack_pool = test_context_task_fiber_stack_pool_t::create();
630 
631  g_test_coroutine_task_fiber_on_finished = 0;
632  g_test_coroutine_task_fiber_status = 0;
633 
634  copp::allocator::stack_allocator_pool<test_context_task_fiber_stack_pool_t> base_alloc(stack_pool);
635  task_ptr_type tp =
636  test_context_task_fiber_stack_pool_test_task_t::create(test_context_task_fiber_next_action(15, 0), base_alloc);
637  tp->then(test_context_task_fiber_next_action(127, 15))
638  ->then(test_context_task_fiber_then_action_func, &g_test_coroutine_task_fiber_status);
639 
641  tp->start();
643 
644  tp->then(test_context_task_fiber_next_action(255, 127))
645  ->then(test_context_task_fiber_then_action_func, &g_test_coroutine_task_fiber_status);
646 
648  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_status, 255);
649  CASE_EXPECT_EQ(g_test_coroutine_task_fiber_on_finished, 5);
650 }
651 
652 static LIBCOPP_COPP_NAMESPACE_ID::util::lock::atomic_int_type<int> g_test_context_task_fiber_test_atomic;
653 static constexpr const int g_test_context_task_fiber_test_mt_run_times = 10000;
654 static size_t g_test_context_task_fiber_test_mt_max_run_thread_number = 0;
655 enum {
656  test_context_task_fiber_test_mt_thread_num = 100,
657  test_context_task_fiber_test_mt_task_num = 1000,
658 };
659 
660 struct test_context_task_fiber_test_action_mt_thread : public cotask::impl::task_action_impl {
661  int run_count;
662 
663  public:
664  test_context_task_fiber_test_action_mt_thread() : run_count(0) {}
665 
666  int operator()(void *thread_func_address) {
667  std::set<void *> thread_counter;
668 
669  while (run_count < g_test_context_task_fiber_test_mt_run_times) {
670  ++run_count;
671  ++g_test_context_task_fiber_test_atomic;
672 
673  thread_counter.insert(thread_func_address);
674 
675  cotask::this_task::get_task()->yield(&thread_func_address);
676  }
677 
678  if (g_test_context_task_fiber_test_mt_max_run_thread_number < thread_counter.size()) {
679  g_test_context_task_fiber_test_mt_max_run_thread_number = thread_counter.size();
680  }
681  return 0;
682  }
683 };
684 
685 struct test_context_task_fiber_test_mt_thread_runner {
686  typedef cotask::task<test_context_task_fiber_default_test_macro>::ptr_t task_ptr_type;
687 
688  std::vector<task_ptr_type> *task_pool;
689  test_context_task_fiber_test_mt_thread_runner(std::vector<task_ptr_type> *pool) : task_pool(pool) {}
690 
691  int operator()() {
692  bool need_continue = true;
693  while (need_continue) {
694  need_continue = false;
695 
696  for (size_t i = 0; i < task_pool->size(); ++i) {
697  if (false == (*task_pool)[i]->is_completed()) {
698  need_continue = true;
699  (*task_pool)[i]->resume(this);
700  }
701  }
702  }
703  return 0;
704  }
705 };
706 
707 CASE_TEST(coroutine_task_fiber, mt_run_competition) {
708  typedef cotask::task<test_context_task_fiber_default_test_macro>::ptr_t task_ptr_type;
709  std::vector<task_ptr_type> task_pool;
710  task_pool.reserve(test_context_task_fiber_test_mt_task_num);
711  for (int i = 0; i < test_context_task_fiber_test_mt_task_num; ++i) {
712  task_pool.push_back(cotask::task<test_context_task_fiber_default_test_macro>::create(
713  test_context_task_fiber_test_action_mt_thread(), 16 * 1024)); // use 16KB for stack
714  }
715 
716  g_test_context_task_fiber_test_atomic.store(0);
717  g_test_context_task_fiber_test_mt_max_run_thread_number = 0;
718 
719  std::unique_ptr<std::thread> thds[test_context_task_fiber_test_mt_thread_num];
720  for (int i = 0; i < test_context_task_fiber_test_mt_thread_num; ++i) {
721  thds[i].reset(new std::thread(test_context_task_fiber_test_mt_thread_runner(&task_pool)));
722  }
723 
724  for (int i = 0; i < test_context_task_fiber_test_mt_thread_num; ++i) {
725  thds[i]->join();
726  }
727 
728  CASE_EXPECT_EQ(g_test_context_task_fiber_test_mt_run_times * test_context_task_fiber_test_mt_task_num,
729  g_test_context_task_fiber_test_atomic.load());
730  CASE_MSG_INFO() << "Fiber tasks are run on " << g_test_context_task_fiber_test_mt_max_run_thread_number
731  << " threads at most." << std::endl;
732 }
733 
734 #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_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