libcopp 2.3.1
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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
20LIBCOPP_COPP_NAMESPACE_BEGIN
25template <typename TALLOC>
27 public:
30 using allocator_type = TALLOC;
32 using ptr_type = LIBCOPP_COPP_NAMESPACE_ID::memory::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 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> >
196#endif
197};
198
200LIBCOPP_COPP_NAMESPACE_END
static size_t align_address_size(size_t sz)
static LIBCOPP_UTIL_FORCEINLINE size_t align_private_data_size(size_t sz)
coroutine container contain stack context, stack allocator and runtime fcontext
coroutine_context::callback_type callback_type
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
coroutine_context_container(const coroutine_context_container &)=delete
const allocator_type & get_allocator() const LIBCOPP_MACRO_NOEXCEPT
get stack allocator
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
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
LIBCOPP_COPP_NAMESPACE_ID::util::lock::atomic_int_type< LIBCOPP_COPP_NAMESPACE_ID::util::lock::unsafe_int_type< size_t > > ref_count_
coroutine_context_container(const allocator_type &alloc) LIBCOPP_MACRO_NOEXCEPT
allocator_type & get_allocator() LIBCOPP_MACRO_NOEXCEPT
get stack allocator
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::memory::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_
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
static LIBCOPP_COPP_API std::size_t default_size() LIBCOPP_MACRO_NOEXCEPT