]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/fiber/doc/html/fiber/callbacks/then_there_s____boost_asio__.html
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / fiber / doc / html / fiber / callbacks / then_there_s____boost_asio__.html
CommitLineData
7c673cae
FG
1<html>
2<head>
3<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
4<title>Then There&#8217;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.75.2">
7<link rel="home" href="../../index.html" title="Chapter&#160;1.&#160;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&#8217;s Boost.Asio">Then
28 There&#8217;s <a href="http://www.boost.org/doc/libs/release/libs/asio/index.html" target="_top">Boost.Asio</a></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<sup>[<a name="fiber.callbacks.then_there_s____boost_asio__.f0" href="#ftn.fiber.callbacks.then_there_s____boost_asio__.f0" class="footnote">4</a>]</sup> 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:<sup>[<a name="fiber.callbacks.then_there_s____boost_asio__.f1" href="#ftn.fiber.callbacks.then_there_s____boost_asio__.f1" class="footnote">5</a>]</sup>
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&#8217;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</p>
130<pre class="programlisting"><span class="comment">// Handler type specialisation for fibers::asio::yield.</span>
131<span class="comment">// When 'yield' is passed as a completion handler which accepts only</span>
132<span class="comment">// error_code, use yield_handler&lt;void&gt;. yield_handler will take care of the</span>
133<span class="comment">// error_code one way or another.</span>
134<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">ReturnType</span> <span class="special">&gt;</span>
135<span class="keyword">struct</span> <span class="identifier">handler_type</span><span class="special">&lt;</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="special">&gt;</span>
136<span class="special">{</span> <span class="keyword">typedef</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="identifier">type</span><span class="special">;</span> <span class="special">};</span>
137</pre>
138<p>
139 </p>
140<p>
141 (There are actually four different specializations in <a href="../../../../examples/asio/detail/yield.hpp" target="_top">detail/yield.hpp</a>,
142 one for each of the four Asio async callback signatures we expect.)
143 </p>
144<p>
145 The above directs Asio to use <code class="computeroutput"><span class="identifier">yield_handler</span></code>
146 as the actual handler for an async operation to which <code class="computeroutput"><span class="identifier">yield</span></code>
147 is passed. There&#8217;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>
148 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>
149 specialization. Let&#8217;s start with the <code class="computeroutput"><span class="special">&lt;</span><span class="keyword">void</span><span class="special">&gt;</span></code> specialization:
150 </p>
151<p>
152</p>
153<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>
154<span class="comment">// just like yield_handler_base.</span>
155<span class="keyword">template</span><span class="special">&lt;&gt;</span>
156<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>
157<span class="keyword">public</span><span class="special">:</span>
158 <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>
159 <span class="identifier">yield_handler_base</span><span class="special">{</span> <span class="identifier">y</span> <span class="special">}</span> <span class="special">{</span>
160 <span class="special">}</span>
161
162 <span class="comment">// nullary completion callback</span>
163 <span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()()</span> <span class="special">{</span>
164 <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>
165 <span class="special">}</span>
166
167 <span class="comment">// inherit operator()(error_code) overload from base class</span>
168 <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>
169<span class="special">};</span>
170</pre>
171<p>
172 </p>
173<p>
174 <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>,
175 having consulted the <code class="computeroutput"><span class="identifier">handler_type</span><span class="special">&lt;&gt;</span></code> traits specialization, instantiates
176 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
177 be passed as the actual callback for the async operation. <code class="computeroutput"><span class="identifier">yield_handler</span></code>&#8217;s
178 constructor accepts the <code class="computeroutput"><span class="identifier">yield_t</span></code>
179 instance (the <code class="computeroutput"><span class="identifier">yield</span></code> object
180 passed to the async function) and passes it along to <code class="computeroutput"><span class="identifier">yield_handler_base</span></code>:
181 </p>
182<p>
183</p>
184<pre class="programlisting"><span class="comment">// This class encapsulates common elements between yield_handler&lt;T&gt; (capturing</span>
185<span class="comment">// a value to return from asio async function) and yield_handler&lt;void&gt; (no</span>
186<span class="comment">// such value). See yield_handler&lt;T&gt; and its &lt;void&gt; specialization below. Both</span>
187<span class="comment">// yield_handler&lt;T&gt; and yield_handler&lt;void&gt; are passed by value through</span>
188<span class="comment">// various layers of asio functions. In other words, they're potentially</span>
189<span class="comment">// copied multiple times. So key data such as the yield_completion instance</span>
190<span class="comment">// must be stored in our async_result&lt;yield_handler&lt;&gt;&gt; specialization, which</span>
191<span class="comment">// should be instantiated only once.</span>
192<span class="keyword">class</span> <span class="identifier">yield_handler_base</span> <span class="special">{</span>
193<span class="keyword">public</span><span class="special">:</span>
194 <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>
195 <span class="comment">// capture the context* associated with the running fiber</span>
196 <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>
197 <span class="comment">// capture the passed yield_t</span>
198 <span class="identifier">yt_</span><span class="special">(</span> <span class="identifier">y</span> <span class="special">)</span> <span class="special">{</span>
199 <span class="special">}</span>
200
201 <span class="comment">// completion callback passing only (error_code)</span>
202 <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>
203 <span class="identifier">BOOST_ASSERT_MSG</span><span class="special">(</span> <span class="identifier">ycomp_</span><span class="special">,</span>
204 <span class="string">"Must inject yield_completion* "</span>
205 <span class="string">"before calling yield_handler_base::operator()()"</span><span class="special">);</span>
206 <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>
207 <span class="string">"Must inject boost::system::error_code* "</span>
208 <span class="string">"before calling yield_handler_base::operator()()"</span><span class="special">);</span>
209 <span class="comment">// If originating fiber is busy testing completed_ flag, wait until it</span>
210 <span class="comment">// has observed (! completed_).</span>
211 <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>
212 <span class="comment">// Notify a subsequent yield_completion::wait() call that it need not</span>
213 <span class="comment">// suspend.</span>
214 <span class="identifier">ycomp_</span><span class="special">-&gt;</span><span class="identifier">completed_</span> <span class="special">=</span> <span class="keyword">true</span><span class="special">;</span>
215 <span class="comment">// set the error_code bound by yield_t</span>
216 <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>
217 <span class="comment">// If ctx_ is still active, e.g. because the async operation</span>
218 <span class="comment">// immediately called its callback (this method!) before the asio</span>
219 <span class="comment">// async function called async_result_base::get(), we must not set it</span>
220 <span class="comment">// ready.</span>
221 <span class="keyword">if</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> <span class="identifier">ctx_</span> <span class="special">)</span> <span class="special">{</span>
222 <span class="comment">// wake the fiber</span>
223 <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">set_ready</span><span class="special">(</span> <span class="identifier">ctx_</span><span class="special">);</span>
224 <span class="special">}</span>
225 <span class="special">}</span>
226
227<span class="comment">//private:</span>
228 <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>
229 <span class="identifier">yield_t</span> <span class="identifier">yt_</span><span class="special">;</span>
230 <span class="comment">// We depend on this pointer to yield_completion, which will be injected</span>
231 <span class="comment">// by async_result.</span>
232 <span class="identifier">yield_completion</span> <span class="special">*</span> <span class="identifier">ycomp_</span><span class="special">{</span> <span class="keyword">nullptr</span> <span class="special">};</span>
233<span class="special">};</span>
234</pre>
235<p>
236 </p>
237<p>
238 <code class="computeroutput"><span class="identifier">yield_handler_base</span></code> stores
239 a copy of the <code class="computeroutput"><span class="identifier">yield_t</span></code> instance
240 &#8212; 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>*
241 for the currently-running fiber by calling <a class="link" href="../scheduling.html#context_active"><code class="computeroutput">context::active()</code></a>.
242 </p>
243<p>
244 You will notice that <code class="computeroutput"><span class="identifier">yield_handler_base</span></code>
245 has one more data member (<code class="computeroutput"><span class="identifier">ycomp_</span></code>)
246 that is initialized to <code class="computeroutput"><span class="keyword">nullptr</span></code>
247 by its constructor &#8212; 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>
248 being non-null. More on this in a moment.
249 </p>
250<p>
251 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>
252 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>
253 specialized for the <code class="computeroutput"><span class="identifier">handler_type</span><span class="special">&lt;&gt;::</span><span class="identifier">type</span></code>:
254 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>.
255 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>
256 instance to the new <code class="computeroutput"><span class="identifier">async_result</span></code>
257 instance.
258 </p>
259<p>
260</p>
261<pre class="programlisting"><span class="comment">// Without the need to handle a passed value, our yield_handler&lt;void&gt;</span>
262<span class="comment">// specialization is just like async_result_base.</span>
263<span class="keyword">template</span><span class="special">&lt;&gt;</span>
264<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">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">&gt;</span> <span class="special">:</span>
265 <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>
266<span class="keyword">public</span><span class="special">:</span>
267 <span class="keyword">typedef</span> <span class="keyword">void</span> <span class="identifier">type</span><span class="special">;</span>
268
269 <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>
270 <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>
271 <span class="special">}</span>
272<span class="special">};</span>
273</pre>
274<p>
275 </p>
276<p>
277 Naturally that leads us straight to <code class="computeroutput"><span class="identifier">async_result_base</span></code>:
278 </p>
279<p>
280</p>
281<pre class="programlisting"><span class="comment">// Factor out commonality between async_result&lt;yield_handler&lt;T&gt;&gt; and</span>
282<span class="comment">// async_result&lt;yield_handler&lt;void&gt;&gt;</span>
283<span class="keyword">class</span> <span class="identifier">async_result_base</span> <span class="special">{</span>
284<span class="keyword">public</span><span class="special">:</span>
285 <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>
286 <span class="comment">// Inject ptr to our yield_completion instance into this</span>
287 <span class="comment">// yield_handler&lt;&gt;.</span>
288 <span class="identifier">h</span><span class="special">.</span><span class="identifier">ycomp_</span> <span class="special">=</span> <span class="special">&amp;</span> <span class="keyword">this</span><span class="special">-&gt;</span><span class="identifier">ycomp_</span><span class="special">;</span>
289 <span class="comment">// if yield_t didn't bind an error_code, make yield_handler_base's</span>
290 <span class="comment">// error_code* point to an error_code local to this object so</span>
291 <span class="comment">// yield_handler_base::operator() can unconditionally store through</span>
292 <span class="comment">// its error_code*</span>
293 <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>
294 <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>
295 <span class="special">}</span>
296 <span class="special">}</span>
297
298 <span class="keyword">void</span> <span class="identifier">get</span><span class="special">()</span> <span class="special">{</span>
299 <span class="comment">// Unless yield_handler_base::operator() has already been called,</span>
300 <span class="comment">// suspend the calling fiber until that call.</span>
301 <span class="identifier">ycomp_</span><span class="special">.</span><span class="identifier">wait</span><span class="special">();</span>
302 <span class="comment">// The only way our own ec_ member could have a non-default value is</span>
303 <span class="comment">// if our yield_handler did not have a bound error_code AND the</span>
304 <span class="comment">// completion callback passed a non-default error_code.</span>
305 <span class="keyword">if</span> <span class="special">(</span> <span class="identifier">ec_</span><span class="special">)</span> <span class="special">{</span>
306 <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>
307 <span class="special">}</span>
308 <span class="special">}</span>
309
310<span class="keyword">private</span><span class="special">:</span>
311 <span class="comment">// If yield_t does not bind an error_code instance, store into here.</span>
312 <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>
313 <span class="comment">// async_result_base owns the yield_completion because, unlike</span>
314 <span class="comment">// yield_handler&lt;&gt;, async_result&lt;&gt; is only instantiated once.</span>
315 <span class="identifier">yield_completion</span> <span class="identifier">ycomp_</span><span class="special">{};</span>
316<span class="special">};</span>
317</pre>
318<p>
319 </p>
320<p>
321 This is how <code class="computeroutput"><span class="identifier">yield_handler_base</span><span class="special">::</span><span class="identifier">ycomp_</span></code>
322 becomes non-null: <code class="computeroutput"><span class="identifier">async_result_base</span></code>&#8217;s
323 constructor injects a pointer back to its own <code class="computeroutput"><span class="identifier">yield_completion</span></code>
324 member.
325 </p>
326<p>
327 Recall that the canonical <code class="computeroutput"><span class="identifier">yield_t</span></code>
328 instance <code class="computeroutput"><span class="identifier">yield</span></code> initializes
329 its <code class="computeroutput"><span class="identifier">error_code</span><span class="special">*</span></code>
330 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>
331 (<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
332 <code class="computeroutput"><span class="identifier">ec_</span></code>. <code class="computeroutput"><span class="identifier">async_result_base</span></code>&#8217;s
333 constructor sets <code class="computeroutput"><span class="identifier">yield_handler_base</span></code>&#8217;s
334 <code class="computeroutput"><span class="identifier">yield_t</span></code>&#8217;s <code class="computeroutput"><span class="identifier">ec_</span></code>
335 member to point to its own <code class="computeroutput"><span class="identifier">error_code</span></code>
336 member.
337 </p>
338<p>
339 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
340 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>
341 instance on completion. Let&#8217;s say, for the sake of argument, that the actual
342 async operation&#8217;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>.
343 </p>
344<p>
345 But since it&#8217;s an async operation, control returns at once to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>.
346 <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>
347 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>,
348 and will return its return value.
349 </p>
350<p>
351 <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
352 <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">get</span><span class="special">()</span></code>.
353 </p>
354<p>
355 <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
356 calls <code class="computeroutput"><span class="identifier">yield_completion</span><span class="special">::</span><span class="identifier">wait</span><span class="special">()</span></code>.
357 </p>
358<p>
359</p>
360<pre class="programlisting"><span class="comment">// Bundle a completion bool flag with a spinlock to protect it.</span>
361<span class="keyword">struct</span> <span class="identifier">yield_completion</span> <span class="special">{</span>
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
365 <span class="identifier">mutex_t</span> <span class="identifier">mtx_</span><span class="special">{};</span>
366 <span class="keyword">bool</span> <span class="identifier">completed_</span><span class="special">{</span> <span class="keyword">false</span> <span class="special">};</span>
367
368 <span class="keyword">void</span> <span class="identifier">wait</span><span class="special">()</span> <span class="special">{</span>
369 <span class="comment">// yield_handler_base::operator()() will set completed_ true and</span>
370 <span class="comment">// attempt to wake a suspended fiber. It would be Bad if that call</span>
371 <span class="comment">// happened between our detecting (! completed_) and suspending.</span>
372 <span class="identifier">lock_t</span> <span class="identifier">lk</span><span class="special">{</span> <span class="identifier">mtx_</span> <span class="special">};</span>
373 <span class="comment">// If completed_ is already set, we're done here: don't suspend.</span>
374 <span class="keyword">if</span> <span class="special">(</span> <span class="special">!</span> <span class="identifier">completed_</span><span class="special">)</span> <span class="special">{</span>
375 <span class="comment">// suspend(unique_lock&lt;spinlock&gt;) unlocks the lock in the act of</span>
376 <span class="comment">// resuming another fiber</span>
377 <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>
378 <span class="special">}</span>
379 <span class="special">}</span>
380<span class="special">};</span>
381</pre>
382<p>
383 </p>
384<p>
385 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
386 the currently-running fiber.
387 </p>
388<p>
389 Other fibers will now have a chance to run.
390 </p>
391<p>
392 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>
393 indicating either success or failure. We&#8217;ll consider both cases.
394 </p>
395<p>
396 <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
397 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>.
398 </p>
399<p>
400 <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>
401 <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>&#8217;s
402 async operation completes immediately &#8212; 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>
403 &#8212; the calling fiber will <span class="emphasis"><em>not</em></span> suspend.
404 </p>
405<p>
406 The actual <code class="computeroutput"><span class="identifier">error_code</span></code> produced
407 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.
408 If <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>&#8217;s
409 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>
410 instance, the actual <code class="computeroutput"><span class="identifier">error_code</span></code>
411 value is stored into the caller&#8217;s variable. Otherwise, it is stored into
412 <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">ec_</span></code>.
413 </p>
414<p>
415 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>
416 is not already running, it is marked as ready to run by passing it to <a class="link" href="../scheduling.html#context_set_ready"><code class="computeroutput">context::set_ready()</code></a>.
417 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.
418 </p>
419<p>
420 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
421 <code class="computeroutput"><span class="identifier">yield_completion</span><span class="special">::</span><span class="identifier">wait</span><span class="special">()</span></code>,
422 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>.
423 </p>
424<div class="itemizedlist"><ul class="itemizedlist" type="disc">
425<li class="listitem">
426 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>
427 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>
428 to the caller&#8217;s <code class="computeroutput"><span class="identifier">my_ec</span></code>
429 instance, leaving <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">ec_</span></code>
430 initialized to success.
431 </li>
432<li class="listitem">
433 If the original caller passed <code class="computeroutput"><span class="identifier">yield</span></code>
434 to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>
435 without binding a local <code class="computeroutput"><span class="identifier">error_code</span></code>
436 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>
437 into <code class="computeroutput"><span class="identifier">async_result_base</span><span class="special">::</span><span class="identifier">ec_</span></code>.
438 If in fact that <code class="computeroutput"><span class="identifier">error_code</span></code>
439 is success, then all is well.
440 </li>
441<li class="listitem">
442 Otherwise &#8212; the original caller did not bind a local <code class="computeroutput"><span class="identifier">error_code</span></code>
443 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>
444 indicating error &#8212; <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>
445 with that <code class="computeroutput"><span class="identifier">error_code</span></code>.
446 </li>
447</ul></div>
448<p>
449 The case in which <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>&#8217;s completion callback has signature <code class="computeroutput"><span class="keyword">void</span><span class="special">()</span></code> is
450 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>
451 invokes the machinery above with a <span class="quote">&#8220;<span class="quote">success</span>&#8221;</span> <code class="computeroutput"><span class="identifier">error_code</span></code>.
452 </p>
453<p>
454 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>
455 (that is: in addition to <code class="computeroutput"><span class="identifier">error_code</span></code>,
456 callback receives some data item) is handled somewhat differently. For this
457 kind of signature, <code class="computeroutput"><span class="identifier">handler_type</span><span class="special">&lt;&gt;::</span><span class="identifier">type</span></code>
458 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
459 <code class="computeroutput"><span class="identifier">T</span></code> other than <code class="computeroutput"><span class="keyword">void</span></code>).
460 </p>
461<p>
462 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
463 a <code class="computeroutput"><span class="identifier">value_</span></code> pointer to a value
464 of type <code class="computeroutput"><span class="identifier">T</span></code>:
465 </p>
466<p>
467</p>
468<pre class="programlisting"><span class="comment">// asio uses handler_type&lt;completion token type, signature&gt;::type to decide</span>
469<span class="comment">// what to instantiate as the actual handler. Below, we specialize</span>
470<span class="comment">// handler_type&lt; yield_t, ... &gt; to indicate yield_handler&lt;&gt;. So when you pass</span>
471<span class="comment">// an instance of yield_t as an asio completion token, asio selects</span>
472<span class="comment">// yield_handler&lt;&gt; as the actual handler class.</span>
473<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>
474<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>
475<span class="keyword">public</span><span class="special">:</span>
476 <span class="comment">// asio passes the completion token to the handler constructor</span>
477 <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>
478 <span class="identifier">yield_handler_base</span><span class="special">{</span> <span class="identifier">y</span> <span class="special">}</span> <span class="special">{</span>
479 <span class="special">}</span>
480
481 <span class="comment">// completion callback passing only value (T)</span>
482 <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>
483 <span class="comment">// just like callback passing success error_code</span>
484 <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>
485 <span class="special">}</span>
486
487 <span class="comment">// completion callback passing (error_code, T)</span>
488 <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>
489 <span class="identifier">BOOST_ASSERT_MSG</span><span class="special">(</span> <span class="identifier">value_</span><span class="special">,</span>
490 <span class="string">"Must inject value ptr "</span>
491 <span class="string">"before caling yield_handler&lt;T&gt;::operator()()"</span><span class="special">);</span>
492 <span class="comment">// move the value to async_result&lt;&gt; instance BEFORE waking up a</span>
493 <span class="comment">// suspended fiber</span>
494 <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>
495 <span class="comment">// forward the call to base-class completion handler</span>
496 <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>
497 <span class="special">}</span>
498
499<span class="comment">//private:</span>
500 <span class="comment">// pointer to destination for eventual value</span>
501 <span class="comment">// this must be injected by async_result before operator()() is called</span>
502 <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>
503<span class="special">};</span>
504</pre>
505<p>
506 </p>
507<p>
508 This pointer is initialized to <code class="computeroutput"><span class="keyword">nullptr</span></code>.
509 </p>
510<p>
511 When <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>
512 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>:
513 </p>
514<p>
515</p>
516<pre class="programlisting"><span class="comment">// asio constructs an async_result&lt;&gt; instance from the yield_handler specified</span>
517<span class="comment">// by handler_type&lt;&gt;::type. A particular asio async method constructs the</span>
518<span class="comment">// yield_handler, constructs this async_result specialization from it, then</span>
519<span class="comment">// returns the result of calling its get() method.</span>
520<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>
521<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">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">&gt;</span> <span class="special">:</span>
522 <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>
523<span class="keyword">public</span><span class="special">:</span>
524 <span class="comment">// type returned by get()</span>
525 <span class="keyword">typedef</span> <span class="identifier">T</span> <span class="identifier">type</span><span class="special">;</span>
526
527 <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>
528 <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>
529 <span class="comment">// Inject ptr to our value_ member into yield_handler&lt;&gt;: result will</span>
530 <span class="comment">// be stored here.</span>
531 <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>
532 <span class="special">}</span>
533
534 <span class="comment">// asio async method returns result of calling get()</span>
535 <span class="identifier">type</span> <span class="identifier">get</span><span class="special">()</span> <span class="special">{</span>
536 <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>
537 <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>
538 <span class="special">}</span>
539
540<span class="keyword">private</span><span class="special">:</span>
541 <span class="identifier">type</span> <span class="identifier">value_</span><span class="special">{};</span>
542<span class="special">};</span>
543</pre>
544<p>
545 </p>
546<p>
547 this <code class="computeroutput"><span class="identifier">async_result</span><span class="special">&lt;&gt;</span></code>
548 specialization reserves a member of type <code class="computeroutput"><span class="identifier">T</span></code>
549 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.
550 </p>
551<p>
552 <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>
553 overrides <code class="computeroutput"><span class="identifier">get</span><span class="special">()</span></code>.
554 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>,
555 so the calling fiber suspends as described above.
556 </p>
557<p>
558 <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
559 its passed <code class="computeroutput"><span class="identifier">T</span></code> value into
560 <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>.
561 </p>
562<p>
563 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
564 described above.
565 </p>
566<p>
567 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,
568 it returns the stored <code class="computeroutput"><span class="identifier">value_</span></code>
569 to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>
570 and ultimately to <code class="computeroutput"><span class="identifier">async_something</span><span class="special">()</span></code>&#8217;s caller.
571 </p>
572<p>
573 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>
574 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
575 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,
576 passing a <span class="quote">&#8220;<span class="quote">success</span>&#8221;</span> <code class="computeroutput"><span class="identifier">error_code</span></code>.
577 </p>
578<p>
579 The source code above is found in <a href="../../../../examples/asio/yield.hpp" target="_top">yield.hpp</a>
580 and <a href="../../../../examples/asio/detail/yield.hpp" target="_top">detail/yield.hpp</a>.
581 </p>
582<div class="footnotes">
583<br><hr width="100" align="left">
584<div class="footnote"><p><sup>[<a name="ftn.fiber.callbacks.then_there_s____boost_asio__.f0" href="#fiber.callbacks.then_there_s____boost_asio__.f0" class="para">4</a>] </sup>
585 This mechanism has been proposed as a conventional way to allow the caller
586 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>.
587 </p></div>
588<div class="footnote"><p><sup>[<a name="ftn.fiber.callbacks.then_there_s____boost_asio__.f1" href="#fiber.callbacks.then_there_s____boost_asio__.f1" class="para">5</a>] </sup>
589 per <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4045.pdf" target="_top">N4045</a>
590 </p></div>
591</div>
592</div>
593<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
594<td align="left"></td>
595<td align="right"><div class="copyright-footer">Copyright &#169; 2013 Oliver Kowalke<p>
596 Distributed under the Boost Software License, Version 1.0. (See accompanying
597 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>)
598 </p>
599</div></td>
600</tr></table>
601<hr>
602<div class="spirit-nav">
603<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>
604</div>
605</body>
606</html>