AFAICT there is no builtin way in C++20 or C++23 to globally query the promise or handle for the coroutine running on the current thread. However any of the functions that let you return a coroutine to trigger running it, e.g. initial_suspend
, final_suspend
, await_suspend
etc would know what coroutine is about to run and could set a thread_local
to the coroutine_handle
they are returning before returning. Is that sufficient or are there more cases to worry about? This is assuming that in typical usage people are doing co_await
on their task types and not manually running their own loop calling handle.resume()
over and over (and if there was an executor/execution-agent switching between stored top-level coroutines that it would cooperate with the scheme).
I had the same problem some time ago - I tried various approaches - also the "co_await"-way mentioned in comments - but the best with performance in mind is to use "co_yield". Just create some get_handle
empty class to tag-dispatch to your yield_value
method. And from this yield_value(get_handle)
method return awaitable type derived from std::suspend_never
- so no "suspend" - and overload await_resume
to return handle to the caller from the actual coroutine body.
#include <coroutine>
struct get_handle{}; // just tag type
struct coro
{
struct promise_type;
using handle_type = std::coroutine_handle<promise_type>;
struct promise_type
{
int some_value = 42; // for presentation purposes
auto initial_suspend() noexcept { return std::suspend_never{}; }
auto final_suspend() noexcept { return std::suspend_never{}; }
coro get_return_object() { return {}; }
void unhandled_exception() {}
void return_void() {}
auto yield_value(get_handle)
{
struct return_handle : std::suspend_never
{
handle_type handle;
handle_type await_resume() const
{
return handle;
}
};
return return_handle{.handle = handle_type::from_promise(*this)};
}
};
};
and proof it works:
coro foo()
{
auto handle = co_yield get_handle{};
std::cout << handle.promise().some_value;
}
int main() {
foo();
}
But maybe most important - you can use "co_yield" (and co_await with await_transform too) to communicate with your promise object - so, actually, in most cases you shall not need to get full handle - so if you can redesign your implementation in the way to not need this handle inside coroutine body - that would be the best probably.