libcopp  1.2.1
coroutine_task_test.cpp
Go to the documentation of this file.
1 #include <cstdio>
2 #include <cstring>
3 #include <iostream>
4 #include <set>
5 #include <vector>
6 
8 
10 #include <libcotask/task.h>
11 
12 #include "frame/test_macros.h"
13 
14 #ifdef LIBCOTASK_MACRO_ENABLED
15 static int g_test_coroutine_task_status = 0;
16 static int g_test_coroutine_task_on_finished = 0;
17 class test_context_task_action_base : public cotask::impl::task_action_impl {
18 public:
19  // add a same name function to find the type detection error
20  virtual int operator()() = 0;
21 
22  int operator()(void *priv_data) {
23  ++g_test_coroutine_task_status;
24 
25  CASE_EXPECT_EQ(&g_test_coroutine_task_status, priv_data);
26 
28  cotask::this_task::get_task()->yield(&priv_data);
30 
32 
33  ++g_test_coroutine_task_status;
34 
35  return 0;
36  }
37 
38  virtual int on_finished(cotask::impl::task_impl &) {
39  ++g_test_coroutine_task_on_finished;
40  return 0;
41  }
42 };
43 
44 class test_context_task_action : public test_context_task_action_base {
45 public:
46  using test_context_task_action_base::operator();
47 
48  // add a same name function to find the type detection error
49  virtual int operator()() { return 0; }
50 };
51 
52 
53 CASE_TEST(coroutine_task, custom_action) {
55  g_test_coroutine_task_status = 0;
56  g_test_coroutine_task_on_finished = 0;
57 
58  {
59  task_ptr_type co_task = cotask::task<>::create(test_context_task_action());
60  task_ptr_type co_another_task = cotask::task<>::create(test_context_task_action()); // share action
61 
62  CASE_EXPECT_EQ(cotask::EN_TS_CREATED, co_task->get_status());
63  CASE_EXPECT_EQ(cotask::EN_TS_CREATED, co_another_task->get_status());
64 
65  CASE_EXPECT_EQ(0, co_task->start(&g_test_coroutine_task_status));
66 
67  CASE_EXPECT_EQ(g_test_coroutine_task_status, 1);
68  CASE_EXPECT_FALSE(co_task->is_completed());
69  CASE_EXPECT_FALSE(co_task->is_canceled());
70  CASE_EXPECT_FALSE(co_task->is_faulted());
71 
72  CASE_EXPECT_EQ(0, co_another_task->start(&g_test_coroutine_task_status));
73  CASE_EXPECT_EQ(g_test_coroutine_task_status, 2);
74 
75  CASE_EXPECT_EQ(cotask::EN_TS_WAITING, co_task->get_status());
76  CASE_EXPECT_EQ(cotask::EN_TS_WAITING, co_another_task->get_status());
77 
78  CASE_EXPECT_EQ(0, co_task->resume(co_task.get()));
79  CASE_EXPECT_EQ(g_test_coroutine_task_status, 3);
80 
81  CASE_EXPECT_EQ(0, co_another_task->resume(co_another_task.get()));
82  CASE_EXPECT_EQ(g_test_coroutine_task_status, 4);
83 
84  CASE_EXPECT_TRUE(co_task->is_completed());
85  CASE_EXPECT_TRUE(co_another_task->is_completed());
86  CASE_EXPECT_FALSE(co_task->is_canceled());
87  CASE_EXPECT_FALSE(co_task->is_faulted());
88 
89  CASE_EXPECT_GT(0, co_another_task->resume(co_another_task.get()));
90  CASE_EXPECT_EQ(g_test_coroutine_task_status, 4);
91 
92  ++g_test_coroutine_task_status;
93  CASE_EXPECT_EQ(g_test_coroutine_task_status, 5);
94 
95  CASE_EXPECT_NE(co_task->get_id(), 0);
96  }
97 
98  CASE_EXPECT_EQ(g_test_coroutine_task_on_finished, 2);
99 }
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) {
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 
139 static int test_context_task_function_1(void *) {
140  ++g_test_coroutine_task_status;
141  CASE_EXPECT_EQ(g_test_coroutine_task_status, 1);
142 
144 
145  ++g_test_coroutine_task_status;
146  CASE_EXPECT_EQ(g_test_coroutine_task_status, 3);
147 
148  return 100;
149 }
150 
151 static void test_context_task_function_2(void *) {
152  ++g_test_coroutine_task_status;
153  CASE_EXPECT_EQ(g_test_coroutine_task_status, 1);
154 
156 
157  ++g_test_coroutine_task_status;
158  CASE_EXPECT_EQ(g_test_coroutine_task_status, 3);
159 }
160 
161 CASE_TEST(coroutine_task, function_action) {
162  {
164  task_ptr_type co_task = cotask::task<>::create(test_context_task_function_1);
165  g_test_coroutine_task_status = 0;
166 
167  CASE_EXPECT_EQ(0, co_task->start());
168 
169  ++g_test_coroutine_task_status;
170  CASE_EXPECT_EQ(g_test_coroutine_task_status, 2);
171 
172  CASE_EXPECT_FALSE(co_task->is_completed());
173  CASE_EXPECT_EQ(0, co_task->resume());
174 
175  CASE_EXPECT_TRUE(co_task->is_completed());
176 
177  ++g_test_coroutine_task_status;
178  CASE_EXPECT_EQ(g_test_coroutine_task_status, 4);
179  CASE_EXPECT_EQ(co_task->get_coroutine_context()->get_ret_code(), 100);
180  }
181 
182  {
184  task_ptr_type co_task = cotask::task<>::create(test_context_task_function_2);
185  g_test_coroutine_task_status = 0;
186 
187  CASE_EXPECT_EQ(0, co_task->start());
188 
189  ++g_test_coroutine_task_status;
190  CASE_EXPECT_EQ(g_test_coroutine_task_status, 2);
191 
192  CASE_EXPECT_FALSE(co_task->is_completed());
193  CASE_EXPECT_EQ(0, co_task->resume());
194 
195  CASE_EXPECT_TRUE(co_task->is_completed());
196 
197  ++g_test_coroutine_task_status;
198  CASE_EXPECT_EQ(g_test_coroutine_task_status, 4);
199  }
200 }
201 
202 CASE_TEST(coroutine_task, cancel) {
204  task_ptr_type co_task = cotask::task<>::create(test_context_task_function_1);
205  g_test_coroutine_task_status = 0;
206 
207  CASE_EXPECT_EQ(0, co_task->start());
208 
209  ++g_test_coroutine_task_status;
210  CASE_EXPECT_EQ(g_test_coroutine_task_status, 2);
211 
212  CASE_EXPECT_FALSE(co_task->is_completed());
213  CASE_EXPECT_EQ(0, co_task->cancel(UTIL_CONFIG_NULLPTR));
214 
215  CASE_EXPECT_TRUE(co_task->is_completed());
216 }
217 
218 // task start and coroutine context yield
219 static void test_context_task_function_3(void *) {
220  ++g_test_coroutine_task_status;
221  CASE_EXPECT_EQ(g_test_coroutine_task_status, 1);
222 
224 
226 
228 
229  ++g_test_coroutine_task_status;
230  CASE_EXPECT_EQ(g_test_coroutine_task_status, 3);
231 }
232 
233 CASE_TEST(coroutine_task, coroutine_context_yield) {
235  task_ptr_type co_task = cotask::task<>::create(test_context_task_function_3);
236  g_test_coroutine_task_status = 0;
237 
238  CASE_EXPECT_EQ(0, co_task->start());
239 
240  ++g_test_coroutine_task_status;
241  CASE_EXPECT_EQ(g_test_coroutine_task_status, 2);
242 
243  CASE_EXPECT_FALSE(co_task->is_completed());
244  CASE_EXPECT_EQ(cotask::EN_TS_WAITING, co_task->get_status());
245  CASE_EXPECT_EQ(0, co_task->resume());
246 
247  CASE_EXPECT_TRUE(co_task->is_completed());
248 
249  ++g_test_coroutine_task_status;
250  CASE_EXPECT_EQ(g_test_coroutine_task_status, 4);
251 
252  CASE_EXPECT_NE(co_task->get_id(), 0);
253 }
254 
255 
256 struct test_context_task_mem_function {
257  cotask::task<>::id_t task_id_;
258 
259  int real_run(void *) {
260  ++g_test_coroutine_task_status;
261  CASE_EXPECT_EQ(g_test_coroutine_task_status, 1);
262 
263  CASE_EXPECT_EQ(task_id_, cotask::task<>::this_task()->get_id());
265  CASE_EXPECT_EQ(task_id_, cotask::task<>::this_task()->get_id());
266 
267  ++g_test_coroutine_task_status;
268  CASE_EXPECT_EQ(g_test_coroutine_task_status, 3);
269 
270  return -1;
271  }
272 };
273 
274 CASE_TEST(coroutine_task, mem_function_action) {
276  test_context_task_mem_function obj;
277  task_ptr_type co_task = cotask::task<>::create(&test_context_task_mem_function::real_run, &obj);
278  g_test_coroutine_task_status = 0;
279  obj.task_id_ = co_task->get_id();
280 
281  CASE_EXPECT_EQ(0, co_task->start());
282 
283  ++g_test_coroutine_task_status;
284  CASE_EXPECT_EQ(g_test_coroutine_task_status, 2);
285 
286  CASE_EXPECT_FALSE(co_task->is_completed());
287  CASE_EXPECT_EQ(0, co_task->resume());
288 
289  CASE_EXPECT_TRUE(co_task->is_completed());
290 
291  ++g_test_coroutine_task_status;
292  CASE_EXPECT_EQ(g_test_coroutine_task_status, 4);
293 
294  CASE_EXPECT_NE(co_task->get_coroutine_context()->get_ret_code(), -1);
295 }
296 
297 CASE_TEST(coroutine_task, auto_finish) {
299  {
300  test_context_task_mem_function obj;
301  task_ptr_type co_task = cotask::task<>::create(&test_context_task_mem_function::real_run, &obj);
302  g_test_coroutine_task_status = 0;
303  obj.task_id_ = co_task->get_id();
304  }
305  CASE_EXPECT_EQ(0, g_test_coroutine_task_status);
306 
307  {
308  test_context_task_mem_function obj;
309  task_ptr_type co_task = cotask::task<>::create(&test_context_task_mem_function::real_run, &obj);
310  g_test_coroutine_task_status = 0;
311  obj.task_id_ = co_task->get_id();
312 
313  CASE_EXPECT_EQ(0, co_task->start());
314 
315  ++g_test_coroutine_task_status;
316  CASE_EXPECT_EQ(g_test_coroutine_task_status, 2);
317 
318  CASE_EXPECT_FALSE(co_task->is_completed());
319  }
320 
321  ++g_test_coroutine_task_status;
322  CASE_EXPECT_EQ(g_test_coroutine_task_status, 4);
323 }
324 
325 struct test_context_task_next_action : public cotask::impl::task_action_impl {
326  int set_;
327  int check_;
328  test_context_task_next_action(int s, int c) : cotask::impl::task_action_impl(), set_(s), check_(c) {}
329 
330  int operator()(void *) {
331  CASE_EXPECT_EQ(g_test_coroutine_task_status, check_);
332  g_test_coroutine_task_status = set_;
333 
335 
336  ++g_test_coroutine_task_on_finished;
337  return 0;
338  }
339 };
340 
341 CASE_TEST(coroutine_task, next) {
343 
344  {
345  g_test_coroutine_task_status = 0;
346 
347  task_ptr_type co_task = cotask::task<>::create(test_context_task_next_action(15, 0));
348  co_task->next(test_context_task_next_action(7, 15))
349  ->next(test_context_task_next_action(99, 7))
350  ->next(test_context_task_next_action(1023, 99))
351  ->next(test_context_task_next_action(5, 1023));
352 
353  CASE_EXPECT_EQ(co_task->next(co_task), co_task);
354  CASE_EXPECT_EQ(0, co_task->start());
355  CASE_EXPECT_EQ(g_test_coroutine_task_status, 5);
356 
358  }
359 
360  {
361  g_test_coroutine_task_status = 0;
362  task_ptr_type co_task_a = cotask::task<>::create(test_context_task_next_action(2, 1));
363  task_ptr_type co_task_b = cotask::task<>::create(test_context_task_function_1);
364 
365  CASE_EXPECT_EQ(0, co_task_b->start());
366  co_task_a->next(co_task_b);
367  CASE_EXPECT_EQ(0, co_task_a->start());
368  CASE_EXPECT_TRUE(co_task_a->is_completed());
369  CASE_EXPECT_TRUE(co_task_b->is_completed());
370  CASE_EXPECT_TRUE(co_task_b->::cotask::impl::task_impl::is_completed());
371  }
372 }
373 
374 #if defined(UTIL_CONFIG_COMPILER_CXX_VARIADIC_TEMPLATES) && UTIL_CONFIG_COMPILER_CXX_VARIADIC_TEMPLATES
375 
376 struct test_context_task_functor_drived : public cotask::impl::task_action_impl {
377 public:
378  int a_;
379  int b_;
380  test_context_task_functor_drived(int a, int b) : a_(a), b_(b) {}
381 
382  virtual int operator()(void *) {
383  CASE_EXPECT_EQ(a_, 1);
384  CASE_EXPECT_EQ(3, b_);
385 
386  return 0;
387  }
388 };
389 
390 CASE_TEST(coroutine_task, functor_drived_action) {
393  task_ptr_type co_task = cotask::task<>::create_with<test_context_task_functor_drived>(alloc, 0, 0, 1, 3);
394  CASE_EXPECT_EQ(0, co_task->start());
395 }
396 
397 #endif
398 
399 
400 static int test_context_task_priavte_buffer(void *) {
401 
402  void * priv_data = cotask::task<>::this_task()->get_private_buffer();
404 
405 
406  CASE_EXPECT_GE(priv_sz, 256);
407 
408  if (priv_sz >= 256) {
409  char checked_data[256];
410  memset(checked_data, 0x5e, 256);
411 
412  CASE_EXPECT_EQ(0, memcmp(priv_data, checked_data, 256));
413  }
414 
415  return 0;
416 }
417 
418 CASE_TEST(coroutine_task, priavte_buffer) {
420  task_ptr_type co_task = cotask::task<>::create(test_context_task_priavte_buffer, 16384, 256);
421 
422  void *priv_data = co_task->get_private_buffer();
423  memset(priv_data, 0x5e, 256);
424 
425  CASE_EXPECT_EQ(0, co_task->start());
426 }
427 
428 static int test_context_task_timeout(void *) {
429 
431 
434  CASE_EXPECT_FALSE(cotask::task<>::this_task()->is_completed());
436 
437  return 0;
438 }
439 
440 CASE_TEST(coroutine_task, kill_and_timeout) {
442  task_ptr_type co_task = cotask::task<>::create(test_context_task_timeout, 16384, 256);
443 
444  void *priv_data = co_task->get_private_buffer();
445  memset(priv_data, 0x5e, 256);
446 
447  CASE_EXPECT_EQ(0, co_task->start());
448 
449  CASE_EXPECT_FALSE(co_task->is_timeout());
450  CASE_EXPECT_FALSE(co_task->is_faulted());
451  CASE_EXPECT_FALSE(co_task->is_completed());
452  CASE_EXPECT_FALSE(co_task->is_exiting());
453 
454  CASE_EXPECT_EQ(0, co_task->kill(cotask::EN_TS_TIMEOUT, NULL));
455 
456  CASE_EXPECT_TRUE(co_task->is_completed());
457 
458  CASE_EXPECT_NE(NULL, co_task->get_raw_action());
459 }
460 
461 
462 static int test_context_task_await_1(void *) {
463 
465 
466  task_ptr_type self = cotask::task<>::this_task();
467 
468  CASE_EXPECT_EQ(copp::COPP_EC_ARGS_ERROR, self->await(NULL));
470 
471 
472  void * priv_data = self->get_private_buffer();
473  cotask::task<>::self_t *other_task = *reinterpret_cast<cotask::task<>::self_t **>(priv_data);
474 
475 
476  if (other_task->is_exiting()) {
477  CASE_EXPECT_EQ(copp::COPP_EC_TASK_IS_EXITING, self->await(other_task));
478  } else {
479  if (self->is_exiting()) {
480  CASE_EXPECT_EQ(copp::COPP_EC_TASK_IS_EXITING, self->await(other_task));
481  } else {
482  CASE_EXPECT_EQ(0, self->await(other_task));
483  }
484  }
485 
486  return 0;
487 }
488 
489 static int test_context_task_await_2(void *) { return 0; }
490 
491 CASE_TEST(coroutine_task, await) {
493 
494  // normal
495  {
496  task_ptr_type co_task_1 = cotask::task<>::create(test_context_task_await_1, 16384, sizeof(cotask::task<>::self_t *));
497  task_ptr_type co_task_2 = cotask::task<>::create(test_context_task_await_2, 16384);
498 
499  void *priv_data = co_task_1->get_private_buffer();
500 
501  *reinterpret_cast<cotask::task<>::self_t **>(priv_data) = co_task_2.get();
502  CASE_EXPECT_EQ(copp::COPP_EC_TASK_NOT_IN_ACTION, co_task_1->await(co_task_2));
503 
504  CASE_EXPECT_FALSE(co_task_1->is_exiting());
505  CASE_EXPECT_FALSE(co_task_2->is_exiting());
506 
507  co_task_1->start();
508  CASE_EXPECT_FALSE(co_task_1->is_exiting());
509  CASE_EXPECT_FALSE(co_task_2->is_exiting());
510 
511  co_task_2->start();
512  CASE_EXPECT_TRUE(co_task_1->is_exiting());
513  CASE_EXPECT_TRUE(co_task_2->is_exiting());
514  }
515 
516  // co_task_1 exiting
517  {
518  task_ptr_type co_task_1 = cotask::task<>::create(test_context_task_await_1, 16384, sizeof(cotask::task<>::self_t *));
519  task_ptr_type co_task_2 = cotask::task<>::create(test_context_task_await_2, 16384);
520 
521  void *priv_data = co_task_1->get_private_buffer();
522 
523  CASE_EXPECT_EQ(copp::COPP_EC_ARGS_ERROR, co_task_1->await(UTIL_CONFIG_NULLPTR));
524  CASE_EXPECT_EQ(copp::COPP_EC_TASK_CAN_NOT_WAIT_SELF, co_task_1->await(co_task_1));
525 
526  *reinterpret_cast<cotask::task<>::self_t **>(priv_data) = co_task_2.get();
527  CASE_EXPECT_EQ(copp::COPP_EC_TASK_NOT_IN_ACTION, co_task_1->await(co_task_2));
528 
529  CASE_EXPECT_FALSE(co_task_1->is_exiting());
530  CASE_EXPECT_FALSE(co_task_2->is_exiting());
531 
532  co_task_1->kill(cotask::EN_TS_TIMEOUT);
533  CASE_EXPECT_TRUE(co_task_1->is_exiting());
534  co_task_1->start();
535  CASE_EXPECT_TRUE(co_task_1->is_exiting());
536  CASE_EXPECT_FALSE(co_task_2->is_exiting());
537 
538  co_task_2->start();
539  CASE_EXPECT_TRUE(co_task_1->is_exiting());
540  CASE_EXPECT_TRUE(co_task_2->is_exiting());
541  }
542 
543  // co_task_2 exiting
544  {
545  task_ptr_type co_task_1 = cotask::task<>::create(test_context_task_await_1, 16384, sizeof(cotask::task<>::self_t *));
546  task_ptr_type co_task_2 = cotask::task<>::create(test_context_task_await_2, 16384);
547 
548  void *priv_data = co_task_1->get_private_buffer();
549 
550  *reinterpret_cast<cotask::task<>::self_t **>(priv_data) = co_task_2.get();
551  CASE_EXPECT_EQ(copp::COPP_EC_TASK_NOT_IN_ACTION, co_task_1->await(co_task_2));
552 
553  CASE_EXPECT_FALSE(co_task_1->is_exiting());
554  CASE_EXPECT_FALSE(co_task_2->is_exiting());
555 
556  co_task_2->start();
557  CASE_EXPECT_FALSE(co_task_1->is_exiting());
558  CASE_EXPECT_TRUE(co_task_2->is_exiting());
559 
560  co_task_1->start();
561  CASE_EXPECT_TRUE(co_task_1->is_exiting());
562  CASE_EXPECT_TRUE(co_task_2->is_exiting());
563  }
564 }
565 
566 static int test_context_task_then_action_func(void *priv_data) {
567  CASE_EXPECT_EQ(&g_test_coroutine_task_status, priv_data);
568  ++g_test_coroutine_task_on_finished;
569  return 0;
570 }
571 
572 CASE_TEST(coroutine_task, then) {
574  g_test_coroutine_task_status = 0;
575  g_test_coroutine_task_on_finished = 0;
576 
577  task_ptr_type co_task = cotask::task<>::create(test_context_task_next_action(15, 0));
578  co_task->then(test_context_task_next_action(7, 15))
579  ->then(test_context_task_next_action(99, 7))
580  ->then(test_context_task_next_action(1023, 99))
581  ->then(test_context_task_next_action(5, 1023));
582 
583 
584  CASE_EXPECT_EQ(0, co_task->start());
585  CASE_EXPECT_EQ(g_test_coroutine_task_status, 5);
586 
588 
589  CASE_EXPECT_TRUE(co_task->is_exiting());
590  CASE_EXPECT_TRUE(co_task->is_completed());
591 
592  co_task->then(test_context_task_next_action(127, 5))->then(test_context_task_then_action_func, &g_test_coroutine_task_status);
593  CASE_EXPECT_EQ(g_test_coroutine_task_status, 127);
594  CASE_EXPECT_EQ(g_test_coroutine_task_on_finished, 7);
595 }
596 
597 
598 typedef copp::stack_pool<copp::allocator::stack_allocator_malloc> test_context_task_stack_pool_t;
599 struct test_context_task_stack_pool_test_macro_coroutine {
601 
603 };
604 
605 typedef cotask::task<test_context_task_stack_pool_test_macro_coroutine> test_context_task_stack_pool_test_task_t;
606 
607 CASE_TEST(coroutine_task, then_with_stack_pool) {
608  typedef test_context_task_stack_pool_test_task_t::ptr_t task_ptr_type;
609  test_context_task_stack_pool_t::ptr_t stack_pool = test_context_task_stack_pool_t::create();
610 
611  g_test_coroutine_task_on_finished = 0;
612  g_test_coroutine_task_status = 0;
613 
615  task_ptr_type tp = test_context_task_stack_pool_test_task_t::create(test_context_task_next_action(15, 0), base_alloc);
616  tp->then(test_context_task_next_action(127, 15))->then(test_context_task_then_action_func, &g_test_coroutine_task_status);
617 
618  CASE_EXPECT_EQ(3, stack_pool->get_limit().used_stack_number);
619  tp->start();
620  CASE_EXPECT_EQ(1, stack_pool->get_limit().used_stack_number);
621 
622  tp->then(test_context_task_next_action(255, 127))->then(test_context_task_then_action_func, &g_test_coroutine_task_status);
623 
624  CASE_EXPECT_EQ(1, stack_pool->get_limit().used_stack_number);
625  CASE_EXPECT_EQ(g_test_coroutine_task_status, 255);
626  CASE_EXPECT_EQ(g_test_coroutine_task_on_finished, 5);
627 }
628 
629 
630 #if ((defined(__cplusplus) && __cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1800)) && \
631  defined(UTIL_CONFIG_COMPILER_CXX_LAMBDAS) && UTIL_CONFIG_COMPILER_CXX_LAMBDAS
632 
633 static util::lock::atomic_int_type<int> g_test_context_task_test_atomic;
634 static const int g_test_context_task_test_mt_run_times = 10000;
635 static size_t g_test_context_task_test_mt_max_run_thread_number = 0;
636 enum {
637  test_context_task_test_mt_thread_num = 100,
638  test_context_task_test_mt_task_num = 1000,
639 };
640 
641 struct test_context_task_test_action_mt_thread : public cotask::impl::task_action_impl {
642  int run_count;
643 
644 public:
645  test_context_task_test_action_mt_thread() : run_count(0) {}
646 
647  int operator()(void *thread_func_address) {
648  std::set<void *> thread_counter;
649 
650  while (run_count < g_test_context_task_test_mt_run_times) {
651  ++run_count;
652  ++g_test_context_task_test_atomic;
653 
654  thread_counter.insert(thread_func_address);
655 
656  cotask::this_task::get_task()->yield(&thread_func_address);
657  }
658 
659  if (g_test_context_task_test_mt_max_run_thread_number < thread_counter.size()) {
660  g_test_context_task_test_mt_max_run_thread_number = thread_counter.size();
661  }
662  return 0;
663  }
664 };
665 
666 struct test_context_task_test_mt_thread_runner {
668 
669  std::vector<task_ptr_type> *task_pool;
670  test_context_task_test_mt_thread_runner(std::vector<task_ptr_type> *pool) : task_pool(pool) {}
671 
672  int operator()() {
673 
674  bool need_continue = true;
675  while (need_continue) {
676  need_continue = false;
677 
678  for (size_t i = 0; i < task_pool->size(); ++i) {
679  if (false == (*task_pool)[i]->is_completed()) {
680  need_continue = true;
681  (*task_pool)[i]->resume(this);
682  }
683  }
684  }
685  return 0;
686  }
687 };
688 
689 CASE_TEST(coroutine_task, mt_run_competition) {
691  std::vector<task_ptr_type> task_pool;
692  task_pool.reserve(test_context_task_test_mt_task_num);
693  for (int i = 0; i < test_context_task_test_mt_task_num; ++i) {
694  task_pool.push_back(cotask::task<>::create(test_context_task_test_action_mt_thread(), 16 * 1024)); // use 16KB for stack
695  }
696 
697  g_test_context_task_test_atomic.store(0);
698  g_test_context_task_test_mt_max_run_thread_number = 0;
699 
700  std::unique_ptr<std::thread> thds[test_context_task_test_mt_thread_num];
701  for (int i = 0; i < test_context_task_test_mt_thread_num; ++i) {
702  thds[i].reset(new std::thread(test_context_task_test_mt_thread_runner(&task_pool)));
703  }
704 
705  for (int i = 0; i < test_context_task_test_mt_thread_num; ++i) {
706  thds[i]->join();
707  }
708 
709  CASE_EXPECT_EQ(g_test_context_task_test_mt_run_times * test_context_task_test_mt_task_num, g_test_context_task_test_atomic.load());
710  CASE_MSG_INFO() << "Coroutine tasks are run on " << g_test_context_task_test_mt_max_run_thread_number << " threads at most."
711  << std::endl;
712 }
713 
714 #endif
715 
716 
717 #endif
#define CASE_TEST(test_name, case_name)
Definition: test_macros.h:43
#define CASE_EXPECT_GT(l, r)
Definition: test_macros.h:66
virtual int operator()(void *)=0
COPP_EC_TASK_IS_EXITING.
Definition: errno.h:36
COPP_EC_TASK_CAN_NOT_WAIT_SELF.
Definition: errno.h:35
void store(value_type desired, EXPLICIT_UNUSED_ATTR::util::lock::memory_order order=::util::lock::memory_order_seq_cst) UTIL_CONFIG_NOEXCEPT
size_t get_private_buffer_size()
Definition: task.h:605
COPP_EC_ALREADY_FINISHED.
Definition: errno.h:27
bool is_exiting() const UTIL_CONFIG_NOEXCEPT
check if a cotask is exiting
Definition: task_impl.cpp:34
#define CASE_EXPECT_EQ(l, r)
Definition: test_macros.h:62
#define CASE_EXPECT_TRUE(c)
Definition: test_macros.h:60
virtual int yield(void **priv_data) UTIL_CONFIG_OVERRIDE
Definition: task.h:531
COPP_EC_IS_RUNNING.
Definition: errno.h:26
#define CASE_MSG_INFO()
Definition: test_macros.h:80
Tt * get()
get current running task and try to convert type
Definition: this_task.h:31
static ptr_t create(const Ty &functor, size_t stack_size=0, size_t private_buffer_size=0)
create task with functor
Definition: task.h:162
macro_task_t::id_t id_t
Definition: task.h:38
int yield(void **priv_data=UTIL_CONFIG_NULLPTR)
yield current coroutine
#define CASE_EXPECT_NE(l, r)
Definition: test_macros.h:63
导入智能指针库 Licensed under the MIT licenses.
#define CASE_EXPECT_GE(l, r)
Definition: test_macros.h:67
coroutine container contain stack context, stack allocator and runtime fcontext
impl::task_impl * get_task() UTIL_CONFIG_NOEXCEPT
get current running task
Definition: this_task.cpp:15
COPP_EC_TASK_NOT_IN_ACTION.
Definition: errno.h:38
static self_t * this_task()
Definition: task.h:444
value_type load(EXPLICIT_UNUSED_ATTR::util::lock::memory_order order=::util::lock::memory_order_seq_cst) const UTIL_CONFIG_NOEXCEPT
element_type * get() const UTIL_CONFIG_NOEXCEPT
void * get_private_buffer()
Definition: task.h:597
memory allocator this allocator will maintain buffer using malloc/free function
virtual int on_finished(task_impl &)
#define CASE_EXPECT_FALSE(c)
Definition: test_macros.h:61
virtual int yield(void **priv_data)=0
my_task_t::ptr_t task_ptr_type
COPP_EC_ARGS_ERROR.
Definition: errno.h:30