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