The co_await
operator makes the current coroutine suspended, and the compiler must save where the coroutine should continue execution when it's resumed, so there is a location information somewhere. Is it possible to obtain this location information and convert it to file and line numbers to help debugging coroutines and trace back asynchronous calls?
I guess if such feature exists, it must be compiler specific, I'm interested in both GCC and MSVC compilers.
My current workaround is having an ugly AWAIT
macro that's declared like this in debug builds:
#define AWAIT(x) (co_await (x).passLocation(__PRETTY_FUNCTION__, __FILE__, __LINE__))
Where x
is the return type of a coroutine that has a passLocation
method which passes the info into the promise, then returns *this
. And I'm using AWAIT(x)
instead of co_await x
.
If there is a way to let obtain location infromation from the handle, then I can avoid using this hack.
The first part of evaluating the co_await x;
expression calls e.await_ready()
, where e
is either x
or a derivative of x
. The await_ready
function is called with no parameters. However, the overload of await_ready
can have default parameters; it just needs to be callable with no parameters.
So you can use the standard C++20 mechanism for capturing program location: std::source_location::current()
as a default parameter to await_ready
.
However, this is part of the awaitable type, not a part of the promise. If you need to get this to the promise, then it needs to go into await_suspend
, which gets a coroutine_handle<P>
to the promise object via the expression e.await_suspend(h)
, where h
is a coroutine_handle<P>
.
That being said, such direct coupling between an awaitable and a promise isn't the most ideal situation. coroutine_handle<>
erases the type of the promise, so you have to explicitly have your await_suspend
overload use coroutine_handle<P>
, where P
is the particular promise type of your current function. You can have a different overload for different promise types (or <>
if you don't care):
auto await_suspend(coroutine_promise<P> h, std::source_location loc = std::source_location::current())
{
h.promise().suspend_location(loc);
//Usual stuff.
}
You would need a generic overload (using coroutine_promise<>
) to handle promises that aren't of type P
.