libcopp  1.1.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"
27 
28 class test_this_context_get_cotoutine_runner {
29 public:
31  typedef value_type *value_ptr_type;
32 
33 public:
34  test_this_context_get_cotoutine_runner() : addr_(NULL), run_(false) {}
35  int operator()(void* passed) {
36  CASE_EXPECT_EQ(this, passed);
37 
38  ++cur_thd_count;
39 
40  value_ptr_type this_co = static_cast<value_ptr_type>(copp::this_coroutine::get_coroutine());
41  CASE_EXPECT_EQ(addr_, this_co);
42  run_ = true;
43 
44  std::chrono::milliseconds dura(4);
45  std::this_thread::sleep_for(dura);
46 
47  using std::max;
48  max_thd_count = max(max_thd_count, cur_thd_count.load());
49 
50  --cur_thd_count;
51  return 0;
52  }
53 
54  void set_co_obj(value_ptr_type addr) { addr_ = addr; }
55  bool is_run() { return run_; }
56 
57  static int get_max_thd_count() { return max_thd_count; }
58 
59 private:
60  value_ptr_type addr_;
61  bool run_;
62  static std::atomic_int cur_thd_count;
63  static int max_thd_count;
64 };
65 
66 std::atomic_int test_this_context_get_cotoutine_runner::cur_thd_count;
67 int test_this_context_get_cotoutine_runner::max_thd_count = 0;
68 
69 static void test_this_context_thread_func(copp::coroutine_context_default::ptr_t co, test_this_context_get_cotoutine_runner* runner) {
70 
71  runner->set_co_obj(co.get());
72 
73  CASE_EXPECT_FALSE(runner->is_run());
74 
76  co->start(runner);
78 
79  CASE_EXPECT_TRUE(runner->is_run());
80 }
81 
82 CASE_TEST(this_context, get_coroutine) {
83  typedef copp::coroutine_context_default co_type;
84 
85  test_this_context_get_cotoutine_runner runners[5];
86  {
87  std::vector<std::thread> th_pool;
88  co_type::ptr_t co_arr[5];
89  for (int i = 0; i < 5 ; ++ i) {
90  co_arr[i] = co_type::create(&runners[i], 128 * 1024);
91 
92  th_pool.push_back(std::thread(std::bind(test_this_context_thread_func, co_arr[i], &runners[i])));
93  }
94 
95  for (std::thread &th : th_pool) {
96  th.join();
97  }
98 
99  CASE_EXPECT_LT(1, test_this_context_get_cotoutine_runner::get_max_thd_count());
100  }
101 }
102 
103 
104 class test_this_context_yield_runner {
105 public:
107  typedef value_type *value_ptr_type;
108 
109 public:
110  test_this_context_yield_runner() : run_(false), finished_(false) {}
111  int operator()(void*) {
112  run_ = true;
114  finished_ = true;
115  return 0;
116  }
117 
118  bool is_run() { return run_; }
119 
120  bool is_finished() { return finished_; }
121 
122 private:
123  bool run_;
124  bool finished_;
125 };
126 
127 CASE_TEST(this_context, yield_) {
128  typedef copp::coroutine_context_default co_type;
129 
130  test_this_context_yield_runner runner;
131  {
132  co_type::ptr_t co = co_type::create(&runner, 128 * 1024);
133 
135  co->start();
137 
138  CASE_EXPECT_TRUE(runner.is_run());
139  CASE_EXPECT_FALSE(runner.is_finished());
140 
141  }
142 }
143 
144 
145 struct test_this_context_rec_runner {
147  typedef value_type *value_ptr_type;
148 
149  test_this_context_rec_runner() : jump_to(NULL), owner(NULL), has_yield(false), has_resume(false) {}
150  int operator()(void* co_startup_raw) {
152 
153  value_ptr_type *co_startup = reinterpret_cast<value_ptr_type *>(co_startup_raw);
154  if (NULL == co_startup[0]) {
155  co_startup[0] = static_cast<value_ptr_type>(ptr);
156  } else {
157  co_startup[1] = static_cast<value_ptr_type>(ptr);
158  }
159 
160  CASE_EXPECT_EQ(ptr, owner);
161 
162  if (NULL != jump_to && NULL != jump_to->owner) {
163  CASE_EXPECT_EQ(false, jump_to->has_yield);
164  CASE_EXPECT_EQ(false, jump_to->has_resume);
165  int res = jump_to->owner->start(co_startup_raw);
166  CASE_EXPECT_EQ(true, jump_to->has_yield);
167  CASE_EXPECT_EQ(false, jump_to->has_resume);
168 
169  jump_to->has_resume = true;
170  jump_to->owner->resume(co_startup_raw);
171  CASE_EXPECT_EQ(0, res);
172  }
173 
175  CASE_EXPECT_EQ(ptr, owner);
176 
177  CASE_EXPECT_EQ(false, has_yield);
178  CASE_EXPECT_EQ(false, has_resume);
179 
180  has_yield = true;
181  owner->yield();
182 
183  CASE_EXPECT_EQ(true, has_yield);
184  CASE_EXPECT_EQ(true, has_resume);
185  return 0;
186  }
187 
188  test_this_context_rec_runner *jump_to;
189  value_ptr_type owner;
190  bool has_yield;
191  bool has_resume;
192 };
193 
194 CASE_TEST(this_context, start_in_co) {
196 
197  co_type *co_startup[2] = {NULL};
198 
199  test_this_context_rec_runner cor1, cor2;
200 
201  {
202  co_type::ptr_t co1, co2;
203  co1 = co_type::create(&cor1, 128 * 1024);
204  co2 = co_type::create(&cor2, 128 * 1024);
205  cor1.owner = co1.get();
206  cor2.owner = co2.get();
207 
208 
210  cor1.jump_to = &cor2;
211 
212  CASE_EXPECT_EQ(false, cor1.has_yield);
213  CASE_EXPECT_EQ(false, cor1.has_resume);
214  co1->start(co_startup);
215  CASE_EXPECT_EQ(true, cor1.has_yield);
216  CASE_EXPECT_EQ(false, cor1.has_resume);
217  cor1.has_resume = true;
218  co1->resume(co_startup);
219 
221 
222  CASE_EXPECT_EQ(co1.get(), co_startup[0]);
223  CASE_EXPECT_EQ(co2.get(), co_startup[1]);
224  }
225 }
226 
227 struct test_this_context_start_failed_when_running {
229 
230  test_this_context_start_failed_when_running(): is_start(false) {}
231  int operator()(void* pco2) {
232  value_type *ptr = copp::this_coroutine::get<value_type>();
233 
234  value_type *co_jump = reinterpret_cast<value_type*>(pco2);
235 
236  if (is_start) {
237  CASE_EXPECT_NE(NULL, co_jump);
238  co_jump->start(ptr);
239  } else {
240  CASE_EXPECT_NE(NULL, co_jump);
241  int res = co_jump->start(ptr); // this should be COPP_EC_IS_RUNNING
243  }
244 
245  // finished and return to caller
246  return 0;
247  }
248 
249  bool is_start;
250 };
251 
252 CASE_TEST(this_context, start_failed_when_running) {
254 
255  test_this_context_start_failed_when_running cor1, cor2;
256 
257  {
258  co_type::ptr_t co1, co2;
259  co1 = co_type::create(&cor1, 128 * 1024);
260  co2 = co_type::create(&cor2, 128 * 1024);
261 
262  cor1.is_start = true;
263  co1->start(co2.get());
264  }
265 }
266 
267 
268 #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
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