libcopp  1.2.0
coroutine_context_this_coroutine_test.cpp
Go to the documentation of this file.
1 /*
2  * couroutine_context_this_coroutine_test.cpp
3  *
4  * Created on: 2014年3月17日
5  * Author: owent
6  *
7  * Released under the MIT license
8  */
9 
10 #if (defined(__cplusplus) && __cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
11 
12 #include <algorithm>
13 #include <assert.h>
14 #include <cstdio>
15 #include <cstring>
16 #include <iostream>
17 
18 #include <atomic>
19 #include <chrono>
20 #include <functional>
21 #include <memory>
22 #include <thread>
23 #include <vector>
24 
25 #include "frame/test_macros.h"
26 
28 #include <libcotask/task.h>
29 
30 class test_this_context_get_cotoutine_runner {
31 public:
33  typedef value_type * value_ptr_type;
34 
35 public:
36  test_this_context_get_cotoutine_runner() : addr_(NULL), run_(false) {}
37  int operator()(void *passed) {
38  CASE_EXPECT_EQ(this, passed);
39 
40  ++cur_thd_count;
41 
42  value_ptr_type this_co = static_cast<value_ptr_type>(copp::this_coroutine::get_coroutine());
43  CASE_EXPECT_EQ(addr_, this_co);
44 #ifdef LIBCOTASK_MACRO_ENABLED
46 #endif
47  run_ = true;
48 
49  std::chrono::milliseconds dura(4);
50  std::this_thread::sleep_for(dura);
51 
52  using std::max;
53  max_thd_count = max(max_thd_count, cur_thd_count.load());
54 
55  --cur_thd_count;
56  return 0;
57  }
58 
59  void set_co_obj(value_ptr_type addr) { addr_ = addr; }
60  bool is_run() { return run_; }
61 
62  static int get_max_thd_count() { return max_thd_count; }
63 
64 private:
65  value_ptr_type addr_;
66  bool run_;
67  static std::atomic_int cur_thd_count;
68  static int max_thd_count;
69 };
70 
71 std::atomic_int test_this_context_get_cotoutine_runner::cur_thd_count;
72 int test_this_context_get_cotoutine_runner::max_thd_count = 0;
73 
74 static void test_this_context_thread_func(copp::coroutine_context_default::ptr_t co, test_this_context_get_cotoutine_runner *runner) {
75 
76  runner->set_co_obj(co.get());
77 
78  CASE_EXPECT_FALSE(runner->is_run());
79 
81  co->start(runner);
83 
84  CASE_EXPECT_TRUE(runner->is_run());
85 }
86 
87 CASE_TEST(this_context, get_coroutine) {
88  typedef copp::coroutine_context_default co_type;
89 
90  test_this_context_get_cotoutine_runner runners[5];
91  {
92  std::vector<std::thread> th_pool;
93  co_type::ptr_t co_arr[5];
94  for (int i = 0; i < 5; ++i) {
95  co_arr[i] = co_type::create(&runners[i], 128 * 1024);
96 
97  th_pool.push_back(std::thread(std::bind(test_this_context_thread_func, co_arr[i], &runners[i])));
98  }
99 
100  for (std::thread &th : th_pool) {
101  th.join();
102  }
103 
104  CASE_EXPECT_LT(1, test_this_context_get_cotoutine_runner::get_max_thd_count());
105  }
106 }
107 
108 
109 class test_this_context_yield_runner {
110 public:
112  typedef value_type * value_ptr_type;
113 
114 public:
115  test_this_context_yield_runner() : run_(false), finished_(false) {}
116  int operator()(void *) {
117  run_ = true;
119  finished_ = true;
120  return 0;
121  }
122 
123  bool is_run() { return run_; }
124 
125  bool is_finished() { return finished_; }
126 
127 private:
128  bool run_;
129  bool finished_;
130 };
131 
132 CASE_TEST(this_context, yield_) {
133  typedef copp::coroutine_context_default co_type;
134 
135  test_this_context_yield_runner runner;
136  {
137  co_type::ptr_t co = co_type::create(&runner, 128 * 1024);
138 
140  co->start();
142 
143  CASE_EXPECT_TRUE(runner.is_run());
144  CASE_EXPECT_FALSE(runner.is_finished());
145  }
146 }
147 
148 
149 struct test_this_context_rec_runner {
151  typedef value_type * value_ptr_type;
152 
153  test_this_context_rec_runner() : jump_to(NULL), owner(NULL), has_yield(false), has_resume(false) {}
154  int operator()(void *co_startup_raw) {
156 
157  value_ptr_type *co_startup = reinterpret_cast<value_ptr_type *>(co_startup_raw);
158  if (NULL == co_startup[0]) {
159  co_startup[0] = static_cast<value_ptr_type>(ptr);
160  } else {
161  co_startup[1] = static_cast<value_ptr_type>(ptr);
162  }
163 
164  CASE_EXPECT_EQ(ptr, owner);
165 
166  if (NULL != jump_to && NULL != jump_to->owner) {
167  CASE_EXPECT_EQ(false, jump_to->has_yield);
168  CASE_EXPECT_EQ(false, jump_to->has_resume);
169  int res = jump_to->owner->start(co_startup_raw);
170  CASE_EXPECT_EQ(true, jump_to->has_yield);
171  CASE_EXPECT_EQ(false, jump_to->has_resume);
172 
173  jump_to->has_resume = true;
174  jump_to->owner->resume(co_startup_raw);
175  CASE_EXPECT_EQ(0, res);
176  }
177 
179  CASE_EXPECT_EQ(ptr, owner);
180 
181  CASE_EXPECT_EQ(false, has_yield);
182  CASE_EXPECT_EQ(false, has_resume);
183 
184  has_yield = true;
185  owner->yield();
186 
187  CASE_EXPECT_EQ(true, has_yield);
188  CASE_EXPECT_EQ(true, has_resume);
189  return 0;
190  }
191 
192  test_this_context_rec_runner *jump_to;
193  value_ptr_type owner;
194  bool has_yield;
195  bool has_resume;
196 };
197 
198 CASE_TEST(this_context, start_in_co) {
200 
201  co_type *co_startup[2] = {NULL};
202 
203  test_this_context_rec_runner cor1, cor2;
204 
205  {
206  co_type::ptr_t co1, co2;
207  co1 = co_type::create(&cor1, 128 * 1024);
208  co2 = co_type::create(&cor2, 128 * 1024);
209  cor1.owner = co1.get();
210  cor2.owner = co2.get();
211 
212 
214  cor1.jump_to = &cor2;
215 
216  CASE_EXPECT_EQ(false, cor1.has_yield);
217  CASE_EXPECT_EQ(false, cor1.has_resume);
218  co1->start(co_startup);
219  CASE_EXPECT_EQ(true, cor1.has_yield);
220  CASE_EXPECT_EQ(false, cor1.has_resume);
221  cor1.has_resume = true;
222  co1->resume(co_startup);
223 
225 
226  CASE_EXPECT_EQ(co1.get(), co_startup[0]);
227  CASE_EXPECT_EQ(co2.get(), co_startup[1]);
228  }
229 }
230 
231 struct test_this_context_start_failed_when_running {
233 
234  test_this_context_start_failed_when_running() : is_start(false) {}
235  int operator()(void *pco2) {
236  value_type *ptr = copp::this_coroutine::get<value_type>();
237 
238  value_type *co_jump = reinterpret_cast<value_type *>(pco2);
239 
240  if (is_start) {
241  CASE_EXPECT_NE(NULL, co_jump);
242  co_jump->start(ptr);
243  } else {
244  CASE_EXPECT_NE(NULL, co_jump);
245  int res = co_jump->start(ptr); // this should be COPP_EC_IS_RUNNING
247  }
248 
249  // finished and return to caller
250  return 0;
251  }
252 
253  bool is_start;
254 };
255 
256 CASE_TEST(this_context, start_failed_when_running) {
258 
259  test_this_context_start_failed_when_running cor1, cor2;
260 
261  {
262  co_type::ptr_t co1, co2;
263  co1 = co_type::create(&cor1, 128 * 1024);
264  co2 = co_type::create(&cor2, 128 * 1024);
265 
266  cor1.is_start = true;
267  co1->start(co2.get());
268  }
269 }
270 
271 
272 #endif
#define CASE_TEST(test_name, case_name)
Definition: test_macros.h:43
#define CASE_EXPECT_EQ(l, r)
Definition: test_macros.h:62
#define CASE_EXPECT_TRUE(c)
Definition: test_macros.h:60
coroutine_context * get_coroutine() UTIL_CONFIG_NOEXCEPT
get current coroutine
COPP_EC_IS_RUNNING.
Definition: errno.h:26
copp::coroutine_context_default::ptr_t * co_arr
int yield(void **priv_data=UTIL_CONFIG_NULLPTR)
yield current coroutine
#define CASE_EXPECT_NE(l, r)
Definition: test_macros.h:63
coroutine container contain stack context, stack allocator and runtime fcontext
impl::task_impl * get_task() UTIL_CONFIG_NOEXCEPT
get current running task
Definition: this_task.cpp:15
element_type * get() const UTIL_CONFIG_NOEXCEPT
#define CASE_EXPECT_LT(l, r)
Definition: test_macros.h:64
#define CASE_EXPECT_FALSE(c)
Definition: test_macros.h:61
std::shared_ptr< cli::cmd_option_value > value_type
Definition: cmd_option.h:53
base type of all coroutine context