{"id":105160,"date":"2021-04-28T07:00:00","date_gmt":"2021-04-28T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=105160"},"modified":"2021-04-28T07:06:16","modified_gmt":"2021-04-28T14:06:16","slug":"20210428-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210428-00\/?p=105160","title":{"rendered":"C++ coroutines: Snooping in on the coroutine body"},"content":{"rendered":"<p>A coroutine promise can snoop on the coroutine body by implementing a method named <code>await_<wbr \/>transform<\/code>. Any time the coroutine body performs a <code>co_await<\/code>, the thing being awaited is passed through the <code>await_<wbr \/>transform<\/code> method, and whatever <code>await_<wbr \/>transform<\/code> returns is the thing that is <i>actually<\/i> awaited. This is the mysterious &#8220;<a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20191218-00\/?p=103221\">We&#8217;re not ready to talk about step 1 yet<\/a>&#8221; that kept reappearing in our introduction to awaitable objects.<\/p>\n<p>One way that <code>await_<wbr \/>transform<\/code> is used is to provide the coroutine body a way to communicate with the promise, by <code>co_await<\/code>&#8216;ing an object with a sentinel type. This is the magic behind secret signals like <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200722-00\/?p=103997\"> <code>co_await get_<wbr \/>cancellation_<wbr \/>token()<\/code><\/a>.<\/p>\n<p>Let&#8217;s use this to allow the coroutine to configure the promise&#8217;s <code>unhandled_exception<\/code> behavior.<\/p>\n<pre><span style=\"color: blue;\">namespace async_helpers::details\r\n{\r\n    struct simple_promise_policies\r\n    {\r\n        bool m_terminate_on_unhandled_exception = false;\r\n    };\r\n}<\/span>\r\n\r\nnamespace async_helpers\r\n{\r\n    template&lt;typename T&gt;\r\n    struct simple_task;\r\n\r\n    <span style=\"color: blue;\">struct simple_task_policy\r\n    {\r\n        simple_task_policy(details::simple_promise_policies&amp; policies)\r\n            : m_policies(policies) {}\r\n\r\n        bool terminate_on_unhandled_exception(bool value = true)\r\n            const noexcept\r\n        {\r\n            return std::exchange(\r\n                m_policies.m_terminate_on_unhandled_exception,\r\n                value);\r\n        }\r\n    private:\r\n        details::simple_promise_policies&amp; m_policies;\r\n    };\r\n\r\n    struct get_simple_task_policy {};<\/span>\r\n}\r\n<\/pre>\n<p>We start by declaring a private structure <code>simple_<wbr \/>promise_<wbr \/>policies<\/code> to hold our simple promise policies. So far, the only policy is whether to terminate on unhandled exception. You can imagine adding additional runtime policies here when they occur to you.<\/p>\n<p>We then provide a public structure <code>simple_<wbr \/>task_<wbr \/>policy<\/code> that wraps the private one. This is what the coroutine itself uses to alter the behavior of the promise.<\/p>\n<p>For now, there is only one method on the policy object, namely <code>terminate_<wbr \/>on_<wbr \/>unhandled_<wbr \/>exception()<\/code> which specifies whether you want the coroutine to terminate if an unhandled exception occurs. The default is <code>true<\/code>, and the method returns the previous setting in case you want to restore it later.<\/p>\n<p>Finally, we define a marker structure <code>get_<wbr \/>simple_<wbr \/>task_<wbr \/>policy<\/code>. The purpose of this structure will become apparent later.<\/p>\n<pre>namespace async_helpers::details\r\n{\r\n    template&lt;typename T&gt;\r\n    struct simple_promise_base\r\n    {\r\n        ...\r\n        <span style=\"color: blue;\">simple_promise_policies m_policies;<\/span>\r\n\r\n        ...\r\n\r\n        void unhandled_exception() noexcept\r\n        {\r\n            <span style=\"color: blue;\">if (m_policies.m_terminate_on_unhandled_exception)\r\n            {\r\n                std::terminate();\r\n            }<\/span>\r\n            m_holder.unhandled_exception();\r\n        }\r\n        ...\r\n<\/pre>\n<p>We add a policies object to our <code>simple_<wbr \/>promise_<wbr \/>base<\/code>, and the <code>unhandled_<wbr \/>exception<\/code> method consults the policy to decide whether to terminate when an unhandled exception occurs, or whether to stow the exception in the holder for later rethrowing when the coroutine is <code>co_await<\/code>ed.<\/p>\n<pre>        \/\/ still in struct simple_promise_base&lt;T&gt;\r\n        <span style=\"color: blue;\">auto await_transform(get_simple_task_policy) noexcept\r\n        {\r\n            struct awaiter : std::experimental::suspend_never\r\n            {\r\n                simple_promise_policies&amp; policies;\r\n                auto await_resume() const noexcept\r\n                {\r\n                    return simple_task_policies(policies);\r\n                }\r\n            };\r\n            return awaiter{ {}, m_policies };\r\n        }<\/span>\r\n<\/pre>\n<p>This is where the magic happens, the mysterious step 1.<\/p>\n<p>If the coroutine promise has a method called <code>await_<wbr \/>transform<\/code>, then every <code>co_await<\/code> is passed to the <code>await_<wbr \/>transform<\/code> method, and the thing it returns is the thing that is actually awaited. This is how the coroutine promise can snoop on all <code>co_await<\/code> activity that occurs inside the coroutine body.<\/p>\n<p>One use of <code>await_<wbr \/>transform<\/code> is for the coroutine to inject some code at every potential suspension point. For example, it could do some extra bookkeeping when suspension occurs, and again when the coroutine resumes.<\/p>\n<p>That&#8217;s not what we&#8217;re going to use it for, though.<\/p>\n<p>In our case, we have an overload that takes a <code>get_<wbr \/>simple_<wbr \/>task_<wbr \/>policy<\/code> object. Any attempt to <code>co_await<\/code> one of those objects will trigger a call to this overload of <code>await_<wbr \/>transform<\/code>, and the overload ignores the parameter and instead returns a custom awaitable whose sole purpose is to return a <code>simple_<wbr \/>task_<wbr \/>policies<\/code> object that wraps the promise&#8217;s policy object.<\/p>\n<p>That&#8217;s what makes <code>await_<wbr \/>transform<\/code> special: Your basic awaitable object doesn&#8217;t know what coroutine is awaiting it. But <code>await_<wbr \/>transform<\/code> is a member of the promise, and therefore it can create an awaitable that is in cahoots with its promise.<\/p>\n<p>It is typical for the custom awaiter for these backchannel communications awaitables not to suspend at all and just produce the desired value in the <code>await_<wbr \/>resume<\/code>.<\/p>\n<p>A coroutine that uses the <code>simple_promise<\/code> can use this secret signal like this:<\/p>\n<pre>async_helpers::simple_task&lt;void&gt; Example()\r\n{\r\n    auto policy = co_await\r\n        async_helpers::get_simple_task_policy();\r\n}\r\n<\/pre>\n<p>There appear to be a few schools of thought on how these secret signals should be made.<\/p>\n<ul>\n<li>One school uses marker structures with default constructors. That&#8217;s what we did here with <code>get_<wbr \/>simple_<wbr \/>task_<wbr \/>policy<\/code>.<\/li>\n<li>Another school uses marker structures that are returned by purpose-built functions. That&#8217;s how C++\/WinRT does things.<\/li>\n<li>A third school of thought uses premade sentinel objects.<\/li>\n<\/ul>\n<p>An implementation that follow the second school would go like this:<\/p>\n<pre>struct get_simple_task_policy_t {};\r\ninline constexpr get_simple_task_policy_t\r\nget_simple_task_policy()\r\n{\r\n    return {};\r\n}\r\n\r\nasync_helpers::simple_task&lt;void&gt; Example()\r\n{\r\n    auto policy = co_await\r\n        async_helpers::get_simple_task_policy();\r\n}\r\n<\/pre>\n<p>The inline function <code>get_<wbr \/>simple_<wbr \/>task_<wbr \/>policy()<\/code> returns an instance of the marker.<\/p>\n<p>An implementation that followed the third school would go like this:<\/p>\n<pre>struct get_simple_task_policy_t {};\r\ninline constexpr get_simple_task_policy_t get_simple_task_policy;\r\n\r\nasync_helpers::simple_task&lt;void&gt; Example()\r\n{\r\n    auto policy = co_await\r\n        async_helpers::get_simple_task_policy;\r\n}\r\n<\/pre>\n<p>An advantage of the first two designs is that you can parameterize the secret signal. For example, you could have<\/p>\n<pre>co_await report_progress(50);\r\n<\/pre>\n<p>to report that you were 50% done.<\/p>\n<p>An advantage of the third design is that it removes a set of pesky parentheses.<\/p>\n<p>Unfortunately, we can&#8217;t just stop there, because the language rules say that <code>await_<wbr \/>transform<\/code> is all-or-nothing. If you have <i>any<\/i> <code>await_<wbr \/>transform<\/code> method, then you must handle <i>all<\/i> possible awaitables. In order to soak up the other awaitables and pass them through, we need to add<\/p>\n<pre>        \/\/ in struct simple_promise_base&lt;T&gt;\r\n        template&lt;typename U&gt;\r\n        U&amp;&amp; await_transform(U&amp;&amp; awaitable) noexcept\r\n        {\r\n            return static_cast&lt;U&amp;&amp;&gt;(awaitable);\r\n        }\r\n    }\r\n<\/pre>\n<p>The <code>await_<wbr \/>transform<\/code> lets you insert code into every <code>co_await<\/code> operation, but sadly the mechanism to do this is quite cumbersome because wrapping the existing awaitable requires you first to <i>find<\/i> the awaitable by replicating the algorithm used by the compiler. You end up having to do a bunch of SFINAE to look for a <code>co_await<\/code> operator that will produce the awaitable you need to wrap, or give up and use the object as its own awaiter. (And good luck expressing the operator overload conflict resolution algorithm in template metaprogramming.)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Transformers are robots in disguise.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-105160","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Transformers are robots in disguise.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105160","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=105160"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105160\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=105160"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=105160"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=105160"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}