Beginning the coroutine with Visual Studio 2015 Update 3 Part 1

I recently started using the cppwinrt library which brought chances dealing with the new C++ standard(yet) coroutine. The cppwinrt recommends using C++ coroutines instead of PPL while handling async operations. Refer to the following github issues for more information:

https://github.com/Microsoft/cppwinrt/issues/54

https://github.com/Microsoft/cppwinrt/issues/46

Although the coroutine concept itself might feel coming familiar because we’re already exposed async programming concept much from python asyncio, C# async/await experiences, however the C++ coroutine requires few prerequisite concepts, predefined structures and functions just in order to begin with. I had absolute no idea those, so I decided to start digging in to understand how things orchestrate and work under the hood.

Fortunately, James McNellis from the Microsoft VC++ team had an introductory talk “Introduction to C++ Coroutines” from the cppcon 2016. The talk is great. You really should watch it first if you want to learn the C++ coroutine. However, it feels like a little ambiguous. So that I decided to write actual codes what he had shown from his slides and test it.

So at the very beginning, I created the simplest C++ console project from the Visual Studio 2015 Update 3.

First, changed the warning level,

Typed the simple awaitable function shown from the slide and tried build it.

#include <future>
std::future<int> compute_value()
{
int result = co_await std::async([]
{
return 30;
});
co_return result;
}
int main()
{
compute_value().get();
return 0;
}

And of course the compiler failed to build and showed the following error:

1>—— Build started: Project: resumable-concept, Configuration: Debug x64 ——

1> Skipping… (no relevant changes detected)

1> stdafx.cpp

1> resumable-concept.cpp

1>d:\workspace\playground\async_research\resumable-idea\resumable-idea\resumable-concept.cpp(10): error C3773: please use /await compiler switch to enable coroutines

1>d:\workspace\playground\async_research\resumable-idea\resumable-idea\resumable-concept.cpp(13): error C3774: cannot find ‘std::experimental’: Please include <experimental/resumable> header

1>d:\workspace\playground\async_research\resumable-idea\resumable-idea\resumable-concept.cpp(15): error C3773: please use /await compiler switch to enable coroutines

1>d:\workspace\playground\async_research\resumable-idea\resumable-idea\resumable-concept.cpp(20): error C2228: left of ‘.get’ must have class/struct/union

========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

So I added the /await option as the error indicated:

Also included required header files at stdafx.h:

// TODO: reference additional headers your program requires here
#include <windows.h>
#include <future>
#include <iostream>
#ifdef _RESUMABLE_FUNCTIONS_SUPPORTED
#include <experimental/resumable>
#endif
view raw stdafx.h hosted with ❤ by GitHub

And tried build again…….

Succeeded!

1>—— Rebuild All started: Project: resumable-concept, Configuration: Debug x64 ——

1> stdafx.cpp

1> resumable-concept.cpp

1> resumable-idea.vcxproj -> D:\workspace\playground\async_research\resumable-idea\x64\Debug\resumable-concept.exe

1> resumable-idea.vcxproj -> D:\workspace\playground\async_research\resumable-idea\x64\Debug\resumable-concept.pdb (Full PDB)

========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========

Let’s see what the co_await actually does in detail:

From the cppcon talk,

He explains that if we use the co_await keyword, the compiler will generate the code shown on the right. Which means in order to work with the co_await keyword, someone should provide the required functions such as await_ready, await_suspend, await_resume, so from the next page it introduces the ‘awaitable_concept’ structure which has the all functions mentioned.

For example, we used the std::future from the first sample, and you’ll see the following snippets if you open the future std header file and search ‘await_ready’ string.

template<class _Ty>
bool await_ready(future<_Ty>& _Fut)
{
return (_Fut._Is_ready());
}
template<class _Ty>
void await_suspend(future<_Ty>& _Fut,
experimental::coroutine_handle<> _ResumeCb)
{ // change to .then when future gets .then
thread _WaitingThread([&_Fut, _ResumeCb]{
_Fut.wait();
_ResumeCb();
});
_WaitingThread.detach();
}
view raw future.h hosted with ❤ by GitHub

If so, how can you make your own type to awaitable to work with co_await instead of using std::future?

From the cppcon talk, James explains it type named ‘resumable_thing’.

Let’s type exactly same code he’d shown us and try build it. I added the ‘resume()’ class method which is not listed from the slide but to work. This is to see what functions exactly required to be implemented to work with co_await keyword.

// resumable-idea.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
using namespace std;
struct resumable_thing
{
void resume() {}
};
resumable_thing counter() {
cout << "counter: called\n";
for (unsigned i = 1; ; i++)
{
co_await std::experimental::suspend_always{};
cout << "counter:: resumed\n";
}
}
void main()
{
cout << "main: calling counter\n";
resumable_thing the_counter = counter();
cout << "main: resuming counter\n";
the_counter.resume();
the_counter.resume();
cout << "main: done\n";
}
view raw resumable.cpp hosted with ❤ by GitHub

You’ll get following errors when you build the example:

1>—— Build started: Project: resumable-concept, Configuration: Debug x64 ——

1> resumable-concept.cpp

1>d:\devtools\vs14\vc\include\experimental\resumable(44): error C2039: ‘promise_type’: is not a member of ‘resumable_thing’

1> d:\workspace\playground\async_research\resumable-idea\resumable-idea\resumable-concept.cpp(9): note: see declaration of ‘resumable_thing’

1> d:\workspace\playground\async_research\resumable-idea\resumable-idea\resumable-concept.cpp(17): note: see reference to class template instantiation ‘std::experimental::coroutine_traits<resumable_thing>’ being compiled

1>d:\devtools\vs14\vc\include\experimental\resumable(44): error C2061: syntax error: identifier ‘promise_type’

1>d:\devtools\vs14\vc\include\experimental\resumable(44): error C2238: unexpected token(s) preceding ‘;’

1>d:\workspace\playground\async_research\resumable-idea\resumable-idea\resumable-concept.cpp(25): error C2440: ‘initializing’: cannot convert from ‘resumable_thing (__cdecl *)(void)’ to ‘resumable_thing’

1> d:\workspace\playground\async_research\resumable-idea\resumable-idea\resumable-concept.cpp(25): note: No constructor could take the source type, or constructor overload resolution was ambiguous

========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Double clicked the first error line to move to exact error location,

1>d:\devtools\vs14\vc\include\experimental\resumable(44): error C2039: ‘promise_type’: is not a member of ‘resumable_thing’

namespace experimental {

    // TEMPLATE CLASS coroutine_traits

    template <typename
_Ret, typename_Ts>

    struct
coroutine_traits

    {

        using
promise_type = typename
_Ret::promise_type;

    };

As you see, the compiler failed to template instantiate coroutine_traits<resumable_thing> because the promise_type is not declared from resumable_thing.

If so, let’s fill up the remaining method implementations as the slide shows:

// resumable-idea.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
using namespace std;
using namespace std::experimental;
struct resumable_thing
{
struct promise_type
{
resumable_thing get_return_object()
{
return resumable_thing(coroutine_handle<promise_type>::from_promise(*this));
}
auto initial_suspend() { return suspend_never{}; }
auto final_suspend() { return suspend_never{}; }
void return_void() {}
};
coroutine_handle<promise_type> _coroutine = nullptr;
resumable_thing() = default;
resumable_thing(resumable_thing const&) = delete;
resumable_thing& operator=(resumable_thing const&) = delete;
resumable_thing(resumable_thing&& other)
: _coroutine(other._coroutine) {
other._coroutine = nullptr;
}
resumable_thing& operator = (resumable_thing&& other) {
if (&other != this) {
_coroutine = other._coroutine;
other._coroutine = nullptr;
}
}
explicit resumable_thing(coroutine_handle<promise_type> coroutine) : _coroutine(coroutine)
{
}
~resumable_thing()
{
if (_coroutine) { _coroutine.destroy(); }
}
void resume() { _coroutine.resume(); }
};
resumable_thing counter() {
cout << "counter: called\n";
for (unsigned i = 1; ; i++)
{
co_await std::experimental::suspend_always{};
cout << "counter:: resumed (#" << i << ")\n";
}
}
void main()
{
cout << "main: calling counter\n";
resumable_thing the_counter = counter();
cout << "main: resuming counter\n";
the_counter.resume();
the_counter.resume();
cout << "main: done\n";
}

Finally works as expected:

If so, what exactly happening from the ‘counter’ coroutine function returns resumable_thing? From the talk, the slide shows the following pseudo code:

If you’re stepping into the assembly code while debugging, you’ll see similar functions are actually implemented:

First of all, it starts its async operation by calling the ‘InitCoro$1’. If you stepped into the inside ‘InitCoro$1’ function, you’ll see the function implements prologue what the next image suggests as the first three lines:

00B12A41 call std::experimental::_Resumable_helper_traits<resumable_thing>::_ConstructPromise (0B1132Ah)

00B12A46 add esp,0Ch

00B12A49 mov byte ptr [ebp-4],1

00B12A4D lea eax,[ebp-0D1h]

00B12A53 push eax

00B12A54 mov ecx,dword ptr [<coro_frame_ptr>]

00B12A57 push ecx

00B12A58 call std::experimental::_Resumable_helper_traits<resumable_thing>::_Promise_from_frame (0B11217h)

00B12A5D add esp,4

00B12A60 mov ecx,eax

00B12A62 call resumable_thing::promise_type::initial_suspend (0B111EFh)

00B12A67 mov dl,byte ptr [eax]

00B12A69 movzx eax,dl

00B12A6C push eax

00B12A6D mov ecx,80h

00B12A72 add ecx,dword ptr [<coro_frame_ptr>]

00B12A75 call `counter’::`5′::<parameters>::<parameters> (0B11FC0h)

00B12A7A mov eax,dword ptr [__$ReturnUdt]

00B12A7D push eax

00B12A7E mov ecx,dword ptr [<coro_frame_ptr>]

00B12A81 push ecx

00B12A82 call std::experimental::_Resumable_helper_traits<resumable_thing>::_Promise_from_frame (0B11217h)

00B12A87 add esp,4

00B12A8A mov ecx,eax

00B12A8C call resumable_thing::promise_type::get_return_object (0B11479h)

00B12A91 mov dword ptr [ebp-4],2

00B12A98 mov ecx,80h

00B12A9D add ecx,dword ptr [<coro_frame_ptr>]

00B12AA0 call std::experimental::suspend_never::await_ready (0B11348h)

00B12AA5 movzx eax,al

00B12AA8 test eax,eax

00B12AAA je counter$_InitCoro$1+0CAh (0B12ABAh)

00B12AAC mov ecx,dword ptr [<coro_frame_ptr>]

00B12AAF push ecx

00B12AB0 call counter$_ResumeCoro$2 (0B12B70h)

00B12AB5 add esp,4

00B12AB8 jmp counter$_InitCoro$1+103h (0B12AF3h)

}

It first creates the Promise instance:

00B12A41 call std::experimental::_Resumable_helper_traits<resumable_thing>::_ConstructPromise (0B1132Ah)

The function creates it by calling the std::experimental::_Resumable_helper_traits<resumable_thing>::_ConstructPromise(void *, void *, int) function which is implemented at “\VC\include\experimental\resumable”

If you open the file and see the code,

        static
void _ConstructPromise(void *_Addr, void *_Resume_addr, int
_HeapElision)

        {

            *reinterpret_cast<void **>(_Addr) = _Resume_addr;

            *reinterpret_cast<uint32_t *>(reinterpret_cast<uintptr_t>(_Addr) +

                                         sizeof(void *)) = 2 + (_HeapElision ? 0 : 0x10000);

            auto _Prom = _Promise_from_frame(_Addr);

            ::new (static_cast<void *>(_Prom)) _PromiseT();

        }

It instantiates the promise_type which is defined within resumable_thing from our example. After instantiated, initial_suspend() will be executed as the deck explained.

As a next step, resumable_thing::promise_type::get_return_object() will be called. The resumable_thing instance is getting created from this get_return_object().

The prologue pseudo code explained that _promise.initial_suspend() will be called as a next step, and from the our example, the resumable_thing::promise_type::initial_suspend() returns suspend_never{}. So suspend_never::await_ready is getting called as next.

Finally, if we step into the function counter$_ResumeCoro$2(void) which is below:

There exists actual counter() function implementation if we stepped into resumeCoro. Later when the the_counter.resume() ran, Instruction Pointer is transferred same as if the resumeCoro ran.

Next time, let’s see how the cppwinrt overloads co_await operator and utilize it.

Part II

One thought on “Beginning the coroutine with Visual Studio 2015 Update 3 Part 1

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s