generalized handling of stack freeing, remove coroutine swap
Swap makes no sense because coroutines are not movable.master
parent
6935e62d06
commit
1ac481d887
|
@ -60,6 +60,24 @@ struct coroutine_error: std::runtime_error {
|
||||||
virtual ~coroutine_error();
|
virtual ~coroutine_error();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
struct stack_free_iface {
|
||||||
|
stack_free_iface() {}
|
||||||
|
/* empty, for vtable placement */
|
||||||
|
virtual ~stack_free_iface();
|
||||||
|
virtual void free(stack_context &ps) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename SA>
|
||||||
|
struct stack_free_obj: stack_free_iface {
|
||||||
|
stack_free_obj(SA &&sa): p_alloc{std::move(sa)} {}
|
||||||
|
void free(stack_context &ps) {
|
||||||
|
p_alloc.deallocate(ps);
|
||||||
|
}
|
||||||
|
SA p_alloc;
|
||||||
|
};
|
||||||
|
} /* namespace detail */
|
||||||
|
|
||||||
/** @brief An encapsulated context any coroutine-type inherits from.
|
/** @brief An encapsulated context any coroutine-type inherits from.
|
||||||
*
|
*
|
||||||
* Internally, this provides some basic infrastructure for creating and
|
* Internally, this provides some basic infrastructure for creating and
|
||||||
|
@ -193,17 +211,6 @@ protected:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Swaps the current context with another. */
|
|
||||||
void swap(coroutine_context &other) noexcept {
|
|
||||||
using std::swap;
|
|
||||||
swap(p_stack, other.p_stack);
|
|
||||||
swap(p_coro, other.p_coro);
|
|
||||||
swap(p_orig, other.p_orig);
|
|
||||||
swap(p_free, other.p_free);
|
|
||||||
swap(p_except, other.p_except);
|
|
||||||
swap(p_state, other.p_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @brief Allocates a stack and creates a context.
|
/** @brief Allocates a stack and creates a context.
|
||||||
*
|
*
|
||||||
* Only call this once at the point where no context was created yet.
|
* Only call this once at the point where no context was created yet.
|
||||||
|
@ -227,8 +234,12 @@ protected:
|
||||||
p_coro = detail::ostd_make_fcontext(
|
p_coro = detail::ostd_make_fcontext(
|
||||||
p_stack.ptr, p_stack.size, &context_call<C, SA>
|
p_stack.ptr, p_stack.size, &context_call<C, SA>
|
||||||
);
|
);
|
||||||
new (&p_salloc) SA(std::move(sa));
|
using SF = detail::stack_free_obj<SA>;
|
||||||
p_free = &free_stack_call<SA>;
|
if (sizeof(SF) <= sizeof(p_salloc)) {
|
||||||
|
p_sfree = ::new(&p_salloc) SF{std::move(sa)};
|
||||||
|
} else {
|
||||||
|
p_sfree = new SF{std::move(sa)};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -260,18 +271,12 @@ private:
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename SA>
|
|
||||||
static void free_stack_call(void *data) {
|
|
||||||
auto &self = *(static_cast<coroutine_context *>(data));
|
|
||||||
auto &sa = *(reinterpret_cast<SA *>(&self.p_salloc));
|
|
||||||
SA dsa{std::move(sa)};
|
|
||||||
sa.~SA();
|
|
||||||
dsa.deallocate(self.p_stack);
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_stack() {
|
void free_stack() {
|
||||||
if (p_free) {
|
using SF = detail::stack_free_iface;
|
||||||
p_free(this);
|
if (static_cast<void *>(p_sfree) == &p_salloc) {
|
||||||
|
p_sfree->~SF();
|
||||||
|
} else {
|
||||||
|
delete p_sfree;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,14 +303,12 @@ private:
|
||||||
self.yield_done();
|
self.yield_done();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* eventually generalize for any stack allocator, for now use
|
/* 3 pointer big is enough to cover just about any allocator */
|
||||||
* the size of the biggest stack allocator we have in the library
|
std::aligned_storage_t<sizeof(void *) * 3> p_salloc;
|
||||||
*/
|
detail::stack_free_iface *p_sfree;
|
||||||
std::aligned_storage_t<sizeof(stack_pool), alignof(stack_pool)> p_salloc;
|
|
||||||
stack_context p_stack;
|
stack_context p_stack;
|
||||||
detail::fcontext_t p_coro = nullptr;
|
detail::fcontext_t p_coro = nullptr;
|
||||||
detail::fcontext_t p_orig = nullptr;
|
detail::fcontext_t p_orig = nullptr;
|
||||||
void (*p_free)(void *) = nullptr;
|
|
||||||
std::exception_ptr p_except;
|
std::exception_ptr p_except;
|
||||||
state p_state = state::HOLD;
|
state p_state = state::HOLD;
|
||||||
};
|
};
|
||||||
|
@ -744,12 +747,6 @@ public:
|
||||||
return p_stor.get_result();
|
return p_stor.get_result();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Swaps two coroutines' states. */
|
|
||||||
void swap(coroutine &other) noexcept {
|
|
||||||
p_stor.swap(other.p_stor);
|
|
||||||
base_t::swap(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @brief Returns the RTTI of the function stored in the coroutine. */
|
/** @brief Returns the RTTI of the function stored in the coroutine. */
|
||||||
std::type_info const &target_type() const {
|
std::type_info const &target_type() const {
|
||||||
return p_stor.p_func.target_type();
|
return p_stor.p_func.target_type();
|
||||||
|
@ -779,12 +776,6 @@ private:
|
||||||
detail::coro_stor<yield_type, R, A...> p_stor;
|
detail::coro_stor<yield_type, R, A...> p_stor;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @brief Swaps two coroutines' states. */
|
|
||||||
template<typename R, typename ...A>
|
|
||||||
inline void swap(coroutine<R(A...)> &a, coroutine<R(A...)> &b) noexcept {
|
|
||||||
a.swap(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template<typename T> struct generator_range;
|
template<typename T> struct generator_range;
|
||||||
template<typename T> struct generator_iterator;
|
template<typename T> struct generator_iterator;
|
||||||
|
@ -1008,14 +999,6 @@ public:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Swaps two generators' states. */
|
|
||||||
void swap(generator &other) noexcept {
|
|
||||||
using std::swap;
|
|
||||||
swap(p_func, other.p_func);
|
|
||||||
swap(p_result, other.p_result);
|
|
||||||
coroutine_context::swap(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @brief Returns the RTTI of the function stored in the generator. */
|
/** @brief Returns the RTTI of the function stored in the generator. */
|
||||||
std::type_info const &target_type() const {
|
std::type_info const &target_type() const {
|
||||||
return p_func.target_type();
|
return p_func.target_type();
|
||||||
|
@ -1051,12 +1034,6 @@ private:
|
||||||
std::remove_reference_t<T> *p_result = nullptr;
|
std::remove_reference_t<T> *p_result = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @brief Swaps two generators' states. */
|
|
||||||
template<typename T>
|
|
||||||
inline void swap(generator<T> &a, generator<T> &b) noexcept {
|
|
||||||
a.swap(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct yield_type_base {
|
struct yield_type_base {
|
||||||
|
|
|
@ -10,6 +10,11 @@ namespace ostd {
|
||||||
/* place the vtable in here */
|
/* place the vtable in here */
|
||||||
coroutine_error::~coroutine_error() {}
|
coroutine_error::~coroutine_error() {}
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
/* place the vtable in here */
|
||||||
|
stack_free_iface::~stack_free_iface() {}
|
||||||
|
} /* namespace detail */
|
||||||
|
|
||||||
/* non-inline for vtable placement */
|
/* non-inline for vtable placement */
|
||||||
coroutine_context::~coroutine_context() {
|
coroutine_context::~coroutine_context() {
|
||||||
unwind();
|
unwind();
|
||||||
|
|
Loading…
Reference in New Issue