libcopp 2.3.1
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
task_promise_task_manager_test.cpp
Go to the documentation of this file.
1// Copyright 2023 owent
2
6
7#include <cstdio>
8#include <cstring>
9#include <iostream>
10#include <memory>
11
12#include "frame/test_macros.h"
13
14#ifdef LIBCOTASK_MACRO_ENABLED
15
16# if defined(LIBCOPP_MACRO_ENABLE_STD_COROUTINE) && LIBCOPP_MACRO_ENABLE_STD_COROUTINE
17
18namespace {
19struct task_manager_future_private_data {};
20
21using task_future_int_type = cotask::task_future<int, task_manager_future_private_data>;
22using generator_future_int_type = copp::generator_future<int>;
23
24std::list<generator_future_int_type::context_pointer_type> g_task_manager_future_pending_int_contexts;
25size_t g_task_manager_future_resume_generator_count = 0;
26size_t g_task_manager_future_suspend_generator_count = 0;
27
28static size_t task_manager_resume_pending_contexts(std::list<int> values, int max_count = 32767) {
29 size_t ret = 0;
30 while (max_count > 0 && !g_task_manager_future_pending_int_contexts.empty()) {
31 --max_count;
32 if (!g_task_manager_future_pending_int_contexts.empty()) {
33 auto ctx = *g_task_manager_future_pending_int_contexts.begin();
34 g_task_manager_future_pending_int_contexts.pop_front();
35
36 if (!values.empty()) {
37 int val = values.front();
38 values.pop_front();
39 ctx->set_value(val);
40 } else {
41 ctx->set_value(0);
42 }
43
44 ++ret;
45 }
46 }
47
48 return ret;
49}
50
51static void task_manager_generator_int_suspend_callback(generator_future_int_type::context_pointer_type ctx) {
52 ++g_task_manager_future_suspend_generator_count;
53 g_task_manager_future_pending_int_contexts.push_back(ctx);
54}
55static void task_manager_generator_int_resume_callback(const generator_future_int_type::context_type&) {
56 ++g_task_manager_future_resume_generator_count;
57}
58
59static task_future_int_type task_func_await_int() {
60 generator_future_int_type generator{task_manager_generator_int_suspend_callback,
61 task_manager_generator_int_resume_callback};
62 auto gen_res = co_await generator;
63 co_return gen_res;
64}
65
66} // namespace
67
68CASE_TEST(task_promise_task_manager, tickspec_t) {
69 cotask::detail::tickspec_t l;
70 cotask::detail::tickspec_t r;
71
72 l.tv_sec = 123;
73 l.tv_nsec = 456;
74
75 r.tv_sec = 123;
76 r.tv_nsec = 456;
77
78 CASE_EXPECT_TRUE(l == r);
79 CASE_EXPECT_FALSE(l != r);
80 CASE_EXPECT_FALSE(l < r);
81 CASE_EXPECT_TRUE(l <= r);
82
83 r.tv_sec = 456;
84 r.tv_nsec = 123;
85
86 CASE_EXPECT_FALSE(l == r);
87 CASE_EXPECT_TRUE(l != r);
88 CASE_EXPECT_TRUE(l < r);
89 CASE_EXPECT_TRUE(l <= r);
90
91 r.tv_sec = 45;
92 r.tv_nsec = 999;
93
94 CASE_EXPECT_FALSE(l == r);
95 CASE_EXPECT_TRUE(l != r);
96 CASE_EXPECT_FALSE(l < r);
97 CASE_EXPECT_FALSE(l <= r);
98}
99
100CASE_TEST(task_promise_task_manager, task_timer_node) {
101 cotask::detail::task_timer_node<task_future_int_type::id_type> l;
102 cotask::detail::task_timer_node<task_future_int_type::id_type> r;
103
104 l.expired_time.tv_sec = 123;
105 l.expired_time.tv_nsec = 456;
106 l.task_id = 10;
107
108 r.expired_time.tv_sec = 123;
109 r.expired_time.tv_nsec = 456;
110 r.task_id = 10;
111
112 CASE_EXPECT_TRUE(l == r);
113 CASE_EXPECT_FALSE(l != r);
114 CASE_EXPECT_FALSE(l < r);
115 CASE_EXPECT_TRUE(l <= r);
116
117 r.task_id = 5;
118
119 CASE_EXPECT_FALSE(l == r);
120 CASE_EXPECT_TRUE(l != r);
121 CASE_EXPECT_FALSE(l < r);
122 CASE_EXPECT_FALSE(l <= r);
123
124 r.expired_time.tv_nsec = 45;
125 r.task_id = 10;
126
127 CASE_EXPECT_FALSE(l == r);
128 CASE_EXPECT_TRUE(l != r);
129 CASE_EXPECT_FALSE(l < r);
130 CASE_EXPECT_FALSE(l <= r);
131
132 r.expired_time.tv_nsec = 456;
133 r.task_id = 15;
134
135 CASE_EXPECT_FALSE(l == r);
136 CASE_EXPECT_TRUE(l != r);
137 CASE_EXPECT_TRUE(l < r);
138 CASE_EXPECT_TRUE(l <= r);
139
140 r.expired_time.tv_nsec = 4567;
141 r.task_id = 10;
142
143 CASE_EXPECT_FALSE(l == r);
144 CASE_EXPECT_TRUE(l != r);
145 CASE_EXPECT_TRUE(l < r);
146 CASE_EXPECT_TRUE(l <= r);
147}
148
149CASE_TEST(task_promise_task_manager, add_and_timeout) {
150 {
151 task_future_int_type co_task = task_func_await_int();
152 task_future_int_type co_another_task = task_func_await_int();
153
154 using mgr_t = cotask::task_manager<task_future_int_type>;
155 mgr_t::ptr_type task_mgr = mgr_t::create();
156
157 CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
158 size_t old_resume_generator_count = g_task_manager_future_resume_generator_count;
159 size_t old_suspend_generator_count = g_task_manager_future_suspend_generator_count;
160
161 task_mgr->add_task(co_task, 5, 0);
162 task_mgr->add_task(co_another_task);
163
164 CASE_EXPECT_EQ(2, (int)task_mgr->get_task_size());
165 CASE_EXPECT_EQ(1, (int)task_mgr->get_tick_checkpoint_size());
166
167 CASE_EXPECT_TRUE(co_task == *task_mgr->find_task(co_task.get_id()));
168 CASE_EXPECT_TRUE(co_another_task == *task_mgr->find_task(co_another_task.get_id()));
169
170 CASE_EXPECT_EQ(0, (int)task_mgr->get_last_tick_time().tv_sec);
171 task_mgr->tick(3);
172 CASE_EXPECT_EQ(2, (int)task_mgr->get_task_size());
173 CASE_EXPECT_EQ(1, (int)task_mgr->get_tick_checkpoint_size());
174
175 co_task.start();
176
177 CASE_EXPECT_EQ(3, (int)task_mgr->get_last_tick_time().tv_sec);
178 task_mgr->tick(8);
179 CASE_EXPECT_EQ(8, (int)task_mgr->get_last_tick_time().tv_sec);
180 // tick reset timeout: 3 + 5 = 8
181 CASE_EXPECT_EQ(8, (int)task_mgr->get_container().find(co_task.get_id())->second.timer_node->expired_time.tv_sec);
182 CASE_EXPECT_EQ(2, (int)task_mgr->get_task_size());
183 CASE_EXPECT_EQ(1, (int)task_mgr->get_tick_checkpoint_size());
184 CASE_EXPECT_EQ(1, (int)task_mgr->get_checkpoints().size());
185 CASE_EXPECT_FALSE(task_future_int_type::task_status_type::kTimeout == co_task.get_status());
186
187 task_mgr->tick(9);
188 CASE_EXPECT_EQ(9, (int)task_mgr->get_last_tick_time().tv_sec);
189 CASE_EXPECT_EQ(1, (int)task_mgr->get_task_size());
190 CASE_EXPECT_EQ(1, (int)task_mgr->get_container().size());
191 CASE_EXPECT_EQ(0, (int)task_mgr->get_tick_checkpoint_size());
192 CASE_EXPECT_TRUE(task_future_int_type::task_status_type::kTimeout == co_task.get_status());
193
194 CASE_EXPECT_EQ(nullptr, task_mgr->find_task(co_task.get_id()));
195 CASE_EXPECT_TRUE(co_another_task == *task_mgr->find_task(co_another_task.get_id()));
196
197 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_task_manager_future_resume_generator_count);
198 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_task_manager_future_suspend_generator_count);
199
200 CASE_EXPECT_EQ(0, task_mgr->start(co_another_task.get_id()));
201
202 CASE_EXPECT_TRUE(task_future_int_type::task_status_type::kRunning == co_another_task.get_status());
203
204 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_task_manager_future_resume_generator_count);
205 CASE_EXPECT_EQ(old_suspend_generator_count + 2, g_task_manager_future_suspend_generator_count);
206
207 task_manager_resume_pending_contexts({901, 902});
208
209 CASE_EXPECT_EQ(old_resume_generator_count + 2, g_task_manager_future_resume_generator_count);
210 CASE_EXPECT_EQ(old_suspend_generator_count + 2, g_task_manager_future_suspend_generator_count);
211
212 CASE_EXPECT_TRUE(task_future_int_type::task_status_type::kTimeout == co_task.get_status());
213 CASE_EXPECT_TRUE(task_future_int_type::task_status_type::kDone == co_another_task.get_status());
214
215 CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
216 CASE_EXPECT_EQ(0, (int)task_mgr->get_tick_checkpoint_size());
217
218 CASE_EXPECT_EQ(copp::COPP_EC_TASK_IS_EXITING, task_mgr->add_task(co_another_task));
219
220 task_mgr.reset();
221 }
222 task_manager_resume_pending_contexts({});
223}
224
225CASE_TEST(task_promise_task_manager, add_and_timeout_no_start) {
226 {
227 task_future_int_type co_task = task_func_await_int();
228 task_future_int_type co_another_task = task_func_await_int();
229
230 using mgr_t = cotask::task_manager<task_future_int_type>;
231 mgr_t::ptr_type task_mgr = mgr_t::create();
232
233 CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
234 size_t old_resume_generator_count = g_task_manager_future_resume_generator_count;
235 size_t old_suspend_generator_count = g_task_manager_future_suspend_generator_count;
236
237 task_mgr->add_task(co_task, 5, 0);
238 task_mgr->add_task(co_another_task);
239
240 CASE_EXPECT_EQ(2, (int)task_mgr->get_task_size());
241 CASE_EXPECT_EQ(1, (int)task_mgr->get_tick_checkpoint_size());
242
243 CASE_EXPECT_TRUE(co_task == *task_mgr->find_task(co_task.get_id()));
244 CASE_EXPECT_TRUE(co_another_task == *task_mgr->find_task(co_another_task.get_id()));
245
246 CASE_EXPECT_EQ(0, (int)task_mgr->get_last_tick_time().tv_sec);
247 task_mgr->tick(3);
248 CASE_EXPECT_EQ(3, (int)task_mgr->get_last_tick_time().tv_sec);
249 task_mgr->tick(8);
250 CASE_EXPECT_EQ(8, (int)task_mgr->get_last_tick_time().tv_sec);
251 // tick reset timeout: 3 + 5 = 8
252 CASE_EXPECT_EQ(8, (int)task_mgr->get_container().find(co_task.get_id())->second.timer_node->expired_time.tv_sec);
253 CASE_EXPECT_EQ(2, (int)task_mgr->get_task_size());
254 CASE_EXPECT_EQ(1, (int)task_mgr->get_tick_checkpoint_size());
255 CASE_EXPECT_EQ(1, (int)task_mgr->get_checkpoints().size());
256 CASE_EXPECT_FALSE(task_future_int_type::task_status_type::kTimeout == co_task.get_status());
257
258 task_mgr->tick(9);
259 CASE_EXPECT_EQ(9, (int)task_mgr->get_last_tick_time().tv_sec);
260 CASE_EXPECT_EQ(1, (int)task_mgr->get_task_size());
261 CASE_EXPECT_EQ(1, (int)task_mgr->get_container().size());
262 CASE_EXPECT_EQ(0, (int)task_mgr->get_tick_checkpoint_size());
263 CASE_EXPECT_TRUE(task_future_int_type::task_status_type::kTimeout == co_task.get_status());
264
265 CASE_EXPECT_EQ(nullptr, task_mgr->find_task(co_task.get_id()));
266 CASE_EXPECT_TRUE(co_another_task == *task_mgr->find_task(co_another_task.get_id()));
267
268 CASE_EXPECT_EQ(old_resume_generator_count, g_task_manager_future_resume_generator_count);
269 CASE_EXPECT_EQ(old_suspend_generator_count, g_task_manager_future_suspend_generator_count);
270
271 CASE_EXPECT_EQ(0, task_mgr->start(co_another_task.get_id()));
272
273 CASE_EXPECT_TRUE(task_future_int_type::task_status_type::kRunning == co_another_task.get_status());
274
275 CASE_EXPECT_EQ(old_resume_generator_count, g_task_manager_future_resume_generator_count);
276 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_task_manager_future_suspend_generator_count);
277
278 task_manager_resume_pending_contexts({901, 902});
279
280 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_task_manager_future_resume_generator_count);
281 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_task_manager_future_suspend_generator_count);
282
283 CASE_EXPECT_TRUE(task_future_int_type::task_status_type::kTimeout == co_task.get_status());
284 CASE_EXPECT_TRUE(task_future_int_type::task_status_type::kDone == co_another_task.get_status());
285
286 CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
287 CASE_EXPECT_EQ(0, (int)task_mgr->get_tick_checkpoint_size());
288
289 CASE_EXPECT_EQ(copp::COPP_EC_TASK_IS_EXITING, task_mgr->add_task(co_another_task));
290
291 task_mgr.reset();
292 }
293 task_manager_resume_pending_contexts({});
294}
295
296CASE_TEST(task_promise_task_manager, add_and_timeout_last_reference) {
297 {
298 size_t old_resume_generator_count = g_task_manager_future_resume_generator_count;
299 size_t old_suspend_generator_count = g_task_manager_future_suspend_generator_count;
300 using mgr_t = cotask::task_manager<task_future_int_type>;
301 mgr_t::ptr_type task_mgr = mgr_t::create();
302
303 task_future_int_type::id_type another_task_id;
304 task_future_int_type::id_type task_id;
305 {
306 task_future_int_type co_task = task_func_await_int();
307 task_future_int_type co_another_task = task_func_await_int();
308
309 CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
310
311 co_task.start();
312 another_task_id = co_another_task.get_id();
313 task_id = co_task.get_id();
314
315 task_mgr->add_task(std::move(co_task), 5, 0);
316 task_mgr->add_task(std::move(co_another_task));
317
318 CASE_EXPECT_EQ(2, (int)task_mgr->get_task_size());
319 CASE_EXPECT_EQ(1, (int)task_mgr->get_tick_checkpoint_size());
320 }
321
322 CASE_EXPECT_EQ(0, (int)task_mgr->get_last_tick_time().tv_sec);
323 task_mgr->tick(3);
324 CASE_EXPECT_EQ(3, (int)task_mgr->get_last_tick_time().tv_sec);
325 task_mgr->tick(8);
326 CASE_EXPECT_EQ(8, (int)task_mgr->get_last_tick_time().tv_sec);
327 // tick reset timeout: 3 + 5 = 8
328 CASE_EXPECT_EQ(8, (int)task_mgr->get_container().find(task_id)->second.timer_node->expired_time.tv_sec);
329 CASE_EXPECT_EQ(2, (int)task_mgr->get_task_size());
330 CASE_EXPECT_EQ(1, (int)task_mgr->get_tick_checkpoint_size());
331 CASE_EXPECT_EQ(1, (int)task_mgr->get_checkpoints().size());
332 CASE_EXPECT_FALSE(nullptr == task_mgr->find_task(task_id));
333
334 task_mgr->tick(9);
335 CASE_EXPECT_EQ(9, (int)task_mgr->get_last_tick_time().tv_sec);
336 CASE_EXPECT_EQ(1, (int)task_mgr->get_task_size());
337 CASE_EXPECT_EQ(1, (int)task_mgr->get_container().size());
338 CASE_EXPECT_EQ(0, (int)task_mgr->get_tick_checkpoint_size());
339 CASE_EXPECT_EQ(nullptr, task_mgr->find_task(task_id));
340
341 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_task_manager_future_resume_generator_count);
342 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_task_manager_future_suspend_generator_count);
343
344 CASE_EXPECT_EQ(0, task_mgr->start(another_task_id));
345
346 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_task_manager_future_resume_generator_count);
347 CASE_EXPECT_EQ(old_suspend_generator_count + 2, g_task_manager_future_suspend_generator_count);
348
349 task_manager_resume_pending_contexts({901, 902});
350
351 CASE_EXPECT_EQ(old_resume_generator_count + 2, g_task_manager_future_resume_generator_count);
352 CASE_EXPECT_EQ(old_suspend_generator_count + 2, g_task_manager_future_suspend_generator_count);
353
354 CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
355 CASE_EXPECT_EQ(0, (int)task_mgr->get_tick_checkpoint_size());
356 }
357 task_manager_resume_pending_contexts({});
358}
359
360CASE_TEST(task_promise_task_manager, kill) {
361 {
362 size_t old_resume_generator_count = g_task_manager_future_resume_generator_count;
363 size_t old_suspend_generator_count = g_task_manager_future_suspend_generator_count;
364 using mgr_t = cotask::task_manager<task_future_int_type>;
365 mgr_t::ptr_type task_mgr = mgr_t::create();
366
367 task_future_int_type co_task = task_func_await_int();
368 task_future_int_type co_another_task = task_func_await_int();
369
370 CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
371 task_mgr->tick(10, 0);
372
373 task_mgr->add_task(co_task, 10, 0);
374 task_mgr->add_task(co_another_task, 10, 0);
375
376 task_mgr->start(co_task.get_id());
377 task_mgr->start(co_another_task.get_id());
378
379 CASE_EXPECT_EQ(2, (int)task_mgr->get_task_size());
380 CASE_EXPECT_EQ(2, (int)task_mgr->get_tick_checkpoint_size());
381
382 task_mgr->kill(co_task.get_id());
383 task_mgr->cancel(co_another_task.get_id());
384
385 CASE_EXPECT_EQ(old_resume_generator_count + 2, g_task_manager_future_resume_generator_count);
386 CASE_EXPECT_EQ(old_suspend_generator_count + 2, g_task_manager_future_suspend_generator_count);
387
388 CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
389 CASE_EXPECT_EQ(0, (int)task_mgr->get_tick_checkpoint_size());
390
391 CASE_EXPECT_TRUE(task_future_int_type::task_status_type::kKilled == co_task.get_status());
392 CASE_EXPECT_TRUE(task_future_int_type::task_status_type::kCancle == co_another_task.get_status());
393 }
394
395 task_manager_resume_pending_contexts({});
396}
397
398CASE_TEST(task_promise_task_manager, duplicated_checkpoints) {
399 {
400 size_t old_resume_generator_count = g_task_manager_future_resume_generator_count;
401 size_t old_suspend_generator_count = g_task_manager_future_suspend_generator_count;
402 using mgr_t = cotask::task_manager<task_future_int_type>;
403 mgr_t::ptr_type task_mgr = mgr_t::create();
404
405 task_future_int_type co_task = task_func_await_int();
406
407 CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
408
409 task_mgr->tick(4);
410 co_task.start();
411
412 task_mgr->add_task(co_task, 10, 0);
413 CASE_EXPECT_EQ(1, (int)task_mgr->get_task_size());
414 CASE_EXPECT_EQ(1, (int)task_mgr->get_tick_checkpoint_size());
415
416 task_mgr->tick(5);
417
418 CASE_EXPECT_EQ(1, (int)task_mgr->get_task_size());
419 CASE_EXPECT_EQ(1, (int)task_mgr->get_tick_checkpoint_size());
420
421 task_mgr->tick(15, 1);
422
423 CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
424 CASE_EXPECT_EQ(0, (int)task_mgr->get_tick_checkpoint_size());
425
426 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_task_manager_future_resume_generator_count);
427 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_task_manager_future_suspend_generator_count);
428 }
429 task_manager_resume_pending_contexts({});
430}
431
432CASE_TEST(task_promise_task_manager, update_timeout) {
433 {
434 size_t old_resume_generator_count = g_task_manager_future_resume_generator_count;
435 size_t old_suspend_generator_count = g_task_manager_future_suspend_generator_count;
436 using mgr_t = cotask::task_manager<task_future_int_type>;
437 mgr_t::ptr_type task_mgr = mgr_t::create();
438
439 task_future_int_type co_task = task_func_await_int();
440
441 CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
442
443 task_mgr->add_task(co_task, 10, 0);
444 co_task.start();
445 CASE_EXPECT_EQ(1, (int)task_mgr->get_task_size());
446 CASE_EXPECT_EQ(1, (int)task_mgr->get_tick_checkpoint_size());
447
448 task_mgr->tick(5);
449 CASE_EXPECT_EQ(copp::COPP_EC_SUCCESS, task_mgr->set_timeout(co_task.get_id(), 20, 0));
450
451 CASE_EXPECT_EQ(1, (int)task_mgr->get_task_size());
452 CASE_EXPECT_EQ(1, (int)task_mgr->get_tick_checkpoint_size());
453
454 task_mgr->tick(24, 1);
455
456 CASE_EXPECT_EQ(1, (int)task_mgr->get_task_size());
457 CASE_EXPECT_EQ(1, (int)task_mgr->get_tick_checkpoint_size());
458
459 task_mgr->tick(25, 1);
460
461 CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
462 CASE_EXPECT_EQ(0, (int)task_mgr->get_tick_checkpoint_size());
463
464 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_task_manager_future_resume_generator_count);
465 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_task_manager_future_suspend_generator_count);
466 }
467 task_manager_resume_pending_contexts({});
468}
469
470// TODO: thread safety check
471
472# if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
473CASE_TEST(task_promise_task_manager, auto_cleanup_for_manager) {
474 {
475 size_t old_resume_generator_count = g_task_manager_future_resume_generator_count;
476 size_t old_suspend_generator_count = g_task_manager_future_suspend_generator_count;
477 using mgr_t = cotask::task_manager<task_future_int_type>;
478
479 task_future_int_type co_task = task_func_await_int();
480
481 mgr_t::ptr_type task_mgr1 = mgr_t::create();
482 mgr_t::ptr_type task_mgr2 = mgr_t::create();
483
484 CASE_EXPECT_EQ(0, task_mgr1->add_task(co_task, 5, 0));
485 CASE_EXPECT_EQ(copp::COPP_EC_TASK_ALREADY_IN_ANOTHER_MANAGER, task_mgr2->add_task(co_task, 5, 0));
486
487 CASE_EXPECT_EQ(1, task_mgr1->get_task_size());
488 CASE_EXPECT_EQ(1, task_mgr1->get_tick_checkpoint_size());
489
490 co_task.start();
491 task_manager_resume_pending_contexts({903});
492
493 CASE_EXPECT_EQ(0, task_mgr1->get_task_size());
494 CASE_EXPECT_EQ(0, task_mgr1->get_tick_checkpoint_size());
495
496 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_task_manager_future_resume_generator_count);
497 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_task_manager_future_suspend_generator_count);
498 }
499 task_manager_resume_pending_contexts({});
500}
501
502CASE_TEST(task_promise_task_manager, remove_last_task_in_manager) {
503 {
504 size_t old_resume_generator_count = g_task_manager_future_resume_generator_count;
505 size_t old_suspend_generator_count = g_task_manager_future_suspend_generator_count;
506 using mgr_t = cotask::task_manager<task_future_int_type>;
507
508 mgr_t::ptr_type task_mgr1 = mgr_t::create();
509
510 {
511 task_future_int_type co_task = task_func_await_int();
512
513 CASE_EXPECT_EQ(0, task_mgr1->add_task(co_task, 5, 0));
514
515 CASE_EXPECT_EQ(1, task_mgr1->get_task_size());
516 CASE_EXPECT_EQ(1, task_mgr1->get_tick_checkpoint_size());
517
518 co_task.start();
519 }
520
521 CASE_EXPECT_EQ(1, task_mgr1->get_task_size());
522 CASE_EXPECT_EQ(1, task_mgr1->get_tick_checkpoint_size());
523
524 task_manager_resume_pending_contexts({903});
525
526 CASE_EXPECT_EQ(0, task_mgr1->get_task_size());
527 CASE_EXPECT_EQ(0, task_mgr1->get_tick_checkpoint_size());
528
529 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_task_manager_future_resume_generator_count);
530 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_task_manager_future_suspend_generator_count);
531 }
532 task_manager_resume_pending_contexts({});
533}
534# endif
535
536// rethrow a exception in c++20 coroutine will crash when using MSVC now(VS2022)
537// We may enable exception in the future
538# if 0 && defined(LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR) && LIBCOPP_MACRO_ENABLE_STD_EXCEPTION_PTR
539namespace {
540static task_future_int_type task_func_await_int_start_exception() {
541 generator_future_int_type generator{task_manager_generator_int_suspend_callback,
542 task_manager_generator_int_resume_callback};
543
544 throw std::exception("test-exception-start");
545
546 auto gen_res = co_await generator;
547 co_return gen_res;
548}
549
550static task_future_int_type task_func_await_int_resume_exception() {
551 generator_future_int_type generator{task_manager_generator_int_suspend_callback,
552 task_manager_generator_int_resume_callback};
553
554 auto gen_res = co_await generator;
555
556 throw std::exception("test-exception-resume");
557
558 co_return gen_res;
559}
560
561} // namespace
562
563CASE_TEST(task_promise_task_manager, start_exception_safe) {
564 {
565 size_t old_resume_generator_count = g_task_manager_future_resume_generator_count;
566 size_t old_suspend_generator_count = g_task_manager_future_suspend_generator_count;
567 using mgr_t = cotask::task_manager<task_future_int_type>;
568
569 task_future_int_type co_task = task_func_await_int_start_exception();
570 mgr_t::ptr_type task_mgr = mgr_t::create();
571
572 CASE_EXPECT_EQ(0, task_mgr->add_task(co_task, 5, 0));
573
574 CASE_EXPECT_EQ(1, task_mgr->get_task_size());
575 CASE_EXPECT_EQ(1, task_mgr->get_tick_checkpoint_size());
576
577 try {
578 co_task.start();
579 task_manager_resume_pending_contexts({907});
580 } catch (const std::exception& e) {
581 CASE_MSG_INFO() << "Catch a exception: " << e.what() << std::endl;
582 } catch (...) {
583 CASE_MSG_INFO() << "Catch a exception" << std::endl;
584 }
585
586 CASE_EXPECT_EQ(0, task_mgr->get_task_size());
587 CASE_EXPECT_EQ(0, task_mgr->get_tick_checkpoint_size());
588 CASE_EXPECT_TRUE(co_task.is_completed());
589
590 CASE_EXPECT_EQ(old_resume_generator_count, g_task_manager_future_resume_generator_count);
591 CASE_EXPECT_EQ(old_suspend_generator_count, g_task_manager_future_suspend_generator_count);
592 }
593 task_manager_resume_pending_contexts({});
594}
595
596CASE_TEST(task_promise_task_manager, resume_exception_safe) {
597 {
598 size_t old_resume_generator_count = g_task_manager_future_resume_generator_count;
599 size_t old_suspend_generator_count = g_task_manager_future_suspend_generator_count;
600 using mgr_t = cotask::task_manager<task_future_int_type>;
601
602 task_future_int_type co_task = task_func_await_int_resume_exception();
603 mgr_t::ptr_type task_mgr = mgr_t::create();
604
605 CASE_EXPECT_EQ(0, task_mgr->add_task(co_task, 5, 0));
606
607 CASE_EXPECT_EQ(1, task_mgr->get_task_size());
608 CASE_EXPECT_EQ(1, task_mgr->get_tick_checkpoint_size());
609
610 try {
611 co_task.start();
612 task_manager_resume_pending_contexts({907});
613 } catch (const std::exception& e) {
614 CASE_MSG_INFO() << "Catch a exception: " << e.what() << std::endl;
615 } catch (...) {
616 CASE_MSG_INFO() << "Catch a exception" << std::endl;
617 }
618
619 CASE_EXPECT_EQ(0, task_mgr->get_task_size());
620 CASE_EXPECT_EQ(0, task_mgr->get_tick_checkpoint_size());
621 CASE_EXPECT_TRUE(co_task.is_completed());
622
623 CASE_EXPECT_EQ(old_resume_generator_count, g_task_manager_future_resume_generator_count);
624 CASE_EXPECT_EQ(old_suspend_generator_count, g_task_manager_future_suspend_generator_count);
625 }
626 task_manager_resume_pending_contexts({});
627}
628
629# endif
630
631# else
632CASE_TEST(task_promise_task_manager, disabled) {}
633# endif
634#else
635CASE_TEST(task_promise_task_manager, disabled) {}
636#endif
cotask::task_manager< my_task_t > mgr_t
mgr_t::ptr_t task_mgr
#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_TEST(test_name, case_name)
Definition test_macros.h:47
#define CASE_EXPECT_TRUE(c)
Definition test_macros.h:97