{"id":109963,"date":"2024-07-10T07:00:00","date_gmt":"2024-07-10T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109963"},"modified":"2024-06-24T10:37:48","modified_gmt":"2024-06-24T17:37:48","slug":"20240710-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240710-00\/?p=109963","title":{"rendered":"Creating an already-completed asynchronous activity in C++\/WinRT, part 2"},"content":{"rendered":"<p>Last time, we tried to <a title=\"Creating an already-completed asynchronous activity in C++\/WinRT, part 1\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240709-00\/?p=109961\"> create an already-completed asynchronous activity in C++\/WinRT<\/a>. We were able to create a coroutine that represented a successful already-completed operation:<\/p>\n<pre>winrt::Windows::Foundation::IAsyncOperation&lt;int&gt;\r\n    ComputeAsync()\r\n{\r\n    co_return 42;\r\n}\r\n<\/pre>\n<p>But the analogous function for creating a failed already-completed operation didn&#8217;t work because its lack of any <code>co_await<\/code> or <code>co_return<\/code> statement means that it wasn&#8217;t a coroutine at all!<\/p>\n<pre>winrt::Windows::Foundation::IAsyncOperation&lt;int&gt;\r\n    ComputeAsync()\r\n{\r\n    throw winrt::hresult_access_denied();\r\n}\r\n<\/pre>\n<p>To make the function a coroutine, we need to put a <code>co_await<\/code> or <code>co_return<\/code> in the body somewhere. We have a few options.<\/p>\n<p>One is to put the <code>co_await<\/code> after the <code>throw<\/code>, so it is physically present in the function body (thereby making it a coroutine), but is unreachable. A safe thing to await is <code>std::suspend_never()<\/code>, which is a built-in awaitable that never awaits.<\/p>\n<pre>winrt::Windows::Foundation::IAsyncOperation&lt;int&gt;\r\n    ComputeAsync()\r\n{\r\n    throw winrt::hresult_access_denied();\r\n    <span style=\"border: solid 1px currentcolor;\">co_await std::suspend_never();<\/span>\r\n}\r\n<\/pre>\n<p>Perhaps a more reasonable thing is to actually try to <code>co_return<\/code> something.<\/p>\n<pre>winrt::Windows::Foundation::IAsyncOperation&lt;int&gt;\r\n    ComputeAsync()\r\n{\r\n    throw winrt::hresult_access_denied();\r\n    <span style=\"border: solid 1px currentcolor;\">co_return 0;<\/span>\r\n}\r\n<\/pre>\n<p>Both of these work, and it appears that the major compilers (gcc, clang, msvc) all optimize out the code that follows a <code>throw<\/code>. And as of this writing, they also do not raise a dead code diagnostic, though that&#8217;s the thing that worries me: It&#8217;s possible that a future version of the compiler will decide to produce dead code diagnostics, and then this code will cause problems when used in code bases that treat warnings as errors.<\/p>\n<p>We can put a <code>co_await<\/code> in front of the <code>throw<\/code>, but again, if we put it in a dead code block, we risk a diagnostic:<\/p>\n<pre>winrt::Windows::Foundation::IAsyncOperation&lt;int&gt;\r\n    ComputeAsync()\r\n{\r\n    <span style=\"border: solid 1px currentcolor;\">if (false) co_return 0;<\/span>\r\n    throw winrt::hresult_access_denied();\r\n}\r\n<\/pre>\n<p>So maybe the thing to do is actually <code>co_await<\/code> something, but await something that does nothing. That&#8217;s where we can use the built-in <code>suspend_never<\/code>.<\/p>\n<pre>winrt::Windows::Foundation::IAsyncOperation&lt;int&gt;\r\n    ComputeAsync()\r\n{\r\n    <span style=\"border: solid 1px currentcolor;\">co_await std::suspend_never{};<\/span>\r\n    throw winrt::hresult_access_denied();\r\n}\r\n<\/pre>\n<p>The major compilers recognize this pattern, and it&#8217;s not dead code, so we don&#8217;t risk an unreachable code diagnostic.<\/p>\n<p>But wait, it&#8217;s still a problem, thanks to our pal <code>await_<wbr \/>transform<\/code>. The C++\/WinRT implementation of <code>await_<wbr \/>transform<\/code> for Windows Runtime <code>IAsyncXxx<\/code> interfaces wraps all awaitables inside an awaiter that check whether the <code>IAsyncXxx<\/code> has been cancelled and throws an <code>hresult_canceled<\/code> exception if so.<\/p>\n<p>Now, we know that the coroutine is never cancelled before it completes, but the compilers&#8217; escape analysis can&#8217;t see that, so in practice, they will include that extra check. The <code>co_await std::suspend_never{}<\/code> cannot be optimized out entirely.<\/p>\n<p>At this point, you have to go looking for a rabbit to pull out of your hat. And in this case, the rabbit is <code>winrt::<wbr \/>cancellation_<wbr \/>token<\/code>.<\/p>\n<p>The <code>winrt::<wbr \/>cancellation_<wbr \/>token<\/code> is a sentinel object that is not generally awaitable, but C++\/WinRT&#8217;s implementation of <code>IAsyncXxx<\/code> recognizes it as as a special awaitable in its <code>await_<wbr \/>transform<\/code> and (here&#8217;s where the rabbit comes from) the custom awaiter returns an object (which is just a wrapper around a pointer to the promise) without any other fanfare.<\/p>\n<p>The trick, therefore, is to await the cancellation token and <a title=\"How can I tell C++ that I want to discard a nodiscard value?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240329-00\/?p=109592\"> discard the resulting object<\/a>.<\/p>\n<pre>winrt::Windows::Foundation::IAsyncOperation&lt;int&gt;\r\n    ComputeAsync()\r\n{\r\n    <span style=\"border: solid 1px currentcolor;\">(void)co_await winrt::get_cancellation_token();<\/span>\r\n\r\n    throw winrt::hresult_access_denied();\r\n}\r\n<\/pre>\n<p>We explicitly discard the result of the <code>co_await<\/code>, just in case some future version of C++\/WinRT adds the <code>[[nodiscard]]<\/code> attribute.<\/p>\n<p>Now that we know how to code up this specific case, we&#8217;ll work on generalizing it next time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Making our function a coroutine.<\/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-109963","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Making our function a coroutine.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109963","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=109963"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109963\/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=109963"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109963"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109963"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}