revert the stack freeing method (can be achieved via stack allocator)

master
Daniel Kolesa 2017-03-11 18:22:01 +01:00
parent 20f57dad9b
commit 88e6fe3906
3 changed files with 30 additions and 48 deletions

View File

@ -37,13 +37,7 @@ int main() {
int val = 5; int val = 5;
for (int i: range(steps)) { for (int i: range(steps)) {
writeln(" calling into coroutine..."); writeln(" calling into coroutine...");
int v; auto v = f(val);
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(" called into coroutine which yielded: %s", v);
writefln(" call loop iteration %s done", i + 1); writefln(" call loop iteration %s done", i + 1);
writefln(" coroutine dead: %s", !f); writefln(" coroutine dead: %s", !f);
@ -291,5 +285,6 @@ starting main...
call loop iteration 6 done call loop iteration 6 done
coroutine dead: true coroutine dead: true
calling into coroutine... calling into coroutine...
coroutine error: dead coroutine terminating with uncaught exception of type ostd::coroutine_error: dead coroutine
zsh: abort ./coro
*/ */

View File

@ -267,14 +267,12 @@ namespace detail {
coro_args<A...> operator()(R &&ret) { coro_args<A...> operator()(R &&ret) {
p_coro.p_result = std::forward<R>(ret); p_coro.p_result = std::forward<R>(ret);
p_coro.set_hold();
p_coro.yield_jump(); p_coro.yield_jump();
return p_coro.get_args(std::make_index_sequence<sizeof...(A)>{}); return p_coro.get_args(std::make_index_sequence<sizeof...(A)>{});
} }
coro_args<A...> operator()(R const &ret) { coro_args<A...> operator()(R const &ret) {
p_coro.p_result = ret; p_coro.p_result = ret;
p_coro.set_hold();
p_coro.yield_jump(); p_coro.yield_jump();
return p_coro.get_args(std::make_index_sequence<sizeof...(A)>{}); return p_coro.get_args(std::make_index_sequence<sizeof...(A)>{});
} }
@ -289,7 +287,6 @@ namespace detail {
coro_args<A...> operator()(R &ret) { coro_args<A...> operator()(R &ret) {
p_coro.p_result = ret; p_coro.p_result = ret;
p_coro.set_hold();
p_coro.yield_jump(); p_coro.yield_jump();
return p_coro.get_args(std::make_index_sequence<sizeof...(A)>{}); return p_coro.get_args(std::make_index_sequence<sizeof...(A)>{});
} }
@ -304,7 +301,6 @@ namespace detail {
coro_args<A...> operator()(R &&ret) { coro_args<A...> operator()(R &&ret) {
p_coro.p_result = std::forward<R>(ret); p_coro.p_result = std::forward<R>(ret);
p_coro.set_hold();
p_coro.yield_jump(); p_coro.yield_jump();
return p_coro.get_args(std::make_index_sequence<sizeof...(A)>{}); return p_coro.get_args(std::make_index_sequence<sizeof...(A)>{});
} }
@ -318,7 +314,6 @@ namespace detail {
coro_yielder(coro_base<void, A...> &coro): p_coro(coro) {} coro_yielder(coro_base<void, A...> &coro): p_coro(coro) {}
coro_args<A...> operator()() { coro_args<A...> operator()() {
p_coro.set_hold();
p_coro.yield_jump(); p_coro.yield_jump();
return p_coro.get_args(std::make_index_sequence<sizeof...(A)>{}); return p_coro.get_args(std::make_index_sequence<sizeof...(A)>{});
} }
@ -424,8 +419,7 @@ private:
} }
/* switch back, release stack */ /* switch back, release stack */
release: release:
self.set_dead(); self.template finish<SA>();
self.yield_jump();
} }
std::function<R(yield_type, A...)> p_func; std::function<R(yield_type, A...)> p_func;
@ -452,13 +446,11 @@ private:
void operator()(T &&ret) { void operator()(T &&ret) {
p_gen.p_result = &ret; p_gen.p_result = &ret;
p_gen.set_hold();
p_gen.yield_jump(); p_gen.yield_jump();
} }
void operator()(T &ret) { void operator()(T &ret) {
p_gen.p_result = &ret; p_gen.p_result = &ret;
p_gen.set_hold();
p_gen.yield_jump(); p_gen.yield_jump();
} }
private: private:
@ -574,8 +566,7 @@ private:
} }
release: release:
self.p_result = nullptr; self.p_result = nullptr;
self.set_dead(); self.template finish<SA>();
self.yield_jump();
} }
std::function<void(yield_type)> p_func; std::function<void(yield_type)> p_func;

View File

@ -56,12 +56,11 @@ protected:
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(std::move(c.p_state)),
p_sa(c.p_sa), p_free(c.p_free) p_sa(c.p_sa)
{ {
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_sa = nullptr; c.p_sa = nullptr;
c.p_free = nullptr;
c.set_dead(); c.set_dead();
} }
@ -80,21 +79,37 @@ protected:
} }
void unwind() { void unwind() {
if (is_dead() || !p_orig) { if (is_dead()) {
/* this coroutine is either done or never started */ /* this coroutine was either initialized with a null function or
free_stack(); * 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();
return; 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( ostd_ontop_fcontext(
std::exchange(p_coro, nullptr), nullptr, std::exchange(p_coro, nullptr), nullptr,
[](transfer_t t) -> transfer_t { [](transfer_t t) -> transfer_t {
throw forced_unwind{t.ctx}; throw forced_unwind{t.ctx};
} }
); );
free_stack(); }
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 };
});
} }
void coro_jump() { void coro_jump() {
@ -102,6 +117,7 @@ protected:
} }
void yield_jump() { void yield_jump() {
p_state = state::HOLD;
p_orig = ostd_jump_fcontext(p_orig, nullptr).ctx; p_orig = ostd_jump_fcontext(p_orig, nullptr).ctx;
} }
@ -113,10 +129,6 @@ protected:
return (p_state == state::TERM); return (p_state == state::TERM);
} }
void set_hold() {
p_state = state::HOLD;
}
void set_dead() { void set_dead() {
p_state = state::TERM; p_state = state::TERM;
} }
@ -129,7 +141,6 @@ protected:
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_sa, other.p_sa); swap(p_sa, other.p_sa);
swap(p_free, other.p_free);
} }
template<typename SA> template<typename SA>
@ -146,20 +157,6 @@ protected:
p_coro = ostd_make_fcontext(sp, asize, callp); p_coro = ostd_make_fcontext(sp, asize, callp);
p_sa = new (sp) SA(std::move(sa)); 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; stack_context p_stack;
@ -168,7 +165,6 @@ protected:
std::exception_ptr p_except; std::exception_ptr p_except;
state p_state = state::HOLD; state p_state = state::HOLD;
void *p_sa = nullptr; void *p_sa = nullptr;
void (*p_free)(void *) = nullptr;
}; };
} /* namespace detail */ } /* namespace detail */