libcopp  2.2.0
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 
18 namespace {
19 struct task_manager_future_private_data {};
20 
21 using task_future_int_type = cotask::task_future<int, task_manager_future_private_data>;
22 using generator_future_int_type = copp::generator_future<int>;
23 
24 std::list<generator_future_int_type::context_pointer_type> g_task_manager_future_pending_int_contexts;
25 size_t g_task_manager_future_resume_generator_count = 0;
26 size_t g_task_manager_future_suspend_generator_count = 0;
27 
28 static 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 
51 static 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 }
55 static void task_manager_generator_int_resume_callback(const generator_future_int_type::context_type&) {
56  ++g_task_manager_future_resume_generator_count;
57 }
58 
59 static 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 
68 CASE_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 
100 CASE_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 
149 CASE_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 
225 CASE_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 
296 CASE_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 
360 CASE_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 
398 CASE_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 
432 CASE_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
473 CASE_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 
502 CASE_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
539 namespace {
540 static 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 
550 static 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 
563 CASE_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 
596 CASE_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
632 CASE_TEST(task_promise_task_manager, disabled) {}
633 # endif
634 #else
635 CASE_TEST(task_promise_task_manager, disabled) {}
636 #endif
@ COPP_EC_SUCCESS
COPP_EC_SUCCESS.
Definition: errno.h:12
@ COPP_EC_TASK_IS_EXITING
COPP_EC_TASK_IS_EXITING.
Definition: errno.h:38
@ COPP_EC_TASK_ALREADY_IN_ANOTHER_MANAGER
COPP_EC_TASK_ALREADY_IN_ANOTHER_MANAGER.
Definition: errno.h:41
cotask::task_manager< my_task_t > mgr_t
mgr_t::ptr_t task_mgr
CASE_TEST(task_promise_task_manager, disabled)
#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_TRUE(c)
Definition: test_macros.h:94