forked from OctaForge/libostd
dealloc stacks in destructor (allows stack reuse)
parent
0185fa7c12
commit
20f57dad9b
|
@ -37,7 +37,13 @@ int main() {
|
|||
int val = 5;
|
||||
for (int i: range(steps)) {
|
||||
writeln(" calling into coroutine...");
|
||||
auto v = f(val);
|
||||
int v;
|
||||
try {
|
||||
v = f(val);
|
||||
} catch (coroutine_error const &e) {
|
||||
writefln("coroutine error: %s", e.what());
|
||||
return 0;
|
||||
}
|
||||
writefln(" called into coroutine which yielded: %s", v);
|
||||
writefln(" call loop iteration %s done", i + 1);
|
||||
writefln(" coroutine dead: %s", !f);
|
||||
|
@ -285,6 +291,5 @@ starting main...
|
|||
call loop iteration 6 done
|
||||
coroutine dead: true
|
||||
calling into coroutine...
|
||||
terminating with uncaught exception of type ostd::coroutine_error: dead coroutine
|
||||
zsh: abort ./coro
|
||||
coroutine error: dead coroutine
|
||||
*/
|
||||
|
|
|
@ -267,12 +267,14 @@ namespace detail {
|
|||
|
||||
coro_args<A...> operator()(R &&ret) {
|
||||
p_coro.p_result = std::forward<R>(ret);
|
||||
p_coro.set_hold();
|
||||
p_coro.yield_jump();
|
||||
return p_coro.get_args(std::make_index_sequence<sizeof...(A)>{});
|
||||
}
|
||||
|
||||
coro_args<A...> operator()(R const &ret) {
|
||||
p_coro.p_result = ret;
|
||||
p_coro.set_hold();
|
||||
p_coro.yield_jump();
|
||||
return p_coro.get_args(std::make_index_sequence<sizeof...(A)>{});
|
||||
}
|
||||
|
@ -287,6 +289,7 @@ namespace detail {
|
|||
|
||||
coro_args<A...> operator()(R &ret) {
|
||||
p_coro.p_result = ret;
|
||||
p_coro.set_hold();
|
||||
p_coro.yield_jump();
|
||||
return p_coro.get_args(std::make_index_sequence<sizeof...(A)>{});
|
||||
}
|
||||
|
@ -301,6 +304,7 @@ namespace detail {
|
|||
|
||||
coro_args<A...> operator()(R &&ret) {
|
||||
p_coro.p_result = std::forward<R>(ret);
|
||||
p_coro.set_hold();
|
||||
p_coro.yield_jump();
|
||||
return p_coro.get_args(std::make_index_sequence<sizeof...(A)>{});
|
||||
}
|
||||
|
@ -314,6 +318,7 @@ namespace detail {
|
|||
coro_yielder(coro_base<void, A...> &coro): p_coro(coro) {}
|
||||
|
||||
coro_args<A...> operator()() {
|
||||
p_coro.set_hold();
|
||||
p_coro.yield_jump();
|
||||
return p_coro.get_args(std::make_index_sequence<sizeof...(A)>{});
|
||||
}
|
||||
|
@ -419,7 +424,8 @@ private:
|
|||
}
|
||||
/* switch back, release stack */
|
||||
release:
|
||||
self.template finish<SA>();
|
||||
self.set_dead();
|
||||
self.yield_jump();
|
||||
}
|
||||
|
||||
std::function<R(yield_type, A...)> p_func;
|
||||
|
@ -446,11 +452,13 @@ private:
|
|||
|
||||
void operator()(T &&ret) {
|
||||
p_gen.p_result = &ret;
|
||||
p_gen.set_hold();
|
||||
p_gen.yield_jump();
|
||||
}
|
||||
|
||||
void operator()(T &ret) {
|
||||
p_gen.p_result = &ret;
|
||||
p_gen.set_hold();
|
||||
p_gen.yield_jump();
|
||||
}
|
||||
private:
|
||||
|
@ -566,7 +574,8 @@ private:
|
|||
}
|
||||
release:
|
||||
self.p_result = nullptr;
|
||||
self.template finish<SA>();
|
||||
self.set_dead();
|
||||
self.yield_jump();
|
||||
}
|
||||
|
||||
std::function<void(yield_type)> p_func;
|
||||
|
|
|
@ -56,11 +56,12 @@ protected:
|
|||
coroutine_context(coroutine_context &&c):
|
||||
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_sa(c.p_sa)
|
||||
p_sa(c.p_sa), p_free(c.p_free)
|
||||
{
|
||||
c.p_coro = c.p_orig = nullptr;
|
||||
c.p_stack = { nullptr, 0 };
|
||||
c.p_sa = nullptr;
|
||||
c.p_free = nullptr;
|
||||
c.set_dead();
|
||||
}
|
||||
|
||||
|
@ -79,37 +80,21 @@ protected:
|
|||
}
|
||||
|
||||
void unwind() {
|
||||
if (is_dead()) {
|
||||
/* this coroutine was either initialized with a null function or
|
||||
* it's already terminated and thus its stack has already unwound
|
||||
*/
|
||||
return;
|
||||
}
|
||||
if (!p_orig) {
|
||||
/* 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();
|
||||
if (is_dead() || !p_orig) {
|
||||
/* this coroutine is either done or never started */
|
||||
free_stack();
|
||||
return;
|
||||
}
|
||||
/* this coroutine is suspended, and we need to make sure all
|
||||
* the destructors for its locals get called by forcing unwind
|
||||
*/
|
||||
ostd_ontop_fcontext(
|
||||
std::exchange(p_coro, nullptr), nullptr,
|
||||
[](transfer_t t) -> transfer_t {
|
||||
throw forced_unwind{t.ctx};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
template<typename SA>
|
||||
void finish() {
|
||||
set_dead();
|
||||
ostd_ontop_fcontext(p_orig, this, [](transfer_t t) -> transfer_t {
|
||||
auto &self = *(static_cast<coroutine_context *>(t.data));
|
||||
auto &sa = *(static_cast<SA *>(self.p_sa));
|
||||
sa.deallocate(self.p_stack);
|
||||
return { nullptr, nullptr };
|
||||
});
|
||||
free_stack();
|
||||
}
|
||||
|
||||
void coro_jump() {
|
||||
|
@ -117,7 +102,6 @@ protected:
|
|||
}
|
||||
|
||||
void yield_jump() {
|
||||
p_state = state::HOLD;
|
||||
p_orig = ostd_jump_fcontext(p_orig, nullptr).ctx;
|
||||
}
|
||||
|
||||
|
@ -129,6 +113,10 @@ protected:
|
|||
return (p_state == state::TERM);
|
||||
}
|
||||
|
||||
void set_hold() {
|
||||
p_state = state::HOLD;
|
||||
}
|
||||
|
||||
void set_dead() {
|
||||
p_state = state::TERM;
|
||||
}
|
||||
|
@ -139,6 +127,9 @@ protected:
|
|||
swap(p_coro, other.p_coro);
|
||||
swap(p_orig, other.p_orig);
|
||||
swap(p_except, other.p_except);
|
||||
swap(p_state, other.p_state);
|
||||
swap(p_sa, other.p_sa);
|
||||
swap(p_free, other.p_free);
|
||||
}
|
||||
|
||||
template<typename SA>
|
||||
|
@ -155,6 +146,20 @@ protected:
|
|||
|
||||
p_coro = ostd_make_fcontext(sp, asize, callp);
|
||||
p_sa = new (sp) SA(std::move(sa));
|
||||
p_free = &free_stack_call<SA>;
|
||||
}
|
||||
|
||||
template<typename SA>
|
||||
static void free_stack_call(void *data) {
|
||||
auto &self = *(static_cast<coroutine_context *>(data));
|
||||
auto &sa = *(static_cast<SA *>(self.p_sa));
|
||||
sa.deallocate(self.p_stack);
|
||||
}
|
||||
|
||||
void free_stack() {
|
||||
if (p_free) {
|
||||
p_free(this);
|
||||
}
|
||||
}
|
||||
|
||||
stack_context p_stack;
|
||||
|
@ -162,7 +167,8 @@ protected:
|
|||
fcontext_t p_orig;
|
||||
std::exception_ptr p_except;
|
||||
state p_state = state::HOLD;
|
||||
void *p_sa;
|
||||
void *p_sa = nullptr;
|
||||
void (*p_free)(void *) = nullptr;
|
||||
};
|
||||
|
||||
} /* namespace detail */
|
||||
|
|
Loading…
Reference in New Issue