libcopp  2.2.0
coroutine_context_container.h
Go to the documentation of this file.
1 // Copyright 2023 owent
2 
3 #pragma once
4 
5 #include <libcopp/utils/config/libcopp_build_features.h>
6 
10 #include <libcopp/utils/errno.h>
11 
12 // clang-format off
13 #include <libcopp/utils/config/stl_include_prefix.h> // NOLINT(build/include_order)
14 // clang-format on
15 #include <cstddef>
16 // clang-format off
17 #include <libcopp/utils/config/stl_include_suffix.h> // NOLINT(build/include_order)
18 // clang-format on
19 
20 LIBCOPP_COPP_NAMESPACE_BEGIN
25 template <typename TALLOC>
27  public:
30  using allocator_type = TALLOC;
32  using ptr_type = LIBCOPP_COPP_NAMESPACE_ID::util::intrusive_ptr<this_type>;
34 
35  // Compability with libcopp-1.x
36  using ptr_t = ptr_type;
38 
40 
41  private:
42  coroutine_context_container(const allocator_type &alloc) LIBCOPP_MACRO_NOEXCEPT : alloc_(alloc), ref_count_(0) {}
43 
44  coroutine_context_container(allocator_type &&alloc) LIBCOPP_MACRO_NOEXCEPT : alloc_(std::move(alloc)),
45  ref_count_(0) {}
46 
47  public:
49 
54  inline const allocator_type &get_allocator() const LIBCOPP_MACRO_NOEXCEPT { return alloc_; }
55 
60  inline allocator_type &get_allocator() LIBCOPP_MACRO_NOEXCEPT { return alloc_; }
61 
62  public:
71  static ptr_type create(callback_type &&runner, allocator_type &alloc, size_t stack_sz = 0,
72  size_t private_buffer_size = 0, size_t coroutine_size = 0) LIBCOPP_MACRO_NOEXCEPT {
73  ptr_type ret;
74  if (0 == stack_sz) {
75  stack_sz = stack_traits::default_size();
76  }
77 
78  // padding to sizeof size_t
79  coroutine_size = align_address_size(coroutine_size);
80  const size_t this_align_size = align_address_size(sizeof(this_type));
81  coroutine_size += this_align_size;
82  private_buffer_size = coroutine_context::align_private_data_size(private_buffer_size);
83 
84  if (stack_sz <= coroutine_size + private_buffer_size) {
85  return ret;
86  }
87 
88  stack_context callee_stack;
89  alloc.allocate(callee_stack, stack_sz);
90 
91  if (nullptr == callee_stack.sp) {
92  return ret;
93  }
94 
95  // placement new
96  unsigned char *this_addr = reinterpret_cast<unsigned char *>(callee_stack.sp);
97  // stack down
98  this_addr -= private_buffer_size + this_align_size;
99  ret.reset(new (reinterpret_cast<void *>(this_addr)) this_type(std::move(alloc)));
100 
101  // callee_stack and alloc unavailable any more.
102  if (ret) {
103  ret->callee_stack_ = 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  if (coroutine_context::create(ret.get(), std::move(runner), ret->callee_stack_, coroutine_size,
111  private_buffer_size) < 0) {
112  ret.reset();
113  }
114 
115  return ret;
116  }
117 
118  template <class TRunner>
119  static inline ptr_type create(TRunner *runner, allocator_type &alloc, size_t stack_size = 0,
120  size_t private_buffer_size = 0, size_t coroutine_size = 0) LIBCOPP_MACRO_NOEXCEPT {
121  if (nullptr == runner) {
122  return create(callback_type(), alloc, stack_size, private_buffer_size, coroutine_size);
123  }
124 
125  return create([runner](void *private_data) { return (*runner)(private_data); }, alloc, stack_size,
126  private_buffer_size, coroutine_size);
127  }
128 
129  static inline ptr_type create(int (*fn)(void *), allocator_type &alloc, size_t stack_size = 0,
130  size_t private_buffer_size = 0, size_t coroutine_size = 0) LIBCOPP_MACRO_NOEXCEPT {
131  if (nullptr == fn) {
132  return create(callback_type(), alloc, stack_size, private_buffer_size, coroutine_size);
133  }
134 
135  return create(callback_type(fn), alloc, stack_size, private_buffer_size, coroutine_size);
136  }
137 
138  static ptr_type create(callback_type &&runner, size_t stack_size = 0, size_t private_buffer_size = 0,
139  size_t coroutine_size = 0) LIBCOPP_MACRO_NOEXCEPT {
140  allocator_type alloc;
141  return create(std::move(runner), alloc, stack_size, private_buffer_size, coroutine_size);
142  }
143 
144  template <class TRunner>
145  static inline ptr_type create(TRunner *runner, size_t stack_size = 0, size_t private_buffer_size = 0,
146  size_t coroutine_size = 0) LIBCOPP_MACRO_NOEXCEPT {
147  return create([runner](void *private_data) { return (*runner)(private_data); }, stack_size, private_buffer_size,
148  coroutine_size);
149  }
150 
151  static inline ptr_type create(int (*fn)(void *), size_t stack_size = 0, size_t private_buffer_size = 0,
152  size_t coroutine_size = 0) LIBCOPP_MACRO_NOEXCEPT {
153  return create(callback_type(fn), stack_size, private_buffer_size, coroutine_size);
154  }
155 
156  inline size_t use_count() const LIBCOPP_MACRO_NOEXCEPT { return ref_count_.load(); }
157 
158  private:
160 
161  private:
163  if (p == nullptr) {
164  return;
165  }
166 
167  ++p->ref_count_;
168  }
169 
171  if (p == nullptr) {
172  return;
173  }
174 
175  size_t left = --p->ref_count_;
176  if (0 == left) {
177  allocator_type copy_alloc(std::move(p->alloc_));
178  stack_context copy_stack(std::move(p->callee_stack_));
179 
180  // then destruct object and reset data
182 
183  // final, recycle stack buffer
184  copy_alloc.deallocate(copy_stack);
185  }
186  }
187 
188  private:
190 #if defined(LIBCOPP_DISABLE_ATOMIC_LOCK) && LIBCOPP_DISABLE_ATOMIC_LOCK
191  LIBCOPP_COPP_NAMESPACE_ID::util::lock::atomic_int_type<
192  LIBCOPP_COPP_NAMESPACE_ID::util::lock::unsafe_int_type<size_t> >
193  ref_count_;
194 #else
195  LIBCOPP_COPP_NAMESPACE_ID::util::lock::atomic_int_type<size_t> ref_count_;
196 #endif
197 };
198 
200 LIBCOPP_COPP_NAMESPACE_END
static UTIL_FORCEINLINE size_t align_private_data_size(size_t sz)
static size_t align_address_size(size_t sz)
coroutine container contain stack context, stack allocator and runtime fcontext
coroutine_context::callback_type callback_type
const allocator_type & get_allocator() const LIBCOPP_MACRO_NOEXCEPT
get stack allocator
static ptr_type create(int(*fn)(void *), allocator_type &alloc, size_t stack_size=0, size_t private_buffer_size=0, size_t coroutine_size=0) LIBCOPP_MACRO_NOEXCEPT
LIBCOPP_COPP_NAMESPACE_ID::util::lock::atomic_int_type< size_t > ref_count_
coroutine_context_container(const coroutine_context_container &)=delete
static ptr_type create(callback_type &&runner, allocator_type &alloc, size_t stack_sz=0, size_t private_buffer_size=0, size_t coroutine_size=0) LIBCOPP_MACRO_NOEXCEPT
create and init coroutine with specify runner and specify stack size
allocator_type & get_allocator() LIBCOPP_MACRO_NOEXCEPT
get stack allocator
friend void intrusive_ptr_add_ref(this_type *p)
static ptr_type create(callback_type &&runner, size_t stack_size=0, size_t private_buffer_size=0, size_t coroutine_size=0) LIBCOPP_MACRO_NOEXCEPT
coroutine_context_container(const allocator_type &alloc) LIBCOPP_MACRO_NOEXCEPT
coroutine_context_container< allocator_type > this_type
static ptr_type create(TRunner *runner, allocator_type &alloc, size_t stack_size=0, size_t private_buffer_size=0, size_t coroutine_size=0) LIBCOPP_MACRO_NOEXCEPT
size_t use_count() const LIBCOPP_MACRO_NOEXCEPT
static ptr_type create(TRunner *runner, size_t stack_size=0, size_t private_buffer_size=0, size_t coroutine_size=0) LIBCOPP_MACRO_NOEXCEPT
LIBCOPP_COPP_NAMESPACE_ID::util::intrusive_ptr< this_type > ptr_type
friend void intrusive_ptr_release(this_type *p)
static ptr_type create(int(*fn)(void *), size_t stack_size=0, size_t private_buffer_size=0, size_t coroutine_size=0) LIBCOPP_MACRO_NOEXCEPT
coroutine_context_container(allocator_type &&alloc) LIBCOPP_MACRO_NOEXCEPT
base type of all stackful coroutine context
LIBCOPP_COPP_API coroutine_context() LIBCOPP_MACRO_NOEXCEPT
stack_context callee_stack_
callback_type callback_t
LIBCOPP_COPP_NAMESPACE_ID::util::intrusive_ptr< coroutine_context > ptr_type
coroutine_context_base::callback_type callback_type
static LIBCOPP_COPP_API int create(coroutine_context *p, callback_type &&runner, const stack_context &callee_stack, size_t coroutine_size, size_t private_buffer_size) LIBCOPP_MACRO_NOEXCEPT
create coroutine context at stack context callee_
#define COROUTINE_CONTEXT_BASE_USING_BASE(base_type)
void reset() LIBCOPP_MACRO_NOEXCEPT
void * sp
stack size
Definition: stack_context.h:20
static LIBCOPP_COPP_API std::size_t default_size() LIBCOPP_MACRO_NOEXCEPT