Home > database >  c coroutines final_suspend for promise_type
c coroutines final_suspend for promise_type

Time:01-01

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.

  • Related