libcopp  2.2.0
coroutine_context_this_coroutine_test.cpp
Go to the documentation of this file.
1 // Copyright 2023 owent
2 
3 #include "frame/test_macros.h"
4 
5 #include <assert.h>
6 #include <algorithm>
7 #include <cstdio>
8 #include <cstring>
9 #include <iostream>
10 
11 #include <atomic>
12 #include <chrono>
13 #include <functional>
14 #include <memory>
15 #include <thread>
16 #include <vector>
17 
19 #include <libcotask/task.h>
20 
22  public:
25 
26  public:
28  int operator()(void *passed) {
29  CASE_EXPECT_EQ(this, passed);
30 
31  ++cur_thd_count;
32 
34  CASE_EXPECT_EQ(addr_, this_co);
35 #ifdef LIBCOTASK_MACRO_ENABLED
37 #endif
38  run_ = true;
39 
40  std::chrono::milliseconds dura(4);
41  std::this_thread::sleep_for(dura);
42 
43  using std::max;
45 
46  --cur_thd_count;
47  return 0;
48  }
49 
50  void set_co_obj(value_ptr_type addr) { addr_ = addr; }
51  bool is_run() { return run_; }
52 
53  static int get_max_thd_count() { return max_thd_count; }
54 
55  private:
57  bool run_;
58  static std::atomic_int cur_thd_count;
59  static int max_thd_count;
60 };
61 
64 
65 static void test_this_context_thread_func(copp::coroutine_context_default::ptr_t co,
67  runner->set_co_obj(co.get());
68 
69  CASE_EXPECT_FALSE(runner->is_run());
70 
72  co->start(runner);
74 
75  CASE_EXPECT_TRUE(runner->is_run());
76 }
77 
78 CASE_TEST(this_context, get_coroutine) {
79  typedef copp::coroutine_context_default co_type;
80 
82  {
83  std::vector<std::thread> th_pool;
84  co_type::ptr_t co_arr[5];
85  for (int i = 0; i < 5; ++i) {
86  co_arr[i] = co_type::create(&runners[i], 128 * 1024);
87 
88  th_pool.push_back(
89  std::thread([&co_arr, &runners, i]() { test_this_context_thread_func(co_arr[i], &runners[i]); }));
90  }
91 
92  for (std::thread &th : th_pool) {
93  th.join();
94  }
95 
97  }
98 }
99 
101  public:
104 
105  public:
107  int operator()(void *) {
108  run_ = true;
110  finished_ = true;
111  return 0;
112  }
113 
114  bool is_run() { return run_; }
115 
116  bool is_finished() { return finished_; }
117 
118  private:
119  bool run_;
120  bool finished_;
121 };
122 
123 CASE_TEST(this_context, yield_) {
124  typedef copp::coroutine_context_default co_type;
125 
127  {
128  co_type::ptr_t co = co_type::create(&runner, 128 * 1024);
129 
131  co->start();
133 
134  CASE_EXPECT_TRUE(runner.is_run());
135  CASE_EXPECT_FALSE(runner.is_finished());
136  }
137 }
138 
142 
143  test_this_context_rec_runner() : jump_to(nullptr), owner(nullptr), has_yield(false), has_resume(false) {}
144  int operator()(void *co_startup_raw) {
145  copp::coroutine_context *ptr = copp::this_coroutine::get_coroutine();
146 
147  value_ptr_type *co_startup = reinterpret_cast<value_ptr_type *>(co_startup_raw);
148  if (nullptr == co_startup[0]) {
149  co_startup[0] = static_cast<value_ptr_type>(ptr);
150  } else {
151  co_startup[1] = static_cast<value_ptr_type>(ptr);
152  }
153 
154  CASE_EXPECT_EQ(ptr, owner);
155 
156  if (nullptr != jump_to && nullptr != jump_to->owner) {
159  int res = jump_to->owner->start(co_startup_raw);
162 
163  jump_to->has_resume = true;
164  jump_to->owner->resume(co_startup_raw);
165  CASE_EXPECT_EQ(0, res);
166  }
167 
169  CASE_EXPECT_EQ(ptr, owner);
170 
171  CASE_EXPECT_EQ(false, has_yield);
172  CASE_EXPECT_EQ(false, has_resume);
173 
174  has_yield = true;
175  owner->yield();
176 
177  CASE_EXPECT_EQ(true, has_yield);
178  CASE_EXPECT_EQ(true, has_resume);
179  return 0;
180  }
181 
184  bool has_yield;
186 };
187 
188 CASE_TEST(this_context, start_in_co) {
190 
191  co_type *co_startup[2] = {nullptr};
192 
193  test_this_context_rec_runner cor1, cor2;
194 
195  {
196  co_type::ptr_t co1, co2;
197  co1 = co_type::create(&cor1, 128 * 1024);
198  co2 = co_type::create(&cor2, 128 * 1024);
199  cor1.owner = co1.get();
200  cor2.owner = co2.get();
201 
203  cor1.jump_to = &cor2;
204 
205  CASE_EXPECT_EQ(false, cor1.has_yield);
206  CASE_EXPECT_EQ(false, cor1.has_resume);
207  co1->start(co_startup);
208  CASE_EXPECT_EQ(true, cor1.has_yield);
209  CASE_EXPECT_EQ(false, cor1.has_resume);
210  cor1.has_resume = true;
211  co1->resume(co_startup);
212 
214 
215  CASE_EXPECT_EQ(co1.get(), co_startup[0]);
216  CASE_EXPECT_EQ(co2.get(), co_startup[1]);
217  }
218 }
219 
222 
224  int operator()(void *pco2) {
225  value_type *ptr = copp::this_coroutine::get<value_type>();
226 
227  value_type *co_jump = reinterpret_cast<value_type *>(pco2);
228 
229  if (is_start) {
230  CASE_EXPECT_NE(nullptr, co_jump);
231  co_jump->start(ptr);
232  } else {
233  CASE_EXPECT_NE(nullptr, co_jump);
234  int res = co_jump->start(ptr); // this should be COPP_EC_IS_RUNNING
236  }
237 
238  // finished and return to caller
239  return 0;
240  }
241 
242  bool is_start;
243 };
244 
245 CASE_TEST(this_context, start_failed_when_running) {
247 
249 
250  {
251  co_type::ptr_t co1, co2;
252  co1 = co_type::create(&cor1, 128 * 1024);
253  co2 = co_type::create(&cor2, 128 * 1024);
254 
255  cor1.is_start = true;
256  co1->start(co2.get());
257  }
258 }
coroutine_context_container< allocator::default_statck_allocator > coroutine_context_default
CASE_TEST(this_context, get_coroutine)
static void test_this_context_thread_func(copp::coroutine_context_default::ptr_t co, test_this_context_get_cotoutine_runner *runner)
@ COPP_EC_IS_RUNNING
COPP_EC_IS_RUNNING.
Definition: errno.h:26
LIBCOPP_COPP_API int yield(void **priv_data=nullptr) LIBCOPP_MACRO_NOEXCEPT
yield current coroutine
LIBCOPP_COPP_API coroutine_context * get_coroutine() LIBCOPP_MACRO_NOEXCEPT
get current coroutine
LIBCOPP_COTASK_API impl::task_impl * get_task() LIBCOPP_MACRO_NOEXCEPT
get current running task
Definition: this_task.cpp:9
copp::coroutine_context_default::ptr_t * co_arr
#define CASE_EXPECT_FALSE(c)
Definition: test_macros.h:95
#define CASE_EXPECT_EQ(l, r)
Definition: test_macros.h:96
#define CASE_EXPECT_NE(l, r)
Definition: test_macros.h:97
#define CASE_EXPECT_LT(l, r)
Definition: test_macros.h:98
#define CASE_EXPECT_TRUE(c)
Definition: test_macros.h:94