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;
for (int i: range(steps)) {
writeln(" calling into coroutine...");
int v;
try {
v = f(val);
} catch (coroutine_error const &e) {
writefln("coroutine error: %s", e.what());
return 0;
}
auto v = f(val);
writefln(" called into coroutine which yielded: %s", v);
writefln(" call loop iteration %s done", i + 1);
writefln(" coroutine dead: %s", !f);
@ -291,5 +285,6 @@ starting main...
call loop iteration 6 done
coroutine dead: true
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) {
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)>{});
}
@ -289,7 +287,6 @@ 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)>{});
}
@ -304,7 +301,6 @@ 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)>{});
}
@ -318,7 +314,6 @@ 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)>{});
}
@ -424,8 +419,7 @@ private:
}
/* switch back, release stack */
release:
self.set_dead();
self.yield_jump();
self.template finish<SA>();
}
std::function<R(yield_type, A...)> p_func;
@ -452,13 +446,11 @@ 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:
@ -574,8 +566,7 @@ private:
}
release:
self.p_result = nullptr;
self.set_dead();
self.yield_jump();
self.template finish<SA>();
}
std::function<void(yield_type)> p_func;

View File

@ -56,12 +56,11 @@ 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_free(c.p_free)
p_sa(c.p_sa)
{
c.p_coro = c.p_orig = nullptr;
c.p_stack = { nullptr, 0 };
c.p_sa = nullptr;
c.p_free = nullptr;
c.set_dead();
}
@ -80,21 +79,37 @@ protected:
}
void unwind() {
if (is_dead() || !p_orig) {
/* this coroutine is either done or never started */
free_stack();
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();
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};
}
);
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() {
@ -102,6 +117,7 @@ protected:
}
void yield_jump() {
p_state = state::HOLD;
p_orig = ostd_jump_fcontext(p_orig, nullptr).ctx;
}
@ -113,10 +129,6 @@ protected:
return (p_state == state::TERM);
}
void set_hold() {
p_state = state::HOLD;
}
void set_dead() {
p_state = state::TERM;
}
@ -129,7 +141,6 @@ protected:
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>
@ -146,20 +157,6 @@ 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;
@ -168,7 +165,6 @@ protected:
std::exception_ptr p_except;
state p_state = state::HOLD;
void *p_sa = nullptr;
void (*p_free)(void *) = nullptr;
};
} /* namespace detail */