libcopp  1.1.0
coroutine_context.h
Go to the documentation of this file.
1 #ifndef COPP_COROUTINE_CONTEXT_COROUTINE_CONTEXT_BASE_H
2 #define COPP_COROUTINE_CONTEXT_COROUTINE_CONTEXT_BASE_H
3 
4 #pragma once
5 
6 #include <cstddef>
7 
11 #include <libcopp/utils/features.h>
15 
16 #ifdef LIBCOPP_MACRO_USE_SEGMENTED_STACKS
17 #define COROUTINE_CONTEXT_BASE_USING_BASE_SEGMENTED_STACKS(base_type) using base_type::caller_stack_;
18 #else
19 #define COROUTINE_CONTEXT_BASE_USING_BASE_SEGMENTED_STACKS(base_type)
20 #endif
21 
22 #define COROUTINE_CONTEXT_BASE_USING_BASE(base_type) \
23 protected: \
24  using base_type::caller_; \
25  using base_type::callee_; \
26  using base_type::callee_stack_; \
27  COROUTINE_CONTEXT_BASE_USING_BASE_SEGMENTED_STACKS(base_type)
28 
29 namespace copp {
30 
31  namespace details {
32  template <size_t N, bool BIGGER_THAN_16>
34 
35  template <size_t N>
36  struct align_helper_inner<N, true> {
37  static const size_t value = N;
38  };
39 
40  template <size_t N>
41  struct align_helper_inner<N, false> {
42  static const size_t value = 16;
43  };
44 
45  template <size_t N>
46  struct align_helper {
47  static const size_t value = align_helper_inner<N, N >= 16>::value;
48  };
49 
50  // We should align to at least 16 bytes, @see https://wiki.osdev.org/System_V_ABI for more details
51 #if (defined(__cplusplus) && __cplusplus >= 201103L) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || \
52  (defined(_MSC_VER) && _MSC_VER >= 1900)
53 #define COROUTINE_CONTEXT_BASE_ALIGN_UNIT_SIZE ::copp::details::align_helper<sizeof(max_align_t)>::value
54 #else
55 #define COROUTINE_CONTEXT_BASE_ALIGN_UNIT_SIZE ::copp::details::align_helper<2 * sizeof(long double)>::value
56 #endif
57 
59  } // namespace details
60 
65  public:
67  typedef std::function<int(void *)> callback_t;
68 
72  struct status_t {
73  enum type {
74  EN_CRS_INVALID = 0,
79  };
80  };
81 
82  struct flag_t {
83  enum type {
84  EN_CFT_UNKNOWN = 0,
85  EN_CFT_FINISHED = 0x01,
86  EN_CFT_MASK = 0xFF,
87  };
88  };
89 
90  private:
92  int flags_;
93  callback_t runner_;
94  void * priv_data_;
96 
97  struct jump_src_data_t {
100  void * priv_data;
101  };
102 
103  protected:
108 #ifdef LIBCOPP_MACRO_USE_SEGMENTED_STACKS
109  stack_context caller_stack_;
110 #endif
111 
112  private:
113 #if defined(PROJECT_DISABLE_MT) && PROJECT_DISABLE_MT
115 #else
117 #endif
118 
119  protected:
120  coroutine_context() UTIL_CONFIG_NOEXCEPT;
121 
122  public:
124 
125  public:
134  static int create(coroutine_context *p, callback_t &runner, const stack_context &callee_stack, size_t coroutine_size,
135  size_t private_buffer_size) UTIL_CONFIG_NOEXCEPT;
136 
137  template <typename TRunner>
138  static int create(coroutine_context *p, TRunner *runner, const stack_context &callee_stack, size_t coroutine_size,
139  size_t private_buffer_size) UTIL_CONFIG_NOEXCEPT {
140  return create(p, std::bind(&TRunner::operator(), runner, std::placeholders::_1), callee_stack, coroutine_size,
141  private_buffer_size);
142  }
143 
149  int start(void *priv_data = UTIL_CONFIG_NULLPTR);
150 
156  int resume(void *priv_data = UTIL_CONFIG_NULLPTR);
157 
158 
164  int yield(void **priv_data = UTIL_CONFIG_NULLPTR);
165 
171  bool set_flags(int flags);
172 
178  bool unset_flags(int flags);
179 
185  bool check_flags(int flags) const;
186 
187  protected:
191  inline void run_and_recv_retcode(void *priv_data) {
192  if (!runner_) return;
193 
194  runner_ret_code_ = runner_(priv_data);
195  }
196 
197  public:
203 #if defined(UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES) && UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES
204  int set_runner(callback_t &&runner);
205 #else
206  int set_runner(const callback_t &runner);
207 #endif
208 
213  inline const std::function<int(void *)> &get_runner() const UTIL_CONFIG_NOEXCEPT { return runner_; }
214 
219  inline int get_ret_code() const UTIL_CONFIG_NOEXCEPT { return runner_ret_code_; }
220 
225  bool is_finished() const UTIL_CONFIG_NOEXCEPT;
226 
230  inline void *get_private_buffer() const UTIL_CONFIG_NOEXCEPT { return priv_data_; }
231 
235  inline size_t get_private_buffer_size() const UTIL_CONFIG_NOEXCEPT { return private_buffer_size_; }
236 
237  protected:
245  static void jump_to(fcontext::fcontext_t &to_fctx, stack_context &from_sctx, stack_context &to_sctx,
246  jump_src_data_t &jump_transfer) UTIL_CONFIG_NOEXCEPT;
247 
252  static void coroutine_context_callback(::copp::fcontext::transfer_t src_ctx);
253 
254  public:
255  static inline size_t align_private_data_size(size_t sz) {
256  // static size_t random_index = 0;
257  // UTIL_CONFIG_CONSTEXPR size_t random_mask = 63;
258  UTIL_CONFIG_CONSTEXPR size_t align_mask = COROUTINE_CONTEXT_BASE_ALIGN_UNIT_SIZE - 1;
259 
260  // align
261  sz += align_mask;
262  sz &= ~align_mask;
263 
264  // random
265  // ++random_index;
266  // random_index &= random_mask;
267  // sz += random_index * (align_mask + 1);
268  return sz;
269  }
270 
271  static inline size_t align_address_size(size_t sz) {
272  UTIL_CONFIG_CONSTEXPR size_t align_mask = COROUTINE_CONTEXT_BASE_ALIGN_UNIT_SIZE - 1;
273 
274  sz += align_mask;
275  sz &= ~align_mask;
276  return sz;
277  }
278  };
279 
280  namespace this_coroutine {
286  coroutine_context *get_coroutine() UTIL_CONFIG_NOEXCEPT;
287 
294  template <typename Tc>
295  Tc *get() {
296  return static_cast<Tc *>(get_coroutine());
297  }
298 
304  int yield(void **priv_data = UTIL_CONFIG_NULLPTR);
305  } // namespace this_coroutine
306 } // namespace copp
307 
308 #endif
UTIL_CONFIG_STATIC_ASSERT(COROUTINE_CONTEXT_BASE_ALIGN_UNIT_SIZE >=16 &&0==COROUTINE_CONTEXT_BASE_ALIGN_UNIT_SIZE% 16)
std::function< int(void *)> callback_t
status of safe coroutine context base
const std::function< int(void *)> & get_runner() const UTIL_CONFIG_NOEXCEPT
#define COROUTINE_CONTEXT_BASE_ALIGN_UNIT_SIZE
void run_and_recv_retcode(void *priv_data)
coroutine entrance function
coroutine_context * get_coroutine() UTIL_CONFIG_NOEXCEPT
get current coroutine
static size_t align_address_size(size_t sz)
util::lock::atomic_int_type< int > status_
int get_ret_code() const UTIL_CONFIG_NOEXCEPT
get runner return code
int yield(void **priv_data=UTIL_CONFIG_NULLPTR)
yield current coroutine
整数类型的原子操作跨平台适配 Licensed under the MIT licenses.
导入智能指针库 Licensed under the MIT licenses.
size_t get_private_buffer_size() const UTIL_CONFIG_NOEXCEPT
get private buffer size
fcontext::fcontext_t callee_
void * get_private_buffer() const UTIL_CONFIG_NOEXCEPT
get private buffer(raw pointer)
std::intrusive_ptr< coroutine_context > ptr_t
base type of all coroutine context
导入高级库,hash、引用包装等 Licensed under the MIT licenses.
fcontext::fcontext_t caller_
static size_t align_private_data_size(size_t sz)