libcopp 2.3.1
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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
21LIBCOPP_COPP_NAMESPACE_BEGIN
26template <typename TALLOC>
27class 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::memory::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 LIBCOPP_MACRO_ENABLE_MULTI_THREAD
191 LIBCOPP_COPP_NAMESPACE_ID::util::lock::atomic_int_type<size_t> ref_count_;
192# else
193 LIBCOPP_COPP_NAMESPACE_ID::util::lock::atomic_int_type<
194 LIBCOPP_COPP_NAMESPACE_ID::util::lock::unsafe_int_type<size_t> >
195 ref_count_;
196# endif
197};
198
199using coroutine_fiber_context_default = coroutine_context_fiber_container<allocator::stack_allocator_malloc>;
200LIBCOPP_COPP_NAMESPACE_END
201
202#endif
#define COROUTINE_CONTEXT_BASE_USING_BASE(base_type)
void reset() LIBCOPP_MACRO_NOEXCEPT
void * sp
stack size
static LIBCOPP_COPP_API std::size_t default_size() LIBCOPP_MACRO_NOEXCEPT