generalized handling of stack freeing, remove coroutine swap

Swap makes no sense because coroutines are not movable.
master
Daniel Kolesa 2019-01-28 02:45:30 +01:00
parent 6935e62d06
commit 1ac481d887
2 changed files with 37 additions and 55 deletions

View File

@ -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 {

View File

@ -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();