• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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">&lt;</span> <span class="special">...,</span> <span class="keyword">class</span> <span class="identifier">CompletionToken</span> <span class="special">&gt;</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">&amp;&amp;</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">&lt;</span><span class="identifier">CompletionToken</span><span class="special">,</span> <span class="special">...&gt;::</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">&lt;</span><span class="keyword">decltype</span><span class="special">(</span><span class="identifier">handler</span><span class="special">)&gt;</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">&lt;&gt;</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">&amp;</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">&amp;</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">&lt;&gt;</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">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span></code>
139        implementation and a <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;</span></code>
140        specialization. Let’s start with the <code class="computeroutput"><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;</span></code> specialization:
141      </p>
142<p>
143</p>
144<pre class="programlisting"><span class="comment">// yield_handler&lt;void&gt; is like yield_handler&lt;T&gt; 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">&lt;&gt;</span>
147<span class="keyword">class</span> <span class="identifier">yield_handler</span><span class="special">&lt;</span> <span class="keyword">void</span> <span class="special">&gt;:</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">&amp;</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">&lt;&gt;</span></code> traits specialization, instantiates
167        a <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;</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&lt;T&gt; (capturing</span>
176<span class="comment">// a value to return from asio async function) and yield_handler&lt;void&gt; (no</span>
177<span class="comment">// such value). See yield_handler&lt;T&gt; and its &lt;void&gt; specialization below. Both</span>
178<span class="comment">// yield_handler&lt;T&gt; and yield_handler&lt;void&gt; 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&lt;yield_handler&lt;&gt;&gt; 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">&amp;</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">&amp;</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">-&gt;</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">-&gt;</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">-&gt;</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">()-&gt;</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">&lt;</span><span class="keyword">void</span><span class="special">&gt;</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">&lt;&gt;::</span><span class="identifier">type</span></code>:
248        in this case, <code class="computeroutput"><span class="identifier">async_result</span><span class="special">&lt;</span><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;&gt;</span></code>.
249        It passes the <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;</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&lt;void&gt;</span>
256<span class="comment">// specialization is just like async_result_base.</span>
257<span class="keyword">template</span><span class="special">&lt;&gt;</span>
258<span class="keyword">class</span> <span class="identifier">async_result</span><span class="special">&lt;</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">&gt;</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">&lt;</span><span class="keyword">void</span><span class="special">&gt;;</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">&lt;</span> <span class="keyword">void</span> <span class="special">&gt;</span> <span class="special">&amp;</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&lt;yield_handler&lt;T&gt;&gt; and</span>
277<span class="comment">// async_result&lt;yield_handler&lt;void&gt;&gt;</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">&amp;</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&lt;&gt;.</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">-&gt;</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">&amp;</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">-&gt;</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">&lt;</span><span class="keyword">void</span><span class="special">&gt;</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">&lt;</span><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;&gt;::</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">&lt;</span><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;&gt;::</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">&lt;</span> <span class="identifier">mutex_t</span> <span class="special">&gt;</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">&lt;</span> <span class="identifier">yield_completion</span> <span class="special">&gt;</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">&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="special">&gt;</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&lt;spinlock&gt;) 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">()-&gt;</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">-&gt;</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">-&gt;</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">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</span><span class="keyword">operator</span><span class="special">()(</span><span class="identifier">error_code</span> <span class="keyword">const</span><span class="special">&amp;)</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">&lt;</span><span class="keyword">void</span><span class="special">&gt;</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">&amp;)</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">&amp;)</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">&lt;</span><span class="keyword">void</span><span class="special">&gt;::</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">&lt;&gt;::</span><span class="identifier">type</span></code>
474        specifies <code class="computeroutput"><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</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">&lt;</span><span class="identifier">T</span><span class="special">&gt;</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&lt;completion token type, signature&gt;::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&lt; yield_t, ... &gt; to indicate yield_handler&lt;&gt;. 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&lt;&gt; as the actual handler class.</span>
489<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">T</span> <span class="special">&gt;</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">&amp;</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">&amp;</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&lt;T&gt;::operator()()"</span><span class="special">);</span>
508        <span class="comment">// move the value to async_result&lt;&gt; 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">&lt;</span><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&gt;</span></code>:
529      </p>
530<p>
531</p>
532<pre class="programlisting"><span class="comment">// asio constructs an async_result&lt;&gt; instance from the yield_handler specified</span>
533<span class="comment">// by handler_type&lt;&gt;::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">&lt;</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">&gt;</span>
537<span class="keyword">class</span> <span class="identifier">async_result</span><span class="special">&lt;</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">&gt;</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">&lt;</span><span class="identifier">T</span><span class="special">&gt;;</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">&lt;</span> <span class="identifier">T</span> <span class="special">&gt;</span> <span class="special">&amp;</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&lt;&gt;: 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">&amp;</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">&lt;&gt;</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">&lt;</span><span class="identifier">T</span><span class="special">&gt;::</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">&lt;</span><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&gt;</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">&lt;</span><span class="identifier">T</span><span class="special">&gt;::</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">&lt;</span><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&gt;::</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">&lt;</span><span class="identifier">yield_handler</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&gt;::</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">&lt;</span><span class="identifier">T</span><span class="special">&gt;::</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