libcopp  1.2.1
coroutine_task_manager_test.cpp
Go to the documentation of this file.
1 #include <cstdio>
2 #include <cstring>
3 #include <iostream>
4 
6 
7 #include "frame/test_macros.h"
8 #include <libcotask/task.h>
10 
11 #ifdef LIBCOTASK_MACRO_ENABLED
12 
13 static int g_test_coroutine_task_manager_status = 0;
14 class test_context_task_manager_action : public cotask::impl::task_action_impl {
15 public:
16  int operator()(void *) {
17  ++g_test_coroutine_task_manager_status;
18 
19  // CASE_EXPECT_EQ(cotask::EN_TS_RUNNING, cotask::this_task::get_task()->get_status());
20  // may be EN_TS_RUNNING or EN_TS_CANCELED or EN_TS_KILLED or EN_TS_TIMEOUT
22 
23  ++g_test_coroutine_task_manager_status;
24 
25  return 0;
26  }
27 };
28 
29 CASE_TEST(coroutine_task_manager, tickspec_t) {
32 
33  l.tv_sec = 123;
34  l.tv_nsec = 456;
35 
36  r.tv_sec = 123;
37  r.tv_nsec = 456;
38 
39  CASE_EXPECT_TRUE(l == r);
40  CASE_EXPECT_FALSE(l != r);
41  CASE_EXPECT_FALSE(l < r);
42  CASE_EXPECT_TRUE(l <= r);
43 
44  r.tv_sec = 456;
45  r.tv_nsec = 123;
46 
47  CASE_EXPECT_FALSE(l == r);
48  CASE_EXPECT_TRUE(l != r);
49  CASE_EXPECT_TRUE(l < r);
50  CASE_EXPECT_TRUE(l <= r);
51 
52  r.tv_sec = 45;
53  r.tv_nsec = 999;
54 
55  CASE_EXPECT_FALSE(l == r);
56  CASE_EXPECT_TRUE(l != r);
57  CASE_EXPECT_FALSE(l < r);
58  CASE_EXPECT_FALSE(l <= r);
59 }
60 
61 CASE_TEST(coroutine_task_manager, task_timer_node) {
64 
65  l.expired_time.tv_sec = 123;
66  l.expired_time.tv_nsec = 456;
67  l.task_id = 10;
68 
69  r.expired_time.tv_sec = 123;
70  r.expired_time.tv_nsec = 456;
71  r.task_id = 10;
72 
73  CASE_EXPECT_TRUE(l == r);
74  CASE_EXPECT_FALSE(l != r);
75  CASE_EXPECT_FALSE(l < r);
76  CASE_EXPECT_TRUE(l <= r);
77 
78  r.task_id = 5;
79 
80  CASE_EXPECT_FALSE(l == r);
81  CASE_EXPECT_TRUE(l != r);
82  CASE_EXPECT_FALSE(l < r);
83  CASE_EXPECT_FALSE(l <= r);
84 
85  r.expired_time.tv_nsec = 45;
86  r.task_id = 10;
87 
88  CASE_EXPECT_FALSE(l == r);
89  CASE_EXPECT_TRUE(l != r);
90  CASE_EXPECT_FALSE(l < r);
91  CASE_EXPECT_FALSE(l <= r);
92 
93  r.expired_time.tv_nsec = 456;
94  r.task_id = 15;
95 
96  CASE_EXPECT_FALSE(l == r);
97  CASE_EXPECT_TRUE(l != r);
98  CASE_EXPECT_TRUE(l < r);
99  CASE_EXPECT_TRUE(l <= r);
100 
101  r.expired_time.tv_nsec = 4567;
102  r.task_id = 10;
103 
104  CASE_EXPECT_FALSE(l == r);
105  CASE_EXPECT_TRUE(l != r);
106  CASE_EXPECT_TRUE(l < r);
107  CASE_EXPECT_TRUE(l <= r);
108 }
109 
110 CASE_TEST(coroutine_task_manager, add_and_timeout) {
112  task_ptr_type co_task = cotask::task<>::create(test_context_task_manager_action());
113  task_ptr_type co_another_task = cotask::task<>::create(test_context_task_manager_action()); // share action
114 
117 
118  CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
119  g_test_coroutine_task_manager_status = 0;
120 
121  task_mgr->add_task(co_task, 5, 0);
122  task_mgr->add_task(co_another_task);
123 
124  CASE_EXPECT_EQ(2, (int)task_mgr->get_task_size());
125  CASE_EXPECT_EQ(1, (int)task_mgr->get_tick_checkpoint_size());
126 
127  CASE_EXPECT_EQ(co_task, task_mgr->find_task(co_task->get_id()));
128  CASE_EXPECT_EQ(co_another_task, task_mgr->find_task(co_another_task->get_id()));
129 
130  CASE_EXPECT_EQ(0, (int)task_mgr->get_last_tick_time().tv_sec);
131  task_mgr->tick(3);
132  CASE_EXPECT_EQ(2, (int)task_mgr->get_task_size());
133  CASE_EXPECT_EQ(1, (int)task_mgr->get_tick_checkpoint_size());
134 
135  task_mgr->tick(8);
136  CASE_EXPECT_EQ(8, (int)task_mgr->get_last_tick_time().tv_sec);
137  CASE_EXPECT_EQ(1, (int)task_mgr->get_task_size());
138  CASE_EXPECT_EQ(0, (int)task_mgr->get_tick_checkpoint_size());
139  CASE_EXPECT_EQ(0, (int)task_mgr->get_checkpoints().size());
140 
141  task_mgr->tick(9);
142  CASE_EXPECT_EQ(9, (int)task_mgr->get_last_tick_time().tv_sec);
143  CASE_EXPECT_EQ(1, (int)task_mgr->get_task_size());
144  CASE_EXPECT_EQ(1, (int)task_mgr->get_container().size());
145  CASE_EXPECT_EQ(0, (int)task_mgr->get_tick_checkpoint_size());
146 
147  CASE_EXPECT_NE(co_task, task_mgr->find_task(co_task->get_id()));
148  CASE_EXPECT_EQ(co_another_task, task_mgr->find_task(co_another_task->get_id()));
149 
150  CASE_EXPECT_EQ(2, g_test_coroutine_task_manager_status);
151 
152  task_mgr->start(co_another_task->get_id());
153 
154  CASE_EXPECT_EQ(cotask::EN_TS_WAITING, co_another_task->get_status());
155 
156  CASE_EXPECT_EQ(3, g_test_coroutine_task_manager_status);
157  task_mgr->resume(co_another_task->get_id());
158  CASE_EXPECT_EQ(4, g_test_coroutine_task_manager_status);
159 
160  CASE_EXPECT_EQ(cotask::EN_TS_TIMEOUT, co_task->get_status());
161  CASE_EXPECT_EQ(cotask::EN_TS_DONE, co_another_task->get_status());
162 
163  CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
164  CASE_EXPECT_EQ(0, (int)task_mgr->get_tick_checkpoint_size());
165 
166  CASE_EXPECT_EQ(copp::COPP_EC_TASK_IS_EXITING, task_mgr->add_task(co_another_task));
167 
168  task_mgr.reset();
169 }
170 
171 
172 CASE_TEST(coroutine_task_manager, kill) {
174  task_ptr_type co_task = cotask::task<>::create(test_context_task_manager_action());
175  task_ptr_type co_another_task = cotask::task<>::create(test_context_task_manager_action()); // share action
176 
178  mgr_t::ptr_t task_mgr = mgr_t::create();
179 
180  CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
181  g_test_coroutine_task_manager_status = 0;
182  task_mgr->tick(10, 0);
183 
184  task_mgr->add_task(co_task, 10, 0);
185  task_mgr->add_task(co_another_task, 10, 0);
186 
187  task_mgr->start(co_task->get_id());
188 
189  CASE_EXPECT_EQ(2, (int)task_mgr->get_task_size());
190  CASE_EXPECT_EQ(2, (int)task_mgr->get_tick_checkpoint_size());
191 
192  task_mgr->kill(co_task->get_id());
193  task_mgr->cancel(co_another_task->get_id());
194 
195  CASE_EXPECT_EQ(4, g_test_coroutine_task_manager_status);
196 
197 
198  CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
199  CASE_EXPECT_EQ(0, (int)task_mgr->get_tick_checkpoint_size());
200 
201  CASE_EXPECT_EQ(cotask::EN_TS_KILLED, co_task->get_status());
202  CASE_EXPECT_EQ(cotask::EN_TS_CANCELED, co_another_task->get_status());
203 }
204 
205 CASE_TEST(coroutine_task_manager, multi_checkpoints) {
207  task_ptr_type co_task = cotask::task<>::create(test_context_task_manager_action());
208 
210  mgr_t::ptr_t task_mgr = mgr_t::create();
211 
212  CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
213  g_test_coroutine_task_manager_status = 0;
214 
215  task_mgr->add_task(co_task, 10, 0);
216  CASE_EXPECT_EQ(1, (int)task_mgr->get_task_size());
217  CASE_EXPECT_EQ(1, (int)task_mgr->get_tick_checkpoint_size());
218 
219  task_mgr->tick(5);
220 
221  CASE_EXPECT_EQ(1, (int)task_mgr->get_task_size());
222  CASE_EXPECT_EQ(1, (int)task_mgr->get_tick_checkpoint_size());
223 
224  task_mgr->tick(15, 1);
225 
226  CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
227  CASE_EXPECT_EQ(0, (int)task_mgr->get_tick_checkpoint_size());
228 
229  CASE_EXPECT_EQ(2, g_test_coroutine_task_manager_status);
230 }
231 
232 CASE_TEST(coroutine_task_manager, update_timeout) {
234  task_ptr_type co_task = cotask::task<>::create(test_context_task_manager_action());
235 
237  mgr_t::ptr_t task_mgr = mgr_t::create();
238 
239  CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
240  g_test_coroutine_task_manager_status = 0;
241 
242  task_mgr->add_task(co_task, 10, 0);
243  CASE_EXPECT_EQ(1, (int)task_mgr->get_task_size());
244  CASE_EXPECT_EQ(1, (int)task_mgr->get_tick_checkpoint_size());
245 
246  task_mgr->tick(5);
247  CASE_EXPECT_EQ(copp::COPP_EC_SUCCESS, task_mgr->set_timeout(co_task->get_id(), 20, 0));
248 
249  CASE_EXPECT_EQ(1, (int)task_mgr->get_task_size());
250  CASE_EXPECT_EQ(1, (int)task_mgr->get_tick_checkpoint_size());
251 
252  task_mgr->tick(24, 1);
253 
254  CASE_EXPECT_EQ(1, (int)task_mgr->get_task_size());
255  CASE_EXPECT_EQ(1, (int)task_mgr->get_tick_checkpoint_size());
256 
257  task_mgr->tick(25, 1);
258 
259  CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
260  CASE_EXPECT_EQ(0, (int)task_mgr->get_tick_checkpoint_size());
261 
262  CASE_EXPECT_EQ(2, g_test_coroutine_task_manager_status);
263 }
264 
265 class test_context_task_manager_action_protect_this_task : public cotask::impl::task_action_impl {
266 public:
267  int operator()(void *) {
268  int use_count = (int)cotask::this_task::get<cotask::task<> >()->use_count();
269  CASE_EXPECT_EQ(2, use_count);
271  use_count = (int)cotask::this_task::get<cotask::task<> >()->use_count();
272  // if we support rvalue-reference, reference may be smaller.
273  // remove action will be 3, resume and destroy will be 1 or 2
274  // CASE_EXPECT_TRUE(use_count >= 1 && use_count <= 3);
275  CASE_EXPECT_TRUE(use_count >= 1 && use_count <= 2);
276 
277  ++g_test_coroutine_task_manager_status;
278  return 0;
279  }
280 };
281 
282 CASE_TEST(coroutine_task_manager, protect_this_task) {
284 
285  {
287  mgr_t::ptr_t task_mgr = mgr_t::create();
288 
289 
290  g_test_coroutine_task_manager_status = 0;
291  task_ptr_type co_task = cotask::task<>::create(test_context_task_manager_action_protect_this_task());
292  cotask::task<>::id_t id_finished = co_task->get_id();
293  task_mgr->add_task(co_task);
294 
295 
296  co_task = cotask::task<>::create(test_context_task_manager_action_protect_this_task());
297  cotask::task<>::id_t id_unfinished = co_task->get_id();
298  task_mgr->add_task(co_task);
299 
300  co_task = cotask::task<>::create(test_context_task_manager_action_protect_this_task());
301  cotask::task<>::id_t id_removed = co_task->get_id();
302  task_mgr->add_task(co_task);
303 
304  co_task.reset();
305 
306  task_mgr->start(id_finished);
307  task_mgr->start(id_unfinished);
308  task_mgr->start(id_removed);
309 
310  CASE_EXPECT_EQ(3, (int)task_mgr->get_task_size());
311  task_mgr->resume(id_finished);
312 
313  CASE_EXPECT_EQ(2, (int)task_mgr->get_task_size());
314 
315  task_mgr->remove_task(id_removed);
316 
317  CASE_EXPECT_EQ(1, (int)task_mgr->get_task_size());
318  }
319 
320  // all task should be finished
321  CASE_EXPECT_EQ(3, (int)g_test_coroutine_task_manager_status);
322 }
323 
324 
325 #if ((defined(__cplusplus) && __cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1800)) && \
326  defined(UTIL_CONFIG_COMPILER_CXX_LAMBDAS) && UTIL_CONFIG_COMPILER_CXX_LAMBDAS
327 
328 static util::lock::atomic_int_type<int> g_test_coroutine_task_manager_atomic;
329 
330 static const int test_context_task_manager_action_mt_run_times = 10000;
331 enum { test_context_task_manager_action_mt_thread_num = 1000 };
332 
333 struct test_context_task_manager_action_mt_thread : public cotask::impl::task_action_impl {
334 public:
335  int operator()(void *run_count_p) {
336  assert(run_count_p);
337  int *run_count = reinterpret_cast<int *>(run_count_p);
338 
339  while (*run_count < test_context_task_manager_action_mt_run_times) {
340  ++(*run_count);
341  ++g_test_coroutine_task_manager_atomic;
342 
343  cotask::this_task::get_task()->yield(&run_count_p);
344 
345  run_count = reinterpret_cast<int *>(run_count_p);
346  }
347  return 0;
348  }
349 };
350 
351 struct test_context_task_manager_mt_thread_runner {
353  int run_count;
355  test_context_task_manager_mt_thread_runner(mgr_t::ptr_t mgr) : run_count(0), task_mgr(mgr) {}
356 
357  int operator()() {
359 
360  task_ptr_type co_task = cotask::task<>::create(test_context_task_manager_action_mt_thread(), 16 * 1024); // use 16KB for stack
361  cotask::task<>::id_t task_id = co_task->get_id();
362  task_mgr->add_task(co_task);
363 
364  task_mgr->start(task_id, &run_count);
365 
366  while (false == co_task->is_completed()) {
367  task_mgr->resume(task_id, &run_count);
368  }
369 
370  CASE_EXPECT_EQ(test_context_task_manager_action_mt_run_times, run_count);
371  return 0;
372  }
373 };
374 
375 CASE_TEST(coroutine_task_manager, create_and_run_mt) {
377  mgr_t::ptr_t task_mgr = mgr_t::create();
378 
379  g_test_coroutine_task_manager_atomic.store(0);
380 
381  std::unique_ptr<std::thread> thds[test_context_task_manager_action_mt_thread_num];
382  for (int i = 0; i < test_context_task_manager_action_mt_thread_num; ++i) {
383  thds[i].reset(new std::thread(test_context_task_manager_mt_thread_runner(task_mgr)));
384  }
385 
386  for (int i = 0; i < test_context_task_manager_action_mt_thread_num; ++i) {
387  thds[i]->join();
388  }
389 
390  CASE_EXPECT_EQ(test_context_task_manager_action_mt_run_times * test_context_task_manager_action_mt_thread_num,
391  g_test_coroutine_task_manager_atomic.load());
392 }
393 
394 #endif
395 
396 
397 #if defined(LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER) && LIBCOTASK_MACRO_AUTO_CLEANUP_MANAGER
398 CASE_TEST(coroutine_task_manager, auto_cleanup_for_manager) {
400  task_ptr_type co_task = cotask::task<>::create(test_context_task_manager_action());
401 
403  mgr_t::ptr_t task_mgr1 = mgr_t::create();
404  mgr_t::ptr_t task_mgr2 = mgr_t::create();
405 
406  CASE_EXPECT_EQ(0, task_mgr1->add_task(co_task, 5, 0));
407  CASE_EXPECT_EQ(copp::COPP_EC_TASK_ALREADY_IN_ANOTHER_MANAGER, task_mgr2->add_task(co_task, 5, 0));
408 
409  CASE_EXPECT_EQ(1, task_mgr1->get_task_size());
410  CASE_EXPECT_EQ(1, task_mgr1->get_tick_checkpoint_size());
411 
412  co_task->start();
413  co_task->resume();
414 
415  CASE_EXPECT_EQ(0, task_mgr1->get_task_size());
416  CASE_EXPECT_EQ(0, task_mgr1->get_tick_checkpoint_size());
417 }
418 #endif
419 
420 #endif
#define CASE_TEST(test_name, case_name)
Definition: test_macros.h:43
virtual int operator()(void *)=0
COPP_EC_TASK_IS_EXITING.
Definition: errno.h:36
void store(value_type desired, EXPLICIT_UNUSED_ATTR::util::lock::memory_order order=::util::lock::memory_order_seq_cst) UTIL_CONFIG_NOEXCEPT
COPP_EC_SUCCESS.
Definition: errno.h:12
COPP_EC_TASK_ALREADY_IN_ANOTHER_MANAGER.
Definition: errno.h:39
#define CASE_EXPECT_EQ(l, r)
Definition: test_macros.h:62
size_t use_count() const
Definition: task.h:614
cotask::task_manager< my_task_t > mgr_t
#define CASE_EXPECT_TRUE(c)
Definition: test_macros.h:60
std::shared_ptr< self_t > ptr_t
Definition: task_manager.h:109
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
#define CASE_EXPECT_NE(l, r)
Definition: test_macros.h:63
导入智能指针库 Licensed under the MIT licenses.
impl::task_impl * get_task() UTIL_CONFIG_NOEXCEPT
get current running task
Definition: this_task.cpp:15
value_type load(EXPLICIT_UNUSED_ATTR::util::lock::memory_order order=::util::lock::memory_order_seq_cst) const UTIL_CONFIG_NOEXCEPT
static ptr_t create()
create a new task manager
Definition: task_manager.h:188
#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
void reset() UTIL_CONFIG_NOEXCEPT
mgr_t::ptr_t task_mgr