forked from OctaForge/libostd
actually free coroutine stacks in dtor (more predictable and safer)
parent
1351ac14f6
commit
422a65cade
|
@ -130,6 +130,7 @@ namespace detail {
|
||||||
/* default case, yield returns args and takes a value */
|
/* default case, yield returns args and takes a value */
|
||||||
template<typename Y, typename R, typename ...A>
|
template<typename Y, typename R, typename ...A>
|
||||||
struct coro_stor {
|
struct coro_stor {
|
||||||
|
coro_stor(): p_func(nullptr) {}
|
||||||
template<typename F>
|
template<typename F>
|
||||||
coro_stor(F &&func): p_func(std::forward<F>(func)) {}
|
coro_stor(F &&func): p_func(std::forward<F>(func)) {}
|
||||||
|
|
||||||
|
@ -171,6 +172,7 @@ namespace detail {
|
||||||
/* yield takes a value but doesn't return any args */
|
/* yield takes a value but doesn't return any args */
|
||||||
template<typename Y, typename R>
|
template<typename Y, typename R>
|
||||||
struct coro_stor<Y, R> {
|
struct coro_stor<Y, R> {
|
||||||
|
coro_stor(): p_func(nullptr) {}
|
||||||
template<typename F>
|
template<typename F>
|
||||||
coro_stor(F &&func): p_func(std::forward<F>(func)) {}
|
coro_stor(F &&func): p_func(std::forward<F>(func)) {}
|
||||||
|
|
||||||
|
@ -199,6 +201,7 @@ namespace detail {
|
||||||
/* yield doesn't take a value and returns args */
|
/* yield doesn't take a value and returns args */
|
||||||
template<typename Y, typename ...A>
|
template<typename Y, typename ...A>
|
||||||
struct coro_stor<Y, void, A...> {
|
struct coro_stor<Y, void, A...> {
|
||||||
|
coro_stor(): p_func(nullptr) {}
|
||||||
template<typename F>
|
template<typename F>
|
||||||
coro_stor(F &&func): p_func(std::forward<F>(func)) {}
|
coro_stor(F &&func): p_func(std::forward<F>(func)) {}
|
||||||
|
|
||||||
|
@ -232,6 +235,7 @@ namespace detail {
|
||||||
/* yield doesn't take a value or return any args */
|
/* yield doesn't take a value or return any args */
|
||||||
template<typename Y>
|
template<typename Y>
|
||||||
struct coro_stor<Y, void> {
|
struct coro_stor<Y, void> {
|
||||||
|
coro_stor(): p_func(nullptr) {}
|
||||||
template<typename F>
|
template<typename F>
|
||||||
coro_stor(F &&func): p_func(std::forward<F>(func)) {}
|
coro_stor(F &&func): p_func(std::forward<F>(func)) {}
|
||||||
|
|
||||||
|
@ -343,7 +347,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename SA = default_stack>
|
template<typename SA = default_stack>
|
||||||
coroutine(std::nullptr_t, SA = SA{0}): base_t(), p_stor() {
|
coroutine(std::nullptr_t, SA = SA{}): base_t(), p_stor() {
|
||||||
this->set_dead();
|
this->set_dead();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,15 +56,17 @@ protected:
|
||||||
/* coroutine context must be polymorphic */
|
/* coroutine context must be polymorphic */
|
||||||
virtual ~coroutine_context() {
|
virtual ~coroutine_context() {
|
||||||
unwind();
|
unwind();
|
||||||
|
free_stack();
|
||||||
}
|
}
|
||||||
|
|
||||||
coroutine_context(coroutine_context const &) = delete;
|
coroutine_context(coroutine_context const &) = delete;
|
||||||
coroutine_context(coroutine_context &&c):
|
coroutine_context(coroutine_context &&c):
|
||||||
p_stack(std::move(c.p_stack)), p_coro(c.p_coro), p_orig(c.p_orig),
|
p_stack(std::move(c.p_stack)), p_coro(c.p_coro), p_orig(c.p_orig),
|
||||||
p_except(std::move(c.p_except)), p_state(std::move(c.p_state))
|
p_except(std::move(c.p_except)), p_state(c.p_state), p_free(c.p_free)
|
||||||
{
|
{
|
||||||
c.p_coro = c.p_orig = nullptr;
|
c.p_coro = c.p_orig = nullptr;
|
||||||
c.p_stack = { nullptr, 0 };
|
c.p_stack = { nullptr, 0 };
|
||||||
|
c.p_free = nullptr;
|
||||||
c.set_dead();
|
c.set_dead();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,6 +95,11 @@ protected:
|
||||||
p_orig = detail::ostd_jump_fcontext(p_orig, nullptr).ctx;
|
p_orig = detail::ostd_jump_fcontext(p_orig, nullptr).ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void yield_done() {
|
||||||
|
set_dead();
|
||||||
|
p_orig = detail::ostd_jump_fcontext(p_orig, nullptr).ctx;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_hold() const {
|
bool is_hold() const {
|
||||||
return (p_state == state::HOLD);
|
return (p_state == state::HOLD);
|
||||||
}
|
}
|
||||||
|
@ -122,6 +129,7 @@ protected:
|
||||||
swap(p_orig, other.p_orig);
|
swap(p_orig, other.p_orig);
|
||||||
swap(p_except, other.p_except);
|
swap(p_except, other.p_except);
|
||||||
swap(p_state, other.p_state);
|
swap(p_state, other.p_state);
|
||||||
|
swap(p_free, other.p_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename C, typename SA>
|
template<typename C, typename SA>
|
||||||
|
@ -134,6 +142,7 @@ protected:
|
||||||
|
|
||||||
p_coro = detail::ostd_make_fcontext(sp, asize, &context_call<C, SA>);
|
p_coro = detail::ostd_make_fcontext(sp, asize, &context_call<C, SA>);
|
||||||
new (sp) SA(std::move(sa));
|
new (sp) SA(std::move(sa));
|
||||||
|
p_free = &free_stack_call<SA>;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -171,11 +180,7 @@ private:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!p_orig) {
|
if (!p_orig) {
|
||||||
/* this coroutine never got to live :(
|
/* this coroutine never got to live :( */
|
||||||
* let it call the entry point at least this once...
|
|
||||||
* this will kill the stack so we don't leak memory
|
|
||||||
*/
|
|
||||||
coro_jump();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
detail::ostd_ontop_fcontext(
|
detail::ostd_ontop_fcontext(
|
||||||
|
@ -187,19 +192,18 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename SA>
|
template<typename SA>
|
||||||
void finish() {
|
static void free_stack_call(void *data) {
|
||||||
set_dead();
|
auto &self = *(static_cast<coroutine_context *>(data));
|
||||||
detail::ostd_ontop_fcontext(
|
auto &sa = *(static_cast<SA *>(self.get_stack_ptr<SA>()));
|
||||||
p_orig, this, [](detail::transfer_t t) -> detail::transfer_t {
|
SA dsa{std::move(sa)};
|
||||||
auto &self = *(static_cast<coroutine_context *>(t.data));
|
sa.~SA();
|
||||||
auto &sa = *(static_cast<SA *>(self.get_stack_ptr<SA>()));
|
dsa.deallocate(self.p_stack);
|
||||||
SA dsa{std::move(sa)};
|
}
|
||||||
/* in case it holds any state that needs destroying */
|
|
||||||
sa.~SA();
|
void free_stack() {
|
||||||
dsa.deallocate(self.p_stack);
|
if (p_free) {
|
||||||
return { nullptr, nullptr };
|
p_free(this);
|
||||||
}
|
}
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename C, typename SA>
|
template<typename C, typename SA>
|
||||||
|
@ -223,7 +227,7 @@ private:
|
||||||
}
|
}
|
||||||
/* switch back, release stack */
|
/* switch back, release stack */
|
||||||
release:
|
release:
|
||||||
self.template finish<SA>();
|
self.yield_done();
|
||||||
}
|
}
|
||||||
|
|
||||||
stack_context p_stack;
|
stack_context p_stack;
|
||||||
|
@ -231,6 +235,7 @@ release:
|
||||||
detail::fcontext_t p_orig = nullptr;
|
detail::fcontext_t p_orig = nullptr;
|
||||||
std::exception_ptr p_except;
|
std::exception_ptr p_except;
|
||||||
state p_state = state::HOLD;
|
state p_state = state::HOLD;
|
||||||
|
void (*p_free)(void *) = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace ostd */
|
} /* namespace ostd */
|
||||||
|
|
Loading…
Reference in New Issue