libcopp  2.2.0
coroutine_context_fiber_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 #if defined(LIBCOPP_MACRO_ENABLE_WIN_FIBER) && LIBCOPP_MACRO_ENABLE_WIN_FIBER
21 LIBCOPP_COPP_NAMESPACE_BEGIN
26 template <typename TALLOC>
27 class coroutine_context_fiber_container : public coroutine_context_fiber {
28  public:
29  using coroutine_context_type = coroutine_context_fiber;
30  using base_type = coroutine_context_fiber;
31  using allocator_type = TALLOC;
32  using this_type = coroutine_context_fiber_container<allocator_type>;
33  using ptr_type = LIBCOPP_COPP_NAMESPACE_ID::util::intrusive_ptr<this_type>;
34  using callback_type = coroutine_context_fiber::callback_type;
35 
36  // Compability with libcopp-1.x
37  using ptr_t = ptr_type;
38  using callback_t = callback_type;
39 
41 
42  private:
43  coroutine_context_fiber_container(const allocator_type &alloc) LIBCOPP_MACRO_NOEXCEPT : alloc_(alloc),
44  ref_count_(0) {}
45 
46  coroutine_context_fiber_container(allocator_type &&alloc) LIBCOPP_MACRO_NOEXCEPT : alloc_(std::move(alloc)),
47  ref_count_(0) {}
48 
49  public:
50  ~coroutine_context_fiber_container() {}
51 
56  inline const allocator_type &get_allocator() const LIBCOPP_MACRO_NOEXCEPT { return alloc_; }
57 
62  inline allocator_type &get_allocator() LIBCOPP_MACRO_NOEXCEPT { return alloc_; }
63 
64  public:
73  static ptr_type create(callback_type &&runner, allocator_type &alloc, size_t stack_sz = 0,
74  size_t private_buffer_size = 0, size_t coroutine_size = 0) LIBCOPP_MACRO_NOEXCEPT {
75  ptr_type ret;
76  if (0 == stack_sz) {
77  stack_sz = stack_traits::default_size();
78  }
79 
80  // padding to sizeof size_t
81  coroutine_size = align_address_size(coroutine_size);
82  const size_t this_align_size = align_address_size(sizeof(this_type));
83  coroutine_size += this_align_size;
84  private_buffer_size = coroutine_context_fiber::align_private_data_size(private_buffer_size);
85 
86  // stack allocator is just used for allocate coroutine and private data
87  stack_context callee_stack;
88  alloc.allocate(callee_stack, coroutine_size + private_buffer_size);
89 
90  if (nullptr == 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 (reinterpret_cast<void *>(this_addr)) this_type(std::move(alloc)));
99 
100  // callee_stack and alloc unavailable any more.
101  if (ret) {
102  ret->callee_stack_ = std::move(callee_stack);
103  } else {
104  alloc.deallocate(callee_stack);
105  return ret;
106  }
107 
108  // after this call runner will be unavailable
109  // stack_sz is used for stack reserve size of fiber
110  if (coroutine_context_fiber::create(ret.get(), std::move(runner), ret->callee_stack_, coroutine_size,
111  private_buffer_size, stack_sz) < 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:
159  coroutine_context_fiber_container(const coroutine_context_fiber_container &) = delete;
160 
161  private:
162  friend void intrusive_ptr_add_ref(this_type *p) {
163  if (p == nullptr) {
164  return;
165  }
166 
167  ++p->ref_count_;
168  }
169 
170  friend void intrusive_ptr_release(this_type *p) {
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
181  p->~coroutine_context_fiber_container();
182 
183  // final, recycle stack buffer
184  copy_alloc.deallocate(copy_stack);
185  }
186  }
187 
188  private:
189  allocator_type alloc_;
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 
199 using coroutine_fiber_context_default = coroutine_context_fiber_container<allocator::stack_allocator_malloc>;
200 LIBCOPP_COPP_NAMESPACE_END
201 
202 #endif
#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