3 <meta http-equiv=
"Content-Type" content=
"text/html; charset=US-ASCII">
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.75.2">
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">
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>
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>
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
<a href=
"http://www.boost.org/doc/libs/release/libs/asio/index.html" target=
"_top">Boost.Asio
</a></a>
29 </h3></div></div></div>
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
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.
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>
45 <pre class=
"programlisting"><span class=
"keyword">template
</span> <span class=
"special"><</span> <span class=
"special">...,
</span> <span class=
"keyword">class
</span> <span class=
"identifier">CompletionToken
</span> <span class=
"special">></span>
46 <span class=
"emphasis"><em>deduced_return_type
</em></span>
47 <span class=
"identifier">async_something
</span><span class=
"special">(
</span> <span class=
"special">...
</span> <span class=
"special">,
</span> <span class=
"identifier">CompletionToken
</span><span class=
"special">&&</span> <span class=
"identifier">token
</span><span class=
"special">)
</span>
48 <span class=
"special">{
</span>
49 <span class=
"comment">// construct handler_type instance from CompletionToken
</span>
50 <span class=
"identifier">handler_type
</span><span class=
"special"><</span><span class=
"identifier">CompletionToken
</span><span class=
"special">,
</span> <span class=
"special">...
>::
</span><span class=
"identifier">type
</span> <span class=
"bold"><strong><code class=
"computeroutput">handler(token)
</code></strong></span><span class=
"special">;
</span>
51 <span class=
"comment">// construct async_result instance from handler_type
</span>
52 <span class=
"identifier">async_result
</span><span class=
"special"><</span><span class=
"keyword">decltype
</span><span class=
"special">(
</span><span class=
"identifier">handler
</span><span class=
"special">)
></span> <span class=
"bold"><strong><code class=
"computeroutput">result(handler)
</code></strong></span><span class=
"special">;
</span>
54 <span class=
"comment">// ... arrange to call handler on completion ...
</span>
55 <span class=
"comment">// ... initiate actual I/O operation ...
</span>
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>
61 We will engage that mechanism, which is based on specializing Asio
’s
<code class=
"computeroutput"><span class=
"identifier">handler_type
</span><span class=
"special"><></span></code>
62 template for the
<code class=
"computeroutput"><span class=
"identifier">CompletionToken
</span></code>
63 type and the signature of the specific callback. The remainder of this discussion
64 will refer back to
<code class=
"computeroutput"><span class=
"identifier">async_something
</span><span class=
"special">()
</span></code> as the Asio async function under consideration.
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>
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>:
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>
84 <span class=
"comment">/**
86 * static yield_t yield;
87 * boost::system::error_code myec;
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.
96 <span class=
"identifier">yield_t
</span> <span class=
"keyword">operator
</span><span class=
"special">[](
</span> <span class=
"identifier">boost
</span><span class=
"special">::
</span><span class=
"identifier">system
</span><span class=
"special">::
</span><span class=
"identifier">error_code
</span> <span class=
"special">&</span> <span class=
"identifier">ec
</span><span class=
"special">)
</span> <span class=
"keyword">const
</span> <span class=
"special">{
</span>
97 <span class=
"identifier">yield_t
</span> <span class=
"identifier">tmp
</span><span class=
"special">;
</span>
98 <span class=
"identifier">tmp
</span><span class=
"special">.
</span><span class=
"identifier">ec_
</span> <span class=
"special">=
</span> <span class=
"special">&</span> <span class=
"identifier">ec
</span><span class=
"special">;
</span>
99 <span class=
"keyword">return
</span> <span class=
"identifier">tmp
</span><span class=
"special">;
</span>
100 <span class=
"special">}
</span>
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>
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
115 <code class=
"computeroutput"><span class=
"identifier">yield
</span></code> is declared as:
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>
125 Asio customization is engaged by specializing
<a href=
"http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/handler_type.html" target=
"_top"><code class=
"computeroutput"><span class=
"identifier">boost
</span><span class=
"special">::
</span><span class=
"identifier">asio
</span><span class=
"special">::
</span><span class=
"identifier">handler_type
</span><span class=
"special"><></span></code></a>
126 for
<code class=
"computeroutput"><span class=
"identifier">yield_t
</span></code>:
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
<void
>. 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"><</span> <span class=
"keyword">typename
</span> <span class=
"identifier">ReturnType
</span> <span class=
"special">></span>
135 <span class=
"keyword">struct
</span> <span class=
"identifier">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">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">></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"><</span> <span class=
"keyword">void
</span> <span class=
"special">></span> <span class=
"identifier">type
</span><span class=
"special">;
</span> <span class=
"special">};
</span>
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.)
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
’s a generic
<code class=
"computeroutput"><span class=
"identifier">yield_handler
</span><span class=
"special"><</span><span class=
"identifier">T
</span><span class=
"special">></span></code>
148 implementation and a
<code class=
"computeroutput"><span class=
"identifier">yield_handler
</span><span class=
"special"><</span><span class=
"keyword">void
</span><span class=
"special">></span></code>
149 specialization. Let
’s start with the
<code class=
"computeroutput"><span class=
"special"><</span><span class=
"keyword">void
</span><span class=
"special">></span></code> specialization:
153 <pre class=
"programlisting"><span class=
"comment">// yield_handler
<void
> is like yield_handler
<T
> 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"><></span>
156 <span class=
"keyword">class
</span> <span class=
"identifier">yield_handler
</span><span class=
"special"><</span> <span class=
"keyword">void
</span> <span class=
"special">>:
</span> <span class=
"keyword">public
</span> <span class=
"identifier">yield_handler_base
</span> <span class=
"special">{
</span>
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">&</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>
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>
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>
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"><></span></code> traits specialization, instantiates
176 a
<code class=
"computeroutput"><span class=
"identifier">yield_handler
</span><span class=
"special"><</span><span class=
"keyword">void
</span><span class=
"special">></span></code> to
177 be passed as the actual callback for the async operation.
<code class=
"computeroutput"><span class=
"identifier">yield_handler
</span></code>’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>:
184 <pre class=
"programlisting"><span class=
"comment">// This class encapsulates common elements between yield_handler
<T
> (capturing
</span>
185 <span class=
"comment">// a value to return from asio async function) and yield_handler
<void
> (no
</span>
186 <span class=
"comment">// such value). See yield_handler
<T
> and its
<void
> specialization below. Both
</span>
187 <span class=
"comment">// yield_handler
<T
> and yield_handler
<void
> 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
<yield_handler
<>> 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">&</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>
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">&</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">-
></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">-
></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">()-
></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>
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>
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 — 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>.
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
— 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.
251 Having constructed the
<code class=
"computeroutput"><span class=
"identifier">yield_handler
</span><span class=
"special"><</span><span class=
"keyword">void
</span><span class=
"special">></span></code>
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"><>::
</span><span class=
"identifier">type
</span></code>:
254 in this case,
<code class=
"computeroutput"><span class=
"identifier">async_result
</span><span class=
"special"><</span><span class=
"identifier">yield_handler
</span><span class=
"special"><</span><span class=
"keyword">void
</span><span class=
"special">>></span></code>.
255 It passes the
<code class=
"computeroutput"><span class=
"identifier">yield_handler
</span><span class=
"special"><</span><span class=
"keyword">void
</span><span class=
"special">></span></code>
256 instance to the new
<code class=
"computeroutput"><span class=
"identifier">async_result
</span></code>
261 <pre class=
"programlisting"><span class=
"comment">// Without the need to handle a passed value, our yield_handler
<void
></span>
262 <span class=
"comment">// specialization is just like async_result_base.
</span>
263 <span class=
"keyword">template
</span><span class=
"special"><></span>
264 <span class=
"keyword">class
</span> <span class=
"identifier">async_result
</span><span class=
"special"><</span> <span class=
"identifier">boost
</span><span class=
"special">::
</span><span class=
"identifier">fibers
</span><span class=
"special">::
</span><span class=
"identifier">asio
</span><span class=
"special">::
</span><span class=
"identifier">detail
</span><span class=
"special">::
</span><span class=
"identifier">yield_handler
</span><span class=
"special"><</span> <span class=
"keyword">void
</span> <span class=
"special">></span> <span class=
"special">></span> <span class=
"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>
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"><</span> <span class=
"keyword">void
</span> <span class=
"special">></span> <span class=
"special">&</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>
277 Naturally that leads us straight to
<code class=
"computeroutput"><span class=
"identifier">async_result_base
</span></code>:
281 <pre class=
"programlisting"><span class=
"comment">// Factor out commonality between async_result
<yield_handler
<T
>> and
</span>
282 <span class=
"comment">// async_result
<yield_handler
<void
>></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">&</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
<>.
</span>
288 <span class=
"identifier">h
</span><span class=
"special">.
</span><span class=
"identifier">ycomp_
</span> <span class=
"special">=
</span> <span class=
"special">&</span> <span class=
"keyword">this
</span><span class=
"special">-
></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">&</span> <span class=
"identifier">ec_
</span><span class=
"special">;
</span>
295 <span class=
"special">}
</span>
296 <span class=
"special">}
</span>
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>
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
<>, async_result
<> 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>
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>’s
323 constructor injects a pointer back to its own
<code class=
"computeroutput"><span class=
"identifier">yield_completion
</span></code>
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>’s
333 constructor sets
<code class=
"computeroutput"><span class=
"identifier">yield_handler_base
</span></code>’s
334 <code class=
"computeroutput"><span class=
"identifier">yield_t
</span></code>’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>
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"><</span><span class=
"keyword">void
</span><span class=
"special">></span></code>
341 instance on completion. Let
’s say, for the sake of argument, that the actual
342 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>.
345 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>.
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"><</span><span class=
"identifier">yield_handler
</span><span class=
"special"><</span><span class=
"keyword">void
</span><span class=
"special">>>::
</span><span class=
"identifier">get
</span><span class=
"special">()
</span></code>,
348 and will return its return value.
351 <code class=
"computeroutput"><span class=
"identifier">async_result
</span><span class=
"special"><</span><span class=
"identifier">yield_handler
</span><span class=
"special"><</span><span class=
"keyword">void
</span><span class=
"special">>>::
</span><span class=
"identifier">get
</span><span class=
"special">()
</span></code> inherits
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>.
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>.
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"><</span> <span class=
"identifier">mutex_t
</span> <span class=
"special">></span> <span class=
"identifier">lock_t
</span><span class=
"special">;
</span>
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>
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
<spinlock
>) 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">()-
></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>
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.
389 Other fibers will now have a chance to run.
392 Some time later, the async operation completes. It calls
<code class=
"computeroutput"><span class=
"identifier">yield_handler
</span><span class=
"special"><</span><span class=
"keyword">void
</span><span class=
"special">>::
</span><span class=
"keyword">operator
</span><span class=
"special">()(
</span><span class=
"identifier">error_code
</span> <span class=
"keyword">const
</span><span class=
"special">&)
</span></code> with an
<code class=
"computeroutput"><span class=
"identifier">error_code
</span></code>
393 indicating either success or failure. We
’ll consider both cases.
396 <code class=
"computeroutput"><span class=
"identifier">yield_handler
</span><span class=
"special"><</span><span class=
"keyword">void
</span><span class=
"special">></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">&)
</span></code> from
<code class=
"computeroutput"><span class=
"identifier">yield_handler_base
</span></code>.
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">&)
</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>’s
402 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>
403 — the calling fiber will
<span class=
"emphasis"><em>not
</em></span> suspend.
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>’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
’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>.
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.
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>.
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
’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.
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.
441 <li class=
"listitem">
442 Otherwise
— 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
— <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>.
449 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
450 similar.
<code class=
"computeroutput"><span class=
"identifier">yield_handler
</span><span class=
"special"><</span><span class=
"keyword">void
</span><span class=
"special">>::
</span><span class=
"keyword">operator
</span><span class=
"special">()()
</span></code>
451 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>.
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"><>::
</span><span class=
"identifier">type
</span></code>
458 specifies
<code class=
"computeroutput"><span class=
"identifier">yield_handler
</span><span class=
"special"><</span><span class=
"identifier">T
</span><span class=
"special">></span></code> (for
459 <code class=
"computeroutput"><span class=
"identifier">T
</span></code> other than
<code class=
"computeroutput"><span class=
"keyword">void
</span></code>).
462 A
<code class=
"computeroutput"><span class=
"identifier">yield_handler
</span><span class=
"special"><</span><span class=
"identifier">T
</span><span class=
"special">></span></code> reserves
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>:
468 <pre class=
"programlisting"><span class=
"comment">// asio uses handler_type
<completion token type, signature
>::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
< yield_t, ...
> to indicate yield_handler
<>. 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
<> as the actual handler class.
</span>
473 <span class=
"keyword">template
</span><span class=
"special"><</span> <span class=
"keyword">typename
</span> <span class=
"identifier">T
</span> <span class=
"special">></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">&</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>
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>
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">&</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<T>::operator()()"</span><span class=
"special">);
</span>
492 <span class=
"comment">// move the value to async_result
<> 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>
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>
508 This pointer is initialized to
<code class=
"computeroutput"><span class=
"keyword">nullptr
</span></code>.
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"><</span><span class=
"identifier">yield_handler
</span><span class=
"special"><</span><span class=
"identifier">T
</span><span class=
"special">>></span></code>:
516 <pre class=
"programlisting"><span class=
"comment">// asio constructs an async_result
<> instance from the yield_handler specified
</span>
517 <span class=
"comment">// by handler_type
<>::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"><</span> <span class=
"keyword">typename
</span> <span class=
"identifier">T
</span> <span class=
"special">></span>
521 <span class=
"keyword">class
</span> <span class=
"identifier">async_result
</span><span class=
"special"><</span> <span class=
"identifier">boost
</span><span class=
"special">::
</span><span class=
"identifier">fibers
</span><span class=
"special">::
</span><span class=
"identifier">asio
</span><span class=
"special">::
</span><span class=
"identifier">detail
</span><span class=
"special">::
</span><span class=
"identifier">yield_handler
</span><span class=
"special"><</span> <span class=
"identifier">T
</span> <span class=
"special">></span> <span class=
"special">></span> <span class=
"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>
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"><</span> <span class=
"identifier">T
</span> <span class=
"special">></span> <span class=
"special">&</span> <span class=
"identifier">h
</span><span class=
"special">)
</span> <span class=
"special">:
</span>
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
<>: 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">&</span> <span class=
"identifier">value_
</span><span class=
"special">;
</span>
532 <span class=
"special">}
</span>
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>
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>
547 this
<code class=
"computeroutput"><span class=
"identifier">async_result
</span><span class=
"special"><></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"><</span><span class=
"identifier">T
</span><span class=
"special">>::
</span><span class=
"identifier">value_
</span></code> to point to its own data member.
552 <code class=
"computeroutput"><span class=
"identifier">async_result
</span><span class=
"special"><</span><span class=
"identifier">yield_handler
</span><span class=
"special"><</span><span class=
"identifier">T
</span><span class=
"special">>></span></code>
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.
558 <code class=
"computeroutput"><span class=
"identifier">yield_handler
</span><span class=
"special"><</span><span class=
"identifier">T
</span><span class=
"special">>::
</span><span class=
"keyword">operator
</span><span class=
"special">()(
</span><span class=
"identifier">error_code
</span><span class=
"special">,
</span> <span class=
"identifier">T
</span><span class=
"special">)
</span></code> stores
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"><</span><span class=
"identifier">yield_handler
</span><span class=
"special"><</span><span class=
"identifier">T
</span><span class=
"special">>>::
</span><span class=
"identifier">value_
</span></code>.
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
567 When
<code class=
"computeroutput"><span class=
"identifier">async_result
</span><span class=
"special"><</span><span class=
"identifier">yield_handler
</span><span class=
"special"><</span><span class=
"identifier">T
</span><span class=
"special">>>::
</span><span class=
"identifier">get
</span><span class=
"special">()
</span></code> resumes,
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>’s caller.
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"><</span><span class=
"identifier">T
</span><span class=
"special">>::
</span><span class=
"keyword">operator
</span><span class=
"special">()(
</span><span class=
"identifier">T
</span><span class=
"special">)
</span></code> engage
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">“<span class=
"quote">success
</span>”</span> <code class=
"computeroutput"><span class=
"identifier">error_code
</span></code>.
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>.
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>.
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>
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
© 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>)
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>