below is a snippet testing empty coroutine playing with promise_type
#include <iostream>
#include <coroutine>
#define DEBUG std::cout << __PRETTY_FUNCTION__ << std::endl
struct TaskSuspendAll {
// must be of this name
struct promise_type {
TaskSuspendAll get_return_object() noexcept {
return TaskSuspendAll{
std::coroutine_handle<promise_type>::from_promise(*this)
};
}
std::suspend_always initial_suspend() noexcept {
DEBUG;
return {};
}
std::suspend_always final_suspend() noexcept {
DEBUG;
return {};
}
void unhandled_exception() {}
void return_void() {
DEBUG;
}
};
std::coroutine_handle<promise_type> ch;
};
TaskSuspendAll TestSuspendAll() {
DEBUG;
co_return;
}
int main() {
std::cout << std::endl;
auto t = TestSuspendAll();
t.ch.resume();
//t.ch.resume()
//t.ch.destroy();
return 0;
}
running this I get
std::__n4861::suspend_always TaskSuspendAll::promise_type::initial_suspend()
TaskSuspendAll TestSuspendAll()
void TaskSuspendAll::promise_type::return_void()
std::__n4861::suspend_always TaskSuspendAll::promise_type::final_suspend()
My understanding is that co_await
is applied to initial_suspend
and final_suspend
. When I call TestSuspendAll
in the main
function it will eventually call co_await promise.initial_suspend()
and return to the caller given i have std::suspend_always
awaitable. Then i resume the coroutine and the body gets executed. At some point, we will have co_await promise.final_suspend()
and again return to the caller.
question: I would expect that i have to do a second call to resume coroutine so that co_await promise.final_suspend()
succeeded and coroutine completed. However that causes seg fault. I know that it's undefined behavior calling resume on completed coroutine, however it's not completed 100% as far as I understand. My expectation was that final_suspend
behaves the same as initial_suspend
... what is the logic here? is that we have to use destroy after call to final_suspend
?
thanks a lot for clarification!
VK
CodePudding user response:
Being suspended at its final suspend point is the definition of a coroutine being done. Literally; that's what coroutine_handle::done
returns. Attempting to resume such a coroutine is UB.
So your expectation is not correct.