libcopp  1.1.0
coroutine_task_manager_test.cpp
Go to the documentation of this file.
1 #ifdef LIBCOTASK_MACRO_ENABLED
2 
3 #include <cstdio>
4 #include <cstring>
5 #include <iostream>
6 
8 
9 #include "frame/test_macros.h"
10 #include <libcotask/task.h>
11 #include <libcotask/task_manager.h>
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 
30 CASE_TEST(coroutine_task_manager, add_and_timeout) {
32  task_ptr_type co_task = cotask::task<>::create(test_context_task_manager_action());
33  task_ptr_type co_another_task = cotask::task<>::create(test_context_task_manager_action()); // share action
34 
37 
38  CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
39  g_test_coroutine_task_manager_status = 0;
40 
41  task_mgr->add_task(co_task, 5, 0);
42  task_mgr->add_task(co_another_task);
43 
44  CASE_EXPECT_EQ(2, (int)task_mgr->get_task_size());
45  CASE_EXPECT_EQ(1, (int)task_mgr->get_tick_checkpoint_size());
46 
47  CASE_EXPECT_EQ(co_task, task_mgr->find_task(co_task->get_id()));
48  CASE_EXPECT_EQ(co_another_task, task_mgr->find_task(co_another_task->get_id()));
49 
50  CASE_EXPECT_EQ(0, (int)task_mgr->get_last_tick_time().tv_sec);
51  task_mgr->tick(3);
52  CASE_EXPECT_EQ(2, (int)task_mgr->get_task_size());
53  CASE_EXPECT_EQ(1, (int)task_mgr->get_tick_checkpoint_size());
54 
55  task_mgr->tick(8);
56  CASE_EXPECT_EQ(8, (int)task_mgr->get_last_tick_time().tv_sec);
57  CASE_EXPECT_EQ(2, (int)task_mgr->get_task_size());
58  CASE_EXPECT_EQ(1, (int)task_mgr->get_tick_checkpoint_size());
59  CASE_EXPECT_EQ(1, (int)task_mgr->get_checkpoints().size());
60 
61  task_mgr->tick(9);
62  CASE_EXPECT_EQ(9, (int)task_mgr->get_last_tick_time().tv_sec);
63  CASE_EXPECT_EQ(1, (int)task_mgr->get_task_size());
64  CASE_EXPECT_EQ(1, (int)task_mgr->get_container().size());
65  CASE_EXPECT_EQ(0, (int)task_mgr->get_tick_checkpoint_size());
66 
67  CASE_EXPECT_NE(co_task, task_mgr->find_task(co_task->get_id()));
68  CASE_EXPECT_EQ(co_another_task, task_mgr->find_task(co_another_task->get_id()));
69 
70  CASE_EXPECT_EQ(2, g_test_coroutine_task_manager_status);
71 
72  task_mgr->start(co_another_task->get_id());
73 
74  CASE_EXPECT_EQ(cotask::EN_TS_WAITING, co_another_task->get_status());
75 
76  CASE_EXPECT_EQ(3, g_test_coroutine_task_manager_status);
77  task_mgr->resume(co_another_task->get_id());
78  CASE_EXPECT_EQ(4, g_test_coroutine_task_manager_status);
79 
80  CASE_EXPECT_EQ(cotask::EN_TS_TIMEOUT, co_task->get_status());
81  CASE_EXPECT_EQ(cotask::EN_TS_DONE, co_another_task->get_status());
82 
83  CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
84  CASE_EXPECT_EQ(0, (int)task_mgr->get_tick_checkpoint_size());
85 }
86 
87 
88 CASE_TEST(coroutine_task_manager, kill) {
90  task_ptr_type co_task = cotask::task<>::create(test_context_task_manager_action());
91  task_ptr_type co_another_task = cotask::task<>::create(test_context_task_manager_action()); // share action
92 
94  mgr_t::ptr_t task_mgr = mgr_t::create();
95 
96  CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
97  g_test_coroutine_task_manager_status = 0;
98  task_mgr->tick(10, 0);
99 
100  task_mgr->add_task(co_task, 10, 0);
101  task_mgr->add_task(co_another_task, 10, 0);
102 
103  task_mgr->start(co_task->get_id());
104 
105  CASE_EXPECT_EQ(2, (int)task_mgr->get_task_size());
106  CASE_EXPECT_EQ(2, (int)task_mgr->get_tick_checkpoint_size());
107 
108  task_mgr->kill(co_task->get_id());
109  task_mgr->cancel(co_another_task->get_id());
110 
111  CASE_EXPECT_EQ(4, g_test_coroutine_task_manager_status);
112 
113 
114  CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
115  CASE_EXPECT_EQ(2, (int)task_mgr->get_tick_checkpoint_size());
116 
117  CASE_EXPECT_EQ(cotask::EN_TS_KILLED, co_task->get_status());
118  CASE_EXPECT_EQ(cotask::EN_TS_CANCELED, co_another_task->get_status());
119 }
120 
121 CASE_TEST(coroutine_task_manager, multi_checkpoints) {
123  task_ptr_type co_task = cotask::task<>::create(test_context_task_manager_action());
124 
126  mgr_t::ptr_t task_mgr = mgr_t::create();
127 
128  CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
129  g_test_coroutine_task_manager_status = 0;
130 
131  task_mgr->add_task(co_task, 10, 0);
132  CASE_EXPECT_EQ(1, (int)task_mgr->get_task_size());
133  CASE_EXPECT_EQ(1, (int)task_mgr->get_tick_checkpoint_size());
134 
135  task_mgr->tick(5);
136 
137  CASE_EXPECT_EQ(1, (int)task_mgr->get_task_size());
138  CASE_EXPECT_EQ(1, (int)task_mgr->get_tick_checkpoint_size());
139 
140  task_mgr->tick(15, 1);
141 
142  CASE_EXPECT_EQ(0, (int)task_mgr->get_task_size());
143  CASE_EXPECT_EQ(0, (int)task_mgr->get_tick_checkpoint_size());
144 
145  CASE_EXPECT_EQ(2, g_test_coroutine_task_manager_status);
146 }
147 
148 
149 class test_context_task_manager_action_protect_this_task : public cotask::impl::task_action_impl {
150 public:
151  int operator()(void *) {
152  int use_count = (int)cotask::this_task::get<cotask::task<> >()->use_count();
153  CASE_EXPECT_EQ(2, use_count);
155  use_count = (int)cotask::this_task::get<cotask::task<> >()->use_count();
156  // if we support rvalue-reference, reference may be smaller.
157  // remove action will be 3, resume and destroy will be 1 or 2
158  // CASE_EXPECT_TRUE(use_count >= 1 && use_count <= 3);
159  CASE_EXPECT_TRUE(use_count >= 1 && use_count <= 2);
160 
161  ++g_test_coroutine_task_manager_status;
162  return 0;
163  }
164 };
165 
166 CASE_TEST(coroutine_task_manager, protect_this_task) {
168 
169  {
171  mgr_t::ptr_t task_mgr = mgr_t::create();
172 
173 
174  g_test_coroutine_task_manager_status = 0;
175  task_ptr_type co_task = cotask::task<>::create(test_context_task_manager_action_protect_this_task());
176  cotask::task<>::id_t id_finished = co_task->get_id();
177  task_mgr->add_task(co_task);
178 
179 
180  co_task = cotask::task<>::create(test_context_task_manager_action_protect_this_task());
181  cotask::task<>::id_t id_unfinished = co_task->get_id();
182  task_mgr->add_task(co_task);
183 
184  co_task = cotask::task<>::create(test_context_task_manager_action_protect_this_task());
185  cotask::task<>::id_t id_removed = co_task->get_id();
186  task_mgr->add_task(co_task);
187 
188  co_task.reset();
189 
190  task_mgr->start(id_finished);
191  task_mgr->start(id_unfinished);
192  task_mgr->start(id_removed);
193 
194  CASE_EXPECT_EQ(3, (int)task_mgr->get_task_size());
195  task_mgr->resume(id_finished);
196 
197  CASE_EXPECT_EQ(2, (int)task_mgr->get_task_size());
198 
199  task_mgr->remove_task(id_removed);
200 
201  CASE_EXPECT_EQ(1, (int)task_mgr->get_task_size());
202  }
203 
204  // all task should be finished
205  CASE_EXPECT_EQ(3, (int)g_test_coroutine_task_manager_status);
206 }
207 
208 
209 #if ((defined(__cplusplus) && __cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1800)) && \
210  defined(UTIL_CONFIG_COMPILER_CXX_LAMBDAS) && UTIL_CONFIG_COMPILER_CXX_LAMBDAS
211 
212 static util::lock::atomic_int_type<int> g_test_coroutine_task_manager_atomic;
213 
214 static const int test_context_task_manager_action_mt_run_times = 10000;
215 enum { test_context_task_manager_action_mt_thread_num = 1000 };
216 
217 struct test_context_task_manager_action_mt_thread : public cotask::impl::task_action_impl {
218 public:
219  int operator()(void *run_count_p) {
220  assert(run_count_p);
221  int *run_count = reinterpret_cast<int *>(run_count_p);
222 
223  while (*run_count < test_context_task_manager_action_mt_run_times) {
224  ++(*run_count);
225  ++g_test_coroutine_task_manager_atomic;
226 
227  cotask::this_task::get_task()->yield(&run_count_p);
228 
229  run_count = reinterpret_cast<int *>(run_count_p);
230  }
231  return 0;
232  }
233 };
234 
235 struct test_context_task_manager_mt_thread_runner {
237  int run_count;
239  test_context_task_manager_mt_thread_runner(mgr_t::ptr_t mgr) : run_count(0), task_mgr(mgr) {}
240 
241  int operator()() {
243 
244  task_ptr_type co_task = cotask::task<>::create(test_context_task_manager_action_mt_thread(), 16 * 1024); // use 16KB for stack
245  cotask::task<>::id_t task_id = co_task->get_id();
246  task_mgr->add_task(co_task);
247 
248  task_mgr->start(task_id, &run_count);
249 
250  while (false == co_task->is_completed()) {
251  task_mgr->resume(task_id, &run_count);
252  }
253 
254  CASE_EXPECT_EQ(test_context_task_manager_action_mt_run_times, run_count);
255  return 0;
256  }
257 };
258 
259 CASE_TEST(coroutine_task_manager, create_and_run_mt) {
261  mgr_t::ptr_t task_mgr = mgr_t::create();
262 
263  g_test_coroutine_task_manager_atomic.store(0);
264 
265  std::unique_ptr<std::thread> thds[test_context_task_manager_action_mt_thread_num];
266  for (int i = 0; i < test_context_task_manager_action_mt_thread_num; ++i) {
267  thds[i].reset(new std::thread(test_context_task_manager_mt_thread_runner(task_mgr)));
268  }
269 
270  for (int i = 0; i < test_context_task_manager_action_mt_thread_num; ++i) {
271  thds[i]->join();
272  }
273 
274  CASE_EXPECT_EQ(test_context_task_manager_action_mt_run_times * test_context_task_manager_action_mt_thread_num,
275  g_test_coroutine_task_manager_atomic.load());
276 }
277 
278 #endif
279 
280 #endif
#define CASE_TEST(test_name, case_name)
Definition: test_macros.h:43
virtual int operator()(void *)=0
void store(value_type desired, EXPLICIT_UNUSED_ATTR::util::lock::memory_order order=::util::lock::memory_order_seq_cst) UTIL_CONFIG_NOEXCEPT
#define CASE_EXPECT_EQ(l, r)
Definition: test_macros.h:62
size_t use_count() const
Definition: task.h:606
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:63
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:155
macro_task_t::id_t id_t
Definition: task.h:37
task manager
Definition: task_manager.h:56
#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:139
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