libcopp  1.2.1
coroutine_context_container.h
Go to the documentation of this file.
1 
4 #ifndef COPP_COROUTINE_CONTEXT_COROUTINE_CONTEXT_CONTAINER_H
5 #define COPP_COROUTINE_CONTEXT_COROUTINE_CONTEXT_CONTAINER_H
6 
7 
8 #pragma once
9 
10 #include <cstddef>
11 
15 #include <libcopp/utils/errno.h>
16 
17 namespace copp {
22  template <typename TALLOC>
24  public:
27  typedef TALLOC allocator_type;
31 
33 
34  private:
35  coroutine_context_container(const allocator_type &alloc) UTIL_CONFIG_NOEXCEPT : alloc_(alloc), ref_count_(0) {}
36 
37 #if defined(UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES) && UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES
38  coroutine_context_container(allocator_type &&alloc) UTIL_CONFIG_NOEXCEPT : alloc_(COPP_MACRO_STD_MOVE(alloc)), ref_count_(0) {}
39 #endif
40 
41  public:
43 
48  inline const allocator_type &get_allocator() const UTIL_CONFIG_NOEXCEPT { return alloc_; }
49 
54  inline allocator_type &get_allocator() UTIL_CONFIG_NOEXCEPT { return alloc_; }
55 
56  public:
65  static ptr_t create(
66 #if defined(UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES) && UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES
67  callback_t &&runner,
68 #else
69  const callback_t &runner,
70 #endif
71  allocator_type &alloc, size_t stack_sz = 0, size_t private_buffer_size = 0, size_t coroutine_size = 0) UTIL_CONFIG_NOEXCEPT {
72  ptr_t ret;
73  if (0 == stack_sz) {
74  stack_sz = stack_traits::default_size();
75  }
76 
77  // padding to sizeof size_t
78  coroutine_size = align_address_size(coroutine_size);
79  const size_t this_align_size = align_address_size(sizeof(this_type));
80  coroutine_size += this_align_size;
81  private_buffer_size = coroutine_context::align_private_data_size(private_buffer_size);
82 
83  if (stack_sz <= coroutine_size + private_buffer_size) {
84  return ret;
85  }
86 
87  stack_context callee_stack;
88  alloc.allocate(callee_stack, stack_sz);
89 
90  if (NULL == callee_stack.sp) {
91  return ret;
92  }
93 
94  // placement new
95  unsigned char *this_addr = reinterpret_cast<unsigned char *>(callee_stack.sp);
96  // stack down
97  this_addr -= private_buffer_size + this_align_size;
98  ret.reset(new ((void *)this_addr) this_type(COPP_MACRO_STD_MOVE(alloc)));
99 
100  // callee_stack and alloc unavailable any more.
101  if (ret) {
102  ret->alloc_ = COPP_MACRO_STD_MOVE(alloc);
103  ret->callee_stack_ = COPP_MACRO_STD_MOVE(callee_stack);
104  } else {
105  alloc.deallocate(callee_stack);
106  return ret;
107  }
108 
109  // after this call runner will be unavailable
110  callback_t callback(COPP_MACRO_STD_MOVE(runner));
111  if (coroutine_context::create(ret.get(), callback, ret->callee_stack_, coroutine_size, private_buffer_size) < 0) {
112  ret.reset();
113  }
114 
115  return ret;
116  }
117 
118  template <class TRunner>
119  static inline ptr_t create(TRunner *runner, allocator_type &alloc, size_t stack_size = 0, size_t private_buffer_size = 0,
120  size_t coroutine_size = 0) UTIL_CONFIG_NOEXCEPT {
121  if (UTIL_CONFIG_NULLPTR == runner) {
122  return create(callback_t(), alloc, stack_size, private_buffer_size, coroutine_size);
123  }
124 
125  typedef int (TRunner::*runner_fn_t)(void *);
126  runner_fn_t fn = &TRunner::operator();
127  return create(std::bind(fn, runner, std::placeholders::_1), alloc, stack_size, private_buffer_size, coroutine_size);
128  }
129 
130  static inline ptr_t create(int (*fn)(void *), allocator_type &alloc, size_t stack_size = 0, size_t private_buffer_size = 0,
131  size_t coroutine_size = 0) UTIL_CONFIG_NOEXCEPT {
132  if (UTIL_CONFIG_NULLPTR == fn) {
133  return create(callback_t(), alloc, stack_size, private_buffer_size, coroutine_size);
134  }
135 
136  return create(callback_t(fn), alloc, stack_size, private_buffer_size, coroutine_size);
137  }
138 
139  static ptr_t create(
140 #if defined(UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES) && UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES
141  callback_t &&runner,
142 #else
143  const callback_t &runner,
144 #endif
145  size_t stack_size = 0, size_t private_buffer_size = 0, size_t coroutine_size = 0) UTIL_CONFIG_NOEXCEPT {
146  allocator_type alloc;
147  return create(COPP_MACRO_STD_MOVE(runner), alloc, stack_size, private_buffer_size, coroutine_size);
148  }
149 
150  template <class TRunner>
151  static inline ptr_t create(TRunner *runner, size_t stack_size = 0, size_t private_buffer_size = 0,
152  size_t coroutine_size = 0) UTIL_CONFIG_NOEXCEPT {
153  typedef int (TRunner::*runner_fn_t)(void *);
154  runner_fn_t fn = &TRunner::operator();
155  return create(std::bind(fn, runner, std::placeholders::_1), stack_size, private_buffer_size, coroutine_size);
156  }
157 
158  static inline ptr_t create(int (*fn)(void *), size_t stack_size = 0, size_t private_buffer_size = 0,
159  size_t coroutine_size = 0) UTIL_CONFIG_NOEXCEPT {
160  return create(callback_t(fn), stack_size, private_buffer_size, coroutine_size);
161  }
162 
163  inline size_t use_count() const UTIL_CONFIG_NOEXCEPT { return ref_count_.load(); }
164 
165  private:
166  coroutine_context_container(const coroutine_context_container &) UTIL_CONFIG_DELETED_FUNCTION;
167 
168  private:
169  friend void intrusive_ptr_add_ref(this_type *p) {
170  if (p == UTIL_CONFIG_NULLPTR) {
171  return;
172  }
173 
174  ++p->ref_count_;
175  }
176 
177  friend void intrusive_ptr_release(this_type *p) {
178  if (p == UTIL_CONFIG_NULLPTR) {
179  return;
180  }
181 
182  size_t left = --p->ref_count_;
183  if (0 == left) {
184  allocator_type copy_alloc(COPP_MACRO_STD_MOVE(p->alloc_));
186 
187  // then destruct object and reset data
189 
190  // final, recycle stack buffer
191  copy_alloc.deallocate(copy_stack);
192  }
193  }
194 
195  private:
196  allocator_type alloc_;
197 #if defined(LIBCOPP_DISABLE_ATOMIC_LOCK) && LIBCOPP_DISABLE_ATOMIC_LOCK
199 #else
201 #endif
202  };
203 
205 } // namespace copp
206 
207 #endif
static std::size_t default_size() COPP_MACRO_NOEXCEPT
std::function< int(void *)> callback_t
coroutine_context::callback_t callback_t
size_t use_count() const UTIL_CONFIG_NOEXCEPT
static ptr_t create(int(*fn)(void *), allocator_type &alloc, size_t stack_size=0, size_t private_buffer_size=0, size_t coroutine_size=0) UTIL_CONFIG_NOEXCEPT
static int create(coroutine_context *p, callback_t &runner, const stack_context &callee_stack, size_t coroutine_size, size_t private_buffer_size) UTIL_CONFIG_NOEXCEPT
create coroutine context at stack context callee_
static ptr_t create(TRunner *runner, allocator_type &alloc, size_t stack_size=0, size_t private_buffer_size=0, size_t coroutine_size=0) UTIL_CONFIG_NOEXCEPT
static ptr_t create(const callback_t &runner, allocator_type &alloc, size_t stack_sz=0, size_t private_buffer_size=0, size_t coroutine_size=0) UTIL_CONFIG_NOEXCEPT
create and init coroutine with specify runner and specify stack size
util::lock::atomic_int_type< size_t > ref_count_
sample endif() if(PROJECT_ENABLE_UNITTEST) add_custom_target(run_test) add_subdirectory("$
Definition: CMakeLists.txt:110
void * sp
stack size
Definition: stack_context.h:14
coroutine_context_container< allocator_type > this_type
allocator_type & get_allocator() UTIL_CONFIG_NOEXCEPT
get stack allocator
#define COPP_MACRO_STD_MOVE(x)
Definition: features.h:171
static size_t align_address_size(size_t sz)
#define COROUTINE_CONTEXT_BASE_USING_BASE(base_type)
const allocator_type & get_allocator() const UTIL_CONFIG_NOEXCEPT
get stack allocator
coroutine_context_container(const allocator_type &alloc) UTIL_CONFIG_NOEXCEPT
std::intrusive_ptr< this_type > ptr_t
coroutine container contain stack context, stack allocator and runtime fcontext
static ptr_t create(TRunner *runner, size_t stack_size=0, size_t private_buffer_size=0, size_t coroutine_size=0) UTIL_CONFIG_NOEXCEPT
value_type load(EXPLICIT_UNUSED_ATTR::util::lock::memory_order order=::util::lock::memory_order_seq_cst) const UTIL_CONFIG_NOEXCEPT
element_type * get() const UTIL_CONFIG_NOEXCEPT
static ptr_t create(int(*fn)(void *), size_t stack_size=0, size_t private_buffer_size=0, size_t coroutine_size=0) UTIL_CONFIG_NOEXCEPT
base type of all coroutine context
void reset() UTIL_CONFIG_NOEXCEPT
static ptr_t create(const callback_t &runner, size_t stack_size=0, size_t private_buffer_size=0, size_t coroutine_size=0) UTIL_CONFIG_NOEXCEPT
coroutine_context_container< allocator::default_statck_allocator > coroutine_context_default
static size_t align_private_data_size(size_t sz)