1<html> 2<head> 3<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 4<title>Then There’s Boost.Asio</title> 5<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css"> 6<meta name="generator" content="DocBook XSL Stylesheets V1.79.1"> 7<link rel="home" href="../../index.html" title="Chapter 1. Fiber"> 8<link rel="up" href="../callbacks.html" title="Integrating Fibers with Asynchronous Callbacks"> 9<link rel="prev" href="success_error_virtual_methods.html" title="Success/Error Virtual Methods"> 10<link rel="next" href="../nonblocking.html" title="Integrating Fibers with Nonblocking I/O"> 11</head> 12<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> 13<table cellpadding="2" width="100%"><tr> 14<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td> 15<td align="center"><a href="../../../../../../index.html">Home</a></td> 16<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td> 17<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> 18<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> 19<td align="center"><a href="../../../../../../more/index.htm">More</a></td> 20</tr></table> 21<hr> 22<div class="spirit-nav"> 23<a accesskey="p" href="success_error_virtual_methods.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../callbacks.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="../nonblocking.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a> 24</div> 25<div class="section"> 26<div class="titlepage"><div><div><h3 class="title"> 27<a name="fiber.callbacks.then_there_s____boost_asio__"></a><a name="callbacks_asio"></a><a class="link" href="then_there_s____boost_asio__.html" title="Then There’s Boost.Asio">Then 28 There’s Boost.Asio</a> 29</h3></div></div></div> 30<p> 31 Since the simplest form of Boost.Asio asynchronous operation completion token 32 is a callback function, we could apply the same tactics for Asio as for our 33 hypothetical <code class="computeroutput"><span class="identifier">AsyncAPI</span></code> asynchronous 34 operations. 35 </p> 36<p> 37 Fortunately we need not. Boost.Asio incorporates a mechanism<a href="#ftn.fiber.callbacks.then_there_s____boost_asio__.f0" class="footnote" name="fiber.callbacks.then_there_s____boost_asio__.f0"><sup class="footnote">[5]</sup></a> by which the caller can customize the notification behavior of 38 any async operation. Therefore we can construct a <span class="emphasis"><em>completion token</em></span> 39 which, when passed to a <a href="http://www.boost.org/doc/libs/release/libs/asio/index.html" target="_top">Boost.Asio</a> 40 async operation, requests blocking for the calling fiber. 41 </p> 42<p> 43 A typical Asio async function might look something like this:<a href="#ftn.fiber.callbacks.then_there_s____boost_asio__.f1" class="footnote" name="fiber.callbacks.then_there_s____boost_asio__.f1"><sup class="footnote">[6]</sup></a> 44 </p> 45<pre class="programlisting"><span class="keyword">template</span> <span class="special"><</span> <span class="special">...,</span> <span class="keyword">class</span> <span class="identifier">CompletionToken</span> <span class="special">></span> 46<span class="emphasis"><em>deduced_return_type</em></span> 47<span class="identifier">async_something</span><span class="special">(</span> <span class="special">...</span> <span class="special">,</span> <span class="identifier">CompletionToken</span><span class="special">&&</span> <span class="identifier">token</span><span class="special">)</span> 48<span class="special">{</span> 49 <span class="comment">// construct handler_type instance from CompletionToken</span> 50 <span class="identifier">handler_type</span><span class="special"><</span><span class="identifier">CompletionToken</span><span class="special">,</span> <span class="special">...>::</span><span class="identifier">type</span> <span class="bold"><strong><code class="computeroutput">handler(token)</code></strong></span><span class="special">;</span> 51 <span class="comment">// construct async_result instance from handler_type</span> 52 <span class="identifier">async_result</span><span class="special"><</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">handler</span><span class="special">)></span> <span class="bold"><strong><code class="computeroutput">result(handler)</code></strong></span><span class="special">;</span> 53 54 <span class="comment">// ... arrange to call handler on completion ...</span> 55 <span class="comment">// ... initiate actual I/O operation ...</span> 56 57 <span class="keyword">return</span> <span class="bold"><strong><code class="computeroutput">result.get()</code></strong></span><span class="special">;</span> 58<span class="special">}</span> 59</pre> 60<p> 61 We will engage that mechanism, which is based on specializing Asio’s <code class="computeroutput"><span class="identifier">handler_type</span><span class="special"><></span></code> 62 template for the <code class="computeroutput"><span class="identifier">CompletionToken</span></code> 63 type and the signature of the specific callback. The remainder of this discussion 64 will refer back to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code> as the Asio async function under consideration. 65 </p> 66<p> 67 The implementation described below uses lower-level facilities than <code class="computeroutput"><span class="identifier">promise</span></code> and <code class="computeroutput"><span class="identifier">future</span></code> 68 because the <code class="computeroutput"><span class="identifier">promise</span></code> mechanism 69 interacts badly with <a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service/stop.html" target="_top"><code class="computeroutput"><span class="identifier">io_service</span><span class="special">::</span><span class="identifier">stop</span><span class="special">()</span></code></a>. 70 It produces <code class="computeroutput"><span class="identifier">broken_promise</span></code> 71 exceptions. 72 </p> 73<p> 74 <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">yield</span></code> is a completion token of this kind. 75 <code class="computeroutput"><span class="identifier">yield</span></code> is an instance of 76 <code class="computeroutput"><span class="identifier">yield_t</span></code>: 77 </p> 78<p> 79</p> 80<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">yield_t</span> <span class="special">{</span> 81<span class="keyword">public</span><span class="special">:</span> 82 <span class="identifier">yield_t</span><span class="special">()</span> <span class="special">=</span> <span class="keyword">default</span><span class="special">;</span> 83 84 <span class="comment">/** 85 * @code 86 * static yield_t yield; 87 * boost::system::error_code myec; 88 * func(yield[myec]); 89 * @endcode 90 * @c yield[myec] returns an instance of @c yield_t whose @c ec_ points 91 * to @c myec. The expression @c yield[myec] "binds" @c myec to that 92 * (anonymous) @c yield_t instance, instructing @c func() to store any 93 * @c error_code it might produce into @c myec rather than throwing @c 94 * boost::system::system_error. 95 */</span> 96 <span class="identifier">yield_t</span> <span class="keyword">operator</span><span class="special">[](</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span> <span class="special">&</span> <span class="identifier">ec</span><span class="special">)</span> <span class="keyword">const</span> <span class="special">{</span> 97 <span class="identifier">yield_t</span> <span class="identifier">tmp</span><span class="special">;</span> 98 <span class="identifier">tmp</span><span class="special">.</span><span class="identifier">ec_</span> <span class="special">=</span> <span class="special">&</span> <span class="identifier">ec</span><span class="special">;</span> 99 <span class="keyword">return</span> <span class="identifier">tmp</span><span class="special">;</span> 100 <span class="special">}</span> 101 102<span class="comment">//private:</span> 103 <span class="comment">// ptr to bound error_code instance if any</span> 104 <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span> <span class="special">*</span> <span class="identifier">ec_</span><span class="special">{</span> <span class="keyword">nullptr</span> <span class="special">};</span> 105<span class="special">};</span> 106</pre> 107<p> 108 </p> 109<p> 110 <code class="computeroutput"><span class="identifier">yield_t</span></code> is in fact only a 111 placeholder, a way to trigger Boost.Asio customization. It can bind a <a href="http://www.boost.org/doc/libs/release/libs/system/doc/reference.html#Class-error_code" target="_top"><code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span></code></a> for use by the actual 112 handler. 113 </p> 114<p> 115 <code class="computeroutput"><span class="identifier">yield</span></code> is declared as: 116 </p> 117<p> 118</p> 119<pre class="programlisting"><span class="comment">// canonical instance</span> 120<span class="keyword">thread_local</span> <span class="identifier">yield_t</span> <span class="identifier">yield</span><span class="special">{};</span> 121</pre> 122<p> 123 </p> 124<p> 125 Asio customization is engaged by specializing <a href="http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/handler_type.html" target="_top"><code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">handler_type</span><span class="special"><></span></code></a> 126 for <code class="computeroutput"><span class="identifier">yield_t</span></code>: 127 </p> 128<p> 129 [asio_handler_type] 130 </p> 131<p> 132 (There are actually four different specializations in <a href="../../../../examples/asio/detail/yield.hpp" target="_top">detail/yield.hpp</a>, 133 one for each of the four Asio async callback signatures we expect.) 134 </p> 135<p> 136 The above directs Asio to use <code class="computeroutput"><span class="identifier">yield_handler</span></code> 137 as the actual handler for an async operation to which <code class="computeroutput"><span class="identifier">yield</span></code> 138 is passed. There’s a generic <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special"><</span><span class="identifier">T</span><span class="special">></span></code> 139 implementation and a <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special"><</span><span class="keyword">void</span><span class="special">></span></code> 140 specialization. Let’s start with the <code class="computeroutput"><span class="special"><</span><span class="keyword">void</span><span class="special">></span></code> specialization: 141 </p> 142<p> 143</p> 144<pre class="programlisting"><span class="comment">// yield_handler<void> is like yield_handler<T> without value_. In fact it's</span> 145<span class="comment">// just like yield_handler_base.</span> 146<span class="keyword">template</span><span class="special"><></span> 147<span class="keyword">class</span> <span class="identifier">yield_handler</span><span class="special"><</span> <span class="keyword">void</span> <span class="special">>:</span> <span class="keyword">public</span> <span class="identifier">yield_handler_base</span> <span class="special">{</span> 148<span class="keyword">public</span><span class="special">:</span> 149 <span class="keyword">explicit</span> <span class="identifier">yield_handler</span><span class="special">(</span> <span class="identifier">yield_t</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">y</span><span class="special">)</span> <span class="special">:</span> 150 <span class="identifier">yield_handler_base</span><span class="special">{</span> <span class="identifier">y</span> <span class="special">}</span> <span class="special">{</span> 151 <span class="special">}</span> 152 153 <span class="comment">// nullary completion callback</span> 154 <span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()()</span> <span class="special">{</span> 155 <span class="special">(</span> <span class="special">*</span> <span class="keyword">this</span><span class="special">)(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span><span class="special">()</span> <span class="special">);</span> 156 <span class="special">}</span> 157 158 <span class="comment">// inherit operator()(error_code) overload from base class</span> 159 <span class="keyword">using</span> <span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">();</span> 160<span class="special">};</span> 161</pre> 162<p> 163 </p> 164<p> 165 <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>, 166 having consulted the <code class="computeroutput"><span class="identifier">handler_type</span><span class="special"><></span></code> traits specialization, instantiates 167 a <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special"><</span><span class="keyword">void</span><span class="special">></span></code> to 168 be passed as the actual callback for the async operation. <code class="computeroutput"><span class="identifier">yield_handler</span></code>’s 169 constructor accepts the <code class="computeroutput"><span class="identifier">yield_t</span></code> 170 instance (the <code class="computeroutput"><span class="identifier">yield</span></code> object 171 passed to the async function) and passes it along to <code class="computeroutput"><span class="identifier">yield_handler_base</span></code>: 172 </p> 173<p> 174</p> 175<pre class="programlisting"><span class="comment">// This class encapsulates common elements between yield_handler<T> (capturing</span> 176<span class="comment">// a value to return from asio async function) and yield_handler<void> (no</span> 177<span class="comment">// such value). See yield_handler<T> and its <void> specialization below. Both</span> 178<span class="comment">// yield_handler<T> and yield_handler<void> are passed by value through</span> 179<span class="comment">// various layers of asio functions. In other words, they're potentially</span> 180<span class="comment">// copied multiple times. So key data such as the yield_completion instance</span> 181<span class="comment">// must be stored in our async_result<yield_handler<>> specialization, which</span> 182<span class="comment">// should be instantiated only once.</span> 183<span class="keyword">class</span> <span class="identifier">yield_handler_base</span> <span class="special">{</span> 184<span class="keyword">public</span><span class="special">:</span> 185 <span class="identifier">yield_handler_base</span><span class="special">(</span> <span class="identifier">yield_t</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">y</span><span class="special">)</span> <span class="special">:</span> 186 <span class="comment">// capture the context* associated with the running fiber</span> 187 <span class="identifier">ctx_</span><span class="special">{</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">context</span><span class="special">::</span><span class="identifier">active</span><span class="special">()</span> <span class="special">},</span> 188 <span class="comment">// capture the passed yield_t</span> 189 <span class="identifier">yt_</span><span class="special">(</span> <span class="identifier">y</span> <span class="special">)</span> <span class="special">{</span> 190 <span class="special">}</span> 191 192 <span class="comment">// completion callback passing only (error_code)</span> 193 <span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">ec</span><span class="special">)</span> <span class="special">{</span> 194 <span class="identifier">BOOST_ASSERT_MSG</span><span class="special">(</span> <span class="identifier">ycomp_</span><span class="special">,</span> 195 <span class="string">"Must inject yield_completion* "</span> 196 <span class="string">"before calling yield_handler_base::operator()()"</span><span class="special">);</span> 197 <span class="identifier">BOOST_ASSERT_MSG</span><span class="special">(</span> <span class="identifier">yt_</span><span class="special">.</span><span class="identifier">ec_</span><span class="special">,</span> 198 <span class="string">"Must inject boost::system::error_code* "</span> 199 <span class="string">"before calling yield_handler_base::operator()()"</span><span class="special">);</span> 200 <span class="comment">// If originating fiber is busy testing state_ flag, wait until it</span> 201 <span class="comment">// has observed (completed != state_).</span> 202 <span class="identifier">yield_completion</span><span class="special">::</span><span class="identifier">lock_t</span> <span class="identifier">lk</span><span class="special">{</span> <span class="identifier">ycomp_</span><span class="special">-></span><span class="identifier">mtx_</span> <span class="special">};</span> 203 <span class="identifier">yield_completion</span><span class="special">::</span><span class="identifier">state_t</span> <span class="identifier">state</span> <span class="special">=</span> <span class="identifier">ycomp_</span><span class="special">-></span><span class="identifier">state_</span><span class="special">;</span> 204 <span class="comment">// Notify a subsequent yield_completion::wait() call that it need not</span> 205 <span class="comment">// suspend.</span> 206 <span class="identifier">ycomp_</span><span class="special">-></span><span class="identifier">state_</span> <span class="special">=</span> <span class="identifier">yield_completion</span><span class="special">::</span><span class="identifier">complete</span><span class="special">;</span> 207 <span class="comment">// set the error_code bound by yield_t</span> 208 <span class="special">*</span> <span class="identifier">yt_</span><span class="special">.</span><span class="identifier">ec_</span> <span class="special">=</span> <span class="identifier">ec</span><span class="special">;</span> 209 <span class="comment">// unlock the lock that protects state_</span> 210 <span class="identifier">lk</span><span class="special">.</span><span class="identifier">unlock</span><span class="special">();</span> 211 <span class="comment">// If ctx_ is still active, e.g. because the async operation</span> 212 <span class="comment">// immediately called its callback (this method!) before the asio</span> 213 <span class="comment">// async function called async_result_base::get(), we must not set it</span> 214 <span class="comment">// ready.</span> 215 <span class="keyword">if</span> <span class="special">(</span> <span class="identifier">yield_completion</span><span class="special">::</span><span class="identifier">waiting</span> <span class="special">==</span> <span class="identifier">state</span><span class="special">)</span> <span class="special">{</span> 216 <span class="comment">// wake the fiber</span> 217 <span class="identifier">fibers</span><span class="special">::</span><span class="identifier">context</span><span class="special">::</span><span class="identifier">active</span><span class="special">()-></span><span class="identifier">schedule</span><span class="special">(</span> <span class="identifier">ctx_</span><span class="special">);</span> 218 <span class="special">}</span> 219 <span class="special">}</span> 220 221<span class="comment">//private:</span> 222 <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">context</span> <span class="special">*</span> <span class="identifier">ctx_</span><span class="special">;</span> 223 <span class="identifier">yield_t</span> <span class="identifier">yt_</span><span class="special">;</span> 224 <span class="comment">// We depend on this pointer to yield_completion, which will be injected</span> 225 <span class="comment">// by async_result.</span> 226 <span class="identifier">yield_completion</span><span class="special">::</span><span class="identifier">ptr_t</span> <span class="identifier">ycomp_</span><span class="special">{};</span> 227<span class="special">};</span> 228</pre> 229<p> 230 </p> 231<p> 232 <code class="computeroutput"><span class="identifier">yield_handler_base</span></code> stores 233 a copy of the <code class="computeroutput"><span class="identifier">yield_t</span></code> instance 234 — which, as shown above, contains only an <code class="computeroutput"><span class="identifier">error_code</span><span class="special">*</span></code>. It also captures the <a class="link" href="../scheduling.html#class_context"><code class="computeroutput">context</code></a>* 235 for the currently-running fiber by calling <a class="link" href="../scheduling.html#context_active"><code class="computeroutput">context::active()</code></a>. 236 </p> 237<p> 238 You will notice that <code class="computeroutput"><span class="identifier">yield_handler_base</span></code> 239 has one more data member (<code class="computeroutput"><span class="identifier">ycomp_</span></code>) 240 that is initialized to <code class="computeroutput"><span class="keyword">nullptr</span></code> 241 by its constructor — though its <code class="computeroutput"><span class="keyword">operator</span><span class="special">()()</span></code> method relies on <code class="computeroutput"><span class="identifier">ycomp_</span></code> 242 being non-null. More on this in a moment. 243 </p> 244<p> 245 Having constructed the <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special"><</span><span class="keyword">void</span><span class="special">></span></code> 246 instance, <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code> goes on to construct an <code class="computeroutput"><span class="identifier">async_result</span></code> 247 specialized for the <code class="computeroutput"><span class="identifier">handler_type</span><span class="special"><>::</span><span class="identifier">type</span></code>: 248 in this case, <code class="computeroutput"><span class="identifier">async_result</span><span class="special"><</span><span class="identifier">yield_handler</span><span class="special"><</span><span class="keyword">void</span><span class="special">>></span></code>. 249 It passes the <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special"><</span><span class="keyword">void</span><span class="special">></span></code> 250 instance to the new <code class="computeroutput"><span class="identifier">async_result</span></code> 251 instance. 252 </p> 253<p> 254</p> 255<pre class="programlisting"><span class="comment">// Without the need to handle a passed value, our yield_handler<void></span> 256<span class="comment">// specialization is just like async_result_base.</span> 257<span class="keyword">template</span><span class="special"><></span> 258<span class="keyword">class</span> <span class="identifier">async_result</span><span class="special"><</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">yield_t</span><span class="special">,</span> <span class="keyword">void</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span><span class="special">)</span> <span class="special">></span> <span class="special">:</span> 259 <span class="keyword">public</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">async_result_base</span> <span class="special">{</span> 260<span class="keyword">public</span><span class="special">:</span> 261 <span class="keyword">using</span> <span class="identifier">return_type</span> <span class="special">=</span> <span class="keyword">void</span><span class="special">;</span> 262 <span class="keyword">using</span> <span class="identifier">completion_handler_type</span> <span class="special">=</span> <span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">yield_handler</span><span class="special"><</span><span class="keyword">void</span><span class="special">>;</span> 263 264 <span class="keyword">explicit</span> <span class="identifier">async_result</span><span class="special">(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">yield_handler</span><span class="special"><</span> <span class="keyword">void</span> <span class="special">></span> <span class="special">&</span> <span class="identifier">h</span><span class="special">):</span> 265 <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">async_result_base</span><span class="special">{</span> <span class="identifier">h</span> <span class="special">}</span> <span class="special">{</span> 266 <span class="special">}</span> 267<span class="special">};</span> 268</pre> 269<p> 270 </p> 271<p> 272 Naturally that leads us straight to <code class="computeroutput"><span class="identifier">async_result_base</span></code>: 273 </p> 274<p> 275</p> 276<pre class="programlisting"><span class="comment">// Factor out commonality between async_result<yield_handler<T>> and</span> 277<span class="comment">// async_result<yield_handler<void>></span> 278<span class="keyword">class</span> <span class="identifier">async_result_base</span> <span class="special">{</span> 279<span class="keyword">public</span><span class="special">:</span> 280 <span class="keyword">explicit</span> <span class="identifier">async_result_base</span><span class="special">(</span> <span class="identifier">yield_handler_base</span> <span class="special">&</span> <span class="identifier">h</span><span class="special">)</span> <span class="special">:</span> 281 <span class="identifier">ycomp_</span><span class="special">{</span> <span class="keyword">new</span> <span class="identifier">yield_completion</span><span class="special">{}</span> <span class="special">}</span> <span class="special">{</span> 282 <span class="comment">// Inject ptr to our yield_completion instance into this</span> 283 <span class="comment">// yield_handler<>.</span> 284 <span class="identifier">h</span><span class="special">.</span><span class="identifier">ycomp_</span> <span class="special">=</span> <span class="keyword">this</span><span class="special">-></span><span class="identifier">ycomp_</span><span class="special">;</span> 285 <span class="comment">// if yield_t didn't bind an error_code, make yield_handler_base's</span> 286 <span class="comment">// error_code* point to an error_code local to this object so</span> 287 <span class="comment">// yield_handler_base::operator() can unconditionally store through</span> 288 <span class="comment">// its error_code*</span> 289 <span class="keyword">if</span> <span class="special">(</span> <span class="special">!</span> <span class="identifier">h</span><span class="special">.</span><span class="identifier">yt_</span><span class="special">.</span><span class="identifier">ec_</span><span class="special">)</span> <span class="special">{</span> 290 <span class="identifier">h</span><span class="special">.</span><span class="identifier">yt_</span><span class="special">.</span><span class="identifier">ec_</span> <span class="special">=</span> <span class="special">&</span> <span class="identifier">ec_</span><span class="special">;</span> 291 <span class="special">}</span> 292 <span class="special">}</span> 293 294 <span class="keyword">void</span> <span class="identifier">get</span><span class="special">()</span> <span class="special">{</span> 295 <span class="comment">// Unless yield_handler_base::operator() has already been called,</span> 296 <span class="comment">// suspend the calling fiber until that call.</span> 297 <span class="identifier">ycomp_</span><span class="special">-></span><span class="identifier">wait</span><span class="special">();</span> 298 <span class="comment">// The only way our own ec_ member could have a non-default value is</span> 299 <span class="comment">// if our yield_handler did not have a bound error_code AND the</span> 300 <span class="comment">// completion callback passed a non-default error_code.</span> 301 <span class="keyword">if</span> <span class="special">(</span> <span class="identifier">ec_</span><span class="special">)</span> <span class="special">{</span> 302 <span class="identifier">throw_exception</span><span class="special">(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">system_error</span><span class="special">{</span> <span class="identifier">ec_</span> <span class="special">}</span> <span class="special">);</span> 303 <span class="special">}</span> 304 <span class="special">}</span> 305 306<span class="keyword">private</span><span class="special">:</span> 307 <span class="comment">// If yield_t does not bind an error_code instance, store into here.</span> 308 <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span> <span class="identifier">ec_</span><span class="special">{};</span> 309 <span class="identifier">yield_completion</span><span class="special">::</span><span class="identifier">ptr_t</span> <span class="identifier">ycomp_</span><span class="special">;</span> 310<span class="special">};</span> 311</pre> 312<p> 313 </p> 314<p> 315 This is how <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="identifier">ycomp_</span></code> 316 becomes non-null: <code class="computeroutput"><span class="identifier">async_result_base</span></code>’s 317 constructor injects a pointer back to its own <code class="computeroutput"><span class="identifier">yield_completion</span></code> 318 member. 319 </p> 320<p> 321 Recall that the canonical <code class="computeroutput"><span class="identifier">yield_t</span></code> 322 instance <code class="computeroutput"><span class="identifier">yield</span></code> initializes 323 its <code class="computeroutput"><span class="identifier">error_code</span><span class="special">*</span></code> 324 member <code class="computeroutput"><span class="identifier">ec_</span></code> to <code class="computeroutput"><span class="keyword">nullptr</span></code>. If this instance is passed to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code> 325 (<code class="computeroutput"><span class="identifier">ec_</span></code> is still <code class="computeroutput"><span class="keyword">nullptr</span></code>), the copy stored in <code class="computeroutput"><span class="identifier">yield_handler_base</span></code> will likewise have null 326 <code class="computeroutput"><span class="identifier">ec_</span></code>. <code class="computeroutput"><span class="identifier">async_result_base</span></code>’s 327 constructor sets <code class="computeroutput"><span class="identifier">yield_handler_base</span></code>’s 328 <code class="computeroutput"><span class="identifier">yield_t</span></code>’s <code class="computeroutput"><span class="identifier">ec_</span></code> 329 member to point to its own <code class="computeroutput"><span class="identifier">error_code</span></code> 330 member. 331 </p> 332<p> 333 The stage is now set. <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code> initiates the actual async operation, arranging 334 to call its <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special"><</span><span class="keyword">void</span><span class="special">></span></code> 335 instance on completion. Let’s say, for the sake of argument, that the actual 336 async operation’s callback has signature <code class="computeroutput"><span class="keyword">void</span><span class="special">(</span><span class="identifier">error_code</span><span class="special">)</span></code>. 337 </p> 338<p> 339 But since it’s an async operation, control returns at once to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>. 340 <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code> 341 calls <code class="computeroutput"><span class="identifier">async_result</span><span class="special"><</span><span class="identifier">yield_handler</span><span class="special"><</span><span class="keyword">void</span><span class="special">>>::</span><span class="identifier">get</span><span class="special">()</span></code>, 342 and will return its return value. 343 </p> 344<p> 345 <code class="computeroutput"><span class="identifier">async_result</span><span class="special"><</span><span class="identifier">yield_handler</span><span class="special"><</span><span class="keyword">void</span><span class="special">>>::</span><span class="identifier">get</span><span class="special">()</span></code> inherits 346 <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">get</span><span class="special">()</span></code>. 347 </p> 348<p> 349 <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">get</span><span class="special">()</span></code> immediately 350 calls <code class="computeroutput"><span class="identifier">yield_completion</span><span class="special">::</span><span class="identifier">wait</span><span class="special">()</span></code>. 351 </p> 352<p> 353</p> 354<pre class="programlisting"><span class="comment">// Bundle a completion bool flag with a spinlock to protect it.</span> 355<span class="keyword">struct</span> <span class="identifier">yield_completion</span> <span class="special">{</span> 356 <span class="keyword">enum</span> <span class="identifier">state_t</span> <span class="special">{</span> 357 <span class="identifier">init</span><span class="special">,</span> 358 <span class="identifier">waiting</span><span class="special">,</span> 359 <span class="identifier">complete</span> 360 <span class="special">};</span> 361 362 <span class="keyword">typedef</span> <span class="identifier">fibers</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">spinlock</span> <span class="identifier">mutex_t</span><span class="special">;</span> 363 <span class="keyword">typedef</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">unique_lock</span><span class="special"><</span> <span class="identifier">mutex_t</span> <span class="special">></span> <span class="identifier">lock_t</span><span class="special">;</span> 364 <span class="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">intrusive_ptr</span><span class="special"><</span> <span class="identifier">yield_completion</span> <span class="special">></span> <span class="identifier">ptr_t</span><span class="special">;</span> 365 366 <span class="identifier">std</span><span class="special">::</span><span class="identifier">atomic</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="special">></span> <span class="identifier">use_count_</span><span class="special">{</span> <span class="number">0</span> <span class="special">};</span> 367 <span class="identifier">mutex_t</span> <span class="identifier">mtx_</span><span class="special">{};</span> 368 <span class="identifier">state_t</span> <span class="identifier">state_</span><span class="special">{</span> <span class="identifier">init</span> <span class="special">};</span> 369 370 <span class="keyword">void</span> <span class="identifier">wait</span><span class="special">()</span> <span class="special">{</span> 371 <span class="comment">// yield_handler_base::operator()() will set state_ `complete` and</span> 372 <span class="comment">// attempt to wake a suspended fiber. It would be Bad if that call</span> 373 <span class="comment">// happened between our detecting (complete != state_) and suspending.</span> 374 <span class="identifier">lock_t</span> <span class="identifier">lk</span><span class="special">{</span> <span class="identifier">mtx_</span> <span class="special">};</span> 375 <span class="comment">// If state_ is already set, we're done here: don't suspend.</span> 376 <span class="keyword">if</span> <span class="special">(</span> <span class="identifier">complete</span> <span class="special">!=</span> <span class="identifier">state_</span><span class="special">)</span> <span class="special">{</span> 377 <span class="identifier">state_</span> <span class="special">=</span> <span class="identifier">waiting</span><span class="special">;</span> 378 <span class="comment">// suspend(unique_lock<spinlock>) unlocks the lock in the act of</span> 379 <span class="comment">// resuming another fiber</span> 380 <span class="identifier">fibers</span><span class="special">::</span><span class="identifier">context</span><span class="special">::</span><span class="identifier">active</span><span class="special">()-></span><span class="identifier">suspend</span><span class="special">(</span> <span class="identifier">lk</span><span class="special">);</span> 381 <span class="special">}</span> 382 <span class="special">}</span> 383 384 <span class="keyword">friend</span> <span class="keyword">void</span> <span class="identifier">intrusive_ptr_add_ref</span><span class="special">(</span> <span class="identifier">yield_completion</span> <span class="special">*</span> <span class="identifier">yc</span><span class="special">)</span> <span class="keyword">noexcept</span> <span class="special">{</span> 385 <span class="identifier">BOOST_ASSERT</span><span class="special">(</span> <span class="keyword">nullptr</span> <span class="special">!=</span> <span class="identifier">yc</span><span class="special">);</span> 386 <span class="identifier">yc</span><span class="special">-></span><span class="identifier">use_count_</span><span class="special">.</span><span class="identifier">fetch_add</span><span class="special">(</span> <span class="number">1</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">memory_order_relaxed</span><span class="special">);</span> 387 <span class="special">}</span> 388 389 <span class="keyword">friend</span> <span class="keyword">void</span> <span class="identifier">intrusive_ptr_release</span><span class="special">(</span> <span class="identifier">yield_completion</span> <span class="special">*</span> <span class="identifier">yc</span><span class="special">)</span> <span class="keyword">noexcept</span> <span class="special">{</span> 390 <span class="identifier">BOOST_ASSERT</span><span class="special">(</span> <span class="keyword">nullptr</span> <span class="special">!=</span> <span class="identifier">yc</span><span class="special">);</span> 391 <span class="keyword">if</span> <span class="special">(</span> <span class="number">1</span> <span class="special">==</span> <span class="identifier">yc</span><span class="special">-></span><span class="identifier">use_count_</span><span class="special">.</span><span class="identifier">fetch_sub</span><span class="special">(</span> <span class="number">1</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">memory_order_release</span><span class="special">)</span> <span class="special">)</span> <span class="special">{</span> 392 <span class="identifier">std</span><span class="special">::</span><span class="identifier">atomic_thread_fence</span><span class="special">(</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">memory_order_acquire</span><span class="special">);</span> 393 <span class="keyword">delete</span> <span class="identifier">yc</span><span class="special">;</span> 394 <span class="special">}</span> 395 <span class="special">}</span> 396<span class="special">};</span> 397</pre> 398<p> 399 </p> 400<p> 401 Supposing that the pending async operation has not yet completed, <code class="computeroutput"><span class="identifier">yield_completion</span><span class="special">::</span><span class="identifier">completed_</span></code> will still be <code class="computeroutput"><span class="keyword">false</span></code>, and <code class="computeroutput"><span class="identifier">wait</span><span class="special">()</span></code> will call <a class="link" href="../scheduling.html#context_suspend"><code class="computeroutput">context::suspend()</code></a> on 402 the currently-running fiber. 403 </p> 404<p> 405 Other fibers will now have a chance to run. 406 </p> 407<p> 408 Some time later, the async operation completes. It calls <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special"><</span><span class="keyword">void</span><span class="special">>::</span><span class="keyword">operator</span><span class="special">()(</span><span class="identifier">error_code</span> <span class="keyword">const</span><span class="special">&)</span></code> with an <code class="computeroutput"><span class="identifier">error_code</span></code> 409 indicating either success or failure. We’ll consider both cases. 410 </p> 411<p> 412 <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special"><</span><span class="keyword">void</span><span class="special">></span></code> explicitly 413 inherits <code class="computeroutput"><span class="keyword">operator</span><span class="special">()(</span><span class="identifier">error_code</span> <span class="keyword">const</span><span class="special">&)</span></code> from <code class="computeroutput"><span class="identifier">yield_handler_base</span></code>. 414 </p> 415<p> 416 <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()(</span><span class="identifier">error_code</span> <span class="keyword">const</span><span class="special">&)</span></code> first sets <code class="computeroutput"><span class="identifier">yield_completion</span><span class="special">::</span><span class="identifier">completed_</span></code> 417 <code class="computeroutput"><span class="keyword">true</span></code>. This way, if <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>’s 418 async operation completes immediately — if <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()</span></code> is called even before <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">get</span><span class="special">()</span></code> 419 — the calling fiber will <span class="emphasis"><em>not</em></span> suspend. 420 </p> 421<p> 422 The actual <code class="computeroutput"><span class="identifier">error_code</span></code> produced 423 by the async operation is then stored through the stored <code class="computeroutput"><span class="identifier">yield_t</span><span class="special">::</span><span class="identifier">ec_</span></code> pointer. 424 If <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>’s 425 caller used (e.g.) <code class="computeroutput"><span class="identifier">yield</span><span class="special">[</span><span class="identifier">my_ec</span><span class="special">]</span></code> to bind a local <code class="computeroutput"><span class="identifier">error_code</span></code> 426 instance, the actual <code class="computeroutput"><span class="identifier">error_code</span></code> 427 value is stored into the caller’s variable. Otherwise, it is stored into 428 <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">ec_</span></code>. 429 </p> 430<p> 431 If the stored fiber context <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="identifier">ctx_</span></code> 432 is not already running, it is marked as ready to run by passing it to <a class="link" href="../scheduling.html#context_schedule"><code class="computeroutput">context::schedule()</code></a>. 433 Control then returns from <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()</span></code>: the callback is done. 434 </p> 435<p> 436 In due course, that fiber is resumed. Control returns from <a class="link" href="../scheduling.html#context_suspend"><code class="computeroutput">context::suspend()</code></a> to 437 <code class="computeroutput"><span class="identifier">yield_completion</span><span class="special">::</span><span class="identifier">wait</span><span class="special">()</span></code>, 438 which returns to <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">get</span><span class="special">()</span></code>. 439 </p> 440<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> 441<li class="listitem"> 442 If the original caller passed <code class="computeroutput"><span class="identifier">yield</span><span class="special">[</span><span class="identifier">my_ec</span><span class="special">]</span></code> to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code> to bind a local <code class="computeroutput"><span class="identifier">error_code</span></code> 443 instance, then <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()</span></code> stored its <code class="computeroutput"><span class="identifier">error_code</span></code> 444 to the caller’s <code class="computeroutput"><span class="identifier">my_ec</span></code> 445 instance, leaving <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">ec_</span></code> 446 initialized to success. 447 </li> 448<li class="listitem"> 449 If the original caller passed <code class="computeroutput"><span class="identifier">yield</span></code> 450 to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code> 451 without binding a local <code class="computeroutput"><span class="identifier">error_code</span></code> 452 variable, then <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()</span></code> stored its <code class="computeroutput"><span class="identifier">error_code</span></code> 453 into <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">ec_</span></code>. 454 If in fact that <code class="computeroutput"><span class="identifier">error_code</span></code> 455 is success, then all is well. 456 </li> 457<li class="listitem"> 458 Otherwise — the original caller did not bind a local <code class="computeroutput"><span class="identifier">error_code</span></code> 459 and <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()</span></code> was called with an <code class="computeroutput"><span class="identifier">error_code</span></code> 460 indicating error — <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">get</span><span class="special">()</span></code> throws <code class="computeroutput"><span class="identifier">system_error</span></code> 461 with that <code class="computeroutput"><span class="identifier">error_code</span></code>. 462 </li> 463</ul></div> 464<p> 465 The case in which <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>’s completion callback has signature <code class="computeroutput"><span class="keyword">void</span><span class="special">()</span></code> is 466 similar. <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special"><</span><span class="keyword">void</span><span class="special">>::</span><span class="keyword">operator</span><span class="special">()()</span></code> 467 invokes the machinery above with a <span class="quote">“<span class="quote">success</span>”</span> <code class="computeroutput"><span class="identifier">error_code</span></code>. 468 </p> 469<p> 470 A completion callback with signature <code class="computeroutput"><span class="keyword">void</span><span class="special">(</span><span class="identifier">error_code</span><span class="special">,</span> <span class="identifier">T</span><span class="special">)</span></code> 471 (that is: in addition to <code class="computeroutput"><span class="identifier">error_code</span></code>, 472 callback receives some data item) is handled somewhat differently. For this 473 kind of signature, <code class="computeroutput"><span class="identifier">handler_type</span><span class="special"><>::</span><span class="identifier">type</span></code> 474 specifies <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special"><</span><span class="identifier">T</span><span class="special">></span></code> (for 475 <code class="computeroutput"><span class="identifier">T</span></code> other than <code class="computeroutput"><span class="keyword">void</span></code>). 476 </p> 477<p> 478 A <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special"><</span><span class="identifier">T</span><span class="special">></span></code> reserves 479 a <code class="computeroutput"><span class="identifier">value_</span></code> pointer to a value 480 of type <code class="computeroutput"><span class="identifier">T</span></code>: 481 </p> 482<p> 483</p> 484<pre class="programlisting"><span class="comment">// asio uses handler_type<completion token type, signature>::type to decide</span> 485<span class="comment">// what to instantiate as the actual handler. Below, we specialize</span> 486<span class="comment">// handler_type< yield_t, ... > to indicate yield_handler<>. So when you pass</span> 487<span class="comment">// an instance of yield_t as an asio completion token, asio selects</span> 488<span class="comment">// yield_handler<> as the actual handler class.</span> 489<span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">T</span> <span class="special">></span> 490<span class="keyword">class</span> <span class="identifier">yield_handler</span><span class="special">:</span> <span class="keyword">public</span> <span class="identifier">yield_handler_base</span> <span class="special">{</span> 491<span class="keyword">public</span><span class="special">:</span> 492 <span class="comment">// asio passes the completion token to the handler constructor</span> 493 <span class="keyword">explicit</span> <span class="identifier">yield_handler</span><span class="special">(</span> <span class="identifier">yield_t</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">y</span><span class="special">)</span> <span class="special">:</span> 494 <span class="identifier">yield_handler_base</span><span class="special">{</span> <span class="identifier">y</span> <span class="special">}</span> <span class="special">{</span> 495 <span class="special">}</span> 496 497 <span class="comment">// completion callback passing only value (T)</span> 498 <span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()(</span> <span class="identifier">T</span> <span class="identifier">t</span><span class="special">)</span> <span class="special">{</span> 499 <span class="comment">// just like callback passing success error_code</span> 500 <span class="special">(*</span><span class="keyword">this</span><span class="special">)(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span><span class="special">(),</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">t</span><span class="special">)</span> <span class="special">);</span> 501 <span class="special">}</span> 502 503 <span class="comment">// completion callback passing (error_code, T)</span> 504 <span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">ec</span><span class="special">,</span> <span class="identifier">T</span> <span class="identifier">t</span><span class="special">)</span> <span class="special">{</span> 505 <span class="identifier">BOOST_ASSERT_MSG</span><span class="special">(</span> <span class="identifier">value_</span><span class="special">,</span> 506 <span class="string">"Must inject value ptr "</span> 507 <span class="string">"before caling yield_handler<T>::operator()()"</span><span class="special">);</span> 508 <span class="comment">// move the value to async_result<> instance BEFORE waking up a</span> 509 <span class="comment">// suspended fiber</span> 510 <span class="special">*</span> <span class="identifier">value_</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span> <span class="identifier">t</span><span class="special">);</span> 511 <span class="comment">// forward the call to base-class completion handler</span> 512 <span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()(</span> <span class="identifier">ec</span><span class="special">);</span> 513 <span class="special">}</span> 514 515<span class="comment">//private:</span> 516 <span class="comment">// pointer to destination for eventual value</span> 517 <span class="comment">// this must be injected by async_result before operator()() is called</span> 518 <span class="identifier">T</span> <span class="special">*</span> <span class="identifier">value_</span><span class="special">{</span> <span class="keyword">nullptr</span> <span class="special">};</span> 519<span class="special">};</span> 520</pre> 521<p> 522 </p> 523<p> 524 This pointer is initialized to <code class="computeroutput"><span class="keyword">nullptr</span></code>. 525 </p> 526<p> 527 When <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code> 528 instantiates <code class="computeroutput"><span class="identifier">async_result</span><span class="special"><</span><span class="identifier">yield_handler</span><span class="special"><</span><span class="identifier">T</span><span class="special">>></span></code>: 529 </p> 530<p> 531</p> 532<pre class="programlisting"><span class="comment">// asio constructs an async_result<> instance from the yield_handler specified</span> 533<span class="comment">// by handler_type<>::type. A particular asio async method constructs the</span> 534<span class="comment">// yield_handler, constructs this async_result specialization from it, then</span> 535<span class="comment">// returns the result of calling its get() method.</span> 536<span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">ReturnType</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">T</span> <span class="special">></span> 537<span class="keyword">class</span> <span class="identifier">async_result</span><span class="special"><</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">yield_t</span><span class="special">,</span> <span class="identifier">ReturnType</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">system</span><span class="special">::</span><span class="identifier">error_code</span><span class="special">,</span> <span class="identifier">T</span><span class="special">)</span> <span class="special">></span> <span class="special">:</span> 538 <span class="keyword">public</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">async_result_base</span> <span class="special">{</span> 539<span class="keyword">public</span><span class="special">:</span> 540 <span class="comment">// type returned by get()</span> 541 <span class="keyword">using</span> <span class="identifier">return_type</span> <span class="special">=</span> <span class="identifier">T</span><span class="special">;</span> 542 <span class="keyword">using</span> <span class="identifier">completion_handler_type</span> <span class="special">=</span> <span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">yield_handler</span><span class="special"><</span><span class="identifier">T</span><span class="special">>;</span> 543 544 <span class="keyword">explicit</span> <span class="identifier">async_result</span><span class="special">(</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">yield_handler</span><span class="special"><</span> <span class="identifier">T</span> <span class="special">></span> <span class="special">&</span> <span class="identifier">h</span><span class="special">)</span> <span class="special">:</span> 545 <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">async_result_base</span><span class="special">{</span> <span class="identifier">h</span> <span class="special">}</span> <span class="special">{</span> 546 <span class="comment">// Inject ptr to our value_ member into yield_handler<>: result will</span> 547 <span class="comment">// be stored here.</span> 548 <span class="identifier">h</span><span class="special">.</span><span class="identifier">value_</span> <span class="special">=</span> <span class="special">&</span> <span class="identifier">value_</span><span class="special">;</span> 549 <span class="special">}</span> 550 551 <span class="comment">// asio async method returns result of calling get()</span> 552 <span class="identifier">return_type</span> <span class="identifier">get</span><span class="special">()</span> <span class="special">{</span> 553 <span class="identifier">boost</span><span class="special">::</span><span class="identifier">fibers</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">detail</span><span class="special">::</span><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">get</span><span class="special">();</span> 554 <span class="keyword">return</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span> <span class="identifier">value_</span><span class="special">);</span> 555 <span class="special">}</span> 556 557<span class="keyword">private</span><span class="special">:</span> 558 <span class="identifier">return_type</span> <span class="identifier">value_</span><span class="special">{};</span> 559<span class="special">};</span> 560</pre> 561<p> 562 </p> 563<p> 564 this <code class="computeroutput"><span class="identifier">async_result</span><span class="special"><></span></code> 565 specialization reserves a member of type <code class="computeroutput"><span class="identifier">T</span></code> 566 to receive the passed data item, and sets <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special"><</span><span class="identifier">T</span><span class="special">>::</span><span class="identifier">value_</span></code> to point to its own data member. 567 </p> 568<p> 569 <code class="computeroutput"><span class="identifier">async_result</span><span class="special"><</span><span class="identifier">yield_handler</span><span class="special"><</span><span class="identifier">T</span><span class="special">>></span></code> 570 overrides <code class="computeroutput"><span class="identifier">get</span><span class="special">()</span></code>. 571 The override calls <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">get</span><span class="special">()</span></code>, 572 so the calling fiber suspends as described above. 573 </p> 574<p> 575 <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special"><</span><span class="identifier">T</span><span class="special">>::</span><span class="keyword">operator</span><span class="special">()(</span><span class="identifier">error_code</span><span class="special">,</span> <span class="identifier">T</span><span class="special">)</span></code> stores 576 its passed <code class="computeroutput"><span class="identifier">T</span></code> value into 577 <code class="computeroutput"><span class="identifier">async_result</span><span class="special"><</span><span class="identifier">yield_handler</span><span class="special"><</span><span class="identifier">T</span><span class="special">>>::</span><span class="identifier">value_</span></code>. 578 </p> 579<p> 580 Then it passes control to <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="keyword">operator</span><span class="special">()(</span><span class="identifier">error_code</span><span class="special">)</span></code> to deal with waking the original fiber as 581 described above. 582 </p> 583<p> 584 When <code class="computeroutput"><span class="identifier">async_result</span><span class="special"><</span><span class="identifier">yield_handler</span><span class="special"><</span><span class="identifier">T</span><span class="special">>>::</span><span class="identifier">get</span><span class="special">()</span></code> resumes, 585 it returns the stored <code class="computeroutput"><span class="identifier">value_</span></code> 586 to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code> 587 and ultimately to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>’s caller. 588 </p> 589<p> 590 The case of a callback signature <code class="computeroutput"><span class="keyword">void</span><span class="special">(</span><span class="identifier">T</span><span class="special">)</span></code> 591 is handled by having <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special"><</span><span class="identifier">T</span><span class="special">>::</span><span class="keyword">operator</span><span class="special">()(</span><span class="identifier">T</span><span class="special">)</span></code> engage 592 the <code class="computeroutput"><span class="keyword">void</span><span class="special">(</span><span class="identifier">error_code</span><span class="special">,</span> <span class="identifier">T</span><span class="special">)</span></code> machinery, 593 passing a <span class="quote">“<span class="quote">success</span>”</span> <code class="computeroutput"><span class="identifier">error_code</span></code>. 594 </p> 595<p> 596 The source code above is found in <a href="../../../../examples/asio/yield.hpp" target="_top">yield.hpp</a> 597 and <a href="../../../../examples/asio/detail/yield.hpp" target="_top">detail/yield.hpp</a>. 598 </p> 599<div class="footnotes"> 600<br><hr style="width:100; text-align:left;margin-left: 0"> 601<div id="ftn.fiber.callbacks.then_there_s____boost_asio__.f0" class="footnote"><p><a href="#fiber.callbacks.then_there_s____boost_asio__.f0" class="para"><sup class="para">[5] </sup></a> 602 This mechanism has been proposed as a conventional way to allow the caller 603 of an arbitrary async function to specify completion handling: <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4045.pdf" target="_top">N4045</a>. 604 </p></div> 605<div id="ftn.fiber.callbacks.then_there_s____boost_asio__.f1" class="footnote"><p><a href="#fiber.callbacks.then_there_s____boost_asio__.f1" class="para"><sup class="para">[6] </sup></a> 606 per <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4045.pdf" target="_top">N4045</a> 607 </p></div> 608</div> 609</div> 610<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr> 611<td align="left"></td> 612<td align="right"><div class="copyright-footer">Copyright © 2013 Oliver Kowalke<p> 613 Distributed under the Boost Software License, Version 1.0. (See accompanying 614 file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>) 615 </p> 616</div></td> 617</tr></table> 618<hr> 619<div class="spirit-nav"> 620<a accesskey="p" href="success_error_virtual_methods.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../callbacks.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="../nonblocking.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a> 621</div> 622</body> 623</html> 624