longjmp-like coroutine support
etorth opened this issue · 1 comments
Hi Andreasbuhr,
Is it possible to add following coroutine model to your repo?
it works like C-stype longjmp function, to suspend/resume through multi-nested-coroutines.
I am not sure if this is a good coroutine model.
This is very useful for game coding when at every round the AI get update a little then jumps back to the main message loop.
The following code is what I got from stackoverflow:
https://stackoverflow.com/questions/61696746/supsending-thrugh-multiple-nested-coroutines
to compile:
g++-10 main.cpp -std=c++20 -fcoroutines -g -fsanitize=address -Wall
#include <cstdio>
#include <coroutine>
#include <optional>
namespace
{
template <typename T>
struct task
{
struct task_promise;
using promise_type = task_promise;
using handle_type = std::coroutine_handle<promise_type>;
mutable handle_type m_handle;
task(handle_type handle)
: m_handle(handle)
{
}
task(task&& other) noexcept
: m_handle(other.m_handle)
{
other.m_handle = nullptr;
}
bool await_ready()
{
return false;
}
bool await_suspend(std::coroutine_handle<> handle)
{
return true;
}
bool await_suspend(std::coroutine_handle<promise_type> handle)
{
handle.promise().m_inner_handler = m_handle;
m_handle.promise().m_outer_handler = handle;
return true;
}
auto await_resume()
{
return *m_handle.promise().m_value;
}
//manualy wait for finish
bool one_step()
{
auto curr = m_handle;
while (curr)
{
if (!curr.promise().m_inner_handler)
{
while (!curr.done())
{
curr.resume();
if (!curr.done())
{
return true;
}
if (curr.promise().m_outer_handler)
{
curr = curr.promise().m_outer_handler;
curr.promise().m_inner_handler = nullptr;
}
else
{
return false;
}
}
break;
}
curr = curr.promise().m_inner_handler;
}
return !curr.done();
}
~task()
{
if (m_handle)
m_handle.destroy();
}
struct task_promise
{
std::optional<T> m_value {};
std::coroutine_handle<promise_type> m_inner_handler {};
std::coroutine_handle<promise_type> m_outer_handler {};
auto value()
{
return m_value;
}
auto initial_suspend()
{
return std::suspend_never{};
}
auto final_suspend()
{
return std::suspend_always{};
}
auto return_value(T t)
{
m_value = t;
return std::suspend_always{};
}
task<T> get_return_object()
{
return {handle_type::from_promise(*this)};
}
void unhandled_exception()
{
std::terminate();
}
void rethrow_if_unhandled_exception()
{
}
};
};
task<int> suspend_one()
{
std::printf("suspend_one \\\n");
co_await std::suspend_always();
std::printf("suspend_one /\n");
co_return 1;
}
task<int> suspend_two()
{
auto a = co_await suspend_one();
auto b = co_await suspend_one();
co_return a + b;
}
task<int> suspend_five()
{
auto a = co_await suspend_two();
auto b = co_await suspend_two();
co_return 1 + a + b;
}
task<int> run()
{
std::printf("run\n");
auto a = co_await suspend_five();
auto b = co_await suspend_five();
auto c = co_await suspend_five();
co_return 5 + a + b + c;
}
}
int main()
{
std::printf( "main in\n");
auto r = run();
std::printf( "main -> while\n");
while (r.one_step()){ std::printf(" while loop\n"); }
std::printf( "main return\n");
return r.await_resume();
}
Hi @etorth , thanks a lot for your proposal. At the moment we are quite busy stabilizing cppcoro and top priority is adding Linux support at the moment, so please be patient before we can add new functionality.
Some thoughts:
- What does "rethrow_if_unhandled_exception" do?
- Is it correct that "return_value" returns a std::suspend_always{} ?
- Is it correct that "await_suspend(std::coroutine_handle<> handle)" does not exchange the coroutine handles?