mirror of
https://github.com/boostorg/asio.git
synced 2026-01-27 18:42:07 +00:00
Merge asio from 'develop'.
This commit is contained in:
@@ -398,10 +398,15 @@ Boost.Asio's asynchronous operations.
|
||||
|
||||
[heading Handler Tracking]
|
||||
|
||||
This example shows how to implement custom handler tracking.
|
||||
This example header file shows how to implement custom handler tracking.
|
||||
|
||||
* [@boost_asio/example/cpp11/handler_tracking/custom_tracking.hpp]
|
||||
|
||||
This example program shows how to include source location information in
|
||||
the handler tracking output.
|
||||
|
||||
* [@boost_asio/example/cpp11/handler_tracking/async_tcp_echo_server.cpp]
|
||||
|
||||
|
||||
[heading HTTP Server]
|
||||
|
||||
|
||||
@@ -44,14 +44,14 @@ below shows the new Networking TS interfaces and the facilities they replace:
|
||||
ExecutionContext].]
|
||||
]
|
||||
[
|
||||
[[link boost_asio.reference.dispatch `post`]]
|
||||
[[link boost_asio.reference.post `post`]]
|
||||
[[link boost_asio.reference.io_context.post `io_service::post`]]
|
||||
[The `dispatch` free function can be used to submit functions to any [link
|
||||
[The `post` free function can be used to submit functions to any [link
|
||||
boost_asio.reference.Executor1 Executor] or [link boost_asio.reference.ExecutionContext
|
||||
ExecutionContext].]
|
||||
]
|
||||
[
|
||||
[[link boost_asio.reference.dispatch `defer`]]
|
||||
[[link boost_asio.reference.defer `defer`]]
|
||||
[[link boost_asio.reference.io_context.post `io_service::post`] when the [link
|
||||
boost_asio.reference.asio_handler_is_continuation `asio_handler_is_continuation`]
|
||||
hook returns true]
|
||||
|
||||
@@ -14,12 +14,7 @@ boost_asio.reference.co_spawn `co_spawn()`] function. These facilities allow pro
|
||||
to implement asynchronous logic in a synchronous manner, in conjunction with
|
||||
the `co_await` keyword, as shown in the following example:
|
||||
|
||||
boost::asio::co_spawn(executor,
|
||||
[socket = std::move(socket)]() mutable
|
||||
{
|
||||
return echo(std::move(socket));
|
||||
},
|
||||
boost::asio::detached);
|
||||
boost::asio::co_spawn(executor, echo(std::move(socket)), boost::asio::detached);
|
||||
|
||||
// ...
|
||||
|
||||
@@ -46,10 +41,12 @@ execute. For example, a server's per-client object may consist of multiple
|
||||
coroutines; they should all run on the same `strand` so that no explicit
|
||||
synchronisation is required.
|
||||
|
||||
The second argument is a nullary function object that returns a [link
|
||||
boost_asio.reference.awaitable `boost::asio::awaitable<R>`],
|
||||
where `R` is the type of return value produced by the coroutine. In the above
|
||||
example, the coroutine returns `void`.
|
||||
The second argument is an [link boost_asio.reference.awaitable `awaitable<R>`],
|
||||
that is the result of the coroutine's entry point function, and in the above
|
||||
example is the result of the call to `echo`. (Alternatively, this argument can
|
||||
be a function object that returns the [link boost_asio.reference.awaitable
|
||||
`awaitable<R>`].) The template parameter `R` is the type of return value
|
||||
produced by the coroutine. In the above example, the coroutine returns `void`.
|
||||
|
||||
The third argument is a completion token, and this is used by `co_spawn()` to
|
||||
produce a completion handler with signature `void(std::exception_ptr, R)`. This
|
||||
|
||||
@@ -18,30 +18,31 @@ asynchronous operations are chained together, or what the pending asynchronous
|
||||
operations are. As an illustration, here is the output when you run the HTTP
|
||||
Server example, handle a single request, then shut down via Ctrl+C:
|
||||
|
||||
@asio|1512254357.979980|0*1|signal_set@0x7ffeaaaa20d8.async_wait
|
||||
@asio|1512254357.980127|0*2|socket@0x7ffeaaaa20f8.async_accept
|
||||
@asio|1512254357.980150|.2|non_blocking_accept,ec=asio.system:11
|
||||
@asio|1512254357.980162|0|resolver@0x7ffeaaaa1fd8.cancel
|
||||
@asio|1512254368.457147|.2|non_blocking_accept,ec=system:0
|
||||
@asio|1512254368.457193|>2|ec=system:0
|
||||
@asio|1512254368.457219|2*3|socket@0x55cf39f0a238.async_receive
|
||||
@asio|1512254368.457244|.3|non_blocking_recv,ec=system:0,bytes_transferred=141
|
||||
@asio|1512254368.457275|2*4|socket@0x7ffeaaaa20f8.async_accept
|
||||
@asio|1512254368.457293|.4|non_blocking_accept,ec=asio.system:11
|
||||
@asio|1512254368.457301|<2|
|
||||
@asio|1512254368.457310|>3|ec=system:0,bytes_transferred=141
|
||||
@asio|1512254368.457441|3*5|socket@0x55cf39f0a238.async_send
|
||||
@asio|1512254368.457502|.5|non_blocking_send,ec=system:0,bytes_transferred=156
|
||||
@asio|1512254368.457511|<3|
|
||||
@asio|1512254368.457519|>5|ec=system:0,bytes_transferred=156
|
||||
@asio|1512254368.457544|5|socket@0x55cf39f0a238.close
|
||||
@asio|1512254368.457559|<5|
|
||||
@asio|1512254371.385106|>1|ec=system:0,signal_number=2
|
||||
@asio|1512254371.385130|1|socket@0x7ffeaaaa20f8.close
|
||||
@asio|1512254371.385163|<1|
|
||||
@asio|1512254371.385175|>4|ec=asio.system:125
|
||||
@asio|1512254371.385182|<4|
|
||||
@asio|1512254371.385202|0|signal_set@0x7ffeaaaa20d8.cancel
|
||||
@asio|1589424178.741850|0*1|signal_set@0x7ffee977d878.async_wait
|
||||
@asio|1589424178.742593|0*2|socket@0x7ffee977d8a8.async_accept
|
||||
@asio|1589424178.742619|.2|non_blocking_accept,ec=asio.system:11
|
||||
@asio|1589424178.742625|0|resolver@0x7ffee977d760.cancel
|
||||
@asio|1589424195.830382|.2|non_blocking_accept,ec=system:0
|
||||
@asio|1589424195.830413|>2|ec=system:0
|
||||
@asio|1589424195.830473|2*3|socket@0x7fa71d808230.async_receive
|
||||
@asio|1589424195.830496|.3|non_blocking_recv,ec=system:0,bytes_transferred=151
|
||||
@asio|1589424195.830503|2*4|socket@0x7ffee977d8a8.async_accept
|
||||
@asio|1589424195.830507|.4|non_blocking_accept,ec=asio.system:11
|
||||
@asio|1589424195.830510|<2|
|
||||
@asio|1589424195.830529|>3|ec=system:0,bytes_transferred=151
|
||||
@asio|1589424195.831143|3^5|in 'async_write' (./../../../boost/asio/impl/write.hpp:330)
|
||||
@asio|1589424195.831143|3*5|socket@0x7fa71d808230.async_send
|
||||
@asio|1589424195.831186|.5|non_blocking_send,ec=system:0,bytes_transferred=1090
|
||||
@asio|1589424195.831194|<3|
|
||||
@asio|1589424195.831218|>5|ec=system:0,bytes_transferred=1090
|
||||
@asio|1589424195.831263|5|socket@0x7fa71d808230.close
|
||||
@asio|1589424195.831298|<5|
|
||||
@asio|1589424199.793770|>1|ec=system:0,signal_number=2
|
||||
@asio|1589424199.793781|1|socket@0x7ffee977d8a8.close
|
||||
@asio|1589424199.793809|<1|
|
||||
@asio|1589424199.793840|>4|ec=asio.system:125
|
||||
@asio|1589424199.793854|<4|
|
||||
@asio|1589424199.793883|0|signal_set@0x7ffee977d878.cancel
|
||||
|
||||
Each line is of the form:
|
||||
|
||||
@@ -74,6 +75,13 @@ The `<action>` takes one of the following forms:
|
||||
usually the case for any unfinished asynchronous operations when the
|
||||
`io_context` is destroyed.]
|
||||
]
|
||||
[
|
||||
[n^m]
|
||||
[The handler number `n` is about to create a new asynchronous operation with
|
||||
completion handler number `m`. The `<description>` contains source location
|
||||
information to help identify where in the program the asynchronous operation
|
||||
is being started.]
|
||||
]
|
||||
[
|
||||
[n*m]
|
||||
[The handler number `n` created a new asynchronous operation with completion
|
||||
@@ -105,6 +113,53 @@ As shown above, Each handler is assigned a numeric identifier. Where the
|
||||
handler tracking output shows a handler number of 0, it means that the action
|
||||
was performed outside of any handler.
|
||||
|
||||
[heading Adding Location Information]
|
||||
|
||||
[c++]
|
||||
Programs may augment the handler tracking output's location information by
|
||||
using the macro `BOOST_ASIO_HANDLER_LOCATION` in the source code. For example:
|
||||
|
||||
#define HANDLER_LOCATION \
|
||||
BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, __func__))
|
||||
|
||||
// ...
|
||||
|
||||
void do_read()
|
||||
{
|
||||
HANDLER_LOCATION;
|
||||
|
||||
auto self(shared_from_this());
|
||||
socket_.async_read_some(boost::asio::buffer(data_, max_length),
|
||||
[this, self](boost::system::error_code ec, std::size_t length)
|
||||
{
|
||||
HANDLER_LOCATION;
|
||||
|
||||
if (!ec)
|
||||
{
|
||||
do_write(length);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[teletype]
|
||||
With the additional location information available, the handler tracking output
|
||||
may include a call stack of source locations:
|
||||
|
||||
@asio|1589423304.861944|>7|ec=system:0,bytes_transferred=5
|
||||
@asio|1589423304.861952|7^8|in 'async_write' (./../../../boost/asio/impl/write.hpp:330)
|
||||
@asio|1589423304.861952|7^8|called from 'do_write' (handler_tracking/async_tcp_echo_server.cpp:62)
|
||||
@asio|1589423304.861952|7^8|called from 'operator()' (handler_tracking/async_tcp_echo_server.cpp:51)
|
||||
@asio|1589423304.861952|7*8|socket@0x7ff61c008230.async_send
|
||||
@asio|1589423304.861975|.8|non_blocking_send,ec=system:0,bytes_transferred=5
|
||||
@asio|1589423304.861980|<7|
|
||||
|
||||
Furthermore, if `std::source_location` or `std::experimental::source_location`
|
||||
are available, the [link boost_asio.reference.use_awaitable_t `use_awaitable_t`]
|
||||
token (when default-constructed or used as a default completion token) will
|
||||
also cause handler tracking to output a source location for each newly created
|
||||
asynchronous operation. A `use_awaitable_t` object may also be explicitly
|
||||
constructed with location information.
|
||||
|
||||
[heading Visual Representations]
|
||||
|
||||
The handler tracking output may be post-processed using the included
|
||||
@@ -137,6 +192,12 @@ preprocessor macros:
|
||||
[`BOOST_ASIO_HANDLER_TRACKING_INIT(args)`]
|
||||
[An expression that is used to initialise the tracking mechanism.]
|
||||
]
|
||||
[
|
||||
[`BOOST_ASIO_HANDLER_LOCATION(args)`]
|
||||
[A variable declaration that is used to define a source code location.
|
||||
`args` is a parenthesised function argument list containing the file
|
||||
name, line number, and function name.]
|
||||
]
|
||||
[
|
||||
[`BOOST_ASIO_HANDLER_CREATION(args)`]
|
||||
[An expression that is called on creation of an asynchronous operation.
|
||||
@@ -214,7 +275,7 @@ preprocessor macros:
|
||||
|
||||
[heading See Also]
|
||||
|
||||
[link boost_asio.examples.cpp11_examples.handler_tracking Custom handler tracking
|
||||
example].
|
||||
[link boost_asio.examples.cpp11_examples.handler_tracking Handler tracking
|
||||
examples].
|
||||
|
||||
[endsect]
|
||||
|
||||
145
doc/quickref.xml
145
doc/quickref.xml
@@ -9,6 +9,135 @@
|
||||
-->
|
||||
|
||||
<informaltable frame="all">
|
||||
<tgroup cols="4">
|
||||
<colspec colname="a"/>
|
||||
<colspec colname="b"/>
|
||||
<colspec colname="c"/>
|
||||
<colspec colname="d"/>
|
||||
<thead>
|
||||
<row>
|
||||
<entry valign="center" namest="a" nameend="a">
|
||||
<bridgehead renderas="sect2">Properties</bridgehead>
|
||||
</entry>
|
||||
<entry valign="center" namest="b" nameend="d">
|
||||
<bridgehead renderas="sect2">Execution</bridgehead>
|
||||
</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3">Customisation Points</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="boost_asio.reference.prefer">prefer</link></member>
|
||||
<member><link linkend="boost_asio.reference.query">query</link></member>
|
||||
<member><link linkend="boost_asio.reference.require">require</link></member>
|
||||
<member><link linkend="boost_asio.reference.require_concept">require_concept</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Traits</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="boost_asio.reference.can_prefer">can_prefer</link></member>
|
||||
<member><link linkend="boost_asio.reference.can_query">can_query</link></member>
|
||||
<member><link linkend="boost_asio.reference.can_require">can_require</link></member>
|
||||
<member><link linkend="boost_asio.reference.can_require_concept">can_require_concept</link></member>
|
||||
<member><link linkend="boost_asio.reference.is_nothrow_prefer">is_nothrow_prefer</link></member>
|
||||
<member><link linkend="boost_asio.reference.is_nothrow_query">is_nothrow_query</link></member>
|
||||
<member><link linkend="boost_asio.reference.is_nothrow_require">is_nothrow_require</link></member>
|
||||
<member><link linkend="boost_asio.reference.is_nothrow_require_concept">is_nothrow_require_concept</link></member>
|
||||
<member><link linkend="boost_asio.reference.prefer_result_type">prefer_result_type</link></member>
|
||||
<member><link linkend="boost_asio.reference.query_result_type">query_result_type</link></member>
|
||||
<member><link linkend="boost_asio.reference.require_result_type">require_result_type</link></member>
|
||||
<member><link linkend="boost_asio.reference.require_concept_result_type">require_concept_result_type</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3">Concepts</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="boost_asio.reference.Executor1">Executor</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Customisation Points</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="boost_asio.reference.execution__execute">execution::execute</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Class Templates</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="boost_asio.reference.execution__any_executor">execution::any_executor</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Classes</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="boost_asio.reference.execution__bad_executor">execution::bad_executor</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__invocable_archetype">execution::invocable_archetype</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Traits</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="boost_asio.reference.execution__is_executor">execution::is_executor</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__can_execute">execution::can_execute</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3">Properties</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="boost_asio.reference.execution__allocator_t">execution::allocator_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__blocking_t">execution::blocking_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__blocking_t__possibly_t">execution::blocking_t::possibly_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__blocking_t__always_t">execution::blocking_t::always_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__blocking_t__never_t">execution::blocking_t::never_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__blocking_adaptation_t">execution::blocking_adaptation_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__blocking_adaptation_t__disallowed_t">execution::blocking_adaptation_t::disallowed_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__blocking_adaptation_t__allowed_t">execution::blocking_adaptation_t::allowed_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__bulk_guarantee_t">execution::bulk_guarantee_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__bulk_guarantee_t__unsequenced_t">execution::bulk_guarantee_t::unsequenced_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__bulk_guarantee_t__sequenced_t">execution::bulk_guarantee_t::sequenced_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__bulk_guarantee_t__parallel_t">execution::bulk_guarantee_t::parallel_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__context_t">execution::context_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__context_as_t">execution::context_as_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__mapping_t">execution::mapping_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__mapping_t__thread_t">execution::mapping_t::thread_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__mapping_t__new_thread_t">execution::mapping_t::new_thread_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__mapping_t__other_t">execution::mapping_t::other_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__occupancy_t">execution::occupancy_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__outstanding_work_t">execution::outstanding_work_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__outstanding_work_t__untracked_t">execution::outstanding_work_t::untracked_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__outstanding_work_t__tracked_t">execution::outstanding_work_t::tracked_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__prefer_only">execution::prefer_only</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__relationship_t">execution::relationship_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__relationship_t__fork_t">execution::relationship_t::fork_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__relationship_t__continuation_t">execution::relationship_t::continuation_t</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3">Property Objects</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="boost_asio.reference.execution__allocator">execution::allocator</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__blocking">execution::blocking</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__blocking_t.possibly">execution::blocking.possibly</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__blocking_t.always">execution::blocking.always</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__blocking_t.never">execution::blocking.never</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__blocking_adaptation">execution::blocking_adaptation</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__blocking_adaptation_t.disallowed">execution::blocking_adaptation.disallowed</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__blocking_adaptation_t.allowed">execution::blocking_adaptation.allowed</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__bulk_guarantee">execution::bulk_guarantee</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__bulk_guarantee_t.unsequenced">execution::bulk_guarantee.unsequenced</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__bulk_guarantee_t.sequenced">execution::bulk_guarantee.sequenced</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__bulk_guarantee_t.parallel">execution::bulk_guarantee.parallel</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__context">execution::context</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__context_as">execution::context_as</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__mapping">execution::mapping</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__mapping_t.thread">execution::mapping.thread</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__mapping_t.new_thread">execution::mapping.new_thread</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__mapping_t.other">execution::mapping.other</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__occupancy">execution::occupancy</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__outstanding_work">execution::outstanding_work</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__outstanding_work_t.untracked">execution::outstanding_work.untracked</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__outstanding_work_t.tracked">execution::outstanding_work.tracked</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__relationship">execution::relationship</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__relationship_t.fork">execution::relationship.fork</link></member>
|
||||
<member><link linkend="boost_asio.reference.execution__relationship_t.continuation">execution::relationship.continuation</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
<tgroup cols="4">
|
||||
<colspec colname="a"/>
|
||||
<colspec colname="b"/>
|
||||
@@ -26,6 +155,7 @@
|
||||
<entry valign="top">
|
||||
<bridgehead renderas="sect3">Classes</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="boost_asio.reference.any_io_executor">any_io_executor</link></member>
|
||||
<member><link linkend="boost_asio.reference.bad_executor">bad_executor</link></member>
|
||||
<member><link linkend="boost_asio.reference.coroutine">coroutine</link></member>
|
||||
<member><link linkend="boost_asio.reference.detached_t">detached_t</link></member>
|
||||
@@ -36,16 +166,18 @@
|
||||
<member><link linkend="boost_asio.reference.executor_arg_t">executor_arg_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.invalid_service_owner">invalid_service_owner</link></member>
|
||||
<member><link linkend="boost_asio.reference.io_context">io_context</link></member>
|
||||
<member><link linkend="boost_asio.reference.io_context__executor_type">io_context::executor_type</link></member>
|
||||
<member><link linkend="boost_asio.reference.io_context.executor_type">io_context::executor_type</link></member>
|
||||
<member><link linkend="boost_asio.reference.io_context__service">io_context::service</link></member>
|
||||
<member><link linkend="boost_asio.reference.io_context__strand">io_context::strand</link></member>
|
||||
<member><link linkend="boost_asio.reference.io_context__work">io_context::work</link> (deprecated)</member>
|
||||
<member><link linkend="boost_asio.reference.multiple_exceptions">multiple_exceptions</link></member>
|
||||
<member><link linkend="boost_asio.reference.service_already_exists">service_already_exists</link></member>
|
||||
<member><link linkend="boost_asio.reference.static_thread_pool">static_thread_pool</link></member>
|
||||
<member><link linkend="boost_asio.reference.system_context">system_context</link></member>
|
||||
<member><link linkend="boost_asio.reference.system_executor">system_executor</link></member>
|
||||
<member><link linkend="boost_asio.reference.this_coro__executor_t">this_coro::executor_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.thread_pool">thread_pool</link></member>
|
||||
<member><link linkend="boost_asio.reference.thread_pool__executor_type">thread_pool::executor_type</link></member>
|
||||
<member><link linkend="boost_asio.reference.thread_pool.executor_type">thread_pool::executor_type</link></member>
|
||||
<member><link linkend="boost_asio.reference.yield_context">yield_context</link></member>
|
||||
</simplelist>
|
||||
</entry>
|
||||
@@ -53,9 +185,9 @@
|
||||
<bridgehead renderas="sect3">Free Functions</bridgehead>
|
||||
<simplelist type="vert" columns="1">
|
||||
<member><link linkend="boost_asio.reference.execution_context.add_service">add_service</link></member>
|
||||
<member><link linkend="boost_asio.reference.asio_handler_allocate">asio_handler_allocate</link></member>
|
||||
<member><link linkend="boost_asio.reference.asio_handler_deallocate">asio_handler_deallocate</link></member>
|
||||
<member><link linkend="boost_asio.reference.asio_handler_invoke">asio_handler_invoke</link></member>
|
||||
<member><link linkend="boost_asio.reference.asio_handler_allocate">asio_handler_allocate</link> (deprecated)</member>
|
||||
<member><link linkend="boost_asio.reference.asio_handler_deallocate">asio_handler_deallocate</link> (deprecated)</member>
|
||||
<member><link linkend="boost_asio.reference.asio_handler_invoke">asio_handler_invoke</link> (deprecated)</member>
|
||||
<member><link linkend="boost_asio.reference.asio_handler_is_continuation">asio_handler_is_continuation</link></member>
|
||||
<member><link linkend="boost_asio.reference.async_compose">async_compose</link></member>
|
||||
<member><link linkend="boost_asio.reference.async_initiate">async_initiate</link></member>
|
||||
@@ -80,11 +212,14 @@
|
||||
<member><link linkend="boost_asio.reference.async_completion">async_completion</link></member>
|
||||
<member><link linkend="boost_asio.reference.awaitable">awaitable</link></member>
|
||||
<member><link linkend="boost_asio.reference.basic_io_object">basic_io_object</link></member>
|
||||
<member><link linkend="boost_asio.reference.basic_system_executor">basic_system_executor</link></member>
|
||||
<member><link linkend="boost_asio.reference.basic_yield_context">basic_yield_context</link></member>
|
||||
<member><link linkend="boost_asio.reference.executor_binder">executor_binder</link></member>
|
||||
<member><link linkend="boost_asio.reference.executor_work_guard">executor_work_guard</link></member>
|
||||
<member><link linkend="boost_asio.reference.io_context__basic_executor_type">io_context::basic_executor_type</link></member>
|
||||
<member><link linkend="boost_asio.reference.redirect_error_t">redirect_error_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.strand">strand</link></member>
|
||||
<member><link linkend="boost_asio.reference.thread_pool__basic_executor_type">thread_pool::basic_executor_type</link></member>
|
||||
<member><link linkend="boost_asio.reference.use_awaitable_t">use_awaitable_t</link></member>
|
||||
<member><link linkend="boost_asio.reference.use_future_t">use_future_t</link></member>
|
||||
</simplelist>
|
||||
|
||||
@@ -81,6 +81,7 @@ INPUT = ./../../../boost/asio.hpp \
|
||||
./../../../boost/asio/posix \
|
||||
./../../../boost/asio/ssl \
|
||||
./../../../boost/asio/windows \
|
||||
./../../../boost/asio/execution \
|
||||
./noncopyable_dox.txt \
|
||||
./std_exception_dox.txt
|
||||
FILE_PATTERNS =
|
||||
@@ -221,7 +222,8 @@ PREDEFINED = GENERATING_DOCUMENTATION \
|
||||
BOOST_ASIO_MUTABLE_BUFFER=mutable_buffer \
|
||||
BOOST_ASIO_SYNC_OP_VOID=void \
|
||||
BOOST_ASIO_STRING_VIEW_PARAM=string_view \
|
||||
BOOST_ASIO_UNUSED_VARIABLE=
|
||||
BOOST_ASIO_UNUSED_VARIABLE= \
|
||||
BOOST_ASIO_UNSPECIFIED(e)=unspecified
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
11198
doc/reference.qbk
11198
doc/reference.qbk
File diff suppressed because it is too large
Load Diff
@@ -110,7 +110,8 @@
|
||||
not(contains(compoundname, 'std_allocator_void')) and
|
||||
not(contains(compoundname, 'thread_function')) and
|
||||
not(contains(compoundname, 'context_impl')) and
|
||||
not(contains(compoundname, 'initiate_'))">
|
||||
not(contains(compoundname, 'initiate_')) and
|
||||
not(contains(compoundname, '_is_deprecated'))">
|
||||
<xsl:call-template name="class"/>
|
||||
</xsl:if>
|
||||
</xsl:when>
|
||||
@@ -124,7 +125,8 @@
|
||||
not(contains(name, 'std_allocator_void')) and
|
||||
not(contains(name, 'thread_function')) and
|
||||
not(contains(name, 'io_context_impl')) and
|
||||
not(contains(name, 'initiate_'))">
|
||||
not(contains(name, 'initiate_')) and
|
||||
not(contains(name, '_is_deprecated'))">
|
||||
<xsl:call-template name="namespace-memberdef"/>
|
||||
</xsl:if>
|
||||
</xsl:otherwise>
|
||||
@@ -133,6 +135,7 @@
|
||||
|
||||
<xsl:value-of select="$newline"/>
|
||||
<xsl:text>[endsect]</xsl:text>
|
||||
<xsl:value-of select="$newline"/>
|
||||
|
||||
</xsl:template>
|
||||
|
||||
@@ -214,7 +217,11 @@
|
||||
|
||||
<xsl:template name="make-id">
|
||||
<xsl:param name="name"/>
|
||||
<xsl:param name="static"/>
|
||||
<xsl:choose>
|
||||
<xsl:when test="$name='query' and $static='yes'">
|
||||
<xsl:text>query__static</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="contains($name, 'boost::system::')">
|
||||
<xsl:call-template name="make-id">
|
||||
<xsl:with-param name="name"
|
||||
@@ -263,6 +270,12 @@
|
||||
select="concat(substring-before($name, '>'), '_gt_', substring-after($name, '>'))"/>
|
||||
</xsl:call-template>
|
||||
</xsl:when>
|
||||
<xsl:when test="contains($name, '&')">
|
||||
<xsl:call-template name="make-id">
|
||||
<xsl:with-param name="name"
|
||||
select="concat(substring-before($name, '&'), '_amp_', substring-after($name, '&'))"/>
|
||||
</xsl:call-template>
|
||||
</xsl:when>
|
||||
<xsl:when test="contains($name, '[')">
|
||||
<xsl:call-template name="make-id">
|
||||
<xsl:with-param name="name"
|
||||
@@ -774,6 +787,9 @@
|
||||
<xsl:value-of select="$newline"/>
|
||||
<xsl:text>['Convenience header: ]</xsl:text>
|
||||
<xsl:choose>
|
||||
<xsl:when test="contains($file, 'boost/asio/execution')">
|
||||
<xsl:text>[^boost/asio/execution.hpp]</xsl:text>
|
||||
</xsl:when>
|
||||
<xsl:when test="contains($file, 'boost/asio/ssl')">
|
||||
<xsl:text>[^boost/asio/ssl.hpp]</xsl:text>
|
||||
</xsl:when>
|
||||
@@ -909,6 +925,7 @@
|
||||
<xsl:variable name="id">
|
||||
<xsl:call-template name="make-id">
|
||||
<xsl:with-param name="name" select="$name"/>
|
||||
<xsl:with-param name="static" select="@static"/>
|
||||
</xsl:call-template>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="doxygen-id">
|
||||
@@ -958,6 +975,7 @@
|
||||
<xsl:variable name="id">
|
||||
<xsl:call-template name="make-id">
|
||||
<xsl:with-param name="name" select="$name"/>
|
||||
<xsl:with-param name="static" select="@static"/>
|
||||
</xsl:call-template>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="doxygen-id">
|
||||
@@ -1008,6 +1026,7 @@
|
||||
<xsl:variable name="id">
|
||||
<xsl:call-template name="make-id">
|
||||
<xsl:with-param name="name" select="$name"/>
|
||||
<xsl:with-param name="static" select="@static"/>
|
||||
</xsl:call-template>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="doxygen-id">
|
||||
@@ -1219,6 +1238,7 @@
|
||||
<xsl:variable name="id">
|
||||
<xsl:call-template name="make-id">
|
||||
<xsl:with-param name="name" select="$name"/>
|
||||
<xsl:with-param name="static" select="@static"/>
|
||||
</xsl:call-template>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="doxygen-id">
|
||||
@@ -1362,7 +1382,7 @@
|
||||
</xsl:text>typedef <xsl:value-of select="type"/><xsl:text> </xsl:text><xsl:value-of select="name"/>;<xsl:text>
|
||||
|
||||
</xsl:text>
|
||||
<xsl:if test="count(type/ref) > 0 and not(contains(type, '*'))">
|
||||
<xsl:if test="count(type/ref) > 0 and not(contains(type, '*')) and not(contains(name, 'polymorphic_query_result_type'))">
|
||||
<xsl:variable name="class-refid">
|
||||
<xsl:choose>
|
||||
<xsl:when test="type='basic_address_iterator< address_v4 >'">
|
||||
@@ -1407,6 +1427,14 @@
|
||||
|
||||
|
||||
<xsl:template name="variable">
|
||||
<xsl:if test="contains(name, 'is_applicable_property_v')">
|
||||
<xsl:text>
|
||||
template <typename T></xsl:text>
|
||||
</xsl:if>
|
||||
<xsl:if test="contains(name, 'context_as')">
|
||||
<xsl:text>
|
||||
template <typename U></xsl:text>
|
||||
</xsl:if>
|
||||
<xsl:text>
|
||||
</xsl:text><xsl:if test="@static='yes'">static </xsl:if><xsl:value-of
|
||||
select="type"/><xsl:text> </xsl:text><xsl:value-of select="name"/>
|
||||
@@ -1492,6 +1520,15 @@
|
||||
<xsl:when test="declname = 'Args'">
|
||||
<xsl:value-of select="declname"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'AwaitableExecutor'">
|
||||
<xsl:value-of select="concat('``[link boost_asio.reference.Executor1 ', declname, ']``')"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'Bits'">
|
||||
<xsl:value-of select="declname"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'Blocking'">
|
||||
<xsl:value-of select="declname"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'BufferSequence'">
|
||||
<xsl:value-of select="declname"/>
|
||||
</xsl:when>
|
||||
@@ -1579,6 +1616,12 @@
|
||||
<xsl:when test="declname = 'OtherHandler'">
|
||||
<xsl:value-of select="declname"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'OtherSupportableProperties'">
|
||||
<xsl:value-of select="declname"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'OutstandingWork'">
|
||||
<xsl:value-of select="declname"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'PasswordCallback'">
|
||||
<xsl:value-of select="declname"/>
|
||||
</xsl:when>
|
||||
@@ -1591,6 +1634,12 @@
|
||||
<xsl:when test="declname = 'PointerToPodType'">
|
||||
<xsl:value-of select="declname"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'Properties'">
|
||||
<xsl:value-of select="declname"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'Property'">
|
||||
<xsl:value-of select="declname"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'Protocol1'">
|
||||
<xsl:value-of select="concat('``[link boost_asio.reference.Protocol ', declname, ']``')"/>
|
||||
</xsl:when>
|
||||
@@ -1600,6 +1649,9 @@
|
||||
<xsl:when test="declname = 'RawSocketService1'">
|
||||
<xsl:value-of select="concat('``[link boost_asio.reference.RawSocketService ', declname, ']``')"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'Relationship'">
|
||||
<xsl:value-of select="declname"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'Rep'">
|
||||
<xsl:value-of select="declname"/>
|
||||
</xsl:when>
|
||||
@@ -1624,6 +1676,9 @@
|
||||
<xsl:when test="declname = 'StreamSocketService1'">
|
||||
<xsl:value-of select="concat('``[link boost_asio.reference.StreamSocketService ', declname, ']``')"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'SupportableProperties'">
|
||||
<xsl:value-of select="declname"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="declname = 'T'">
|
||||
<xsl:value-of select="declname"/>
|
||||
</xsl:when>
|
||||
|
||||
@@ -7,6 +7,78 @@
|
||||
|
||||
[section:Executor1 Executor requirements]
|
||||
|
||||
[heading Standard executors]
|
||||
|
||||
An executor is defined by the following concept:
|
||||
|
||||
template<class E>
|
||||
concept executor =
|
||||
invocable<remove_cvref_t<F>&>
|
||||
&& constructible_from<remove_cvref_t<F>, F>
|
||||
&& move_constructible<remove_cvref_t<F>>
|
||||
&& copy_constructible<E>
|
||||
&& is_nothrow_copy_constructible_v<E>
|
||||
&& equality_comparable<E>
|
||||
&&
|
||||
requires(const E& e, invocable_archetype f)
|
||||
{
|
||||
execution::execute(e, static_cast<invocable_archetype&&>(f));
|
||||
};
|
||||
|
||||
Neither an executor's equality comparison nor `swap` operation shall exit via
|
||||
an exception.
|
||||
|
||||
None of an executor type's copy constructor, destructor, equality comparison,
|
||||
`swap` function, `execute` function, or associated `query` functions shall
|
||||
introduce data races as a result of concurrent invocations of those functions
|
||||
from different threads.
|
||||
|
||||
For any two (possibly const) values `x1` and `x2` of some executor type `X`,
|
||||
`x1 == x2` shall return `true` only if `boost::asio::query(x1,p) == boost::asio::query(x2,p)`
|
||||
for every property `p` where both `boost::asio::query(x1,p)` and `boost::asio::query(x2,p)`
|
||||
are well-formed and result in a non-void type that is `equality_comparable`
|
||||
(C++Std [equalitycomparable]). [inline_note The above requirements imply that `x1
|
||||
== x2` returns `true` if `x1` and `x2` can be interchanged with identical
|
||||
effects. An executor may conceptually contain additional properties which are
|
||||
not exposed by a named property type that can be observed via `boost::asio::query`; in
|
||||
this case, it is up to the concrete executor implementation to decide if these
|
||||
properties affect equality. Returning `false` does not necessarily imply that
|
||||
the effects are not identical.]
|
||||
|
||||
An executor type's destructor shall not block pending completion of the
|
||||
submitted function objects. [inline_note The ability to wait for completion of
|
||||
submitted function objects may be provided by the associated execution
|
||||
context.]
|
||||
|
||||
In addition to the above requirements, types `E` and `F` model `executor_of`
|
||||
only if they satisfy the requirements of the Table below.
|
||||
|
||||
Let:
|
||||
|
||||
* `e` denotes a (possibly const) executor object of type `E`,
|
||||
|
||||
* `cf` denotes the function object `DECAY_COPY(std::forward<F>(f))`
|
||||
|
||||
* `f` denotes a function of type `F&&` invocable as `cf()` and where
|
||||
`decay_t<F>` models `move_constructible`.
|
||||
|
||||
The expression `execution::execute(e, f)`:
|
||||
|
||||
* Evaluates `DECAY_COPY(std::forward<F>(f))` on the calling thread to create
|
||||
`cf` that will be invoked at most once by an execution agent.
|
||||
|
||||
* May block pending completion of this invocation. Synchronizes with
|
||||
[intro.multithread] the invocation of `f`.
|
||||
|
||||
* Shall not propagate any exception thrown by the function object or any other
|
||||
function submitted to the executor.
|
||||
|
||||
[inline_note The treatment of exceptions thrown by one-way submitted functions
|
||||
is implementation-defined. The forward progress guarantee of the associated
|
||||
execution agent(s) is implementation-defined.]
|
||||
|
||||
[heading Networking TS-style executors]
|
||||
|
||||
The library describes a standard set of requirements for ['executors]. A type
|
||||
meeting the `Executor` requirements embodies a set of rules for determining how
|
||||
submitted function objects are to be executed.
|
||||
|
||||
@@ -1536,6 +1536,8 @@ We use an [link boost_asio.reference.ip__udp.resolver ip::udp::resolver] object
|
||||
|
||||
The [link boost_asio.reference.ip__basic_resolver.resolve ip::udp::resolver::resolve()] function is guaranteed to return at least one endpoint in the list if it does not fail. This means it is safe to dereference the return value directly.
|
||||
|
||||
Since UDP is datagram-oriented, we will not be using a stream socket. Create an [link boost_asio.reference.ip__udp.socket ip::udp::socket] and initiate contact with the remote endpoint.
|
||||
|
||||
|
||||
|
||||
``''''''`` udp::socket socket(io_context);
|
||||
@@ -1544,26 +1546,32 @@ The [link boost_asio.reference.ip__basic_resolver.resolve ip::udp::resolver::res
|
||||
``''''''`` boost::array<char, 1> send_buf = {{ 0 }};
|
||||
``''''''`` socket.send_to(boost::asio::buffer(send_buf), receiver_endpoint);
|
||||
|
||||
``''''''`` boost::array<char, 128> recv_buf;
|
||||
``''''''`` udp::endpoint sender_endpoint;
|
||||
|
||||
|
||||
|
||||
Since UDP is datagram-oriented, we will not be using a stream socket. Create an [link boost_asio.reference.ip__udp.socket ip::udp::socket] and initiate contact with the remote endpoint.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Now we need to be ready to accept whatever the server sends back to us. The endpoint on our side that receives the server's response will be initialised by [link boost_asio.reference.basic_datagram_socket.receive_from ip::udp::socket::receive_from()].
|
||||
|
||||
|
||||
|
||||
``''''''`` boost::array<char, 128> recv_buf;
|
||||
``''''''`` udp::endpoint sender_endpoint;
|
||||
``''''''`` size_t len = socket.receive_from(
|
||||
``''''''`` boost::asio::buffer(recv_buf), sender_endpoint);
|
||||
|
||||
``''''''`` std::cout.write(recv_buf.data(), len);
|
||||
``''''''`` }
|
||||
|
||||
|
||||
|
||||
Finally, handle any exceptions that may have been thrown.
|
||||
|
||||
|
||||
``''''''`` catch (std::exception& e)
|
||||
``''''''`` {
|
||||
``''''''`` std::cerr << e.what() << std::endl;
|
||||
``''''''`` }
|
||||
|
||||
``''''''`` return 0;
|
||||
``''''''``}
|
||||
|
||||
See the [link boost_asio.tutorial.tutdaytime4.src full source listing]
|
||||
|
||||
@@ -2378,4 +2386,4 @@ Return to [link boost_asio.tutorial.tutdaytime7 Daytime.7 - A combined TCP/UDP a
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
|
||||
<xsl:value-of select="$newline"/>
|
||||
<xsl:text>[endsect]</xsl:text>
|
||||
<xsl:value-of select="$newline"/>
|
||||
|
||||
</xsl:template>
|
||||
|
||||
@@ -121,6 +122,12 @@
|
||||
select="concat(substring-before($name, '>'), '_gt_', substring-after($name, '>'))"/>
|
||||
</xsl:call-template>
|
||||
</xsl:when>
|
||||
<xsl:when test="contains($name, '&')">
|
||||
<xsl:call-template name="make-id">
|
||||
<xsl:with-param name="name"
|
||||
select="concat(substring-before($name, '&'), '_amp_', substring-after($name, '&'))"/>
|
||||
</xsl:call-template>
|
||||
</xsl:when>
|
||||
<xsl:when test="contains($name, '+')">
|
||||
<xsl:call-template name="make-id">
|
||||
<xsl:with-param name="name"
|
||||
|
||||
@@ -29,7 +29,8 @@ io_context_pool::io_context_pool(std::size_t pool_size)
|
||||
{
|
||||
io_context_ptr io_context(new boost::asio::io_context);
|
||||
io_contexts_.push_back(io_context);
|
||||
work_.push_back(boost::asio::make_work_guard(*io_context));
|
||||
work_.push_back(boost::asio::require(io_context->get_executor(),
|
||||
boost::asio::execution::outstanding_work.tracked));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,14 +39,12 @@ public:
|
||||
|
||||
private:
|
||||
typedef boost::shared_ptr<boost::asio::io_context> io_context_ptr;
|
||||
typedef boost::asio::executor_work_guard<
|
||||
boost::asio::io_context::executor_type> io_context_work;
|
||||
|
||||
/// The pool of io_contexts.
|
||||
std::vector<io_context_ptr> io_contexts_;
|
||||
|
||||
/// The work that keeps the io_contexts running.
|
||||
std::list<io_context_work> work_;
|
||||
/// The work-tracking executors that keep the io_contexts running.
|
||||
std::list<boost::asio::any_io_executor> work_;
|
||||
|
||||
/// The next io_context to use for a connection.
|
||||
std::size_t next_io_context_;
|
||||
|
||||
@@ -83,7 +83,7 @@ class connection
|
||||
public:
|
||||
typedef boost::shared_ptr<connection> pointer;
|
||||
|
||||
static pointer create(const boost::asio::executor& ex)
|
||||
static pointer create(const boost::asio::any_io_executor& ex)
|
||||
{
|
||||
return pointer(new connection(ex));
|
||||
}
|
||||
@@ -102,7 +102,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
connection(const boost::asio::executor& ex)
|
||||
connection(const boost::asio::any_io_executor& ex)
|
||||
: socket_(ex),
|
||||
session_impl_(socket_),
|
||||
read_in_progress_(false),
|
||||
|
||||
@@ -52,12 +52,6 @@ public:
|
||||
service_.destroy(impl_);
|
||||
}
|
||||
|
||||
/// Get the io_context associated with the object.
|
||||
boost::asio::io_context& get_io_context()
|
||||
{
|
||||
return service_.get_io_context();
|
||||
}
|
||||
|
||||
/// Set the output file for all logger instances.
|
||||
void use_file(const std::string& file)
|
||||
{
|
||||
|
||||
@@ -30,7 +30,9 @@ void read_handler(const boost::system::error_code& e,
|
||||
}
|
||||
else
|
||||
{
|
||||
services::logger logger(s->get_executor().context(), "read_handler");
|
||||
boost::asio::execution_context& context = boost::asio::query(
|
||||
s->get_executor(), boost::asio::execution::context);
|
||||
services::logger logger(context, "read_handler");
|
||||
|
||||
std::string msg = "Read error: ";
|
||||
msg += e.message();
|
||||
@@ -40,7 +42,9 @@ void read_handler(const boost::system::error_code& e,
|
||||
|
||||
void connect_handler(const boost::system::error_code& e, tcp::socket* s)
|
||||
{
|
||||
services::logger logger(s->get_executor().context(), "connect_handler");
|
||||
boost::asio::execution_context& context = boost::asio::query(
|
||||
s->get_executor(), boost::asio::execution::context);
|
||||
services::logger logger(context, "connect_handler");
|
||||
|
||||
if (!e)
|
||||
{
|
||||
|
||||
@@ -45,7 +45,8 @@ public:
|
||||
logger_service(boost::asio::execution_context& context)
|
||||
: boost::asio::execution_context::service(context),
|
||||
work_io_context_(),
|
||||
work_(boost::asio::make_work_guard(work_io_context_)),
|
||||
work_(boost::asio::require(work_io_context_.get_executor(),
|
||||
boost::asio::execution::outstanding_work.tracked)),
|
||||
work_thread_(new boost::thread(
|
||||
boost::bind(&boost::asio::io_context::run, &work_io_context_)))
|
||||
{
|
||||
@@ -56,7 +57,7 @@ public:
|
||||
{
|
||||
/// Indicate that we have finished with the private io_context. Its
|
||||
/// io_context::run() function will exit once all other work has completed.
|
||||
work_.reset();
|
||||
work_ = boost::asio::any_io_executor();
|
||||
if (work_thread_)
|
||||
work_thread_->join();
|
||||
}
|
||||
@@ -128,11 +129,10 @@ private:
|
||||
/// Private io_context used for performing logging operations.
|
||||
boost::asio::io_context work_io_context_;
|
||||
|
||||
/// Work for the private io_context to perform. If we do not give the
|
||||
/// io_context some work to do then the io_context::run() function will exit
|
||||
/// immediately.
|
||||
boost::asio::executor_work_guard<
|
||||
boost::asio::io_context::executor_type> work_;
|
||||
/// A work-tracking executor giving work for the private io_context to
|
||||
/// perform. If we do not give the io_context some work to do then the
|
||||
/// io_context::run() function will exit immediately.
|
||||
boost::asio::any_io_executor work_;
|
||||
|
||||
/// Thread used for running the work io_context's run loop.
|
||||
boost::scoped_ptr<boost::thread> work_thread_;
|
||||
|
||||
@@ -98,7 +98,8 @@ public:
|
||||
// use this function to run the io_context until the operation is complete.
|
||||
return_type get()
|
||||
{
|
||||
boost::asio::io_context& io_context = socket_.get_executor().context();
|
||||
boost::asio::io_context& io_context = boost::asio::query(
|
||||
socket_.get_executor(), boost::asio::execution::context);
|
||||
|
||||
// Restart the io_context, as it may have been left in the "stopped" state
|
||||
// by a previous operation.
|
||||
|
||||
@@ -277,8 +277,6 @@ The boost::asio::ip::udp::resolver::resolve() function is guaranteed to return a
|
||||
least one endpoint in the list if it does not fail. This means it is safe to
|
||||
dereference the return value directly.
|
||||
|
||||
\until udp::endpoint
|
||||
|
||||
Since UDP is datagram-oriented, we will not be using a stream socket. Create an
|
||||
boost::asio::ip::udp::socket and initiate contact with the remote endpoint.
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
#include <boost/asio/defer.hpp>
|
||||
#include <boost/asio/executor.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/asio/system_executor.hpp>
|
||||
@@ -10,8 +10,8 @@
|
||||
#include <typeinfo>
|
||||
#include <vector>
|
||||
|
||||
using boost::asio::any_io_executor;
|
||||
using boost::asio::defer;
|
||||
using boost::asio::executor;
|
||||
using boost::asio::post;
|
||||
using boost::asio::strand;
|
||||
using boost::asio::system_executor;
|
||||
@@ -106,7 +106,7 @@ public:
|
||||
|
||||
protected:
|
||||
// Construct the actor to use the specified executor for all message handlers.
|
||||
actor(executor e)
|
||||
actor(any_io_executor e)
|
||||
: executor_(std::move(e))
|
||||
{
|
||||
}
|
||||
@@ -124,7 +124,7 @@ protected:
|
||||
template <class Actor, class Message>
|
||||
void deregister_handler(void (Actor::* mf)(Message, actor_address))
|
||||
{
|
||||
const std::type_info& id = typeid(message_handler<Message>);
|
||||
const std::type_info& id = typeid(Message);
|
||||
for (auto iter = handlers_.begin(); iter != handlers_.end(); ++iter)
|
||||
{
|
||||
if ((*iter)->message_id() == id)
|
||||
@@ -171,7 +171,7 @@ private:
|
||||
// All messages associated with a single actor object should be processed
|
||||
// non-concurrently. We use a strand to ensure non-concurrent execution even
|
||||
// if the underlying executor may use multiple threads.
|
||||
strand<executor> executor_;
|
||||
strand<any_io_executor> executor_;
|
||||
|
||||
std::vector<std::shared_ptr<message_handler_base>> handlers_;
|
||||
};
|
||||
@@ -221,7 +221,7 @@ using boost::asio::thread_pool;
|
||||
class member : public actor
|
||||
{
|
||||
public:
|
||||
explicit member(executor e)
|
||||
explicit member(any_io_executor e)
|
||||
: actor(std::move(e))
|
||||
{
|
||||
register_handler(&member::init_handler);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/asio/thread_pool.hpp>
|
||||
#include <boost/asio/execution.hpp>
|
||||
#include <boost/asio/static_thread_pool.hpp>
|
||||
#include <iostream>
|
||||
|
||||
using boost::asio::post;
|
||||
using boost::asio::thread_pool;
|
||||
using boost::asio::static_thread_pool;
|
||||
namespace execution = boost::asio::execution;
|
||||
|
||||
// Traditional active object pattern.
|
||||
// Member functions do not block.
|
||||
@@ -11,37 +11,43 @@ using boost::asio::thread_pool;
|
||||
class bank_account
|
||||
{
|
||||
int balance_ = 0;
|
||||
mutable thread_pool pool_{1};
|
||||
mutable static_thread_pool pool_{1};
|
||||
|
||||
public:
|
||||
void deposit(int amount)
|
||||
{
|
||||
post(pool_, [=]
|
||||
{
|
||||
balance_ += amount;
|
||||
});
|
||||
execution::execute(
|
||||
pool_.executor(),
|
||||
[this, amount]
|
||||
{
|
||||
balance_ += amount;
|
||||
});
|
||||
}
|
||||
|
||||
void withdraw(int amount)
|
||||
{
|
||||
post(pool_, [=]
|
||||
{
|
||||
if (balance_ >= amount)
|
||||
balance_ -= amount;
|
||||
});
|
||||
execution::execute(
|
||||
pool_.executor(),
|
||||
[this, amount]
|
||||
{
|
||||
if (balance_ >= amount)
|
||||
balance_ -= amount;
|
||||
});
|
||||
}
|
||||
|
||||
void print_balance() const
|
||||
{
|
||||
post(pool_, [=]
|
||||
{
|
||||
std::cout << "balance = " << balance_ << "\n";
|
||||
});
|
||||
execution::execute(
|
||||
pool_.executor(),
|
||||
[this]
|
||||
{
|
||||
std::cout << "balance = " << balance_ << "\n";
|
||||
});
|
||||
}
|
||||
|
||||
~bank_account()
|
||||
{
|
||||
pool_.join();
|
||||
pool_.wait();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/asio/thread_pool.hpp>
|
||||
#include <boost/asio/use_future.hpp>
|
||||
#include <boost/asio/execution.hpp>
|
||||
#include <boost/asio/static_thread_pool.hpp>
|
||||
#include <iostream>
|
||||
|
||||
using boost::asio::post;
|
||||
using boost::asio::thread_pool;
|
||||
using boost::asio::use_future;
|
||||
using boost::asio::static_thread_pool;
|
||||
namespace execution = boost::asio::execution;
|
||||
|
||||
// Traditional active object pattern.
|
||||
// Member functions block until operation is finished.
|
||||
@@ -13,35 +11,43 @@ using boost::asio::use_future;
|
||||
class bank_account
|
||||
{
|
||||
int balance_ = 0;
|
||||
mutable thread_pool pool_{1};
|
||||
mutable static_thread_pool pool_{1};
|
||||
|
||||
public:
|
||||
void deposit(int amount)
|
||||
{
|
||||
post(pool_,
|
||||
use_future([=]
|
||||
execution::execute(
|
||||
boost::asio::require(pool_.executor(),
|
||||
execution::blocking.always),
|
||||
[this, amount]
|
||||
{
|
||||
balance_ += amount;
|
||||
})).get();
|
||||
});
|
||||
}
|
||||
|
||||
void withdraw(int amount)
|
||||
{
|
||||
post(pool_,
|
||||
use_future([=]
|
||||
execution::execute(
|
||||
boost::asio::require(pool_.executor(),
|
||||
execution::blocking.always),
|
||||
[this, amount]
|
||||
{
|
||||
if (balance_ >= amount)
|
||||
balance_ -= amount;
|
||||
})).get();
|
||||
});
|
||||
}
|
||||
|
||||
int balance() const
|
||||
{
|
||||
return post(pool_,
|
||||
use_future([=]
|
||||
int result = 0;
|
||||
execution::execute(
|
||||
boost::asio::require(pool_.executor(),
|
||||
execution::blocking.always),
|
||||
[this, &result]
|
||||
{
|
||||
return balance_;
|
||||
})).get();
|
||||
result = balance_;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <boost/asio/dispatch.hpp>
|
||||
#include <boost/asio/execution_context.hpp>
|
||||
#include <boost/asio/thread_pool.hpp>
|
||||
#include <boost/asio/execution.hpp>
|
||||
#include <boost/asio/static_thread_pool.hpp>
|
||||
#include <algorithm>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
@@ -8,14 +8,13 @@
|
||||
#include <thread>
|
||||
#include <numeric>
|
||||
|
||||
using boost::asio::dispatch;
|
||||
using boost::asio::execution_context;
|
||||
using boost::asio::thread_pool;
|
||||
using boost::asio::static_thread_pool;
|
||||
namespace execution = boost::asio::execution;
|
||||
|
||||
// A fixed-size thread pool used to implement fork/join semantics. Functions
|
||||
// are scheduled using a simple FIFO queue. Implementing work stealing, or
|
||||
// using a queue based on atomic operations, are left as tasks for the reader.
|
||||
class fork_join_pool : public execution_context
|
||||
class fork_join_pool
|
||||
{
|
||||
public:
|
||||
// The constructor starts a thread pool with the specified number of threads.
|
||||
@@ -23,7 +22,7 @@ public:
|
||||
// Additional threads may temporarily be added to the pool if they join a
|
||||
// fork_executor.
|
||||
explicit fork_join_pool(
|
||||
std::size_t thread_count = std::thread::hardware_concurrency() * 2)
|
||||
std::size_t thread_count = std::max(std::thread::hardware_concurrency(), 1u) * 2)
|
||||
: use_count_(1),
|
||||
threads_(thread_count)
|
||||
{
|
||||
@@ -33,7 +32,9 @@ public:
|
||||
// it is time to shut down, i.e. the use count is zero.
|
||||
for (thread_count_ = 0; thread_count_ < thread_count; ++thread_count_)
|
||||
{
|
||||
dispatch(threads_, [&]
|
||||
execution::execute(
|
||||
threads_.executor(),
|
||||
[this]
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
while (use_count_ > 0)
|
||||
@@ -45,7 +46,7 @@ public:
|
||||
catch (...)
|
||||
{
|
||||
stop_threads();
|
||||
threads_.join();
|
||||
threads_.wait();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
@@ -54,7 +55,7 @@ public:
|
||||
~fork_join_pool()
|
||||
{
|
||||
stop_threads();
|
||||
threads_.join();
|
||||
threads_.wait();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -118,7 +119,7 @@ private:
|
||||
|
||||
// Dispatch a function, executing it immediately if the queue is already
|
||||
// loaded. Otherwise adds the function to the queue and wakes a thread.
|
||||
void do_dispatch(std::shared_ptr<function_base> p,
|
||||
void do_execute(std::shared_ptr<function_base> p,
|
||||
const std::shared_ptr<std::size_t>& work_count)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
@@ -136,16 +137,6 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
// Add a function to the queue and wake a thread.
|
||||
void do_post(std::shared_ptr<function_base> p,
|
||||
const std::shared_ptr<std::size_t>& work_count)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
queue_.push(p);
|
||||
do_work_started(work_count);
|
||||
condition_.notify_one();
|
||||
}
|
||||
|
||||
// Ask all threads to shut down.
|
||||
void stop_threads()
|
||||
{
|
||||
@@ -159,7 +150,7 @@ private:
|
||||
std::queue<std::shared_ptr<function_base>> queue_;
|
||||
std::size_t use_count_;
|
||||
std::size_t thread_count_;
|
||||
thread_pool threads_;
|
||||
static_thread_pool threads_;
|
||||
};
|
||||
|
||||
// A class that satisfies the Executor requirements. Every function or piece of
|
||||
@@ -173,45 +164,16 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
fork_join_pool& context() const noexcept
|
||||
fork_join_pool& query(execution::context_t) const noexcept
|
||||
{
|
||||
return context_;
|
||||
}
|
||||
|
||||
void on_work_started() const noexcept
|
||||
template <class Func>
|
||||
void execute(Func f) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(context_.mutex_);
|
||||
context_.do_work_started(work_count_);
|
||||
}
|
||||
|
||||
void on_work_finished() const noexcept
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(context_.mutex_);
|
||||
context_.do_work_finished(work_count_);
|
||||
}
|
||||
|
||||
template <class Func, class Alloc>
|
||||
void dispatch(Func&& f, const Alloc& a) const
|
||||
{
|
||||
auto p(std::allocate_shared<function<Func>>(
|
||||
typename std::allocator_traits<Alloc>::template rebind_alloc<char>(a),
|
||||
std::move(f), work_count_));
|
||||
context_.do_dispatch(p, work_count_);
|
||||
}
|
||||
|
||||
template <class Func, class Alloc>
|
||||
void post(Func f, const Alloc& a) const
|
||||
{
|
||||
auto p(std::allocate_shared<function<Func>>(
|
||||
typename std::allocator_traits<Alloc>::template rebind_alloc<char>(a),
|
||||
std::move(f), work_count_));
|
||||
context_.do_post(p, work_count_);
|
||||
}
|
||||
|
||||
template <class Func, class Alloc>
|
||||
void defer(Func&& f, const Alloc& a) const
|
||||
{
|
||||
post(std::forward<Func>(f), a);
|
||||
auto p(std::make_shared<function<Func>>(std::move(f), work_count_));
|
||||
context_.do_execute(p, work_count_);
|
||||
}
|
||||
|
||||
friend bool operator==(const fork_executor& a,
|
||||
@@ -290,8 +252,8 @@ void fork_join_sort(Iterator begin, Iterator end)
|
||||
{
|
||||
fork_executor fork(pool);
|
||||
join_guard join(fork);
|
||||
dispatch(fork, [=]{ fork_join_sort(begin, begin + n / 2); });
|
||||
dispatch(fork, [=]{ fork_join_sort(begin + n / 2, end); });
|
||||
execution::execute(fork, [=]{ fork_join_sort(begin, begin + n / 2); });
|
||||
execution::execute(fork, [=]{ fork_join_sort(begin + n / 2, end); });
|
||||
}
|
||||
std::inplace_merge(begin, begin + n / 2, end);
|
||||
}
|
||||
|
||||
@@ -20,9 +20,10 @@ using boost::asio::post;
|
||||
using boost::asio::system_executor;
|
||||
using boost::asio::use_future;
|
||||
using boost::asio::use_service;
|
||||
namespace execution = boost::asio::execution;
|
||||
|
||||
// An executor that launches a new thread for each function submitted to it.
|
||||
// This class satisfies the Executor requirements.
|
||||
// This class satisfies the executor requirements.
|
||||
class thread_executor
|
||||
{
|
||||
private:
|
||||
@@ -55,40 +56,28 @@ private:
|
||||
};
|
||||
|
||||
public:
|
||||
execution_context& context() const noexcept
|
||||
execution_context& query(execution::context_t) const
|
||||
{
|
||||
return system_executor().context();
|
||||
return boost::asio::query(system_executor(), execution::context);
|
||||
}
|
||||
|
||||
void on_work_started() const noexcept
|
||||
execution::blocking_t query(execution::blocking_t) const
|
||||
{
|
||||
// This executor doesn't count work.
|
||||
return execution::blocking.never;
|
||||
}
|
||||
|
||||
void on_work_finished() const noexcept
|
||||
thread_executor require(execution::blocking_t::never_t) const
|
||||
{
|
||||
// This executor doesn't count work.
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class Func, class Alloc>
|
||||
void dispatch(Func&& f, const Alloc& a) const
|
||||
template <class Func>
|
||||
void execute(Func f) const
|
||||
{
|
||||
post(std::forward<Func>(f), a);
|
||||
}
|
||||
|
||||
template <class Func, class Alloc>
|
||||
void post(Func f, const Alloc&) const
|
||||
{
|
||||
thread_bag& bag = use_service<thread_bag>(context());
|
||||
thread_bag& bag = use_service<thread_bag>(query(execution::context));
|
||||
bag.add_thread(std::thread(std::move(f)));
|
||||
}
|
||||
|
||||
template <class Func, class Alloc>
|
||||
void defer(Func&& f, const Alloc& a) const
|
||||
{
|
||||
post(std::forward<Func>(f), a);
|
||||
}
|
||||
|
||||
friend bool operator==(const thread_executor&,
|
||||
const thread_executor&) noexcept
|
||||
{
|
||||
@@ -292,7 +281,7 @@ void writer(queue_back<std::string> in)
|
||||
|
||||
int main()
|
||||
{
|
||||
thread_pool pool;
|
||||
thread_pool pool(1);
|
||||
|
||||
auto f = pipeline(reader, filter, bind_executor(pool, upper), writer);
|
||||
f.wait();
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
using boost::asio::dispatch;
|
||||
using boost::asio::execution_context;
|
||||
namespace execution = boost::asio::execution;
|
||||
|
||||
class priority_scheduler : public execution_context
|
||||
{
|
||||
@@ -21,47 +22,20 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
priority_scheduler& context() const noexcept
|
||||
priority_scheduler& query(execution::context_t) const noexcept
|
||||
{
|
||||
return context_;
|
||||
}
|
||||
|
||||
void on_work_started() const noexcept
|
||||
template <class Func>
|
||||
void execute(Func f) const
|
||||
{
|
||||
// This executor doesn't count work. Instead, the scheduler simply runs
|
||||
// until explicitly stopped.
|
||||
}
|
||||
|
||||
void on_work_finished() const noexcept
|
||||
{
|
||||
// This executor doesn't count work. Instead, the scheduler simply runs
|
||||
// until explicitly stopped.
|
||||
}
|
||||
|
||||
template <class Func, class Alloc>
|
||||
void dispatch(Func&& f, const Alloc& a) const
|
||||
{
|
||||
post(std::forward<Func>(f), a);
|
||||
}
|
||||
|
||||
template <class Func, class Alloc>
|
||||
void post(Func f, const Alloc& a) const
|
||||
{
|
||||
auto p(std::allocate_shared<item<Func>>(
|
||||
typename std::allocator_traits<
|
||||
Alloc>::template rebind_alloc<char>(a),
|
||||
priority_, std::move(f)));
|
||||
auto p(std::make_shared<item<Func>>(priority_, std::move(f)));
|
||||
std::lock_guard<std::mutex> lock(context_.mutex_);
|
||||
context_.queue_.push(p);
|
||||
context_.condition_.notify_one();
|
||||
}
|
||||
|
||||
template <class Func, class Alloc>
|
||||
void defer(Func&& f, const Alloc& a) const
|
||||
{
|
||||
post(std::forward<Func>(f), a);
|
||||
}
|
||||
|
||||
friend bool operator==(const executor_type& a,
|
||||
const executor_type& b) noexcept
|
||||
{
|
||||
|
||||
@@ -77,7 +77,8 @@ int main(int argc, char* argv[])
|
||||
// We run the io_context off in its own thread so that it operates
|
||||
// completely asynchronously with respect to the rest of the program.
|
||||
boost::asio::io_context io_context;
|
||||
auto work = boost::asio::make_work_guard(io_context);
|
||||
auto work = boost::asio::require(io_context.get_executor(),
|
||||
boost::asio::execution::outstanding_work.tracked);
|
||||
std::thread thread([&io_context](){ io_context.run(); });
|
||||
|
||||
get_daytime(io_context, argv[1]);
|
||||
|
||||
@@ -16,6 +16,13 @@
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
// Define a helper macro to invoke BOOST_ASIO_HANDLER_LOCATION with the current
|
||||
// file name, line number, and function name. For the function name, you might
|
||||
// also consider using __PRETTY_FUNCTION__, BOOST_CURRENT_FUNCTION, or a hand-
|
||||
// crafted name. For C++20 or later, you may also use std::source_location.
|
||||
#define HANDLER_LOCATION \
|
||||
BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, __func__))
|
||||
|
||||
class session
|
||||
: public std::enable_shared_from_this<session>
|
||||
{
|
||||
@@ -27,16 +34,22 @@ public:
|
||||
|
||||
void start()
|
||||
{
|
||||
HANDLER_LOCATION;
|
||||
|
||||
do_read();
|
||||
}
|
||||
|
||||
private:
|
||||
void do_read()
|
||||
{
|
||||
HANDLER_LOCATION;
|
||||
|
||||
auto self(shared_from_this());
|
||||
socket_.async_read_some(boost::asio::buffer(data_, max_length),
|
||||
[this, self](boost::system::error_code ec, std::size_t length)
|
||||
{
|
||||
HANDLER_LOCATION;
|
||||
|
||||
if (!ec)
|
||||
{
|
||||
do_write(length);
|
||||
@@ -46,10 +59,14 @@ private:
|
||||
|
||||
void do_write(std::size_t length)
|
||||
{
|
||||
HANDLER_LOCATION;
|
||||
|
||||
auto self(shared_from_this());
|
||||
boost::asio::async_write(socket_, boost::asio::buffer(data_, length),
|
||||
[this, self](boost::system::error_code ec, std::size_t /*length*/)
|
||||
{
|
||||
HANDLER_LOCATION;
|
||||
|
||||
if (!ec)
|
||||
{
|
||||
do_read();
|
||||
@@ -74,9 +91,13 @@ public:
|
||||
private:
|
||||
void do_accept()
|
||||
{
|
||||
HANDLER_LOCATION;
|
||||
|
||||
acceptor_.async_accept(
|
||||
[this](boost::system::error_code ec, tcp::socket socket)
|
||||
{
|
||||
HANDLER_LOCATION;
|
||||
|
||||
if (!ec)
|
||||
{
|
||||
std::make_shared<session>(std::move(socket))->start();
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
# define BOOST_ASIO_HANDLER_TRACKING_INIT \
|
||||
::custom_tracking::init()
|
||||
|
||||
# define BOOST_ASIO_HANDLER_LOCATION(args) \
|
||||
::custom_tracking::location args
|
||||
|
||||
# define BOOST_ASIO_HANDLER_CREATION(args) \
|
||||
::custom_tracking::creation args
|
||||
|
||||
@@ -71,6 +74,13 @@ struct custom_tracking
|
||||
{
|
||||
}
|
||||
|
||||
// Record a source location.
|
||||
static void location(const char* file_name,
|
||||
int line, const char* function_name)
|
||||
{
|
||||
std::printf("At location %s:%d in %s\n", file_name, line, function_name);
|
||||
}
|
||||
|
||||
// Record the creation of a tracked handler.
|
||||
static void creation(boost::asio::execution_context& /*ctx*/,
|
||||
tracked_handler& h, const char* object_type, void* /*object*/,
|
||||
|
||||
@@ -97,7 +97,9 @@ struct async_write_message_initiation
|
||||
// As our composed operation performs multiple underlying I/O operations,
|
||||
// we should maintain a work object against the I/O executor. This tells
|
||||
// the I/O executor that there is still more work to come in the future.
|
||||
boost::asio::executor_work_guard<tcp::socket::executor_type> io_work_;
|
||||
typename std::decay<decltype(boost::asio::prefer(
|
||||
std::declval<tcp::socket::executor_type>(),
|
||||
boost::asio::execution::outstanding_work.tracked))>::type io_work_;
|
||||
|
||||
// The user-supplied completion handler, called once only on completion
|
||||
// of the entire composed operation.
|
||||
@@ -134,9 +136,6 @@ struct async_write_message_initiation
|
||||
// This point is reached only on completion of the entire composed
|
||||
// operation.
|
||||
|
||||
// We no longer have any future work coming for the I/O executor.
|
||||
io_work_.reset();
|
||||
|
||||
// Deallocate the encoded message before calling the user-supplied
|
||||
// completion handler.
|
||||
encoded_message_.reset();
|
||||
@@ -187,7 +186,8 @@ struct async_write_message_initiation
|
||||
socket, std::move(encoded_message),
|
||||
repeat_count, std::move(delay_timer),
|
||||
intermediate_completion_handler::starting,
|
||||
boost::asio::make_work_guard(socket.get_executor()),
|
||||
boost::asio::prefer(socket.get_executor(),
|
||||
boost::asio::execution::outstanding_work.tracked),
|
||||
std::forward<CompletionHandler>(completion_handler)});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -44,7 +44,8 @@ int main(int argc, char* argv[])
|
||||
|
||||
// Get an endpoint for the Boost website. This will be passed to the SOCKS
|
||||
// 4 server. Explicitly specify IPv4 since SOCKS 4 does not support IPv6.
|
||||
auto http_endpoint = *resolver.resolve(tcp::v4(), "www.boost.org", "http");
|
||||
auto http_endpoint =
|
||||
*resolver.resolve(tcp::v4(), "www.boost.org", "http").begin();
|
||||
|
||||
// Send the request to the SOCKS 4 server.
|
||||
socks4::request socks_request(
|
||||
|
||||
@@ -19,8 +19,8 @@ using boost::asio::ip::tcp;
|
||||
class session : public std::enable_shared_from_this<session>
|
||||
{
|
||||
public:
|
||||
session(tcp::socket socket, boost::asio::ssl::context& context)
|
||||
: socket_(std::move(socket), context)
|
||||
session(boost::asio::ssl::stream<tcp::socket> socket)
|
||||
: socket_(std::move(socket))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -106,7 +106,9 @@ private:
|
||||
{
|
||||
if (!error)
|
||||
{
|
||||
std::make_shared<session>(std::move(socket), context_)->start();
|
||||
std::make_shared<session>(
|
||||
boost::asio::ssl::stream<tcp::socket>(
|
||||
std::move(socket), context_))->start();
|
||||
}
|
||||
|
||||
do_accept();
|
||||
|
||||
@@ -98,7 +98,8 @@ public:
|
||||
// use this function to run the io_context until the operation is complete.
|
||||
return_type get()
|
||||
{
|
||||
boost::asio::io_context& io_context = socket_.get_executor().context();
|
||||
boost::asio::io_context& io_context = boost::asio::query(
|
||||
socket_.get_executor(), boost::asio::execution::context);
|
||||
|
||||
// Restart the io_context, as it may have been left in the "stopped" state
|
||||
// by a previous operation.
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
#include <boost/asio/ts/executor.hpp>
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
#include <boost/asio/defer.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/asio/system_executor.hpp>
|
||||
#include <condition_variable>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
@@ -6,8 +10,8 @@
|
||||
#include <typeinfo>
|
||||
#include <vector>
|
||||
|
||||
using boost::asio::any_io_executor;
|
||||
using boost::asio::defer;
|
||||
using boost::asio::executor;
|
||||
using boost::asio::post;
|
||||
using boost::asio::strand;
|
||||
using boost::asio::system_executor;
|
||||
@@ -94,7 +98,7 @@ public:
|
||||
{
|
||||
// Execute the message handler in the context of the target's executor.
|
||||
post(to->executor_,
|
||||
[=, msg=std::move(msg)]
|
||||
[=, msg=std::move(msg)]() mutable
|
||||
{
|
||||
to->call_handler(std::move(msg), from);
|
||||
});
|
||||
@@ -102,7 +106,7 @@ public:
|
||||
|
||||
protected:
|
||||
// Construct the actor to use the specified executor for all message handlers.
|
||||
actor(executor e)
|
||||
actor(any_io_executor e)
|
||||
: executor_(std::move(e))
|
||||
{
|
||||
}
|
||||
@@ -166,7 +170,7 @@ private:
|
||||
// All messages associated with a single actor object should be processed
|
||||
// non-concurrently. We use a strand to ensure non-concurrent execution even
|
||||
// if the underlying executor may use multiple threads.
|
||||
strand<executor> executor_;
|
||||
strand<any_io_executor> executor_;
|
||||
|
||||
std::vector<std::shared_ptr<message_handler_base>> handlers_;
|
||||
};
|
||||
@@ -216,7 +220,7 @@ using boost::asio::thread_pool;
|
||||
class member : public actor
|
||||
{
|
||||
public:
|
||||
explicit member(executor e)
|
||||
explicit member(any_io_executor e)
|
||||
: actor(std::move(e))
|
||||
{
|
||||
register_handler(&member::init_handler);
|
||||
|
||||
@@ -1,29 +1,35 @@
|
||||
#include <boost/asio/ts/executor.hpp>
|
||||
#include <boost/asio/thread_pool.hpp>
|
||||
#include <boost/asio/associated_executor.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/execution.hpp>
|
||||
#include <boost/asio/static_thread_pool.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
using boost::asio::bind_executor;
|
||||
using boost::asio::dispatch;
|
||||
using boost::asio::make_work_guard;
|
||||
using boost::asio::post;
|
||||
using boost::asio::thread_pool;
|
||||
using boost::asio::get_associated_executor;
|
||||
using boost::asio::static_thread_pool;
|
||||
namespace execution = boost::asio::execution;
|
||||
|
||||
// A function to asynchronously read a single line from an input stream.
|
||||
template <class Handler>
|
||||
void async_getline(std::istream& is, Handler handler)
|
||||
template <class IoExecutor, class Handler>
|
||||
void async_getline(IoExecutor io_ex, std::istream& is, Handler handler)
|
||||
{
|
||||
// Create executor_work for the handler's associated executor.
|
||||
auto work = make_work_guard(handler);
|
||||
// Track work for the handler's associated executor.
|
||||
auto work_ex = boost::asio::prefer(
|
||||
get_associated_executor(handler, io_ex),
|
||||
execution::outstanding_work.tracked);
|
||||
|
||||
// Post a function object to do the work asynchronously.
|
||||
post([&is, work, handler=std::move(handler)]() mutable
|
||||
execution::execute(
|
||||
boost::asio::require(io_ex, execution::blocking.never),
|
||||
[&is, work_ex, handler=std::move(handler)]() mutable
|
||||
{
|
||||
std::string line;
|
||||
std::getline(is, line);
|
||||
|
||||
// Pass the result to the handler, via the associated executor.
|
||||
dispatch(work.get_executor(),
|
||||
execution::execute(
|
||||
boost::asio::prefer(work_ex, execution::blocking.possibly),
|
||||
[line=std::move(line), handler=std::move(handler)]() mutable
|
||||
{
|
||||
handler(std::move(line));
|
||||
@@ -33,15 +39,18 @@ void async_getline(std::istream& is, Handler handler)
|
||||
|
||||
int main()
|
||||
{
|
||||
thread_pool pool;
|
||||
static_thread_pool io_pool(1);
|
||||
static_thread_pool completion_pool(1);
|
||||
|
||||
std::cout << "Enter a line: ";
|
||||
|
||||
async_getline(std::cin,
|
||||
bind_executor(pool, [](std::string line)
|
||||
async_getline(io_pool.executor(), std::cin,
|
||||
bind_executor(completion_pool.executor(),
|
||||
[](std::string line)
|
||||
{
|
||||
std::cout << "Line: " << line << "\n";
|
||||
}));
|
||||
|
||||
pool.join();
|
||||
io_pool.wait();
|
||||
completion_pool.wait();
|
||||
}
|
||||
|
||||
@@ -1,30 +1,35 @@
|
||||
#include <boost/asio/ts/executor.hpp>
|
||||
#include <boost/asio/thread_pool.hpp>
|
||||
#include <boost/asio/associated_executor.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/execution.hpp>
|
||||
#include <boost/asio/static_thread_pool.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
using boost::asio::bind_executor;
|
||||
using boost::asio::dispatch;
|
||||
using boost::asio::get_associated_executor;
|
||||
using boost::asio::make_work_guard;
|
||||
using boost::asio::post;
|
||||
using boost::asio::thread_pool;
|
||||
using boost::asio::static_thread_pool;
|
||||
namespace execution = boost::asio::execution;
|
||||
|
||||
// A function to asynchronously read a single line from an input stream.
|
||||
template <class Handler>
|
||||
void async_getline(std::istream& is, Handler handler)
|
||||
template <class IoExecutor, class Handler>
|
||||
void async_getline(IoExecutor io_ex, std::istream& is, Handler handler)
|
||||
{
|
||||
// Create executor_work for the handler's associated executor.
|
||||
auto work = make_work_guard(handler);
|
||||
// Track work for the handler's associated executor.
|
||||
auto work_ex = boost::asio::prefer(
|
||||
get_associated_executor(handler, io_ex),
|
||||
execution::outstanding_work.tracked);
|
||||
|
||||
// Post a function object to do the work asynchronously.
|
||||
post([&is, work, handler=std::move(handler)]() mutable
|
||||
execution::execute(
|
||||
boost::asio::require(io_ex, execution::blocking.never),
|
||||
[&is, work_ex, handler=std::move(handler)]() mutable
|
||||
{
|
||||
std::string line;
|
||||
std::getline(is, line);
|
||||
|
||||
// Pass the result to the handler, via the associated executor.
|
||||
dispatch(work.get_executor(),
|
||||
execution::execute(
|
||||
boost::asio::prefer(work_ex, execution::blocking.possibly),
|
||||
[line=std::move(line), handler=std::move(handler)]() mutable
|
||||
{
|
||||
handler(std::move(line));
|
||||
@@ -33,36 +38,44 @@ void async_getline(std::istream& is, Handler handler)
|
||||
}
|
||||
|
||||
// A function to asynchronously read multiple lines from an input stream.
|
||||
template <class Handler>
|
||||
void async_getlines(std::istream& is, std::string init, Handler handler)
|
||||
template <class IoExecutor, class Handler>
|
||||
void async_getlines(IoExecutor io_ex, std::istream& is, std::string init, Handler handler)
|
||||
{
|
||||
// Get the final handler's associated executor.
|
||||
auto ex = get_associated_executor(handler);
|
||||
// Track work for the I/O executor.
|
||||
auto io_work_ex = boost::asio::prefer(io_ex,
|
||||
execution::outstanding_work.tracked);
|
||||
|
||||
// Track work for the handler's associated executor.
|
||||
auto handler_work_ex = boost::asio::prefer(
|
||||
get_associated_executor(handler, io_ex),
|
||||
execution::outstanding_work.tracked);
|
||||
|
||||
// Use the associated executor for each operation in the composition.
|
||||
async_getline(is,
|
||||
bind_executor(ex,
|
||||
[&is, lines=std::move(init), handler=std::move(handler)]
|
||||
async_getline(io_work_ex, is,
|
||||
bind_executor(handler_work_ex,
|
||||
[io_work_ex, &is, lines=std::move(init), handler=std::move(handler)]
|
||||
(std::string line) mutable
|
||||
{
|
||||
if (line.empty())
|
||||
handler(lines);
|
||||
else
|
||||
async_getlines(is, lines + line + "\n", std::move(handler));
|
||||
async_getlines(io_work_ex, is, lines + line + "\n", std::move(handler));
|
||||
}));
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
thread_pool pool;
|
||||
static_thread_pool io_pool(1);
|
||||
static_thread_pool completion_pool(1);
|
||||
|
||||
std::cout << "Enter text, terminating with a blank line:\n";
|
||||
|
||||
async_getlines(std::cin, "",
|
||||
bind_executor(pool, [](std::string lines)
|
||||
async_getlines(io_pool.executor(), std::cin, "",
|
||||
bind_executor(completion_pool.executor(), [](std::string lines)
|
||||
{
|
||||
std::cout << "Lines:\n" << lines << "\n";
|
||||
}));
|
||||
|
||||
pool.join();
|
||||
io_pool.wait();
|
||||
completion_pool.wait();
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include <boost/asio/ts/executor.hpp>
|
||||
#include <boost/asio/thread_pool.hpp>
|
||||
#include <boost/asio/execution.hpp>
|
||||
#include <boost/asio/static_thread_pool.hpp>
|
||||
#include <iostream>
|
||||
|
||||
using boost::asio::post;
|
||||
using boost::asio::thread_pool;
|
||||
using boost::asio::static_thread_pool;
|
||||
namespace execution = boost::asio::execution;
|
||||
|
||||
// Traditional active object pattern.
|
||||
// Member functions do not block.
|
||||
@@ -11,37 +11,43 @@ using boost::asio::thread_pool;
|
||||
class bank_account
|
||||
{
|
||||
int balance_ = 0;
|
||||
mutable thread_pool pool_{1};
|
||||
mutable static_thread_pool pool_{1};
|
||||
|
||||
public:
|
||||
void deposit(int amount)
|
||||
{
|
||||
post(pool_, [=]
|
||||
{
|
||||
balance_ += amount;
|
||||
});
|
||||
execution::execute(
|
||||
pool_.executor(),
|
||||
[this, amount]
|
||||
{
|
||||
balance_ += amount;
|
||||
});
|
||||
}
|
||||
|
||||
void withdraw(int amount)
|
||||
{
|
||||
post(pool_, [=]
|
||||
{
|
||||
if (balance_ >= amount)
|
||||
balance_ -= amount;
|
||||
});
|
||||
execution::execute(
|
||||
pool_.executor(),
|
||||
[this, amount]
|
||||
{
|
||||
if (balance_ >= amount)
|
||||
balance_ -= amount;
|
||||
});
|
||||
}
|
||||
|
||||
void print_balance() const
|
||||
{
|
||||
post(pool_, [=]
|
||||
{
|
||||
std::cout << "balance = " << balance_ << "\n";
|
||||
});
|
||||
execution::execute(
|
||||
pool_.executor(),
|
||||
[this]
|
||||
{
|
||||
std::cout << "balance = " << balance_ << "\n";
|
||||
});
|
||||
}
|
||||
|
||||
~bank_account()
|
||||
{
|
||||
pool_.join();
|
||||
pool_.wait();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#include <boost/asio/ts/executor.hpp>
|
||||
#include <boost/asio/thread_pool.hpp>
|
||||
#include <boost/asio/execution.hpp>
|
||||
#include <boost/asio/static_thread_pool.hpp>
|
||||
#include <iostream>
|
||||
|
||||
using boost::asio::post;
|
||||
using boost::asio::thread_pool;
|
||||
using boost::asio::use_future;
|
||||
using boost::asio::static_thread_pool;
|
||||
namespace execution = boost::asio::execution;
|
||||
|
||||
// Traditional active object pattern.
|
||||
// Member functions block until operation is finished.
|
||||
@@ -12,35 +11,43 @@ using boost::asio::use_future;
|
||||
class bank_account
|
||||
{
|
||||
int balance_ = 0;
|
||||
mutable thread_pool pool_{1};
|
||||
mutable static_thread_pool pool_{1};
|
||||
|
||||
public:
|
||||
void deposit(int amount)
|
||||
{
|
||||
post(pool_,
|
||||
use_future([=]
|
||||
execution::execute(
|
||||
boost::asio::require(pool_.executor(),
|
||||
execution::blocking.always),
|
||||
[this, amount]
|
||||
{
|
||||
balance_ += amount;
|
||||
})).get();
|
||||
});
|
||||
}
|
||||
|
||||
void withdraw(int amount)
|
||||
{
|
||||
post(pool_,
|
||||
use_future([=]
|
||||
execution::execute(
|
||||
boost::asio::require(pool_.executor(),
|
||||
execution::blocking.always),
|
||||
[this, amount]
|
||||
{
|
||||
if (balance_ >= amount)
|
||||
balance_ -= amount;
|
||||
})).get();
|
||||
});
|
||||
}
|
||||
|
||||
int balance() const
|
||||
{
|
||||
return post(pool_,
|
||||
use_future([=]
|
||||
int result = 0;
|
||||
execution::execute(
|
||||
boost::asio::require(pool_.executor(),
|
||||
execution::blocking.always),
|
||||
[this, &result]
|
||||
{
|
||||
return balance_;
|
||||
})).get();
|
||||
result = balance_;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <boost/asio/ts/executor.hpp>
|
||||
#include <boost/asio/thread_pool.hpp>
|
||||
#include <boost/asio/execution.hpp>
|
||||
#include <boost/asio/static_thread_pool.hpp>
|
||||
#include <algorithm>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
@@ -7,14 +8,13 @@
|
||||
#include <thread>
|
||||
#include <numeric>
|
||||
|
||||
using boost::asio::dispatch;
|
||||
using boost::asio::execution_context;
|
||||
using boost::asio::thread_pool;
|
||||
using boost::asio::static_thread_pool;
|
||||
namespace execution = boost::asio::execution;
|
||||
|
||||
// A fixed-size thread pool used to implement fork/join semantics. Functions
|
||||
// are scheduled using a simple FIFO queue. Implementing work stealing, or
|
||||
// using a queue based on atomic operations, are left as tasks for the reader.
|
||||
class fork_join_pool : public execution_context
|
||||
class fork_join_pool
|
||||
{
|
||||
public:
|
||||
// The constructor starts a thread pool with the specified number of threads.
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
// Additional threads may temporarily be added to the pool if they join a
|
||||
// fork_executor.
|
||||
explicit fork_join_pool(
|
||||
std::size_t thread_count = std::thread::hardware_concurrency() * 2)
|
||||
std::size_t thread_count = std::max(std::thread::hardware_concurrency(), 1u) * 2)
|
||||
: use_count_(1),
|
||||
threads_(thread_count)
|
||||
{
|
||||
@@ -32,7 +32,9 @@ public:
|
||||
// it is time to shut down, i.e. the use count is zero.
|
||||
for (thread_count_ = 0; thread_count_ < thread_count; ++thread_count_)
|
||||
{
|
||||
dispatch(threads_, [&]
|
||||
execution::execute(
|
||||
threads_.executor(),
|
||||
[this]
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
while (use_count_ > 0)
|
||||
@@ -44,7 +46,7 @@ public:
|
||||
catch (...)
|
||||
{
|
||||
stop_threads();
|
||||
threads_.join();
|
||||
threads_.wait();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
@@ -53,7 +55,7 @@ public:
|
||||
~fork_join_pool()
|
||||
{
|
||||
stop_threads();
|
||||
threads_.join();
|
||||
threads_.wait();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -117,7 +119,7 @@ private:
|
||||
|
||||
// Dispatch a function, executing it immediately if the queue is already
|
||||
// loaded. Otherwise adds the function to the queue and wakes a thread.
|
||||
void do_dispatch(std::shared_ptr<function_base> p,
|
||||
void do_execute(std::shared_ptr<function_base> p,
|
||||
const std::shared_ptr<std::size_t>& work_count)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
@@ -135,16 +137,6 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
// Add a function to the queue and wake a thread.
|
||||
void do_post(std::shared_ptr<function_base> p,
|
||||
const std::shared_ptr<std::size_t>& work_count)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
queue_.push(p);
|
||||
do_work_started(work_count);
|
||||
condition_.notify_one();
|
||||
}
|
||||
|
||||
// Ask all threads to shut down.
|
||||
void stop_threads()
|
||||
{
|
||||
@@ -158,7 +150,7 @@ private:
|
||||
std::queue<std::shared_ptr<function_base>> queue_;
|
||||
std::size_t use_count_;
|
||||
std::size_t thread_count_;
|
||||
thread_pool threads_;
|
||||
static_thread_pool threads_;
|
||||
};
|
||||
|
||||
// A class that satisfies the Executor requirements. Every function or piece of
|
||||
@@ -172,45 +164,16 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
fork_join_pool& context() const noexcept
|
||||
fork_join_pool& query(execution::context_t) const noexcept
|
||||
{
|
||||
return context_;
|
||||
}
|
||||
|
||||
void on_work_started() const noexcept
|
||||
template <class Func>
|
||||
void execute(Func f) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(context_.mutex_);
|
||||
context_.do_work_started(work_count_);
|
||||
}
|
||||
|
||||
void on_work_finished() const noexcept
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(context_.mutex_);
|
||||
context_.do_work_finished(work_count_);
|
||||
}
|
||||
|
||||
template <class Func, class Alloc>
|
||||
void dispatch(Func&& f, const Alloc& a) const
|
||||
{
|
||||
auto p(std::allocate_shared<function<Func>>(
|
||||
typename std::allocator_traits<Alloc>::template rebind_alloc<char>(a),
|
||||
std::move(f), work_count_));
|
||||
context_.do_dispatch(p, work_count_);
|
||||
}
|
||||
|
||||
template <class Func, class Alloc>
|
||||
void post(Func f, const Alloc& a) const
|
||||
{
|
||||
auto p(std::allocate_shared<function<Func>>(
|
||||
typename std::allocator_traits<Alloc>::template rebind_alloc<char>(a),
|
||||
std::move(f), work_count_));
|
||||
context_.do_post(p, work_count_);
|
||||
}
|
||||
|
||||
template <class Func, class Alloc>
|
||||
void defer(Func&& f, const Alloc& a) const
|
||||
{
|
||||
post(std::forward<Func>(f), a);
|
||||
auto p(std::make_shared<function<Func>>(std::move(f), work_count_));
|
||||
context_.do_execute(p, work_count_);
|
||||
}
|
||||
|
||||
friend bool operator==(const fork_executor& a,
|
||||
@@ -289,8 +252,8 @@ void fork_join_sort(Iterator begin, Iterator end)
|
||||
{
|
||||
fork_executor fork(pool);
|
||||
join_guard join(fork);
|
||||
dispatch(fork, [=]{ fork_join_sort(begin, begin + n / 2); });
|
||||
dispatch(fork, [=]{ fork_join_sort(begin + n / 2, end); });
|
||||
execution::execute(fork, [=]{ fork_join_sort(begin, begin + n / 2); });
|
||||
execution::execute(fork, [=]{ fork_join_sort(begin + n / 2, end); });
|
||||
}
|
||||
std::inplace_merge(begin, begin + n / 2, end);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#include <boost/asio/ts/executor.hpp>
|
||||
#include <boost/asio/associated_executor.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/execution.hpp>
|
||||
#include <condition_variable>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
@@ -8,29 +10,19 @@
|
||||
#include <vector>
|
||||
#include <cctype>
|
||||
|
||||
using boost::asio::execution_context;
|
||||
using boost::asio::executor_binder;
|
||||
using boost::asio::get_associated_executor;
|
||||
using boost::asio::post;
|
||||
using boost::asio::system_executor;
|
||||
using boost::asio::use_future;
|
||||
using boost::asio::use_service;
|
||||
namespace execution = boost::asio::execution;
|
||||
|
||||
// An executor that launches a new thread for each function submitted to it.
|
||||
// This class satisfies the Executor requirements.
|
||||
// This class satisfies the executor requirements.
|
||||
class thread_executor
|
||||
{
|
||||
private:
|
||||
// Service to track all threads started through a thread_executor.
|
||||
class thread_bag : public execution_context::service
|
||||
// Singleton execution context that manages threads launched by the new_thread_executor.
|
||||
class thread_bag
|
||||
{
|
||||
public:
|
||||
typedef thread_bag key_type;
|
||||
|
||||
explicit thread_bag(execution_context& ctx)
|
||||
: execution_context::service(ctx)
|
||||
{
|
||||
}
|
||||
friend class thread_executor;
|
||||
|
||||
void add_thread(std::thread&& t)
|
||||
{
|
||||
@@ -38,8 +30,9 @@ private:
|
||||
threads_.push_back(std::move(t));
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void shutdown()
|
||||
thread_bag() = default;
|
||||
|
||||
~thread_bag()
|
||||
{
|
||||
for (auto& t : threads_)
|
||||
t.join();
|
||||
@@ -50,40 +43,24 @@ private:
|
||||
};
|
||||
|
||||
public:
|
||||
execution_context& context() const noexcept
|
||||
static thread_bag& query(execution::context_t)
|
||||
{
|
||||
return system_executor().context();
|
||||
static thread_bag threads;
|
||||
return threads;
|
||||
}
|
||||
|
||||
void on_work_started() const noexcept
|
||||
static constexpr auto query(execution::blocking_t)
|
||||
{
|
||||
// This executor doesn't count work.
|
||||
return execution::blocking.never;
|
||||
}
|
||||
|
||||
void on_work_finished() const noexcept
|
||||
template <class Func>
|
||||
void execute(Func f) const
|
||||
{
|
||||
// This executor doesn't count work.
|
||||
}
|
||||
|
||||
template <class Func, class Alloc>
|
||||
void dispatch(Func&& f, const Alloc& a) const
|
||||
{
|
||||
post(std::forward<Func>(f), a);
|
||||
}
|
||||
|
||||
template <class Func, class Alloc>
|
||||
void post(Func f, const Alloc&) const
|
||||
{
|
||||
thread_bag& bag = use_service<thread_bag>(context());
|
||||
thread_bag& bag = query(execution::context);
|
||||
bag.add_thread(std::thread(std::move(f)));
|
||||
}
|
||||
|
||||
template <class Func, class Alloc>
|
||||
void defer(Func&& f, const Alloc& a) const
|
||||
{
|
||||
post(std::forward<Func>(f), a);
|
||||
}
|
||||
|
||||
friend bool operator==(const thread_executor&,
|
||||
const thread_executor&) noexcept
|
||||
{
|
||||
@@ -186,7 +163,16 @@ std::future<void> pipeline(queue_back<T> in, F f)
|
||||
|
||||
// Run the function, and as we're the last stage return a future so that the
|
||||
// caller can wait for the pipeline to finish.
|
||||
return post(ex, use_future([in, f = std::move(f)]() mutable { f(in); }));
|
||||
std::packaged_task<void()> task(
|
||||
[in, f = std::move(f)]() mutable
|
||||
{
|
||||
f(in);
|
||||
});
|
||||
std::future<void> fut = task.get_future();
|
||||
execution::execute(
|
||||
boost::asio::require(ex, execution::blocking.never),
|
||||
std::move(task));
|
||||
return fut;
|
||||
}
|
||||
|
||||
// Launch an intermediate stage in a pipeline.
|
||||
@@ -205,7 +191,9 @@ std::future<void> pipeline(queue_back<T> in, F f, Tail... t)
|
||||
auto ex = get_associated_executor(f, thread_executor());
|
||||
|
||||
// Run the function.
|
||||
post(ex, [in, out, f = std::move(f)]() mutable
|
||||
execution::execute(
|
||||
boost::asio::require(ex, execution::blocking.never),
|
||||
[in, out, f = std::move(f)]() mutable
|
||||
{
|
||||
f(in, out);
|
||||
out.stop();
|
||||
@@ -231,7 +219,9 @@ std::future<void> pipeline(F f, Tail... t)
|
||||
auto ex = get_associated_executor(f, thread_executor());
|
||||
|
||||
// Run the function.
|
||||
post(ex, [out, f = std::move(f)]() mutable
|
||||
execution::execute(
|
||||
boost::asio::require(ex, execution::blocking.never),
|
||||
[out, f = std::move(f)]() mutable
|
||||
{
|
||||
f(out);
|
||||
out.stop();
|
||||
@@ -243,12 +233,12 @@ std::future<void> pipeline(F f, Tail... t)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include <boost/asio/thread_pool.hpp>
|
||||
#include <boost/asio/static_thread_pool.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
using boost::asio::bind_executor;
|
||||
using boost::asio::thread_pool;
|
||||
using boost::asio::static_thread_pool;
|
||||
|
||||
void reader(queue_front<std::string> out)
|
||||
{
|
||||
@@ -287,8 +277,8 @@ void writer(queue_back<std::string> in)
|
||||
|
||||
int main()
|
||||
{
|
||||
thread_pool pool;
|
||||
static_thread_pool pool(1);
|
||||
|
||||
auto f = pipeline(reader, filter, bind_executor(pool, upper), writer);
|
||||
auto f = pipeline(reader, filter, bind_executor(pool.executor(), upper), writer);
|
||||
f.wait();
|
||||
}
|
||||
|
||||
@@ -1,66 +1,74 @@
|
||||
#include <boost/asio/ts/executor.hpp>
|
||||
#include <boost/asio/execution.hpp>
|
||||
#include <condition_variable>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
using boost::asio::dispatch;
|
||||
using boost::asio::execution_context;
|
||||
namespace execution = boost::asio::execution;
|
||||
|
||||
class priority_scheduler : public execution_context
|
||||
namespace custom_props {
|
||||
|
||||
struct priority
|
||||
{
|
||||
template <typename T>
|
||||
static constexpr bool is_applicable_property_v =
|
||||
execution::is_executor<T>::value;
|
||||
|
||||
static constexpr bool is_requirable = true;
|
||||
static constexpr bool is_preferable = true;
|
||||
|
||||
using polymorphic_query_result_type = int;
|
||||
|
||||
int value() const { return value_; }
|
||||
|
||||
int value_ = 1;
|
||||
};
|
||||
|
||||
constexpr priority low_priority{0};
|
||||
constexpr priority normal_priority{1};
|
||||
constexpr priority high_priority{2};
|
||||
|
||||
} // namespace custom_props
|
||||
|
||||
class priority_scheduler
|
||||
{
|
||||
public:
|
||||
// A class that satisfies the Executor requirements.
|
||||
class executor_type
|
||||
{
|
||||
public:
|
||||
executor_type(priority_scheduler& ctx, int pri) noexcept
|
||||
: context_(ctx), priority_(pri)
|
||||
executor_type(priority_scheduler& ctx) noexcept
|
||||
: context_(ctx), priority_(custom_props::normal_priority.value())
|
||||
{
|
||||
}
|
||||
|
||||
priority_scheduler& context() const noexcept
|
||||
priority_scheduler& query(execution::context_t) const noexcept
|
||||
{
|
||||
return context_;
|
||||
}
|
||||
|
||||
void on_work_started() const noexcept
|
||||
int query(custom_props::priority) const noexcept
|
||||
{
|
||||
// This executor doesn't count work. Instead, the scheduler simply runs
|
||||
// until explicitly stopped.
|
||||
return priority_;
|
||||
}
|
||||
|
||||
void on_work_finished() const noexcept
|
||||
executor_type require(custom_props::priority pri) const
|
||||
{
|
||||
// This executor doesn't count work. Instead, the scheduler simply runs
|
||||
// until explicitly stopped.
|
||||
executor_type new_ex(*this);
|
||||
new_ex.priority_ = pri.value();
|
||||
return new_ex;
|
||||
}
|
||||
|
||||
template <class Func, class Alloc>
|
||||
void dispatch(Func&& f, const Alloc& a) const
|
||||
template <class Func>
|
||||
void execute(Func f) const
|
||||
{
|
||||
post(std::forward<Func>(f), a);
|
||||
}
|
||||
|
||||
template <class Func, class Alloc>
|
||||
void post(Func f, const Alloc& a) const
|
||||
{
|
||||
auto p(std::allocate_shared<item<Func>>(
|
||||
typename std::allocator_traits<
|
||||
Alloc>::template rebind_alloc<char>(a),
|
||||
priority_, std::move(f)));
|
||||
auto p(std::make_shared<item<Func>>(priority_, std::move(f)));
|
||||
std::lock_guard<std::mutex> lock(context_.mutex_);
|
||||
context_.queue_.push(p);
|
||||
context_.condition_.notify_one();
|
||||
}
|
||||
|
||||
template <class Func, class Alloc>
|
||||
void defer(Func&& f, const Alloc& a) const
|
||||
{
|
||||
post(std::forward<Func>(f), a);
|
||||
}
|
||||
|
||||
friend bool operator==(const executor_type& a,
|
||||
const executor_type& b) noexcept
|
||||
{
|
||||
@@ -78,15 +86,9 @@ public:
|
||||
int priority_;
|
||||
};
|
||||
|
||||
~priority_scheduler() noexcept
|
||||
executor_type executor() noexcept
|
||||
{
|
||||
shutdown();
|
||||
destroy();
|
||||
}
|
||||
|
||||
executor_type get_executor(int pri = 0) noexcept
|
||||
{
|
||||
return executor_type(*const_cast<priority_scheduler*>(this), pri);
|
||||
return executor_type(*const_cast<priority_scheduler*>(this));
|
||||
}
|
||||
|
||||
void run()
|
||||
@@ -158,16 +160,22 @@ private:
|
||||
int main()
|
||||
{
|
||||
priority_scheduler sched;
|
||||
auto low = sched.get_executor(0);
|
||||
auto med = sched.get_executor(1);
|
||||
auto high = sched.get_executor(2);
|
||||
dispatch(low, []{ std::cout << "1\n"; });
|
||||
dispatch(low, []{ std::cout << "11\n"; });
|
||||
dispatch(med, []{ std::cout << "2\n"; });
|
||||
dispatch(med, []{ std::cout << "22\n"; });
|
||||
dispatch(high, []{ std::cout << "3\n"; });
|
||||
dispatch(high, []{ std::cout << "33\n"; });
|
||||
dispatch(high, []{ std::cout << "333\n"; });
|
||||
dispatch(sched.get_executor(-1), [&]{ sched.stop(); });
|
||||
auto ex = sched.executor();
|
||||
auto prefer_low = boost::asio::prefer(ex, custom_props::low_priority);
|
||||
auto low = boost::asio::require(ex, custom_props::low_priority);
|
||||
auto med = boost::asio::require(ex, custom_props::normal_priority);
|
||||
auto high = boost::asio::require(ex, custom_props::high_priority);
|
||||
execution::any_executor<custom_props::priority> poly_high(high);
|
||||
execution::execute(prefer_low, []{ std::cout << "1\n"; });
|
||||
execution::execute(low, []{ std::cout << "11\n"; });
|
||||
execution::execute(low, []{ std::cout << "111\n"; });
|
||||
execution::execute(med, []{ std::cout << "2\n"; });
|
||||
execution::execute(med, []{ std::cout << "22\n"; });
|
||||
execution::execute(high, []{ std::cout << "3\n"; });
|
||||
execution::execute(high, []{ std::cout << "33\n"; });
|
||||
execution::execute(high, []{ std::cout << "333\n"; });
|
||||
execution::execute(poly_high, []{ std::cout << "3333\n"; });
|
||||
execution::execute(boost::asio::require(ex, custom_props::priority{-1}), [&]{ sched.stop(); });
|
||||
sched.run();
|
||||
std::cout << "polymorphic query result = " << boost::asio::query(poly_high, custom_props::priority{}) << "\n";
|
||||
}
|
||||
|
||||
@@ -108,7 +108,9 @@ auto async_write_messages(tcp::socket& socket,
|
||||
// As our composed operation performs multiple underlying I/O operations,
|
||||
// we should maintain a work object against the I/O executor. This tells
|
||||
// the I/O executor that there is still more work to come in the future.
|
||||
boost::asio::executor_work_guard<tcp::socket::executor_type> io_work_;
|
||||
typename std::decay<decltype(boost::asio::prefer(
|
||||
std::declval<tcp::socket::executor_type>(),
|
||||
boost::asio::execution::outstanding_work.tracked))>::type io_work_;
|
||||
|
||||
// The user-supplied completion handler, called once only on completion
|
||||
// of the entire composed operation.
|
||||
@@ -145,9 +147,6 @@ auto async_write_messages(tcp::socket& socket,
|
||||
// This point is reached only on completion of the entire composed
|
||||
// operation.
|
||||
|
||||
// We no longer have any future work coming for the I/O executor.
|
||||
io_work_.reset();
|
||||
|
||||
// Deallocate the encoded message before calling the user-supplied
|
||||
// completion handler.
|
||||
encoded_message_.reset();
|
||||
@@ -198,7 +197,8 @@ auto async_write_messages(tcp::socket& socket,
|
||||
socket, std::move(encoded_message),
|
||||
repeat_count, std::move(delay_timer),
|
||||
intermediate_completion_handler::starting,
|
||||
boost::asio::make_work_guard(socket.get_executor()),
|
||||
boost::asio::prefer(socket.get_executor(),
|
||||
boost::asio::execution::outstanding_work.tracked),
|
||||
std::forward<decltype(completion_handler)>(completion_handler)});
|
||||
};
|
||||
|
||||
|
||||
@@ -204,10 +204,7 @@ int main(int argc, char* argv[])
|
||||
{
|
||||
unsigned short port = std::atoi(argv[i]);
|
||||
co_spawn(io_context,
|
||||
[&io_context, port]
|
||||
{
|
||||
return listener(tcp::acceptor(io_context, {tcp::v4(), port}));
|
||||
},
|
||||
listener(tcp::acceptor(io_context, {tcp::v4(), port})),
|
||||
detached);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,11 @@ using boost::asio::detached;
|
||||
using boost::asio::use_awaitable;
|
||||
namespace this_coro = boost::asio::this_coro;
|
||||
|
||||
#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
|
||||
# define use_awaitable \
|
||||
boost::asio::use_awaitable_t(__FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||
#endif
|
||||
|
||||
awaitable<void> echo(tcp::socket socket)
|
||||
{
|
||||
try
|
||||
@@ -47,12 +52,7 @@ awaitable<void> listener()
|
||||
for (;;)
|
||||
{
|
||||
tcp::socket socket = co_await acceptor.async_accept(use_awaitable);
|
||||
co_spawn(executor,
|
||||
[socket = std::move(socket)]() mutable
|
||||
{
|
||||
return echo(std::move(socket));
|
||||
},
|
||||
detached);
|
||||
co_spawn(executor, echo(std::move(socket)), detached);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ int main()
|
||||
boost::asio::signal_set signals(io_context, SIGINT, SIGTERM);
|
||||
signals.async_wait([&](auto, auto){ io_context.stop(); });
|
||||
|
||||
co_spawn(io_context, listener, detached);
|
||||
co_spawn(io_context, listener(), detached);
|
||||
|
||||
io_context.run();
|
||||
}
|
||||
|
||||
@@ -49,12 +49,7 @@ awaitable<void> listener()
|
||||
for (;;)
|
||||
{
|
||||
auto socket = co_await acceptor.async_accept();
|
||||
co_spawn(executor,
|
||||
[socket = std::move(socket)]() mutable
|
||||
{
|
||||
return echo(std::move(socket));
|
||||
},
|
||||
detached);
|
||||
co_spawn(executor, echo(std::move(socket)), detached);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +62,7 @@ int main()
|
||||
boost::asio::signal_set signals(io_context, SIGINT, SIGTERM);
|
||||
signals.async_wait([&](auto, auto){ io_context.stop(); });
|
||||
|
||||
co_spawn(io_context, listener, detached);
|
||||
co_spawn(io_context, listener(), detached);
|
||||
|
||||
io_context.run();
|
||||
}
|
||||
|
||||
@@ -91,12 +91,7 @@ int main()
|
||||
signals.async_wait([&](auto, auto){ io_context.stop(); });
|
||||
|
||||
tcp::acceptor acceptor(io_context, {tcp::v4(), 55555});
|
||||
co_spawn(io_context,
|
||||
[acceptor = std::move(acceptor)]() mutable
|
||||
{
|
||||
return listener(std::move(acceptor));
|
||||
},
|
||||
detached);
|
||||
co_spawn(io_context, listener(std::move(acceptor)), detached);
|
||||
|
||||
io_context.run();
|
||||
}
|
||||
|
||||
@@ -56,12 +56,7 @@ awaitable<void> listener()
|
||||
for (;;)
|
||||
{
|
||||
tcp::socket socket = co_await acceptor.async_accept(use_awaitable);
|
||||
co_spawn(executor,
|
||||
[socket = std::move(socket)]() mutable
|
||||
{
|
||||
return echo(std::move(socket));
|
||||
},
|
||||
detached);
|
||||
co_spawn(executor, echo(std::move(socket)), detached);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +69,7 @@ int main()
|
||||
boost::asio::signal_set signals(io_context, SIGINT, SIGTERM);
|
||||
signals.async_wait([&](auto, auto){ io_context.stop(); });
|
||||
|
||||
co_spawn(io_context, listener, detached);
|
||||
co_spawn(io_context, listener(), detached);
|
||||
|
||||
io_context.run();
|
||||
}
|
||||
|
||||
@@ -54,6 +54,22 @@
|
||||
#include <boost/asio/detached.hpp>
|
||||
#include <boost/asio/dispatch.hpp>
|
||||
#include <boost/asio/error.hpp>
|
||||
#include <boost/asio/execution.hpp>
|
||||
#include <boost/asio/execution/allocator.hpp>
|
||||
#include <boost/asio/execution/any_executor.hpp>
|
||||
#include <boost/asio/execution/blocking.hpp>
|
||||
#include <boost/asio/execution/blocking_adaptation.hpp>
|
||||
#include <boost/asio/execution/bulk_guarantee.hpp>
|
||||
#include <boost/asio/execution/context.hpp>
|
||||
#include <boost/asio/execution/context_as.hpp>
|
||||
#include <boost/asio/execution/execute.hpp>
|
||||
#include <boost/asio/execution/executor.hpp>
|
||||
#include <boost/asio/execution/invocable_archetype.hpp>
|
||||
#include <boost/asio/execution/mapping.hpp>
|
||||
#include <boost/asio/execution/occupancy.hpp>
|
||||
#include <boost/asio/execution/outstanding_work.hpp>
|
||||
#include <boost/asio/execution/prefer_only.hpp>
|
||||
#include <boost/asio/execution/relationship.hpp>
|
||||
#include <boost/asio/execution_context.hpp>
|
||||
#include <boost/asio/executor.hpp>
|
||||
#include <boost/asio/executor_work_guard.hpp>
|
||||
@@ -94,6 +110,7 @@
|
||||
#include <boost/asio/ip/udp.hpp>
|
||||
#include <boost/asio/ip/unicast.hpp>
|
||||
#include <boost/asio/ip/v6_only.hpp>
|
||||
#include <boost/asio/is_applicable_property.hpp>
|
||||
#include <boost/asio/is_executor.hpp>
|
||||
#include <boost/asio/is_read_buffered.hpp>
|
||||
#include <boost/asio/is_write_buffered.hpp>
|
||||
@@ -101,6 +118,7 @@
|
||||
#include <boost/asio/local/connect_pair.hpp>
|
||||
#include <boost/asio/local/datagram_protocol.hpp>
|
||||
#include <boost/asio/local/stream_protocol.hpp>
|
||||
#include <boost/asio/multiple_exceptions.hpp>
|
||||
#include <boost/asio/packaged_task.hpp>
|
||||
#include <boost/asio/placeholders.hpp>
|
||||
#include <boost/asio/posix/basic_descriptor.hpp>
|
||||
@@ -109,14 +127,19 @@
|
||||
#include <boost/asio/posix/descriptor_base.hpp>
|
||||
#include <boost/asio/posix/stream_descriptor.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/asio/prefer.hpp>
|
||||
#include <boost/asio/query.hpp>
|
||||
#include <boost/asio/read.hpp>
|
||||
#include <boost/asio/read_at.hpp>
|
||||
#include <boost/asio/read_until.hpp>
|
||||
#include <boost/asio/redirect_error.hpp>
|
||||
#include <boost/asio/require.hpp>
|
||||
#include <boost/asio/require_concept.hpp>
|
||||
#include <boost/asio/serial_port.hpp>
|
||||
#include <boost/asio/serial_port_base.hpp>
|
||||
#include <boost/asio/signal_set.hpp>
|
||||
#include <boost/asio/socket_base.hpp>
|
||||
#include <boost/asio/static_thread_pool.hpp>
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/asio/streambuf.hpp>
|
||||
|
||||
73
include/boost/asio/any_io_executor.hpp
Normal file
73
include/boost/asio/any_io_executor.hpp
Normal file
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// any_io_executor.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_ASIO_ANY_IO_EXECUTOR_HPP
|
||||
#define BOOST_ASIO_ANY_IO_EXECUTOR_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include <boost/asio/detail/config.hpp>
|
||||
#if defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
|
||||
# include <boost/asio/executor.hpp>
|
||||
#else // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
|
||||
# include <boost/asio/execution.hpp>
|
||||
# include <boost/asio/execution_context.hpp>
|
||||
#endif // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
|
||||
#if defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
|
||||
|
||||
typedef executor any_io_executor;
|
||||
|
||||
#else // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
|
||||
|
||||
/// Polymorphic executor type for use with I/O objects.
|
||||
/**
|
||||
* The @c any_io_executor type is a polymorphic executor that supports the set
|
||||
* of properties required by I/O objects. It is defined as the
|
||||
* execution::any_executor class template parameterised as follows:
|
||||
* @code execution::any_executor<
|
||||
* execution::context_as_t<execution_context&>,
|
||||
* execution::blocking_t::never_t,
|
||||
* execution::prefer_only<execution::blocking_t::possibly_t>,
|
||||
* execution::prefer_only<execution::outstanding_work_t::tracked_t>,
|
||||
* execution::prefer_only<execution::outstanding_work_t::untracked_t>,
|
||||
* execution::prefer_only<execution::relationship_t::fork_t>,
|
||||
* execution::prefer_only<execution::relationship_t::continuation_t>
|
||||
* > @endcode
|
||||
*/
|
||||
#if defined(GENERATING_DOCUMENTATION)
|
||||
typedef execution::any_executor<...> any_io_executor;
|
||||
#else // defined(GENERATING_DOCUMENTATION)
|
||||
typedef execution::any_executor<
|
||||
execution::context_as_t<execution_context&>,
|
||||
execution::blocking_t::never_t,
|
||||
execution::prefer_only<execution::blocking_t::possibly_t>,
|
||||
execution::prefer_only<execution::outstanding_work_t::tracked_t>,
|
||||
execution::prefer_only<execution::outstanding_work_t::untracked_t>,
|
||||
execution::prefer_only<execution::relationship_t::fork_t>,
|
||||
execution::prefer_only<execution::relationship_t::continuation_t>
|
||||
> any_io_executor;
|
||||
#endif // defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
#endif // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
|
||||
|
||||
} // namespace asio
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#endif // BOOST_ASIO_ANY_IO_EXECUTOR_HPP
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <boost/asio/detail/config.hpp>
|
||||
#include <boost/asio/detail/type_traits.hpp>
|
||||
#include <boost/asio/execution/executor.hpp>
|
||||
#include <boost/asio/is_executor.hpp>
|
||||
#include <boost/asio/system_executor.hpp>
|
||||
|
||||
@@ -114,8 +115,9 @@ get_associated_executor(const T& t) BOOST_ASIO_NOEXCEPT
|
||||
template <typename T, typename Executor>
|
||||
inline typename associated_executor<T, Executor>::type
|
||||
get_associated_executor(const T& t, const Executor& ex,
|
||||
typename enable_if<is_executor<
|
||||
Executor>::value>::type* = 0) BOOST_ASIO_NOEXCEPT
|
||||
typename enable_if<
|
||||
is_executor<Executor>::value || execution::is_executor<Executor>::value
|
||||
>::type* = 0) BOOST_ASIO_NOEXCEPT
|
||||
{
|
||||
return associated_executor<T, Executor>::get(t, ex);
|
||||
}
|
||||
|
||||
@@ -19,8 +19,13 @@
|
||||
|
||||
#if defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
#include <experimental/coroutine>
|
||||
#include <boost/asio/executor.hpp>
|
||||
#if defined(BOOST_ASIO_HAS_STD_COROUTINE)
|
||||
# include <coroutine>
|
||||
#else // defined(BOOST_ASIO_HAS_STD_COROUTINE)
|
||||
# include <experimental/coroutine>
|
||||
#endif // defined(BOOST_ASIO_HAS_STD_COROUTINE)
|
||||
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
@@ -28,8 +33,13 @@ namespace boost {
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
#if defined(BOOST_ASIO_HAS_STD_COROUTINE)
|
||||
using std::coroutine_handle;
|
||||
using std::suspend_always;
|
||||
#else // defined(BOOST_ASIO_HAS_STD_COROUTINE)
|
||||
using std::experimental::coroutine_handle;
|
||||
using std::experimental::suspend_always;
|
||||
#endif // defined(BOOST_ASIO_HAS_STD_COROUTINE)
|
||||
|
||||
template <typename> class awaitable_thread;
|
||||
template <typename, typename> class awaitable_frame;
|
||||
@@ -37,7 +47,7 @@ template <typename, typename> class awaitable_frame;
|
||||
} // namespace detail
|
||||
|
||||
/// The return type of a coroutine or asynchronous operation.
|
||||
template <typename T, typename Executor = executor>
|
||||
template <typename T, typename Executor = any_io_executor>
|
||||
class awaitable
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace asio {
|
||||
#define BOOST_ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL
|
||||
|
||||
// Forward declaration with defaulted arguments.
|
||||
template <typename Protocol, typename Executor = executor>
|
||||
template <typename Protocol, typename Executor = any_io_executor>
|
||||
class basic_datagram_socket;
|
||||
|
||||
#endif // !defined(BOOST_ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL)
|
||||
@@ -1094,7 +1094,7 @@ private:
|
||||
detail::non_const_lvalue<WriteHandler> handler2(handler);
|
||||
self_->impl_.get_service().async_send(
|
||||
self_->impl_.get_implementation(), buffers, flags,
|
||||
handler2.value, self_->impl_.get_implementation_executor());
|
||||
handler2.value, self_->impl_.get_executor());
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -1127,8 +1127,8 @@ private:
|
||||
|
||||
detail::non_const_lvalue<WriteHandler> handler2(handler);
|
||||
self_->impl_.get_service().async_send_to(
|
||||
self_->impl_.get_implementation(), buffers, destination, flags,
|
||||
handler2.value, self_->impl_.get_implementation_executor());
|
||||
self_->impl_.get_implementation(), buffers, destination,
|
||||
flags, handler2.value, self_->impl_.get_executor());
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -1162,7 +1162,7 @@ private:
|
||||
detail::non_const_lvalue<ReadHandler> handler2(handler);
|
||||
self_->impl_.get_service().async_receive(
|
||||
self_->impl_.get_implementation(), buffers, flags,
|
||||
handler2.value, self_->impl_.get_implementation_executor());
|
||||
handler2.value, self_->impl_.get_executor());
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -1195,8 +1195,8 @@ private:
|
||||
|
||||
detail::non_const_lvalue<ReadHandler> handler2(handler);
|
||||
self_->impl_.get_service().async_receive_from(
|
||||
self_->impl_.get_implementation(), buffers, *sender_endpoint, flags,
|
||||
handler2.value, self_->impl_.get_implementation_executor());
|
||||
self_->impl_.get_implementation(), buffers, *sender_endpoint,
|
||||
flags, handler2.value, self_->impl_.get_executor());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|| defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
#include <cstddef>
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
#include <boost/asio/detail/deadline_timer_service.hpp>
|
||||
#include <boost/asio/detail/handler_type_requirements.hpp>
|
||||
#include <boost/asio/detail/io_object_impl.hpp>
|
||||
@@ -28,7 +29,6 @@
|
||||
#include <boost/asio/detail/throw_error.hpp>
|
||||
#include <boost/asio/error.hpp>
|
||||
#include <boost/asio/execution_context.hpp>
|
||||
#include <boost/asio/executor.hpp>
|
||||
#include <boost/asio/time_traits.hpp>
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
@@ -126,7 +126,7 @@ namespace asio {
|
||||
*/
|
||||
template <typename Time,
|
||||
typename TimeTraits = boost::asio::time_traits<Time>,
|
||||
typename Executor = executor>
|
||||
typename Executor = any_io_executor>
|
||||
class basic_deadline_timer
|
||||
{
|
||||
public:
|
||||
@@ -672,8 +672,8 @@ private:
|
||||
|
||||
detail::non_const_lvalue<WaitHandler> handler2(handler);
|
||||
self_->impl_.get_service().async_wait(
|
||||
self_->impl_.get_implementation(), handler2.value,
|
||||
self_->impl_.get_implementation_executor());
|
||||
self_->impl_.get_implementation(),
|
||||
handler2.value, self_->impl_.get_executor());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace asio {
|
||||
#define BOOST_ASIO_BASIC_RAW_SOCKET_FWD_DECL
|
||||
|
||||
// Forward declaration with defaulted arguments.
|
||||
template <typename Protocol, typename Executor = executor>
|
||||
template <typename Protocol, typename Executor = any_io_executor>
|
||||
class basic_raw_socket;
|
||||
|
||||
#endif // !defined(BOOST_ASIO_BASIC_RAW_SOCKET_FWD_DECL)
|
||||
@@ -1086,7 +1086,7 @@ private:
|
||||
detail::non_const_lvalue<WriteHandler> handler2(handler);
|
||||
self_->impl_.get_service().async_send(
|
||||
self_->impl_.get_implementation(), buffers, flags,
|
||||
handler2.value, self_->impl_.get_implementation_executor());
|
||||
handler2.value, self_->impl_.get_executor());
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -1119,8 +1119,8 @@ private:
|
||||
|
||||
detail::non_const_lvalue<WriteHandler> handler2(handler);
|
||||
self_->impl_.get_service().async_send_to(
|
||||
self_->impl_.get_implementation(), buffers, destination, flags,
|
||||
handler2.value, self_->impl_.get_implementation_executor());
|
||||
self_->impl_.get_implementation(), buffers, destination,
|
||||
flags, handler2.value, self_->impl_.get_executor());
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -1154,7 +1154,7 @@ private:
|
||||
detail::non_const_lvalue<ReadHandler> handler2(handler);
|
||||
self_->impl_.get_service().async_receive(
|
||||
self_->impl_.get_implementation(), buffers, flags,
|
||||
handler2.value, self_->impl_.get_implementation_executor());
|
||||
handler2.value, self_->impl_.get_executor());
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -1187,8 +1187,8 @@ private:
|
||||
|
||||
detail::non_const_lvalue<ReadHandler> handler2(handler);
|
||||
self_->impl_.get_service().async_receive_from(
|
||||
self_->impl_.get_implementation(), buffers, *sender_endpoint, flags,
|
||||
handler2.value, self_->impl_.get_implementation_executor());
|
||||
self_->impl_.get_implementation(), buffers, *sender_endpoint,
|
||||
flags, handler2.value, self_->impl_.get_executor());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace asio {
|
||||
#define BOOST_ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL
|
||||
|
||||
// Forward declaration with defaulted arguments.
|
||||
template <typename Protocol, typename Executor = executor>
|
||||
template <typename Protocol, typename Executor = any_io_executor>
|
||||
class basic_seq_packet_socket;
|
||||
|
||||
#endif // !defined(BOOST_ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL)
|
||||
@@ -707,7 +707,7 @@ private:
|
||||
detail::non_const_lvalue<WriteHandler> handler2(handler);
|
||||
self_->impl_.get_service().async_send(
|
||||
self_->impl_.get_implementation(), buffers, flags,
|
||||
handler2.value, self_->impl_.get_implementation_executor());
|
||||
handler2.value, self_->impl_.get_executor());
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -741,8 +741,8 @@ private:
|
||||
|
||||
detail::non_const_lvalue<ReadHandler> handler2(handler);
|
||||
self_->impl_.get_service().async_receive_with_flags(
|
||||
self_->impl_.get_implementation(), buffers, in_flags, *out_flags,
|
||||
handler2.value, self_->impl_.get_implementation_executor());
|
||||
self_->impl_.get_implementation(), buffers, in_flags,
|
||||
*out_flags, handler2.value, self_->impl_.get_executor());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|| defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
#include <string>
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
#include <boost/asio/async_result.hpp>
|
||||
#include <boost/asio/detail/handler_type_requirements.hpp>
|
||||
#include <boost/asio/detail/io_object_impl.hpp>
|
||||
@@ -30,7 +31,6 @@
|
||||
#include <boost/asio/detail/type_traits.hpp>
|
||||
#include <boost/asio/error.hpp>
|
||||
#include <boost/asio/execution_context.hpp>
|
||||
#include <boost/asio/executor.hpp>
|
||||
#include <boost/asio/serial_port_base.hpp>
|
||||
#if defined(BOOST_ASIO_HAS_IOCP)
|
||||
# include <boost/asio/detail/win_iocp_serial_port_service.hpp>
|
||||
@@ -56,7 +56,7 @@ namespace asio {
|
||||
* @e Distinct @e objects: Safe.@n
|
||||
* @e Shared @e objects: Unsafe.
|
||||
*/
|
||||
template <typename Executor = executor>
|
||||
template <typename Executor = any_io_executor>
|
||||
class basic_serial_port
|
||||
: public serial_port_base
|
||||
{
|
||||
@@ -850,8 +850,8 @@ private:
|
||||
|
||||
detail::non_const_lvalue<WriteHandler> handler2(handler);
|
||||
self_->impl_.get_service().async_write_some(
|
||||
self_->impl_.get_implementation(), buffers, handler2.value,
|
||||
self_->impl_.get_implementation_executor());
|
||||
self_->impl_.get_implementation(), buffers,
|
||||
handler2.value, self_->impl_.get_executor());
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -883,8 +883,8 @@ private:
|
||||
|
||||
detail::non_const_lvalue<ReadHandler> handler2(handler);
|
||||
self_->impl_.get_service().async_read_some(
|
||||
self_->impl_.get_implementation(), buffers, handler2.value,
|
||||
self_->impl_.get_implementation_executor());
|
||||
self_->impl_.get_implementation(), buffers,
|
||||
handler2.value, self_->impl_.get_executor());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <boost/asio/detail/config.hpp>
|
||||
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
#include <boost/asio/async_result.hpp>
|
||||
#include <boost/asio/detail/handler_type_requirements.hpp>
|
||||
#include <boost/asio/detail/io_object_impl.hpp>
|
||||
@@ -26,7 +27,6 @@
|
||||
#include <boost/asio/detail/type_traits.hpp>
|
||||
#include <boost/asio/error.hpp>
|
||||
#include <boost/asio/execution_context.hpp>
|
||||
#include <boost/asio/executor.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
@@ -91,7 +91,7 @@ namespace asio {
|
||||
* that any signals registered using signal_set objects are unblocked in at
|
||||
* least one thread.
|
||||
*/
|
||||
template <typename Executor = executor>
|
||||
template <typename Executor = any_io_executor>
|
||||
class basic_signal_set
|
||||
{
|
||||
public:
|
||||
@@ -553,8 +553,8 @@ private:
|
||||
|
||||
detail::non_const_lvalue<SignalHandler> handler2(handler);
|
||||
self_->impl_.get_service().async_wait(
|
||||
self_->impl_.get_implementation(), handler2.value,
|
||||
self_->impl_.get_implementation_executor());
|
||||
self_->impl_.get_implementation(),
|
||||
handler2.value, self_->impl_.get_executor());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
#include <boost/asio/detail/config.hpp>
|
||||
#include <boost/asio/async_result.hpp>
|
||||
#include <boost/asio/detail/handler_type_requirements.hpp>
|
||||
@@ -24,7 +25,6 @@
|
||||
#include <boost/asio/detail/type_traits.hpp>
|
||||
#include <boost/asio/error.hpp>
|
||||
#include <boost/asio/execution_context.hpp>
|
||||
#include <boost/asio/executor.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/asio/socket_base.hpp>
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace asio {
|
||||
#define BOOST_ASIO_BASIC_SOCKET_FWD_DECL
|
||||
|
||||
// Forward declaration with defaulted arguments.
|
||||
template <typename Protocol, typename Executor = executor>
|
||||
template <typename Protocol, typename Executor = any_io_executor>
|
||||
class basic_socket;
|
||||
|
||||
#endif // !defined(BOOST_ASIO_BASIC_SOCKET_FWD_DECL)
|
||||
@@ -1847,7 +1847,7 @@ private:
|
||||
detail::non_const_lvalue<ConnectHandler> handler2(handler);
|
||||
self_->impl_.get_service().async_connect(
|
||||
self_->impl_.get_implementation(), peer_endpoint,
|
||||
handler2.value, self_->impl_.get_implementation_executor());
|
||||
handler2.value, self_->impl_.get_executor());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1879,8 +1879,8 @@ private:
|
||||
|
||||
detail::non_const_lvalue<WaitHandler> handler2(handler);
|
||||
self_->impl_.get_service().async_wait(
|
||||
self_->impl_.get_implementation(), w, handler2.value,
|
||||
self_->impl_.get_implementation_executor());
|
||||
self_->impl_.get_implementation(), w,
|
||||
handler2.value, self_->impl_.get_executor());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include <boost/asio/detail/config.hpp>
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
#include <boost/asio/basic_socket.hpp>
|
||||
#include <boost/asio/detail/handler_type_requirements.hpp>
|
||||
#include <boost/asio/detail/io_object_impl.hpp>
|
||||
@@ -24,7 +25,6 @@
|
||||
#include <boost/asio/detail/type_traits.hpp>
|
||||
#include <boost/asio/error.hpp>
|
||||
#include <boost/asio/execution_context.hpp>
|
||||
#include <boost/asio/executor.hpp>
|
||||
#include <boost/asio/socket_base.hpp>
|
||||
|
||||
#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
|
||||
@@ -48,7 +48,7 @@ namespace asio {
|
||||
#define BOOST_ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL
|
||||
|
||||
// Forward declaration with defaulted arguments.
|
||||
template <typename Protocol, typename Executor = executor>
|
||||
template <typename Protocol, typename Executor = any_io_executor>
|
||||
class basic_socket_acceptor;
|
||||
|
||||
#endif // !defined(BOOST_ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL)
|
||||
@@ -2401,8 +2401,8 @@ private:
|
||||
|
||||
detail::non_const_lvalue<WaitHandler> handler2(handler);
|
||||
self_->impl_.get_service().async_wait(
|
||||
self_->impl_.get_implementation(), w, handler2.value,
|
||||
self_->impl_.get_implementation_executor());
|
||||
self_->impl_.get_implementation(), w,
|
||||
handler2.value, self_->impl_.get_executor());
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -2436,7 +2436,7 @@ private:
|
||||
detail::non_const_lvalue<AcceptHandler> handler2(handler);
|
||||
self_->impl_.get_service().async_accept(
|
||||
self_->impl_.get_implementation(), *peer, peer_endpoint,
|
||||
handler2.value, self_->impl_.get_implementation_executor());
|
||||
handler2.value, self_->impl_.get_executor());
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -2470,7 +2470,7 @@ private:
|
||||
detail::non_const_lvalue<MoveAcceptHandler> handler2(handler);
|
||||
self_->impl_.get_service().async_move_accept(
|
||||
self_->impl_.get_implementation(), peer_ex, peer_endpoint,
|
||||
handler2.value, self_->impl_.get_implementation_executor());
|
||||
handler2.value, self_->impl_.get_executor());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace asio {
|
||||
#define BOOST_ASIO_BASIC_STREAM_SOCKET_FWD_DECL
|
||||
|
||||
// Forward declaration with defaulted arguments.
|
||||
template <typename Protocol, typename Executor = executor>
|
||||
template <typename Protocol, typename Executor = any_io_executor>
|
||||
class basic_stream_socket;
|
||||
|
||||
#endif // !defined(BOOST_ASIO_BASIC_STREAM_SOCKET_FWD_DECL)
|
||||
@@ -1001,7 +1001,7 @@ private:
|
||||
detail::non_const_lvalue<WriteHandler> handler2(handler);
|
||||
self_->impl_.get_service().async_send(
|
||||
self_->impl_.get_implementation(), buffers, flags,
|
||||
handler2.value, self_->impl_.get_implementation_executor());
|
||||
handler2.value, self_->impl_.get_executor());
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -1035,7 +1035,7 @@ private:
|
||||
detail::non_const_lvalue<ReadHandler> handler2(handler);
|
||||
self_->impl_.get_service().async_receive(
|
||||
self_->impl_.get_implementation(), buffers, flags,
|
||||
handler2.value, self_->impl_.get_implementation_executor());
|
||||
handler2.value, self_->impl_.get_executor());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <boost/asio/detail/config.hpp>
|
||||
#include <cstddef>
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
#include <boost/asio/detail/chrono_time_traits.hpp>
|
||||
#include <boost/asio/detail/deadline_timer_service.hpp>
|
||||
#include <boost/asio/detail/handler_type_requirements.hpp>
|
||||
@@ -24,7 +25,6 @@
|
||||
#include <boost/asio/detail/non_const_lvalue.hpp>
|
||||
#include <boost/asio/detail/throw_error.hpp>
|
||||
#include <boost/asio/error.hpp>
|
||||
#include <boost/asio/executor.hpp>
|
||||
#include <boost/asio/wait_traits.hpp>
|
||||
|
||||
#if defined(BOOST_ASIO_HAS_MOVE)
|
||||
@@ -42,7 +42,7 @@ namespace asio {
|
||||
// Forward declaration with defaulted arguments.
|
||||
template <typename Clock,
|
||||
typename WaitTraits = boost::asio::wait_traits<Clock>,
|
||||
typename Executor = executor>
|
||||
typename Executor = any_io_executor>
|
||||
class basic_waitable_timer;
|
||||
|
||||
#endif // !defined(BOOST_ASIO_BASIC_WAITABLE_TIMER_FWD_DECL)
|
||||
@@ -319,6 +319,54 @@ public:
|
||||
impl_ = std::move(other.impl_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// All timers have access to each other's implementations.
|
||||
template <typename Clock1, typename WaitTraits1, typename Executor1>
|
||||
friend class basic_waitable_timer;
|
||||
|
||||
/// Move-construct a basic_waitable_timer from another.
|
||||
/**
|
||||
* This constructor moves a timer from one object to another.
|
||||
*
|
||||
* @param other The other basic_waitable_timer object from which the move will
|
||||
* occur.
|
||||
*
|
||||
* @note Following the move, the moved-from object is in the same state as if
|
||||
* constructed using the @c basic_waitable_timer(const executor_type&)
|
||||
* constructor.
|
||||
*/
|
||||
template <typename Executor1>
|
||||
basic_waitable_timer(
|
||||
basic_waitable_timer<Clock, WaitTraits, Executor1>&& other,
|
||||
typename enable_if<
|
||||
is_convertible<Executor1, Executor>::value
|
||||
>::type* = 0)
|
||||
: impl_(std::move(other.impl_))
|
||||
{
|
||||
}
|
||||
|
||||
/// Move-assign a basic_waitable_timer from another.
|
||||
/**
|
||||
* This assignment operator moves a timer from one object to another. Cancels
|
||||
* any outstanding asynchronous operations associated with the target object.
|
||||
*
|
||||
* @param other The other basic_waitable_timer object from which the move will
|
||||
* occur.
|
||||
*
|
||||
* @note Following the move, the moved-from object is in the same state as if
|
||||
* constructed using the @c basic_waitable_timer(const executor_type&)
|
||||
* constructor.
|
||||
*/
|
||||
template <typename Executor1>
|
||||
typename enable_if<
|
||||
is_convertible<Executor1, Executor>::value,
|
||||
basic_waitable_timer&
|
||||
>::type operator=(basic_waitable_timer<Clock, WaitTraits, Executor1>&& other)
|
||||
{
|
||||
basic_waitable_timer tmp(std::move(other));
|
||||
impl_ = std::move(tmp.impl_);
|
||||
return *this;
|
||||
}
|
||||
#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
/// Destroys the timer.
|
||||
@@ -743,8 +791,8 @@ private:
|
||||
|
||||
detail::non_const_lvalue<WaitHandler> handler2(handler);
|
||||
self_->impl_.get_service().async_wait(
|
||||
self_->impl_.get_implementation(), handler2.value,
|
||||
self_->impl_.get_implementation_executor());
|
||||
self_->impl_.get_implementation(),
|
||||
handler2.value, self_->impl_.get_executor());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <boost/asio/associated_executor.hpp>
|
||||
#include <boost/asio/associated_allocator.hpp>
|
||||
#include <boost/asio/async_result.hpp>
|
||||
#include <boost/asio/execution/executor.hpp>
|
||||
#include <boost/asio/execution_context.hpp>
|
||||
#include <boost/asio/is_executor.hpp>
|
||||
#include <boost/asio/uses_executor.hpp>
|
||||
@@ -155,16 +156,14 @@ struct executor_binder_argument_type<R(&)(A1, A2)>
|
||||
typedef A2 second_argument_type;
|
||||
};
|
||||
|
||||
// Helper to:
|
||||
// - Apply the empty base optimisation to the executor.
|
||||
// - Perform uses_executor construction of the target type, if required.
|
||||
// Helper to perform uses_executor construction of the target type, if
|
||||
// required.
|
||||
|
||||
template <typename T, typename Executor, bool UsesExecutor>
|
||||
class executor_binder_base;
|
||||
|
||||
template <typename T, typename Executor>
|
||||
class executor_binder_base<T, Executor, true>
|
||||
: protected Executor
|
||||
{
|
||||
protected:
|
||||
template <typename E, typename U>
|
||||
@@ -496,7 +495,9 @@ private:
|
||||
template <typename Executor, typename T>
|
||||
inline executor_binder<typename decay<T>::type, Executor>
|
||||
bind_executor(const Executor& ex, BOOST_ASIO_MOVE_ARG(T) t,
|
||||
typename enable_if<is_executor<Executor>::value>::type* = 0)
|
||||
typename enable_if<
|
||||
is_executor<Executor>::value || execution::is_executor<Executor>::value
|
||||
>::type* = 0)
|
||||
{
|
||||
return executor_binder<typename decay<T>::type, Executor>(
|
||||
executor_arg_t(), ex, BOOST_ASIO_MOVE_CAST(T)(t));
|
||||
|
||||
@@ -50,11 +50,13 @@
|
||||
|
||||
#if defined(BOOST_ASIO_HAS_BOOST_WORKAROUND)
|
||||
# include <boost/detail/workaround.hpp>
|
||||
# if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) \
|
||||
|| BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
|
||||
# if !defined(__clang__)
|
||||
# if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
|
||||
# define BOOST_ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND
|
||||
# endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
|
||||
# elif BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
|
||||
# define BOOST_ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND
|
||||
# endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
|
||||
// || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
|
||||
# endif // BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
|
||||
#endif // defined(BOOST_ASIO_HAS_BOOST_WORKAROUND)
|
||||
|
||||
#if defined(BOOST_ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND)
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#if defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
#include <boost/asio/awaitable.hpp>
|
||||
#include <boost/asio/execution/executor.hpp>
|
||||
#include <boost/asio/execution_context.hpp>
|
||||
#include <boost/asio/is_executor.hpp>
|
||||
|
||||
@@ -46,13 +47,321 @@ struct awaitable_signature<awaitable<void, Executor>>
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// Spawn a new thread of execution.
|
||||
/// Spawn a new coroutined-based thread of execution.
|
||||
/**
|
||||
* The entry point function object @c f must have the signature:
|
||||
* @param ex The executor that will be used to schedule the new thread of
|
||||
* execution.
|
||||
*
|
||||
* @code awaitable<void, E> f(); @endcode
|
||||
* @param a The boost::asio::awaitable object that is the result of calling the
|
||||
* coroutine's entry point function.
|
||||
*
|
||||
* where @c E is convertible from @c Executor.
|
||||
* @param token The completion token that will handle the notification that
|
||||
* the thread of execution has completed. The function signature of the
|
||||
* completion handler must be:
|
||||
* @code void handler(std::exception_ptr, T); @endcode
|
||||
*
|
||||
* @par Example
|
||||
* @code
|
||||
* boost::asio::awaitable<std::size_t> echo(tcp::socket socket)
|
||||
* {
|
||||
* std::size_t bytes_transferred = 0;
|
||||
*
|
||||
* try
|
||||
* {
|
||||
* char data[1024];
|
||||
* for (;;)
|
||||
* {
|
||||
* std::size_t n = co_await socket.async_read_some(
|
||||
* boost::asio::buffer(data), boost::asio::use_awaitable);
|
||||
*
|
||||
* co_await boost::asio::async_write(socket,
|
||||
* boost::asio::buffer(data, n), boost::asio::use_awaitable);
|
||||
*
|
||||
* bytes_transferred += n;
|
||||
* }
|
||||
* }
|
||||
* catch (const std::exception&)
|
||||
* {
|
||||
* }
|
||||
*
|
||||
* co_return bytes_transferred;
|
||||
* }
|
||||
*
|
||||
* // ...
|
||||
*
|
||||
* boost::asio::co_spawn(my_executor,
|
||||
* echo(std::move(my_tcp_socket)),
|
||||
* [](std::exception_ptr e, std::size_t n)
|
||||
* {
|
||||
* std::cout << "transferred " << n << "\n";
|
||||
* });
|
||||
* @endcode
|
||||
*/
|
||||
template <typename Executor, typename T, typename AwaitableExecutor,
|
||||
BOOST_ASIO_COMPLETION_TOKEN_FOR(
|
||||
void(std::exception_ptr, T)) CompletionToken
|
||||
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
|
||||
inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
|
||||
CompletionToken, void(std::exception_ptr, T))
|
||||
co_spawn(const Executor& ex, awaitable<T, AwaitableExecutor> a,
|
||||
CompletionToken&& token
|
||||
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
|
||||
typename enable_if<
|
||||
(is_executor<Executor>::value || execution::is_executor<Executor>::value)
|
||||
&& is_convertible<Executor, AwaitableExecutor>::value
|
||||
>::type* = 0);
|
||||
|
||||
/// Spawn a new coroutined-based thread of execution.
|
||||
/**
|
||||
* @param ex The executor that will be used to schedule the new thread of
|
||||
* execution.
|
||||
*
|
||||
* @param a The boost::asio::awaitable object that is the result of calling the
|
||||
* coroutine's entry point function.
|
||||
*
|
||||
* @param token The completion token that will handle the notification that
|
||||
* the thread of execution has completed. The function signature of the
|
||||
* completion handler must be:
|
||||
* @code void handler(std::exception_ptr); @endcode
|
||||
*
|
||||
* @par Example
|
||||
* @code
|
||||
* boost::asio::awaitable<void> echo(tcp::socket socket)
|
||||
* {
|
||||
* try
|
||||
* {
|
||||
* char data[1024];
|
||||
* for (;;)
|
||||
* {
|
||||
* std::size_t n = co_await socket.async_read_some(
|
||||
* boost::asio::buffer(data), boost::asio::use_awaitable);
|
||||
*
|
||||
* co_await boost::asio::async_write(socket,
|
||||
* boost::asio::buffer(data, n), boost::asio::use_awaitable);
|
||||
* }
|
||||
* }
|
||||
* catch (const std::exception& e)
|
||||
* {
|
||||
* std::cerr << "Exception: " << e.what() << "\n";
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* // ...
|
||||
*
|
||||
* boost::asio::co_spawn(my_executor,
|
||||
* echo(std::move(my_tcp_socket)),
|
||||
* boost::asio::detached);
|
||||
* @endcode
|
||||
*/
|
||||
template <typename Executor, typename AwaitableExecutor,
|
||||
BOOST_ASIO_COMPLETION_TOKEN_FOR(
|
||||
void(std::exception_ptr)) CompletionToken
|
||||
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
|
||||
inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
|
||||
CompletionToken, void(std::exception_ptr))
|
||||
co_spawn(const Executor& ex, awaitable<void, AwaitableExecutor> a,
|
||||
CompletionToken&& token
|
||||
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
|
||||
typename enable_if<
|
||||
(is_executor<Executor>::value || execution::is_executor<Executor>::value)
|
||||
&& is_convertible<Executor, AwaitableExecutor>::value
|
||||
>::type* = 0);
|
||||
|
||||
/// Spawn a new coroutined-based thread of execution.
|
||||
/**
|
||||
* @param ctx An execution context that will provide the executor to be used to
|
||||
* schedule the new thread of execution.
|
||||
*
|
||||
* @param a The boost::asio::awaitable object that is the result of calling the
|
||||
* coroutine's entry point function.
|
||||
*
|
||||
* @param token The completion token that will handle the notification that
|
||||
* the thread of execution has completed. The function signature of the
|
||||
* completion handler must be:
|
||||
* @code void handler(std::exception_ptr); @endcode
|
||||
*
|
||||
* @par Example
|
||||
* @code
|
||||
* boost::asio::awaitable<std::size_t> echo(tcp::socket socket)
|
||||
* {
|
||||
* std::size_t bytes_transferred = 0;
|
||||
*
|
||||
* try
|
||||
* {
|
||||
* char data[1024];
|
||||
* for (;;)
|
||||
* {
|
||||
* std::size_t n = co_await socket.async_read_some(
|
||||
* boost::asio::buffer(data), boost::asio::use_awaitable);
|
||||
*
|
||||
* co_await boost::asio::async_write(socket,
|
||||
* boost::asio::buffer(data, n), boost::asio::use_awaitable);
|
||||
*
|
||||
* bytes_transferred += n;
|
||||
* }
|
||||
* }
|
||||
* catch (const std::exception&)
|
||||
* {
|
||||
* }
|
||||
*
|
||||
* co_return bytes_transferred;
|
||||
* }
|
||||
*
|
||||
* // ...
|
||||
*
|
||||
* boost::asio::co_spawn(my_io_context,
|
||||
* echo(std::move(my_tcp_socket)),
|
||||
* [](std::exception_ptr e, std::size_t n)
|
||||
* {
|
||||
* std::cout << "transferred " << n << "\n";
|
||||
* });
|
||||
* @endcode
|
||||
*/
|
||||
template <typename ExecutionContext, typename T, typename AwaitableExecutor,
|
||||
BOOST_ASIO_COMPLETION_TOKEN_FOR(
|
||||
void(std::exception_ptr, T)) CompletionToken
|
||||
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
|
||||
typename ExecutionContext::executor_type)>
|
||||
inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
|
||||
CompletionToken, void(std::exception_ptr, T))
|
||||
co_spawn(ExecutionContext& ctx, awaitable<T, AwaitableExecutor> a,
|
||||
CompletionToken&& token
|
||||
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(
|
||||
typename ExecutionContext::executor_type),
|
||||
typename enable_if<
|
||||
is_convertible<ExecutionContext&, execution_context&>::value
|
||||
&& is_convertible<typename ExecutionContext::executor_type,
|
||||
AwaitableExecutor>::value
|
||||
>::type* = 0);
|
||||
|
||||
/// Spawn a new coroutined-based thread of execution.
|
||||
/**
|
||||
* @param ctx An execution context that will provide the executor to be used to
|
||||
* schedule the new thread of execution.
|
||||
*
|
||||
* @param a The boost::asio::awaitable object that is the result of calling the
|
||||
* coroutine's entry point function.
|
||||
*
|
||||
* @param token The completion token that will handle the notification that
|
||||
* the thread of execution has completed. The function signature of the
|
||||
* completion handler must be:
|
||||
* @code void handler(std::exception_ptr); @endcode
|
||||
*
|
||||
* @par Example
|
||||
* @code
|
||||
* boost::asio::awaitable<void> echo(tcp::socket socket)
|
||||
* {
|
||||
* try
|
||||
* {
|
||||
* char data[1024];
|
||||
* for (;;)
|
||||
* {
|
||||
* std::size_t n = co_await socket.async_read_some(
|
||||
* boost::asio::buffer(data), boost::asio::use_awaitable);
|
||||
*
|
||||
* co_await boost::asio::async_write(socket,
|
||||
* boost::asio::buffer(data, n), boost::asio::use_awaitable);
|
||||
* }
|
||||
* }
|
||||
* catch (const std::exception& e)
|
||||
* {
|
||||
* std::cerr << "Exception: " << e.what() << "\n";
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* // ...
|
||||
*
|
||||
* boost::asio::co_spawn(my_io_context,
|
||||
* echo(std::move(my_tcp_socket)),
|
||||
* boost::asio::detached);
|
||||
* @endcode
|
||||
*/
|
||||
template <typename ExecutionContext, typename AwaitableExecutor,
|
||||
BOOST_ASIO_COMPLETION_TOKEN_FOR(
|
||||
void(std::exception_ptr)) CompletionToken
|
||||
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
|
||||
typename ExecutionContext::executor_type)>
|
||||
inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
|
||||
CompletionToken, void(std::exception_ptr))
|
||||
co_spawn(ExecutionContext& ctx, awaitable<void, AwaitableExecutor> a,
|
||||
CompletionToken&& token
|
||||
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(
|
||||
typename ExecutionContext::executor_type),
|
||||
typename enable_if<
|
||||
is_convertible<ExecutionContext&, execution_context&>::value
|
||||
&& is_convertible<typename ExecutionContext::executor_type,
|
||||
AwaitableExecutor>::value
|
||||
>::type* = 0);
|
||||
|
||||
/// Spawn a new coroutined-based thread of execution.
|
||||
/**
|
||||
* @param ex The executor that will be used to schedule the new thread of
|
||||
* execution.
|
||||
*
|
||||
* @param f A nullary function object with a return type of the form
|
||||
* @c boost::asio::awaitable<R,E> that will be used as the coroutine's entry
|
||||
* point.
|
||||
*
|
||||
* @param token The completion token that will handle the notification that the
|
||||
* thread of execution has completed. If @c R is @c void, the function
|
||||
* signature of the completion handler must be:
|
||||
*
|
||||
* @code void handler(std::exception_ptr); @endcode
|
||||
* Otherwise, the function signature of the completion handler must be:
|
||||
* @code void handler(std::exception_ptr, R); @endcode
|
||||
*
|
||||
*
|
||||
* @par Example
|
||||
* @code
|
||||
* boost::asio::awaitable<std::size_t> echo(tcp::socket socket)
|
||||
* {
|
||||
* std::size_t bytes_transferred = 0;
|
||||
*
|
||||
* try
|
||||
* {
|
||||
* char data[1024];
|
||||
* for (;;)
|
||||
* {
|
||||
* std::size_t n = co_await socket.async_read_some(
|
||||
* boost::asio::buffer(data), boost::asio::use_awaitable);
|
||||
*
|
||||
* co_await boost::asio::async_write(socket,
|
||||
* boost::asio::buffer(data, n), boost::asio::use_awaitable);
|
||||
*
|
||||
* bytes_transferred += n;
|
||||
* }
|
||||
* }
|
||||
* catch (const std::exception&)
|
||||
* {
|
||||
* }
|
||||
*
|
||||
* co_return bytes_transferred;
|
||||
* }
|
||||
*
|
||||
* // ...
|
||||
*
|
||||
* boost::asio::co_spawn(my_executor,
|
||||
* [socket = std::move(my_tcp_socket)]() mutable
|
||||
* -> boost::asio::awaitable<void>
|
||||
* {
|
||||
* try
|
||||
* {
|
||||
* char data[1024];
|
||||
* for (;;)
|
||||
* {
|
||||
* std::size_t n = co_await socket.async_read_some(
|
||||
* boost::asio::buffer(data), boost::asio::use_awaitable);
|
||||
*
|
||||
* co_await boost::asio::async_write(socket,
|
||||
* boost::asio::buffer(data, n), boost::asio::use_awaitable);
|
||||
* }
|
||||
* }
|
||||
* catch (const std::exception& e)
|
||||
* {
|
||||
* std::cerr << "Exception: " << e.what() << "\n";
|
||||
* }
|
||||
* }, boost::asio::detached);
|
||||
* @endcode
|
||||
*/
|
||||
template <typename Executor, typename F,
|
||||
BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
|
||||
@@ -64,16 +373,78 @@ co_spawn(const Executor& ex, F&& f,
|
||||
CompletionToken&& token
|
||||
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
|
||||
typename enable_if<
|
||||
is_executor<Executor>::value
|
||||
is_executor<Executor>::value || execution::is_executor<Executor>::value
|
||||
>::type* = 0);
|
||||
|
||||
/// Spawn a new thread of execution.
|
||||
/// Spawn a new coroutined-based thread of execution.
|
||||
/**
|
||||
* The entry point function object @c f must have the signature:
|
||||
* @param ctx An execution context that will provide the executor to be used to
|
||||
* schedule the new thread of execution.
|
||||
*
|
||||
* @code awaitable<void, E> f(); @endcode
|
||||
* @param f A nullary function object with a return type of the form
|
||||
* @c boost::asio::awaitable<R,E> that will be used as the coroutine's entry
|
||||
* point.
|
||||
*
|
||||
* where @c E is convertible from @c ExecutionContext::executor_type.
|
||||
* @param token The completion token that will handle the notification that the
|
||||
* thread of execution has completed. If @c R is @c void, the function
|
||||
* signature of the completion handler must be:
|
||||
*
|
||||
* @code void handler(std::exception_ptr); @endcode
|
||||
* Otherwise, the function signature of the completion handler must be:
|
||||
* @code void handler(std::exception_ptr, R); @endcode
|
||||
*
|
||||
*
|
||||
* @par Example
|
||||
* @code
|
||||
* boost::asio::awaitable<std::size_t> echo(tcp::socket socket)
|
||||
* {
|
||||
* std::size_t bytes_transferred = 0;
|
||||
*
|
||||
* try
|
||||
* {
|
||||
* char data[1024];
|
||||
* for (;;)
|
||||
* {
|
||||
* std::size_t n = co_await socket.async_read_some(
|
||||
* boost::asio::buffer(data), boost::asio::use_awaitable);
|
||||
*
|
||||
* co_await boost::asio::async_write(socket,
|
||||
* boost::asio::buffer(data, n), boost::asio::use_awaitable);
|
||||
*
|
||||
* bytes_transferred += n;
|
||||
* }
|
||||
* }
|
||||
* catch (const std::exception&)
|
||||
* {
|
||||
* }
|
||||
*
|
||||
* co_return bytes_transferred;
|
||||
* }
|
||||
*
|
||||
* // ...
|
||||
*
|
||||
* boost::asio::co_spawn(my_io_context,
|
||||
* [socket = std::move(my_tcp_socket)]() mutable
|
||||
* -> boost::asio::awaitable<void>
|
||||
* {
|
||||
* try
|
||||
* {
|
||||
* char data[1024];
|
||||
* for (;;)
|
||||
* {
|
||||
* std::size_t n = co_await socket.async_read_some(
|
||||
* boost::asio::buffer(data), boost::asio::use_awaitable);
|
||||
*
|
||||
* co_await boost::asio::async_write(socket,
|
||||
* boost::asio::buffer(data, n), boost::asio::use_awaitable);
|
||||
* }
|
||||
* }
|
||||
* catch (const std::exception& e)
|
||||
* {
|
||||
* std::cerr << "Exception: " << e.what() << "\n";
|
||||
* }
|
||||
* }, boost::asio::detached);
|
||||
* @endcode
|
||||
*/
|
||||
template <typename ExecutionContext, typename F,
|
||||
BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <boost/asio/async_result.hpp>
|
||||
#include <boost/asio/detail/type_traits.hpp>
|
||||
#include <boost/asio/execution_context.hpp>
|
||||
#include <boost/asio/execution/executor.hpp>
|
||||
#include <boost/asio/is_executor.hpp>
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
@@ -101,7 +102,9 @@ BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer(
|
||||
const Executor& ex,
|
||||
BOOST_ASIO_MOVE_ARG(CompletionToken) token
|
||||
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
|
||||
typename enable_if<is_executor<Executor>::value>::type* = 0);
|
||||
typename enable_if<
|
||||
execution::is_executor<Executor>::value || is_executor<Executor>::value
|
||||
>::type* = 0);
|
||||
|
||||
/// Submits a completion token or function object for execution.
|
||||
/**
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <boost/asio/detail/config.hpp>
|
||||
#include <memory>
|
||||
#include <boost/asio/detail/type_traits.hpp>
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
@@ -42,6 +43,55 @@ public:
|
||||
BOOST_ASIO_CONSTEXPR detached_t()
|
||||
{
|
||||
}
|
||||
|
||||
/// Adapts an executor to add the @c detached_t completion token as the
|
||||
/// default.
|
||||
template <typename InnerExecutor>
|
||||
struct executor_with_default : InnerExecutor
|
||||
{
|
||||
/// Specify @c detached_t as the default completion token type.
|
||||
typedef detached_t default_completion_token_type;
|
||||
|
||||
/// Construct the adapted executor from the inner executor type.
|
||||
executor_with_default(const InnerExecutor& ex) BOOST_ASIO_NOEXCEPT
|
||||
: InnerExecutor(ex)
|
||||
{
|
||||
}
|
||||
|
||||
/// Convert the specified executor to the inner executor type, then use
|
||||
/// that to construct the adapted executor.
|
||||
template <typename OtherExecutor>
|
||||
executor_with_default(const OtherExecutor& ex,
|
||||
typename enable_if<
|
||||
is_convertible<OtherExecutor, InnerExecutor>::value
|
||||
>::type* = 0) BOOST_ASIO_NOEXCEPT
|
||||
: InnerExecutor(ex)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/// Type alias to adapt an I/O object to use @c detached_t as its
|
||||
/// default completion token type.
|
||||
#if defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) \
|
||||
|| defined(GENERATING_DOCUMENTATION)
|
||||
template <typename T>
|
||||
using as_default_on_t = typename T::template rebind_executor<
|
||||
executor_with_default<typename T::executor_type> >::other;
|
||||
#endif // defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES)
|
||||
// || defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
/// Function helper to adapt an I/O object to use @c detached_t as its
|
||||
/// default completion token type.
|
||||
template <typename T>
|
||||
static typename decay<T>::type::template rebind_executor<
|
||||
executor_with_default<typename decay<T>::type::executor_type>
|
||||
>::other
|
||||
as_default_on(BOOST_ASIO_MOVE_ARG(T) object)
|
||||
{
|
||||
return typename decay<T>::type::template rebind_executor<
|
||||
executor_with_default<typename decay<T>::type::executor_type>
|
||||
>::other(BOOST_ASIO_MOVE_CAST(T)(object));
|
||||
}
|
||||
};
|
||||
|
||||
/// A special value, similar to std::nothrow.
|
||||
|
||||
@@ -29,4 +29,12 @@
|
||||
# define BOOST_ASIO_ASSERT(expr) assert(expr)
|
||||
#endif // defined(BOOST_ASIO_HAS_BOOST_ASSERT)
|
||||
|
||||
#if defined(BOOST_ASIO_HAS_STATIC_ASSERT)
|
||||
# define BOOST_ASIO_STATIC_ASSERT(c, n, m) static_assert((c), m)
|
||||
#else // defined(BOOST_ASIO_HAS_STATIC_ASSERT)
|
||||
# define BOOST_ASIO_STATIC_ASSERT(c, n, m) \
|
||||
typedef char static_assert_ ## n \
|
||||
[(c) ? 1 : -1] BOOST_ASIO_UNUSED_TYPEDEF
|
||||
#endif // defined(BOOST_ASIO_HAS_STATIC_ASSERT)
|
||||
|
||||
#endif // BOOST_ASIO_DETAIL_ASSERT_HPP
|
||||
|
||||
@@ -32,12 +32,31 @@ namespace detail {
|
||||
#if !defined(BOOST_ASIO_HAS_THREADS)
|
||||
typedef long atomic_count;
|
||||
inline void increment(atomic_count& a, long b) { a += b; }
|
||||
inline void ref_count_up(atomic_count& a) { ++a; }
|
||||
inline bool ref_count_down(atomic_count& a) { return --a == 0; }
|
||||
#elif defined(BOOST_ASIO_HAS_STD_ATOMIC)
|
||||
typedef std::atomic<long> atomic_count;
|
||||
inline void increment(atomic_count& a, long b) { a += b; }
|
||||
|
||||
inline void ref_count_up(atomic_count& a)
|
||||
{
|
||||
a.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline bool ref_count_down(atomic_count& a)
|
||||
{
|
||||
if (a.fetch_sub(1, std::memory_order_release) == 1)
|
||||
{
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#else // defined(BOOST_ASIO_HAS_STD_ATOMIC)
|
||||
typedef boost::detail::atomic_count atomic_count;
|
||||
inline void increment(atomic_count& a, long b) { while (b > 0) ++a, --b; }
|
||||
inline void ref_count_up(atomic_count& a) { ++a; }
|
||||
inline bool ref_count_down(atomic_count& a) { return --a == 0; }
|
||||
#endif // defined(BOOST_ASIO_HAS_STD_ATOMIC)
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -76,19 +76,29 @@ public:
|
||||
};
|
||||
|
||||
template <typename Handler, typename Arg1>
|
||||
inline void* asio_handler_allocate(std::size_t size,
|
||||
inline asio_handler_allocate_is_deprecated
|
||||
asio_handler_allocate(std::size_t size,
|
||||
binder1<Handler, Arg1>* this_handler)
|
||||
{
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
|
||||
return asio_handler_allocate_is_no_longer_used();
|
||||
#else // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return boost_asio_handler_alloc_helpers::allocate(
|
||||
size, this_handler->handler_);
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
template <typename Handler, typename Arg1>
|
||||
inline void asio_handler_deallocate(void* pointer, std::size_t size,
|
||||
inline asio_handler_deallocate_is_deprecated
|
||||
asio_handler_deallocate(void* pointer, std::size_t size,
|
||||
binder1<Handler, Arg1>* this_handler)
|
||||
{
|
||||
boost_asio_handler_alloc_helpers::deallocate(
|
||||
pointer, size, this_handler->handler_);
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return asio_handler_deallocate_is_no_longer_used();
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
template <typename Handler, typename Arg1>
|
||||
@@ -100,19 +110,27 @@ inline bool asio_handler_is_continuation(
|
||||
}
|
||||
|
||||
template <typename Function, typename Handler, typename Arg1>
|
||||
inline void asio_handler_invoke(Function& function,
|
||||
inline asio_handler_invoke_is_deprecated
|
||||
asio_handler_invoke(Function& function,
|
||||
binder1<Handler, Arg1>* this_handler)
|
||||
{
|
||||
boost_asio_handler_invoke_helpers::invoke(
|
||||
function, this_handler->handler_);
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return asio_handler_invoke_is_no_longer_used();
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
template <typename Function, typename Handler, typename Arg1>
|
||||
inline void asio_handler_invoke(const Function& function,
|
||||
inline asio_handler_invoke_is_deprecated
|
||||
asio_handler_invoke(const Function& function,
|
||||
binder1<Handler, Arg1>* this_handler)
|
||||
{
|
||||
boost_asio_handler_invoke_helpers::invoke(
|
||||
function, this_handler->handler_);
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return asio_handler_invoke_is_no_longer_used();
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
template <typename Handler, typename Arg1>
|
||||
@@ -177,19 +195,29 @@ public:
|
||||
};
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2>
|
||||
inline void* asio_handler_allocate(std::size_t size,
|
||||
inline asio_handler_allocate_is_deprecated
|
||||
asio_handler_allocate(std::size_t size,
|
||||
binder2<Handler, Arg1, Arg2>* this_handler)
|
||||
{
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
|
||||
return asio_handler_allocate_is_no_longer_used();
|
||||
#else // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return boost_asio_handler_alloc_helpers::allocate(
|
||||
size, this_handler->handler_);
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2>
|
||||
inline void asio_handler_deallocate(void* pointer, std::size_t size,
|
||||
inline asio_handler_deallocate_is_deprecated
|
||||
asio_handler_deallocate(void* pointer, std::size_t size,
|
||||
binder2<Handler, Arg1, Arg2>* this_handler)
|
||||
{
|
||||
boost_asio_handler_alloc_helpers::deallocate(
|
||||
pointer, size, this_handler->handler_);
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return asio_handler_deallocate_is_no_longer_used();
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2>
|
||||
@@ -201,19 +229,27 @@ inline bool asio_handler_is_continuation(
|
||||
}
|
||||
|
||||
template <typename Function, typename Handler, typename Arg1, typename Arg2>
|
||||
inline void asio_handler_invoke(Function& function,
|
||||
inline asio_handler_invoke_is_deprecated
|
||||
asio_handler_invoke(Function& function,
|
||||
binder2<Handler, Arg1, Arg2>* this_handler)
|
||||
{
|
||||
boost_asio_handler_invoke_helpers::invoke(
|
||||
function, this_handler->handler_);
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return asio_handler_invoke_is_no_longer_used();
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
template <typename Function, typename Handler, typename Arg1, typename Arg2>
|
||||
inline void asio_handler_invoke(const Function& function,
|
||||
inline asio_handler_invoke_is_deprecated
|
||||
asio_handler_invoke(const Function& function,
|
||||
binder2<Handler, Arg1, Arg2>* this_handler)
|
||||
{
|
||||
boost_asio_handler_invoke_helpers::invoke(
|
||||
function, this_handler->handler_);
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return asio_handler_invoke_is_no_longer_used();
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2>
|
||||
@@ -284,19 +320,29 @@ public:
|
||||
};
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
|
||||
inline void* asio_handler_allocate(std::size_t size,
|
||||
inline asio_handler_allocate_is_deprecated
|
||||
asio_handler_allocate(std::size_t size,
|
||||
binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
|
||||
{
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
|
||||
return asio_handler_allocate_is_no_longer_used();
|
||||
#else // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return boost_asio_handler_alloc_helpers::allocate(
|
||||
size, this_handler->handler_);
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
|
||||
inline void asio_handler_deallocate(void* pointer, std::size_t size,
|
||||
inline asio_handler_deallocate_is_deprecated
|
||||
asio_handler_deallocate(void* pointer, std::size_t size,
|
||||
binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
|
||||
{
|
||||
boost_asio_handler_alloc_helpers::deallocate(
|
||||
pointer, size, this_handler->handler_);
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return asio_handler_deallocate_is_no_longer_used();
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
|
||||
@@ -309,20 +355,28 @@ inline bool asio_handler_is_continuation(
|
||||
|
||||
template <typename Function, typename Handler,
|
||||
typename Arg1, typename Arg2, typename Arg3>
|
||||
inline void asio_handler_invoke(Function& function,
|
||||
inline asio_handler_invoke_is_deprecated
|
||||
asio_handler_invoke(Function& function,
|
||||
binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
|
||||
{
|
||||
boost_asio_handler_invoke_helpers::invoke(
|
||||
function, this_handler->handler_);
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return asio_handler_invoke_is_no_longer_used();
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
template <typename Function, typename Handler,
|
||||
typename Arg1, typename Arg2, typename Arg3>
|
||||
inline void asio_handler_invoke(const Function& function,
|
||||
inline asio_handler_invoke_is_deprecated
|
||||
asio_handler_invoke(const Function& function,
|
||||
binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
|
||||
{
|
||||
boost_asio_handler_invoke_helpers::invoke(
|
||||
function, this_handler->handler_);
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return asio_handler_invoke_is_no_longer_used();
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
|
||||
@@ -402,20 +456,30 @@ public:
|
||||
|
||||
template <typename Handler, typename Arg1,
|
||||
typename Arg2, typename Arg3, typename Arg4>
|
||||
inline void* asio_handler_allocate(std::size_t size,
|
||||
inline asio_handler_allocate_is_deprecated
|
||||
asio_handler_allocate(std::size_t size,
|
||||
binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
|
||||
{
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
|
||||
return asio_handler_allocate_is_no_longer_used();
|
||||
#else // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return boost_asio_handler_alloc_helpers::allocate(
|
||||
size, this_handler->handler_);
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
template <typename Handler, typename Arg1,
|
||||
typename Arg2, typename Arg3, typename Arg4>
|
||||
inline void asio_handler_deallocate(void* pointer, std::size_t size,
|
||||
inline asio_handler_deallocate_is_deprecated
|
||||
asio_handler_deallocate(void* pointer, std::size_t size,
|
||||
binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
|
||||
{
|
||||
boost_asio_handler_alloc_helpers::deallocate(
|
||||
pointer, size, this_handler->handler_);
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return asio_handler_deallocate_is_no_longer_used();
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
template <typename Handler, typename Arg1,
|
||||
@@ -429,20 +493,28 @@ inline bool asio_handler_is_continuation(
|
||||
|
||||
template <typename Function, typename Handler, typename Arg1,
|
||||
typename Arg2, typename Arg3, typename Arg4>
|
||||
inline void asio_handler_invoke(Function& function,
|
||||
inline asio_handler_invoke_is_deprecated
|
||||
asio_handler_invoke(Function& function,
|
||||
binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
|
||||
{
|
||||
boost_asio_handler_invoke_helpers::invoke(
|
||||
function, this_handler->handler_);
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return asio_handler_invoke_is_no_longer_used();
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
template <typename Function, typename Handler, typename Arg1,
|
||||
typename Arg2, typename Arg3, typename Arg4>
|
||||
inline void asio_handler_invoke(const Function& function,
|
||||
inline asio_handler_invoke_is_deprecated
|
||||
asio_handler_invoke(const Function& function,
|
||||
binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
|
||||
{
|
||||
boost_asio_handler_invoke_helpers::invoke(
|
||||
function, this_handler->handler_);
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return asio_handler_invoke_is_no_longer_used();
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
template <typename Handler, typename Arg1,
|
||||
@@ -528,20 +600,30 @@ public:
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2,
|
||||
typename Arg3, typename Arg4, typename Arg5>
|
||||
inline void* asio_handler_allocate(std::size_t size,
|
||||
inline asio_handler_allocate_is_deprecated
|
||||
asio_handler_allocate(std::size_t size,
|
||||
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
|
||||
{
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
|
||||
return asio_handler_allocate_is_no_longer_used();
|
||||
#else // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return boost_asio_handler_alloc_helpers::allocate(
|
||||
size, this_handler->handler_);
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2,
|
||||
typename Arg3, typename Arg4, typename Arg5>
|
||||
inline void asio_handler_deallocate(void* pointer, std::size_t size,
|
||||
inline asio_handler_deallocate_is_deprecated
|
||||
asio_handler_deallocate(void* pointer, std::size_t size,
|
||||
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
|
||||
{
|
||||
boost_asio_handler_alloc_helpers::deallocate(
|
||||
pointer, size, this_handler->handler_);
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return asio_handler_deallocate_is_no_longer_used();
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2,
|
||||
@@ -555,20 +637,28 @@ inline bool asio_handler_is_continuation(
|
||||
|
||||
template <typename Function, typename Handler, typename Arg1,
|
||||
typename Arg2, typename Arg3, typename Arg4, typename Arg5>
|
||||
inline void asio_handler_invoke(Function& function,
|
||||
inline asio_handler_invoke_is_deprecated
|
||||
asio_handler_invoke(Function& function,
|
||||
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
|
||||
{
|
||||
boost_asio_handler_invoke_helpers::invoke(
|
||||
function, this_handler->handler_);
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return asio_handler_invoke_is_no_longer_used();
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
template <typename Function, typename Handler, typename Arg1,
|
||||
typename Arg2, typename Arg3, typename Arg4, typename Arg5>
|
||||
inline void asio_handler_invoke(const Function& function,
|
||||
inline asio_handler_invoke_is_deprecated
|
||||
asio_handler_invoke(const Function& function,
|
||||
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
|
||||
{
|
||||
boost_asio_handler_invoke_helpers::invoke(
|
||||
function, this_handler->handler_);
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return asio_handler_invoke_is_no_longer_used();
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2,
|
||||
@@ -611,19 +701,29 @@ public:
|
||||
};
|
||||
|
||||
template <typename Handler, typename Arg1>
|
||||
inline void* asio_handler_allocate(std::size_t size,
|
||||
inline asio_handler_allocate_is_deprecated
|
||||
asio_handler_allocate(std::size_t size,
|
||||
move_binder1<Handler, Arg1>* this_handler)
|
||||
{
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
|
||||
return asio_handler_allocate_is_no_longer_used();
|
||||
#else // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return boost_asio_handler_alloc_helpers::allocate(
|
||||
size, this_handler->handler_);
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
template <typename Handler, typename Arg1>
|
||||
inline void asio_handler_deallocate(void* pointer, std::size_t size,
|
||||
inline asio_handler_deallocate_is_deprecated
|
||||
asio_handler_deallocate(void* pointer, std::size_t size,
|
||||
move_binder1<Handler, Arg1>* this_handler)
|
||||
{
|
||||
boost_asio_handler_alloc_helpers::deallocate(
|
||||
pointer, size, this_handler->handler_);
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return asio_handler_deallocate_is_no_longer_used();
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
template <typename Handler, typename Arg1>
|
||||
@@ -635,11 +735,15 @@ inline bool asio_handler_is_continuation(
|
||||
}
|
||||
|
||||
template <typename Function, typename Handler, typename Arg1>
|
||||
inline void asio_handler_invoke(BOOST_ASIO_MOVE_ARG(Function) function,
|
||||
inline asio_handler_invoke_is_deprecated
|
||||
asio_handler_invoke(BOOST_ASIO_MOVE_ARG(Function) function,
|
||||
move_binder1<Handler, Arg1>* this_handler)
|
||||
{
|
||||
boost_asio_handler_invoke_helpers::invoke(
|
||||
BOOST_ASIO_MOVE_CAST(Function)(function), this_handler->handler_);
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return asio_handler_invoke_is_no_longer_used();
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2>
|
||||
@@ -674,19 +778,29 @@ public:
|
||||
};
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2>
|
||||
inline void* asio_handler_allocate(std::size_t size,
|
||||
inline asio_handler_allocate_is_deprecated
|
||||
asio_handler_allocate(std::size_t size,
|
||||
move_binder2<Handler, Arg1, Arg2>* this_handler)
|
||||
{
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_);
|
||||
return asio_handler_allocate_is_no_longer_used();
|
||||
#else // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return boost_asio_handler_alloc_helpers::allocate(
|
||||
size, this_handler->handler_);
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2>
|
||||
inline void asio_handler_deallocate(void* pointer, std::size_t size,
|
||||
inline asio_handler_deallocate_is_deprecated
|
||||
asio_handler_deallocate(void* pointer, std::size_t size,
|
||||
move_binder2<Handler, Arg1, Arg2>* this_handler)
|
||||
{
|
||||
boost_asio_handler_alloc_helpers::deallocate(
|
||||
pointer, size, this_handler->handler_);
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return asio_handler_deallocate_is_no_longer_used();
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
template <typename Handler, typename Arg1, typename Arg2>
|
||||
@@ -698,11 +812,15 @@ inline bool asio_handler_is_continuation(
|
||||
}
|
||||
|
||||
template <typename Function, typename Handler, typename Arg1, typename Arg2>
|
||||
inline void asio_handler_invoke(BOOST_ASIO_MOVE_ARG(Function) function,
|
||||
inline asio_handler_invoke_is_deprecated
|
||||
asio_handler_invoke(BOOST_ASIO_MOVE_ARG(Function) function,
|
||||
move_binder2<Handler, Arg1, Arg2>* this_handler)
|
||||
{
|
||||
boost_asio_handler_invoke_helpers::invoke(
|
||||
BOOST_ASIO_MOVE_CAST(Function)(function), this_handler->handler_);
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
return asio_handler_invoke_is_no_longer_used();
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
}
|
||||
|
||||
#endif // defined(BOOST_ASIO_HAS_MOVE)
|
||||
|
||||
109
include/boost/asio/detail/blocking_executor_op.hpp
Normal file
109
include/boost/asio/detail/blocking_executor_op.hpp
Normal file
@@ -0,0 +1,109 @@
|
||||
//
|
||||
// detail/blocking_executor_op.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_ASIO_DETAIL_BLOCKING_EXECUTOR_OP_HPP
|
||||
#define BOOST_ASIO_DETAIL_BLOCKING_EXECUTOR_OP_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include <boost/asio/detail/config.hpp>
|
||||
#include <boost/asio/detail/event.hpp>
|
||||
#include <boost/asio/detail/fenced_block.hpp>
|
||||
#include <boost/asio/detail/handler_invoke_helpers.hpp>
|
||||
#include <boost/asio/detail/mutex.hpp>
|
||||
#include <boost/asio/detail/scheduler_operation.hpp>
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
template <typename Operation = scheduler_operation>
|
||||
class blocking_executor_op_base : public Operation
|
||||
{
|
||||
public:
|
||||
blocking_executor_op_base(typename Operation::func_type complete_func)
|
||||
: Operation(complete_func),
|
||||
is_complete_(false)
|
||||
{
|
||||
}
|
||||
|
||||
void wait()
|
||||
{
|
||||
boost::asio::detail::mutex::scoped_lock lock(mutex_);
|
||||
while (!is_complete_)
|
||||
event_.wait(lock);
|
||||
}
|
||||
|
||||
protected:
|
||||
struct do_complete_cleanup
|
||||
{
|
||||
~do_complete_cleanup()
|
||||
{
|
||||
boost::asio::detail::mutex::scoped_lock lock(op_->mutex_);
|
||||
op_->is_complete_ = true;
|
||||
op_->event_.unlock_and_signal_one_for_destruction(lock);
|
||||
}
|
||||
|
||||
blocking_executor_op_base* op_;
|
||||
};
|
||||
|
||||
private:
|
||||
boost::asio::detail::mutex mutex_;
|
||||
boost::asio::detail::event event_;
|
||||
bool is_complete_;
|
||||
};
|
||||
|
||||
template <typename Handler, typename Operation = scheduler_operation>
|
||||
class blocking_executor_op : public blocking_executor_op_base<Operation>
|
||||
{
|
||||
public:
|
||||
blocking_executor_op(Handler& h)
|
||||
: blocking_executor_op_base<Operation>(&blocking_executor_op::do_complete),
|
||||
handler_(h)
|
||||
{
|
||||
}
|
||||
|
||||
static void do_complete(void* owner, Operation* base,
|
||||
const boost::system::error_code& /*ec*/,
|
||||
std::size_t /*bytes_transferred*/)
|
||||
{
|
||||
blocking_executor_op* o(static_cast<blocking_executor_op*>(base));
|
||||
|
||||
typename blocking_executor_op_base<Operation>::do_complete_cleanup
|
||||
on_exit = { o };
|
||||
(void)on_exit;
|
||||
|
||||
BOOST_ASIO_HANDLER_COMPLETION((*o));
|
||||
|
||||
// Make the upcall if required.
|
||||
if (owner)
|
||||
{
|
||||
fenced_block b(fenced_block::half);
|
||||
BOOST_ASIO_HANDLER_INVOCATION_BEGIN(());
|
||||
boost_asio_handler_invoke_helpers::invoke(o->handler_, o->handler_);
|
||||
BOOST_ASIO_HANDLER_INVOCATION_END;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Handler& handler_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace asio
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#endif // BOOST_ASIO_DETAIL_BLOCKING_EXECUTOR_OP_HPP
|
||||
@@ -105,6 +105,8 @@ class buffer_sequence_adapter
|
||||
: buffer_sequence_adapter_base
|
||||
{
|
||||
public:
|
||||
enum { is_single_buffer = false };
|
||||
|
||||
explicit buffer_sequence_adapter(const Buffers& buffer_sequence)
|
||||
: count_(0), total_buffer_size_(0)
|
||||
{
|
||||
@@ -154,6 +156,16 @@ public:
|
||||
boost::asio::buffer_sequence_end(buffer_sequence));
|
||||
}
|
||||
|
||||
enum { linearisation_storage_size = 8192 };
|
||||
|
||||
static Buffer linearise(const Buffers& buffer_sequence,
|
||||
const boost::asio::mutable_buffer& storage)
|
||||
{
|
||||
return buffer_sequence_adapter::linearise(
|
||||
boost::asio::buffer_sequence_begin(buffer_sequence),
|
||||
boost::asio::buffer_sequence_end(buffer_sequence), storage);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Iterator>
|
||||
void init(Iterator begin, Iterator end)
|
||||
@@ -202,6 +214,30 @@ private:
|
||||
return Buffer();
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
static Buffer linearise(Iterator begin, Iterator end,
|
||||
const boost::asio::mutable_buffer& storage)
|
||||
{
|
||||
boost::asio::mutable_buffer unused_storage = storage;
|
||||
Iterator iter = begin;
|
||||
while (iter != end && unused_storage.size() != 0)
|
||||
{
|
||||
Buffer buffer(*iter);
|
||||
++iter;
|
||||
if (buffer.size() == 0)
|
||||
continue;
|
||||
if (unused_storage.size() == storage.size())
|
||||
{
|
||||
if (iter == end)
|
||||
return buffer;
|
||||
if (buffer.size() >= unused_storage.size())
|
||||
return buffer;
|
||||
}
|
||||
unused_storage += boost::asio::buffer_copy(unused_storage, buffer);
|
||||
}
|
||||
return Buffer(storage.data(), storage.size() - unused_storage.size());
|
||||
}
|
||||
|
||||
native_buffer_type buffers_[max_buffers];
|
||||
std::size_t count_;
|
||||
std::size_t total_buffer_size_;
|
||||
@@ -212,6 +248,8 @@ class buffer_sequence_adapter<Buffer, boost::asio::mutable_buffer>
|
||||
: buffer_sequence_adapter_base
|
||||
{
|
||||
public:
|
||||
enum { is_single_buffer = true };
|
||||
|
||||
explicit buffer_sequence_adapter(
|
||||
const boost::asio::mutable_buffer& buffer_sequence)
|
||||
{
|
||||
@@ -254,6 +292,14 @@ public:
|
||||
return Buffer(buffer_sequence);
|
||||
}
|
||||
|
||||
enum { linearisation_storage_size = 1 };
|
||||
|
||||
static Buffer linearise(const boost::asio::mutable_buffer& buffer_sequence,
|
||||
const Buffer&)
|
||||
{
|
||||
return Buffer(buffer_sequence);
|
||||
}
|
||||
|
||||
private:
|
||||
native_buffer_type buffer_;
|
||||
std::size_t total_buffer_size_;
|
||||
@@ -264,6 +310,8 @@ class buffer_sequence_adapter<Buffer, boost::asio::const_buffer>
|
||||
: buffer_sequence_adapter_base
|
||||
{
|
||||
public:
|
||||
enum { is_single_buffer = true };
|
||||
|
||||
explicit buffer_sequence_adapter(
|
||||
const boost::asio::const_buffer& buffer_sequence)
|
||||
{
|
||||
@@ -306,6 +354,14 @@ public:
|
||||
return Buffer(buffer_sequence);
|
||||
}
|
||||
|
||||
enum { linearisation_storage_size = 1 };
|
||||
|
||||
static Buffer linearise(const boost::asio::const_buffer& buffer_sequence,
|
||||
const Buffer&)
|
||||
{
|
||||
return Buffer(buffer_sequence);
|
||||
}
|
||||
|
||||
private:
|
||||
native_buffer_type buffer_;
|
||||
std::size_t total_buffer_size_;
|
||||
@@ -318,6 +374,8 @@ class buffer_sequence_adapter<Buffer, boost::asio::mutable_buffers_1>
|
||||
: buffer_sequence_adapter_base
|
||||
{
|
||||
public:
|
||||
enum { is_single_buffer = true };
|
||||
|
||||
explicit buffer_sequence_adapter(
|
||||
const boost::asio::mutable_buffers_1& buffer_sequence)
|
||||
{
|
||||
@@ -360,6 +418,14 @@ public:
|
||||
return Buffer(buffer_sequence);
|
||||
}
|
||||
|
||||
enum { linearisation_storage_size = 1 };
|
||||
|
||||
static Buffer linearise(const boost::asio::mutable_buffers_1& buffer_sequence,
|
||||
const Buffer&)
|
||||
{
|
||||
return Buffer(buffer_sequence);
|
||||
}
|
||||
|
||||
private:
|
||||
native_buffer_type buffer_;
|
||||
std::size_t total_buffer_size_;
|
||||
@@ -370,6 +436,8 @@ class buffer_sequence_adapter<Buffer, boost::asio::const_buffers_1>
|
||||
: buffer_sequence_adapter_base
|
||||
{
|
||||
public:
|
||||
enum { is_single_buffer = true };
|
||||
|
||||
explicit buffer_sequence_adapter(
|
||||
const boost::asio::const_buffers_1& buffer_sequence)
|
||||
{
|
||||
@@ -412,6 +480,14 @@ public:
|
||||
return Buffer(buffer_sequence);
|
||||
}
|
||||
|
||||
enum { linearisation_storage_size = 1 };
|
||||
|
||||
static Buffer linearise(const boost::asio::const_buffers_1& buffer_sequence,
|
||||
const Buffer&)
|
||||
{
|
||||
return Buffer(buffer_sequence);
|
||||
}
|
||||
|
||||
private:
|
||||
native_buffer_type buffer_;
|
||||
std::size_t total_buffer_size_;
|
||||
@@ -424,6 +500,8 @@ class buffer_sequence_adapter<Buffer, boost::array<Elem, 2> >
|
||||
: buffer_sequence_adapter_base
|
||||
{
|
||||
public:
|
||||
enum { is_single_buffer = false };
|
||||
|
||||
explicit buffer_sequence_adapter(
|
||||
const boost::array<Elem, 2>& buffer_sequence)
|
||||
{
|
||||
@@ -469,6 +547,19 @@ public:
|
||||
? buffer_sequence[0] : buffer_sequence[1]);
|
||||
}
|
||||
|
||||
enum { linearisation_storage_size = 8192 };
|
||||
|
||||
static Buffer linearise(const boost::array<Elem, 2>& buffer_sequence,
|
||||
const boost::asio::mutable_buffer& storage)
|
||||
{
|
||||
if (buffer_sequence[0].size() == 0)
|
||||
return Buffer(buffer_sequence[1]);
|
||||
if (buffer_sequence[1].size() == 0)
|
||||
return Buffer(buffer_sequence[0]);
|
||||
return Buffer(storage.data(),
|
||||
boost::asio::buffer_copy(storage, buffer_sequence));
|
||||
}
|
||||
|
||||
private:
|
||||
native_buffer_type buffers_[2];
|
||||
std::size_t total_buffer_size_;
|
||||
@@ -481,6 +572,8 @@ class buffer_sequence_adapter<Buffer, std::array<Elem, 2> >
|
||||
: buffer_sequence_adapter_base
|
||||
{
|
||||
public:
|
||||
enum { is_single_buffer = false };
|
||||
|
||||
explicit buffer_sequence_adapter(
|
||||
const std::array<Elem, 2>& buffer_sequence)
|
||||
{
|
||||
@@ -526,6 +619,19 @@ public:
|
||||
? buffer_sequence[0] : buffer_sequence[1]);
|
||||
}
|
||||
|
||||
enum { linearisation_storage_size = 8192 };
|
||||
|
||||
static Buffer linearise(const std::array<Elem, 2>& buffer_sequence,
|
||||
const boost::asio::mutable_buffer& storage)
|
||||
{
|
||||
if (buffer_sequence[0].size() == 0)
|
||||
return Buffer(buffer_sequence[1]);
|
||||
if (buffer_sequence[1].size() == 0)
|
||||
return Buffer(buffer_sequence[0]);
|
||||
return Buffer(storage.data(),
|
||||
boost::asio::buffer_copy(storage, buffer_sequence));
|
||||
}
|
||||
|
||||
private:
|
||||
native_buffer_type buffers_[2];
|
||||
std::size_t total_buffer_size_;
|
||||
|
||||
@@ -28,17 +28,17 @@ namespace boost {
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
template <typename Handler>
|
||||
template <typename Handler, typename IoExecutor>
|
||||
class completion_handler : public operation
|
||||
{
|
||||
public:
|
||||
BOOST_ASIO_DEFINE_HANDLER_PTR(completion_handler);
|
||||
|
||||
completion_handler(Handler& h)
|
||||
completion_handler(Handler& h, const IoExecutor& io_ex)
|
||||
: operation(&completion_handler::do_complete),
|
||||
handler_(BOOST_ASIO_MOVE_CAST(Handler)(h))
|
||||
handler_(BOOST_ASIO_MOVE_CAST(Handler)(h)),
|
||||
work_(handler_, io_ex)
|
||||
{
|
||||
handler_work<Handler>::start(handler_);
|
||||
}
|
||||
|
||||
static void do_complete(void* owner, operation* base,
|
||||
@@ -48,10 +48,14 @@ public:
|
||||
// Take ownership of the handler object.
|
||||
completion_handler* h(static_cast<completion_handler*>(base));
|
||||
ptr p = { boost::asio::detail::addressof(h->handler_), h, h };
|
||||
handler_work<Handler> w(h->handler_);
|
||||
|
||||
BOOST_ASIO_HANDLER_COMPLETION((*h));
|
||||
|
||||
// Take ownership of the operation's outstanding work.
|
||||
handler_work<Handler, IoExecutor> w(
|
||||
BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
|
||||
h->work_));
|
||||
|
||||
// Make a copy of the handler so that the memory can be deallocated before
|
||||
// the upcall is made. Even if we're not about to make an upcall, a
|
||||
// sub-object of the handler may be the true owner of the memory associated
|
||||
@@ -74,6 +78,7 @@ public:
|
||||
|
||||
private:
|
||||
Handler handler_;
|
||||
handler_work<Handler, IoExecutor> work_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -65,6 +65,14 @@ public:
|
||||
event_.unlock_and_signal_one(lock);
|
||||
}
|
||||
|
||||
// Unlock the mutex and signal one waiter who may destroy us.
|
||||
void unlock_and_signal_one_for_destruction(
|
||||
conditionally_enabled_mutex::scoped_lock& lock)
|
||||
{
|
||||
if (lock.mutex_.enabled_)
|
||||
event_.unlock_and_signal_one(lock);
|
||||
}
|
||||
|
||||
// If there's a waiter, unlock the mutex and signal it.
|
||||
bool maybe_unlock_and_signal_one(
|
||||
conditionally_enabled_mutex::scoped_lock& lock)
|
||||
|
||||
@@ -61,6 +61,9 @@
|
||||
# define BOOST_ASIO_DECL
|
||||
#endif // !defined(BOOST_ASIO_DECL)
|
||||
|
||||
// Helper macro for documentation.
|
||||
#define BOOST_ASIO_UNSPECIFIED(e) e
|
||||
|
||||
// Microsoft Visual C++ detection.
|
||||
#if !defined(BOOST_ASIO_MSVC)
|
||||
# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC)
|
||||
@@ -180,6 +183,13 @@
|
||||
# endif // defined(BOOST_ASIO_MSVC)
|
||||
# endif // !defined(BOOST_ASIO_DISABLE_VARIADIC_TEMPLATES)
|
||||
#endif // !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
|
||||
#if !defined(BOOST_ASIO_ELLIPSIS)
|
||||
# if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
|
||||
# define BOOST_ASIO_ELLIPSIS ...
|
||||
# else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
|
||||
# define BOOST_ASIO_ELLIPSIS
|
||||
# endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
|
||||
#endif // !defined(BOOST_ASIO_ELLIPSIS)
|
||||
|
||||
// Support deleted functions on compilers known to allow it.
|
||||
#if !defined(BOOST_ASIO_DELETED)
|
||||
@@ -234,39 +244,87 @@
|
||||
# define BOOST_ASIO_CONSTEXPR
|
||||
# endif // defined(BOOST_ASIO_HAS_CONSTEXPR)
|
||||
#endif // !defined(BOOST_ASIO_CONSTEXPR)
|
||||
#if !defined(BOOST_ASIO_STATIC_CONSTEXPR)
|
||||
# if defined(BOOST_ASIO_HAS_CONSTEXPR)
|
||||
# define BOOST_ASIO_STATIC_CONSTEXPR(type, assignment) \
|
||||
static constexpr type assignment
|
||||
# else // defined(BOOST_ASIO_HAS_CONSTEXPR)
|
||||
# define BOOST_ASIO_STATIC_CONSTEXPR(type, assignment) \
|
||||
static const type assignment
|
||||
# endif // defined(BOOST_ASIO_HAS_CONSTEXPR)
|
||||
#endif // !defined(BOOST_ASIO_STATIC_CONSTEXPR)
|
||||
#if !defined(BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT)
|
||||
# if defined(BOOST_ASIO_HAS_CONSTEXPR)
|
||||
# if defined(__GNUC__)
|
||||
# if (__GNUC__ >= 8)
|
||||
# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \
|
||||
static constexpr const type name{}
|
||||
# else // (__GNUC__ >= 8)
|
||||
# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \
|
||||
static const type name
|
||||
# endif // (__GNUC__ >= 8)
|
||||
# else // defined(__GNUC__)
|
||||
# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \
|
||||
static constexpr const type name{}
|
||||
# endif // defined(__GNUC__)
|
||||
# else // defined(BOOST_ASIO_HAS_CONSTEXPR)
|
||||
# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \
|
||||
static const type name
|
||||
# endif // defined(BOOST_ASIO_HAS_CONSTEXPR)
|
||||
#endif // !defined(BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT)
|
||||
|
||||
// Support noexcept on compilers known to allow it.
|
||||
#if !defined(BOOST_ASIO_NOEXCEPT)
|
||||
#if !defined(BOOST_ASIO_HAS_NOEXCEPT)
|
||||
# if !defined(BOOST_ASIO_DISABLE_NOEXCEPT)
|
||||
# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105300)
|
||||
# if !defined(BOOST_NO_NOEXCEPT)
|
||||
# define BOOST_ASIO_HAS_NOEXCEPT 1
|
||||
# endif // !defined(BOOST_NO_NOEXCEPT)
|
||||
# define BOOST_ASIO_NOEXCEPT BOOST_NOEXCEPT
|
||||
# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW BOOST_NOEXCEPT_OR_NOTHROW
|
||||
# define BOOST_ASIO_NOEXCEPT_IF(c) BOOST_NOEXCEPT_IF(c)
|
||||
# elif defined(__clang__)
|
||||
# if __has_feature(__cxx_noexcept__)
|
||||
# define BOOST_ASIO_NOEXCEPT noexcept(true)
|
||||
# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW noexcept(true)
|
||||
# define BOOST_ASIO_HAS_NOEXCEPT 1
|
||||
# endif // __has_feature(__cxx_noexcept__)
|
||||
# elif defined(__GNUC__)
|
||||
# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
|
||||
# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
# define BOOST_ASIO_NOEXCEPT noexcept(true)
|
||||
# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW noexcept(true)
|
||||
# define BOOST_ASIO_HAS_NOEXCEPT 1
|
||||
# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
|
||||
# elif defined(BOOST_ASIO_MSVC)
|
||||
# if (_MSC_VER >= 1900)
|
||||
# define BOOST_ASIO_NOEXCEPT noexcept(true)
|
||||
# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW noexcept(true)
|
||||
# define BOOST_ASIO_HAS_NOEXCEPT 1
|
||||
# endif // (_MSC_VER >= 1900)
|
||||
# endif // defined(BOOST_ASIO_MSVC)
|
||||
# endif // !defined(BOOST_ASIO_DISABLE_NOEXCEPT)
|
||||
# if !defined(BOOST_ASIO_NOEXCEPT)
|
||||
# define BOOST_ASIO_NOEXCEPT
|
||||
# endif // !defined(BOOST_ASIO_NOEXCEPT)
|
||||
# if !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW)
|
||||
# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW throw()
|
||||
# endif // !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW)
|
||||
#endif // !defined(BOOST_ASIO_HAS_NOEXCEPT)
|
||||
#if !defined(BOOST_ASIO_NOEXCEPT)
|
||||
# if defined(BOOST_ASIO_HAS_NOEXCEPT)
|
||||
# define BOOST_ASIO_NOEXCEPT noexcept(true)
|
||||
# else // defined(BOOST_ASIO_HAS_NOEXCEPT)
|
||||
# define BOOST_ASIO_NOEXCEPT
|
||||
# endif // defined(BOOST_ASIO_HAS_NOEXCEPT)
|
||||
#endif // !defined(BOOST_ASIO_NOEXCEPT)
|
||||
#if !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW)
|
||||
# if defined(BOOST_ASIO_HAS_NOEXCEPT)
|
||||
# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW noexcept(true)
|
||||
# else // defined(BOOST_ASIO_HAS_NOEXCEPT)
|
||||
# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW throw()
|
||||
# endif // defined(BOOST_ASIO_HAS_NOEXCEPT)
|
||||
#endif // !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW)
|
||||
#if !defined(BOOST_ASIO_NOEXCEPT_IF)
|
||||
# if defined(BOOST_ASIO_HAS_NOEXCEPT)
|
||||
# define BOOST_ASIO_NOEXCEPT_IF(c) noexcept(c)
|
||||
# else // defined(BOOST_ASIO_HAS_NOEXCEPT)
|
||||
# define BOOST_ASIO_NOEXCEPT_IF(c)
|
||||
# endif // defined(BOOST_ASIO_HAS_NOEXCEPT)
|
||||
#endif // !defined(BOOST_ASIO_NOEXCEPT_IF)
|
||||
|
||||
// Support automatic type deduction on compilers known to support it.
|
||||
#if !defined(BOOST_ASIO_HAS_DECLTYPE)
|
||||
@@ -354,6 +412,113 @@
|
||||
# endif // !defined(BOOST_ASIO_DISABLE_CONCEPTS)
|
||||
#endif // !defined(BOOST_ASIO_HAS_CONCEPTS)
|
||||
|
||||
// Support template variables on compilers known to allow it.
|
||||
#if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
|
||||
# if !defined(BOOST_ASIO_DISABLE_VARIABLE_TEMPLATES)
|
||||
# if defined(__clang__)
|
||||
# if (__cplusplus >= 201402)
|
||||
# if __has_feature(__cxx_variable_templates__)
|
||||
# define BOOST_ASIO_HAS_VARIABLE_TEMPLATES 1
|
||||
# endif // __has_feature(__cxx_variable_templates__)
|
||||
# endif // (__cplusplus >= 201703)
|
||||
# endif // defined(__clang__)
|
||||
# if defined(__GNUC__)
|
||||
# if (__GNUC__ >= 5)
|
||||
# if (__cplusplus >= 201402)
|
||||
# define BOOST_ASIO_HAS_VARIABLE_TEMPLATES 1
|
||||
# endif // (__cplusplus >= 201402)
|
||||
# endif // (__GNUC__ >= 5)
|
||||
# endif // defined(__GNUC__)
|
||||
# if defined(BOOST_ASIO_MSVC)
|
||||
# if (_MSC_VER >= 1901)
|
||||
# define BOOST_ASIO_HAS_VARIABLE_TEMPLATES 1
|
||||
# endif // (_MSC_VER >= 1901)
|
||||
# endif // defined(BOOST_ASIO_MSVC)
|
||||
# endif // !defined(BOOST_ASIO_DISABLE_VARIABLE_TEMPLATES)
|
||||
#endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
|
||||
|
||||
// Support SFINAEd template variables on compilers known to allow it.
|
||||
#if !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
|
||||
# if !defined(BOOST_ASIO_DISABLE_SFINAE_VARIABLE_TEMPLATES)
|
||||
# if defined(__clang__)
|
||||
# if (__cplusplus >= 201703)
|
||||
# if __has_feature(__cxx_variable_templates__)
|
||||
# define BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1
|
||||
# endif // __has_feature(__cxx_variable_templates__)
|
||||
# endif // (__cplusplus >= 201703)
|
||||
# endif // defined(__clang__)
|
||||
# if defined(__GNUC__)
|
||||
# if (__GNUC__ >= 7)
|
||||
# if (__cplusplus >= 201402)
|
||||
# define BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1
|
||||
# endif // (__cplusplus >= 201402)
|
||||
# endif // (__GNUC__ >= 7)
|
||||
# endif // defined(__GNUC__)
|
||||
# if defined(BOOST_ASIO_MSVC)
|
||||
# if (_MSC_VER >= 1901)
|
||||
# define BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1
|
||||
# endif // (_MSC_VER >= 1901)
|
||||
# endif // defined(BOOST_ASIO_MSVC)
|
||||
# endif // !defined(BOOST_ASIO_DISABLE_SFINAE_VARIABLE_TEMPLATES)
|
||||
#endif // !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
|
||||
|
||||
// Support SFINAE use of constant expressions on compilers known to allow it.
|
||||
#if !defined(BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE)
|
||||
# if !defined(BOOST_ASIO_DISABLE_CONSTANT_EXPRESSION_SFINAE)
|
||||
# if defined(__clang__)
|
||||
# if (__cplusplus >= 201402)
|
||||
# define BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1
|
||||
# endif // (__cplusplus >= 201703)
|
||||
# endif // defined(__clang__)
|
||||
# if defined(__GNUC__)
|
||||
# if (__GNUC__ >= 7)
|
||||
# if (__cplusplus >= 201402)
|
||||
# define BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1
|
||||
# endif // (__cplusplus >= 201402)
|
||||
# endif // (__GNUC__ >= 7)
|
||||
# endif // defined(__GNUC__)
|
||||
# if defined(BOOST_ASIO_MSVC)
|
||||
# if (_MSC_VER >= 1901)
|
||||
# define BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1
|
||||
# endif // (_MSC_VER >= 1901)
|
||||
# endif // defined(BOOST_ASIO_MSVC)
|
||||
# endif // !defined(BOOST_ASIO_DISABLE_CONSTANT_EXPRESSION_SFINAE)
|
||||
#endif // !defined(BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE)
|
||||
|
||||
// Enable workarounds for lack of working expression SFINAE.
|
||||
#if !defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE)
|
||||
# if !defined(BOOST_ASIO_DISABLE_WORKING_EXPRESSION_SFINAE)
|
||||
# if !defined(BOOST_ASIO_MSVC)
|
||||
# if (__cplusplus >= 201103)
|
||||
# define BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE 1
|
||||
# endif // (__cplusplus >= 201103)
|
||||
# endif // defined(BOOST_ASIO_MSVC)
|
||||
# endif // !defined(BOOST_ASIO_DISABLE_WORKING_EXPRESSION_SFINAE)
|
||||
#endif // !defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE)
|
||||
|
||||
// Support static_assert on compilers known to allow it.
|
||||
#if !defined(BOOST_ASIO_HAS_STATIC_ASSERT)
|
||||
# if !defined(BOOST_ASIO_DISABLE_STATIC_ASSERT)
|
||||
# if defined(__clang__)
|
||||
# if __has_feature(__cxx_static_assert__)
|
||||
# define BOOST_ASIO_HAS_STATIC_ASSERT 1
|
||||
# endif // __has_feature(__cxx_static_assert__)
|
||||
# endif // defined(__clang__)
|
||||
# if defined(__GNUC__)
|
||||
# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
|
||||
# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
# define BOOST_ASIO_HAS_STATIC_ASSERT 1
|
||||
# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
|
||||
# endif // defined(__GNUC__)
|
||||
# if defined(BOOST_ASIO_MSVC)
|
||||
# if (_MSC_VER >= 1900)
|
||||
# define BOOST_ASIO_HAS_STATIC_ASSERT 1
|
||||
# endif // (_MSC_VER >= 1900)
|
||||
# endif // defined(BOOST_ASIO_MSVC)
|
||||
# endif // !defined(BOOST_ASIO_DISABLE_STATIC_ASSERT)
|
||||
#endif // !defined(BOOST_ASIO_HAS_STATIC_ASSERT)
|
||||
|
||||
// Standard library support for system errors.
|
||||
# if !defined(BOOST_ASIO_DISABLE_STD_SYSTEM_ERROR)
|
||||
# if defined(__clang__)
|
||||
@@ -927,6 +1092,61 @@
|
||||
# endif // !defined(BOOST_ASIO_DISABLE_STD_INVOKE_RESULT)
|
||||
#endif // !defined(BOOST_ASIO_HAS_STD_INVOKE_RESULT)
|
||||
|
||||
// Standard library support for std::exception_ptr and std::current_exception.
|
||||
#if !defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR)
|
||||
# if !defined(BOOST_ASIO_DISABLE_STD_EXCEPTION_PTR)
|
||||
# if defined(__clang__)
|
||||
# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX)
|
||||
# define BOOST_ASIO_HAS_STD_EXCEPTION_PTR 1
|
||||
# elif (__cplusplus >= 201103)
|
||||
# define BOOST_ASIO_HAS_STD_EXCEPTION_PTR 1
|
||||
# endif // (__cplusplus >= 201103)
|
||||
# elif defined(__GNUC__)
|
||||
# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
|
||||
# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
# define BOOST_ASIO_HAS_STD_EXCEPTION_PTR 1
|
||||
# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
|
||||
# endif // defined(__GNUC__)
|
||||
# if defined(BOOST_ASIO_MSVC)
|
||||
# if (_MSC_VER >= 1800)
|
||||
# define BOOST_ASIO_HAS_STD_EXCEPTION_PTR 1
|
||||
# endif // (_MSC_VER >= 1800)
|
||||
# endif // defined(BOOST_ASIO_MSVC)
|
||||
# endif // !defined(BOOST_ASIO_DISABLE_STD_EXCEPTION_PTR)
|
||||
#endif // !defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR)
|
||||
|
||||
// Standard library support for std::source_location.
|
||||
#if !defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION)
|
||||
# if !defined(BOOST_ASIO_DISABLE_STD_SOURCE_LOCATION)
|
||||
// ...
|
||||
# endif // !defined(BOOST_ASIO_DISABLE_STD_SOURCE_LOCATION)
|
||||
#endif // !defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION)
|
||||
|
||||
// Standard library support for std::experimental::source_location.
|
||||
#if !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION)
|
||||
# if !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_SOURCE_LOCATION)
|
||||
# if defined(__GNUC__)
|
||||
# if (__cplusplus >= 201709)
|
||||
# if __has_include(<experimental/source_location>)
|
||||
# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION 1
|
||||
# endif // __has_include(<experimental/source_location>)
|
||||
# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4)
|
||||
# endif // defined(__GNUC__)
|
||||
# endif // !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_SOURCE_LOCATION)
|
||||
#endif // !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION)
|
||||
|
||||
// Standard library has a source_location that we can use.
|
||||
#if !defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
|
||||
# if !defined(BOOST_ASIO_DISABLE_SOURCE_LOCATION)
|
||||
# if defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION)
|
||||
# define BOOST_ASIO_HAS_SOURCE_LOCATION 1
|
||||
# elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION)
|
||||
# define BOOST_ASIO_HAS_SOURCE_LOCATION 1
|
||||
# endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION)
|
||||
# endif // !defined(BOOST_ASIO_DISABLE_SOURCE_LOCATION)
|
||||
#endif // !defined(BOOST_ASIO_HAS_SOURCE_LOCATION)
|
||||
|
||||
// Windows App target. Windows but with a limited API.
|
||||
#if !defined(BOOST_ASIO_WINDOWS_APP)
|
||||
# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603)
|
||||
@@ -970,17 +1190,17 @@
|
||||
// Windows: target OS version.
|
||||
#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
|
||||
# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
|
||||
# if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
# if defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__))
|
||||
# pragma message( \
|
||||
"Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\
|
||||
"- add -D_WIN32_WINNT=0x0601 to the compiler command line; or\n"\
|
||||
"- add _WIN32_WINNT=0x0601 to your project's Preprocessor Definitions.\n"\
|
||||
"Assuming _WIN32_WINNT=0x0601 (i.e. Windows 7 target).")
|
||||
# else // defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
# else // defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__))
|
||||
# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately.
|
||||
# warning For example, add -D_WIN32_WINNT=0x0601 to the compiler command line.
|
||||
# warning Assuming _WIN32_WINNT=0x0601 (i.e. Windows 7 target).
|
||||
# endif // defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
# endif // defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__))
|
||||
# define _WIN32_WINNT 0x0601
|
||||
# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
|
||||
# if defined(_MSC_VER)
|
||||
@@ -1379,9 +1599,9 @@
|
||||
# if (__GNUC__ >= 3)
|
||||
# define BOOST_ASIO_HAS_HANDLER_HOOKS 1
|
||||
# endif // (__GNUC__ >= 3)
|
||||
# elif !defined(__BORLANDC__)
|
||||
# elif !defined(__BORLANDC__) || defined(__clang__)
|
||||
# define BOOST_ASIO_HAS_HANDLER_HOOKS 1
|
||||
# endif // !defined(__BORLANDC__)
|
||||
# endif // !defined(__BORLANDC__) || defined(__clang__)
|
||||
# endif // !defined(BOOST_ASIO_DISABLE_HANDLER_HOOKS)
|
||||
#endif // !defined(BOOST_ASIO_HAS_HANDLER_HOOKS)
|
||||
|
||||
@@ -1460,7 +1680,7 @@
|
||||
# define BOOST_ASIO_UNUSED_VARIABLE
|
||||
#endif // !defined(BOOST_ASIO_UNUSED_VARIABLE)
|
||||
|
||||
// Support co_await on compilers known to allow it.
|
||||
// Support the co_await keyword on compilers known to allow it.
|
||||
#if !defined(BOOST_ASIO_HAS_CO_AWAIT)
|
||||
# if !defined(BOOST_ASIO_DISABLE_CO_AWAIT)
|
||||
# if defined(BOOST_ASIO_MSVC)
|
||||
@@ -1470,14 +1690,33 @@
|
||||
# endif // defined(_RESUMABLE_FUNCTIONS_SUPPORTED)
|
||||
# endif // (_MSC_FULL_VER >= 190023506)
|
||||
# endif // defined(BOOST_ASIO_MSVC)
|
||||
# if defined(__clang__)
|
||||
# if (__cplusplus >= 201703) && (__cpp_coroutines >= 201703)
|
||||
# if __has_include(<experimental/coroutine>)
|
||||
# define BOOST_ASIO_HAS_CO_AWAIT 1
|
||||
# endif // __has_include(<experimental/coroutine>)
|
||||
# endif // (__cplusplus >= 201703) && (__cpp_coroutines >= 201703)
|
||||
# elif defined(__GNUC__)
|
||||
# if (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902)
|
||||
# if __has_include(<coroutine>)
|
||||
# define BOOST_ASIO_HAS_CO_AWAIT 1
|
||||
# endif // __has_include(<coroutine>)
|
||||
# endif // (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902)
|
||||
# endif // defined(__GNUC__)
|
||||
# endif // !defined(BOOST_ASIO_DISABLE_CO_AWAIT)
|
||||
# if defined(__clang__)
|
||||
# if (__cplusplus >= 201703) && (__cpp_coroutines >= 201703)
|
||||
# if __has_include(<experimental/coroutine>)
|
||||
# define BOOST_ASIO_HAS_CO_AWAIT 1
|
||||
# endif // __has_include(<experimental/coroutine>)
|
||||
# endif // (__cplusplus >= 201703) && (__cpp_coroutines >= 201703)
|
||||
# endif // defined(__clang__)
|
||||
#endif // !defined(BOOST_ASIO_HAS_CO_AWAIT)
|
||||
|
||||
// Standard library support for coroutines.
|
||||
#if !defined(BOOST_ASIO_HAS_STD_COROUTINE)
|
||||
# if !defined(BOOST_ASIO_DISABLE_STD_COROUTINE)
|
||||
# if defined(__GNUC__)
|
||||
# if (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902)
|
||||
# if __has_include(<coroutine>)
|
||||
# define BOOST_ASIO_HAS_STD_COROUTINE 1
|
||||
# endif // __has_include(<coroutine>)
|
||||
# endif // (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902)
|
||||
# endif // defined(__GNUC__)
|
||||
# endif // !defined(BOOST_ASIO_DISABLE_STD_COROUTINE)
|
||||
#endif // !defined(BOOST_ASIO_HAS_STD_COROUTINE)
|
||||
|
||||
#endif // BOOST_ASIO_DETAIL_CONFIG_HPP
|
||||
|
||||
@@ -98,7 +98,7 @@ public:
|
||||
cancel(impl, ec);
|
||||
}
|
||||
|
||||
// Move-construct a new serial port implementation.
|
||||
// Move-construct a new timer implementation.
|
||||
void move_construct(implementation_type& impl,
|
||||
implementation_type& other_impl)
|
||||
{
|
||||
@@ -111,7 +111,7 @@ public:
|
||||
other_impl.might_have_pending_waits = false;
|
||||
}
|
||||
|
||||
// Move-assign from another serial port implementation.
|
||||
// Move-assign from another timer implementation.
|
||||
void move_assign(implementation_type& impl,
|
||||
deadline_timer_service& other_service,
|
||||
implementation_type& other_impl)
|
||||
@@ -130,6 +130,21 @@ public:
|
||||
other_impl.might_have_pending_waits = false;
|
||||
}
|
||||
|
||||
// Move-construct a new timer implementation.
|
||||
void converting_move_construct(implementation_type& impl,
|
||||
deadline_timer_service&, implementation_type& other_impl)
|
||||
{
|
||||
move_construct(impl, other_impl);
|
||||
}
|
||||
|
||||
// Move-assign from another timer implementation.
|
||||
void converting_move_assign(implementation_type& impl,
|
||||
deadline_timer_service& other_service,
|
||||
implementation_type& other_impl)
|
||||
{
|
||||
move_assign(impl, other_service, other_impl);
|
||||
}
|
||||
|
||||
// Cancel any asynchronous wait operations associated with the timer.
|
||||
std::size_t cancel(implementation_type& impl, boost::system::error_code& ec)
|
||||
{
|
||||
|
||||
@@ -51,13 +51,18 @@ enum
|
||||
|
||||
typedef unsigned char state_type;
|
||||
|
||||
template <typename ReturnType>
|
||||
inline ReturnType error_wrapper(ReturnType return_value,
|
||||
boost::system::error_code& ec)
|
||||
inline void get_last_error(
|
||||
boost::system::error_code& ec, bool is_error_condition)
|
||||
{
|
||||
ec = boost::system::error_code(errno,
|
||||
boost::asio::error::get_system_category());
|
||||
return return_value;
|
||||
if (!is_error_condition)
|
||||
{
|
||||
ec.assign(0, ec.category());
|
||||
}
|
||||
else
|
||||
{
|
||||
ec = boost::system::error_code(errno,
|
||||
boost::asio::error::get_system_category());
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_ASIO_DECL int open(const char* path, int flags,
|
||||
@@ -77,17 +82,30 @@ typedef iovec buf;
|
||||
BOOST_ASIO_DECL std::size_t sync_read(int d, state_type state, buf* bufs,
|
||||
std::size_t count, bool all_empty, boost::system::error_code& ec);
|
||||
|
||||
BOOST_ASIO_DECL std::size_t sync_read1(int d, state_type state, void* data,
|
||||
std::size_t size, boost::system::error_code& ec);
|
||||
|
||||
BOOST_ASIO_DECL bool non_blocking_read(int d, buf* bufs, std::size_t count,
|
||||
boost::system::error_code& ec, std::size_t& bytes_transferred);
|
||||
|
||||
BOOST_ASIO_DECL bool non_blocking_read1(int d, void* data, std::size_t size,
|
||||
boost::system::error_code& ec, std::size_t& bytes_transferred);
|
||||
|
||||
BOOST_ASIO_DECL std::size_t sync_write(int d, state_type state,
|
||||
const buf* bufs, std::size_t count, bool all_empty,
|
||||
boost::system::error_code& ec);
|
||||
|
||||
BOOST_ASIO_DECL std::size_t sync_write1(int d, state_type state,
|
||||
const void* data, std::size_t size, boost::system::error_code& ec);
|
||||
|
||||
BOOST_ASIO_DECL bool non_blocking_write(int d,
|
||||
const buf* bufs, std::size_t count,
|
||||
boost::system::error_code& ec, std::size_t& bytes_transferred);
|
||||
|
||||
BOOST_ASIO_DECL bool non_blocking_write1(int d,
|
||||
const void* data, std::size_t size,
|
||||
boost::system::error_code& ec, std::size_t& bytes_transferred);
|
||||
|
||||
BOOST_ASIO_DECL int ioctl(int d, state_type& state, long cmd,
|
||||
ioctl_arg_type* arg, boost::system::error_code& ec);
|
||||
|
||||
|
||||
@@ -37,9 +37,11 @@ template <typename MutableBufferSequence>
|
||||
class descriptor_read_op_base : public reactor_op
|
||||
{
|
||||
public:
|
||||
descriptor_read_op_base(int descriptor,
|
||||
const MutableBufferSequence& buffers, func_type complete_func)
|
||||
: reactor_op(&descriptor_read_op_base::do_perform, complete_func),
|
||||
descriptor_read_op_base(const boost::system::error_code& success_ec,
|
||||
int descriptor, const MutableBufferSequence& buffers,
|
||||
func_type complete_func)
|
||||
: reactor_op(success_ec,
|
||||
&descriptor_read_op_base::do_perform, complete_func),
|
||||
descriptor_(descriptor),
|
||||
buffers_(buffers)
|
||||
{
|
||||
@@ -49,12 +51,24 @@ public:
|
||||
{
|
||||
descriptor_read_op_base* o(static_cast<descriptor_read_op_base*>(base));
|
||||
|
||||
buffer_sequence_adapter<boost::asio::mutable_buffer,
|
||||
MutableBufferSequence> bufs(o->buffers_);
|
||||
typedef buffer_sequence_adapter<boost::asio::mutable_buffer,
|
||||
MutableBufferSequence> bufs_type;
|
||||
|
||||
status result = descriptor_ops::non_blocking_read(o->descriptor_,
|
||||
bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_)
|
||||
? done : not_done;
|
||||
status result;
|
||||
if (bufs_type::is_single_buffer)
|
||||
{
|
||||
result = descriptor_ops::non_blocking_read1(o->descriptor_,
|
||||
bufs_type::first(o->buffers_).data(),
|
||||
bufs_type::first(o->buffers_).size(),
|
||||
o->ec_, o->bytes_transferred_) ? done : not_done;
|
||||
}
|
||||
else
|
||||
{
|
||||
bufs_type bufs(o->buffers_);
|
||||
result = descriptor_ops::non_blocking_read(o->descriptor_,
|
||||
bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_)
|
||||
? done : not_done;
|
||||
}
|
||||
|
||||
BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_read",
|
||||
o->ec_, o->bytes_transferred_));
|
||||
@@ -74,14 +88,14 @@ class descriptor_read_op
|
||||
public:
|
||||
BOOST_ASIO_DEFINE_HANDLER_PTR(descriptor_read_op);
|
||||
|
||||
descriptor_read_op(int descriptor, const MutableBufferSequence& buffers,
|
||||
descriptor_read_op(const boost::system::error_code& success_ec,
|
||||
int descriptor, const MutableBufferSequence& buffers,
|
||||
Handler& handler, const IoExecutor& io_ex)
|
||||
: descriptor_read_op_base<MutableBufferSequence>(
|
||||
: descriptor_read_op_base<MutableBufferSequence>(success_ec,
|
||||
descriptor, buffers, &descriptor_read_op::do_complete),
|
||||
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)),
|
||||
io_executor_(io_ex)
|
||||
work_(handler_, io_ex)
|
||||
{
|
||||
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
|
||||
}
|
||||
|
||||
static void do_complete(void* owner, operation* base,
|
||||
@@ -91,10 +105,14 @@ public:
|
||||
// Take ownership of the handler object.
|
||||
descriptor_read_op* o(static_cast<descriptor_read_op*>(base));
|
||||
ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
|
||||
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
|
||||
|
||||
BOOST_ASIO_HANDLER_COMPLETION((*o));
|
||||
|
||||
// Take ownership of the operation's outstanding work.
|
||||
handler_work<Handler, IoExecutor> w(
|
||||
BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
|
||||
o->work_));
|
||||
|
||||
// Make a copy of the handler so that the memory can be deallocated before
|
||||
// the upcall is made. Even if we're not about to make an upcall, a
|
||||
// sub-object of the handler may be the true owner of the memory associated
|
||||
@@ -118,7 +136,7 @@ public:
|
||||
|
||||
private:
|
||||
Handler handler_;
|
||||
IoExecutor io_executor_;
|
||||
handler_work<Handler, IoExecutor> work_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -37,9 +37,11 @@ template <typename ConstBufferSequence>
|
||||
class descriptor_write_op_base : public reactor_op
|
||||
{
|
||||
public:
|
||||
descriptor_write_op_base(int descriptor,
|
||||
const ConstBufferSequence& buffers, func_type complete_func)
|
||||
: reactor_op(&descriptor_write_op_base::do_perform, complete_func),
|
||||
descriptor_write_op_base(const boost::system::error_code& success_ec,
|
||||
int descriptor, const ConstBufferSequence& buffers,
|
||||
func_type complete_func)
|
||||
: reactor_op(success_ec,
|
||||
&descriptor_write_op_base::do_perform, complete_func),
|
||||
descriptor_(descriptor),
|
||||
buffers_(buffers)
|
||||
{
|
||||
@@ -49,12 +51,24 @@ public:
|
||||
{
|
||||
descriptor_write_op_base* o(static_cast<descriptor_write_op_base*>(base));
|
||||
|
||||
buffer_sequence_adapter<boost::asio::const_buffer,
|
||||
ConstBufferSequence> bufs(o->buffers_);
|
||||
typedef buffer_sequence_adapter<boost::asio::const_buffer,
|
||||
ConstBufferSequence> bufs_type;
|
||||
|
||||
status result = descriptor_ops::non_blocking_write(o->descriptor_,
|
||||
bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_)
|
||||
? done : not_done;
|
||||
status result;
|
||||
if (bufs_type::is_single_buffer)
|
||||
{
|
||||
result = descriptor_ops::non_blocking_write1(o->descriptor_,
|
||||
bufs_type::first(o->buffers_).data(),
|
||||
bufs_type::first(o->buffers_).size(),
|
||||
o->ec_, o->bytes_transferred_) ? done : not_done;
|
||||
}
|
||||
else
|
||||
{
|
||||
bufs_type bufs(o->buffers_);
|
||||
result = descriptor_ops::non_blocking_write(o->descriptor_,
|
||||
bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_)
|
||||
? done : not_done;
|
||||
}
|
||||
|
||||
BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_write",
|
||||
o->ec_, o->bytes_transferred_));
|
||||
@@ -74,14 +88,14 @@ class descriptor_write_op
|
||||
public:
|
||||
BOOST_ASIO_DEFINE_HANDLER_PTR(descriptor_write_op);
|
||||
|
||||
descriptor_write_op(int descriptor, const ConstBufferSequence& buffers,
|
||||
descriptor_write_op(const boost::system::error_code& success_ec,
|
||||
int descriptor, const ConstBufferSequence& buffers,
|
||||
Handler& handler, const IoExecutor& io_ex)
|
||||
: descriptor_write_op_base<ConstBufferSequence>(
|
||||
: descriptor_write_op_base<ConstBufferSequence>(success_ec,
|
||||
descriptor, buffers, &descriptor_write_op::do_complete),
|
||||
handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)),
|
||||
io_executor_(io_ex)
|
||||
work_(handler_, io_ex)
|
||||
{
|
||||
handler_work<Handler, IoExecutor>::start(handler_, io_executor_);
|
||||
}
|
||||
|
||||
static void do_complete(void* owner, operation* base,
|
||||
@@ -91,10 +105,14 @@ public:
|
||||
// Take ownership of the handler object.
|
||||
descriptor_write_op* o(static_cast<descriptor_write_op*>(base));
|
||||
ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
|
||||
handler_work<Handler, IoExecutor> w(o->handler_, o->io_executor_);
|
||||
|
||||
BOOST_ASIO_HANDLER_COMPLETION((*o));
|
||||
|
||||
// Take ownership of the operation's outstanding work.
|
||||
handler_work<Handler, IoExecutor> w(
|
||||
BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
|
||||
o->work_));
|
||||
|
||||
// Make a copy of the handler so that the memory can be deallocated before
|
||||
// the upcall is made. Even if we're not about to make an upcall, a
|
||||
// sub-object of the handler may be the true owner of the memory associated
|
||||
@@ -118,7 +136,7 @@ public:
|
||||
|
||||
private:
|
||||
Handler handler_;
|
||||
IoExecutor io_executor_;
|
||||
handler_work<Handler, IoExecutor> work_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <boost/asio/detail/config.hpp>
|
||||
#include <boost/asio/detail/handler_alloc_helpers.hpp>
|
||||
#include <boost/asio/detail/memory.hpp>
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
@@ -24,57 +25,80 @@ namespace boost {
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
class executor_function_base
|
||||
#if defined(BOOST_ASIO_HAS_MOVE)
|
||||
|
||||
// Lightweight, move-only function object wrapper.
|
||||
class executor_function
|
||||
{
|
||||
public:
|
||||
void complete()
|
||||
template <typename F, typename Alloc>
|
||||
explicit executor_function(F f, const Alloc& a)
|
||||
{
|
||||
func_(this, true);
|
||||
// Allocate and construct an object to wrap the function.
|
||||
typedef impl<F, Alloc> impl_type;
|
||||
typename impl_type::ptr p = {
|
||||
detail::addressof(a), impl_type::ptr::allocate(a), 0 };
|
||||
impl_ = new (p.v) impl_type(BOOST_ASIO_MOVE_CAST(F)(f), a);
|
||||
p.v = 0;
|
||||
}
|
||||
|
||||
void destroy()
|
||||
executor_function(executor_function&& other) BOOST_ASIO_NOEXCEPT
|
||||
: impl_(other.impl_)
|
||||
{
|
||||
func_(this, false);
|
||||
other.impl_ = 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
typedef void (*func_type)(executor_function_base*, bool);
|
||||
|
||||
executor_function_base(func_type func)
|
||||
: func_(func)
|
||||
~executor_function()
|
||||
{
|
||||
if (impl_)
|
||||
impl_->complete_(impl_, false);
|
||||
}
|
||||
|
||||
// Prevents deletion through this type.
|
||||
~executor_function_base()
|
||||
void operator()()
|
||||
{
|
||||
if (impl_)
|
||||
{
|
||||
impl_base* i = impl_;
|
||||
impl_ = 0;
|
||||
i->complete_(i, true);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
func_type func_;
|
||||
};
|
||||
|
||||
template <typename Function, typename Alloc>
|
||||
class executor_function : public executor_function_base
|
||||
{
|
||||
public:
|
||||
BOOST_ASIO_DEFINE_TAGGED_HANDLER_ALLOCATOR_PTR(
|
||||
thread_info_base::executor_function_tag, executor_function);
|
||||
|
||||
template <typename F>
|
||||
executor_function(BOOST_ASIO_MOVE_ARG(F) f, const Alloc& allocator)
|
||||
: executor_function_base(&executor_function::do_complete),
|
||||
function_(BOOST_ASIO_MOVE_CAST(F)(f)),
|
||||
allocator_(allocator)
|
||||
// Base class for polymorphic function implementations.
|
||||
struct impl_base
|
||||
{
|
||||
}
|
||||
void (*complete_)(impl_base*, bool);
|
||||
};
|
||||
|
||||
static void do_complete(executor_function_base* base, bool call)
|
||||
// Polymorphic function implementation.
|
||||
template <typename Function, typename Alloc>
|
||||
struct impl : impl_base
|
||||
{
|
||||
BOOST_ASIO_DEFINE_TAGGED_HANDLER_ALLOCATOR_PTR(
|
||||
thread_info_base::executor_function_tag, impl);
|
||||
|
||||
template <typename F>
|
||||
impl(BOOST_ASIO_MOVE_ARG(F) f, const Alloc& a)
|
||||
: function_(BOOST_ASIO_MOVE_CAST(F)(f)),
|
||||
allocator_(a)
|
||||
{
|
||||
complete_ = &executor_function::complete<Function, Alloc>;
|
||||
}
|
||||
|
||||
Function function_;
|
||||
Alloc allocator_;
|
||||
};
|
||||
|
||||
// Helper to complete function invocation.
|
||||
template <typename Function, typename Alloc>
|
||||
static void complete(impl_base* base, bool call)
|
||||
{
|
||||
// Take ownership of the function object.
|
||||
executor_function* o(static_cast<executor_function*>(base));
|
||||
Alloc allocator(o->allocator_);
|
||||
ptr p = { detail::addressof(allocator), o, o };
|
||||
impl<Function, Alloc>* i(static_cast<impl<Function, Alloc>*>(base));
|
||||
Alloc allocator(i->allocator_);
|
||||
typename impl<Function, Alloc>::ptr p = {
|
||||
detail::addressof(allocator), i, i };
|
||||
|
||||
// Make a copy of the function so that the memory can be deallocated before
|
||||
// the upcall is made. Even if we're not about to make an upcall, a
|
||||
@@ -82,7 +106,7 @@ public:
|
||||
// associated with the function. Consequently, a local copy of the function
|
||||
// is required to ensure that any owning sub-object remains valid until
|
||||
// after we have deallocated the memory here.
|
||||
Function function(BOOST_ASIO_MOVE_CAST(Function)(o->function_));
|
||||
Function function(BOOST_ASIO_MOVE_CAST(Function)(i->function_));
|
||||
p.reset();
|
||||
|
||||
// Make the upcall if required.
|
||||
@@ -92,9 +116,84 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
impl_base* impl_;
|
||||
};
|
||||
|
||||
#else // defined(BOOST_ASIO_HAS_MOVE)
|
||||
|
||||
// Not so lightweight, copyable function object wrapper.
|
||||
class executor_function
|
||||
{
|
||||
public:
|
||||
template <typename F, typename Alloc>
|
||||
explicit executor_function(const F& f, const Alloc&)
|
||||
: impl_(new impl<typename decay<F>::type>(f))
|
||||
{
|
||||
}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
impl_->complete_(impl_.get());
|
||||
}
|
||||
|
||||
private:
|
||||
Function function_;
|
||||
Alloc allocator_;
|
||||
// Base class for polymorphic function implementations.
|
||||
struct impl_base
|
||||
{
|
||||
void (*complete_)(impl_base*);
|
||||
};
|
||||
|
||||
// Polymorphic function implementation.
|
||||
template <typename F>
|
||||
struct impl : impl_base
|
||||
{
|
||||
impl(const F& f)
|
||||
: function_(f)
|
||||
{
|
||||
complete_ = &executor_function::complete<F>;
|
||||
}
|
||||
|
||||
F function_;
|
||||
};
|
||||
|
||||
// Helper to complete function invocation.
|
||||
template <typename F>
|
||||
static void complete(impl_base* i)
|
||||
{
|
||||
static_cast<impl<F>*>(i)->function_();
|
||||
}
|
||||
|
||||
shared_ptr<impl_base> impl_;
|
||||
};
|
||||
|
||||
#endif // defined(BOOST_ASIO_HAS_MOVE)
|
||||
|
||||
// Lightweight, non-owning, copyable function object wrapper.
|
||||
class executor_function_view
|
||||
{
|
||||
public:
|
||||
template <typename F>
|
||||
explicit executor_function_view(F& f) BOOST_ASIO_NOEXCEPT
|
||||
: complete_(&executor_function_view::complete<F>),
|
||||
function_(&f)
|
||||
{
|
||||
}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
complete_(function_);
|
||||
}
|
||||
|
||||
private:
|
||||
// Helper to complete function invocation.
|
||||
template <typename F>
|
||||
static void complete(void* f)
|
||||
{
|
||||
(*static_cast<F*>(f))();
|
||||
}
|
||||
|
||||
void (*complete_)(void*);
|
||||
void* function_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <boost/asio/detail/memory.hpp>
|
||||
#include <boost/asio/detail/noncopyable.hpp>
|
||||
#include <boost/asio/detail/recycling_allocator.hpp>
|
||||
#include <boost/asio/detail/thread_info_base.hpp>
|
||||
#include <boost/asio/associated_allocator.hpp>
|
||||
#include <boost/asio/handler_alloc_hook.hpp>
|
||||
|
||||
@@ -29,11 +30,41 @@
|
||||
// boost_asio_handler_alloc_helpers namespace is defined here for that purpose.
|
||||
namespace boost_asio_handler_alloc_helpers {
|
||||
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
template <typename Handler>
|
||||
inline void error_if_hooks_are_defined(Handler& h)
|
||||
{
|
||||
using boost::asio::asio_handler_allocate;
|
||||
// If you get an error here it is because some of your handlers still
|
||||
// overload asio_handler_allocate, but this hook is no longer used.
|
||||
(void)static_cast<boost::asio::asio_handler_allocate_is_no_longer_used>(
|
||||
asio_handler_allocate(static_cast<std::size_t>(0),
|
||||
boost::asio::detail::addressof(h)));
|
||||
|
||||
using boost::asio::asio_handler_deallocate;
|
||||
// If you get an error here it is because some of your handlers still
|
||||
// overload asio_handler_deallocate, but this hook is no longer used.
|
||||
(void)static_cast<boost::asio::asio_handler_deallocate_is_no_longer_used>(
|
||||
asio_handler_deallocate(static_cast<void*>(0),
|
||||
static_cast<std::size_t>(0), boost::asio::detail::addressof(h)));
|
||||
}
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
|
||||
template <typename Handler>
|
||||
inline void* allocate(std::size_t s, Handler& h)
|
||||
{
|
||||
#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS)
|
||||
return ::operator new(s);
|
||||
#elif defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
// The asio_handler_allocate hook is no longer used to obtain memory.
|
||||
(void)&error_if_hooks_are_defined<Handler>;
|
||||
(void)h;
|
||||
#if !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
|
||||
return boost::asio::detail::thread_info_base::allocate(
|
||||
boost::asio::detail::thread_context::thread_call_stack::top(), s);
|
||||
#else // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
|
||||
return ::operator new(size);
|
||||
#endif // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
|
||||
#else
|
||||
using boost::asio::asio_handler_allocate;
|
||||
return asio_handler_allocate(s, boost::asio::detail::addressof(h));
|
||||
@@ -45,6 +76,17 @@ inline void deallocate(void* p, std::size_t s, Handler& h)
|
||||
{
|
||||
#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS)
|
||||
::operator delete(p);
|
||||
#elif defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
// The asio_handler_allocate hook is no longer used to obtain memory.
|
||||
(void)&error_if_hooks_are_defined<Handler>;
|
||||
(void)h;
|
||||
#if !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
|
||||
boost::asio::detail::thread_info_base::deallocate(
|
||||
boost::asio::detail::thread_context::thread_call_stack::top(), p, s);
|
||||
#else // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
|
||||
(void)s;
|
||||
::operator delete(p);
|
||||
#endif // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
|
||||
#else
|
||||
using boost::asio::asio_handler_deallocate;
|
||||
asio_handler_deallocate(p, s, boost::asio::detail::addressof(h));
|
||||
|
||||
@@ -26,12 +26,29 @@
|
||||
// namespace is defined here for that purpose.
|
||||
namespace boost_asio_handler_invoke_helpers {
|
||||
|
||||
#if defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
template <typename Function, typename Context>
|
||||
inline void error_if_hook_is_defined(Function& function, Context& context)
|
||||
{
|
||||
using boost::asio::asio_handler_invoke;
|
||||
// If you get an error here it is because some of your handlers still
|
||||
// overload asio_handler_invoke, but this hook is no longer used.
|
||||
(void)static_cast<boost::asio::asio_handler_invoke_is_no_longer_used>(
|
||||
asio_handler_invoke(function, boost::asio::detail::addressof(context)));
|
||||
}
|
||||
#endif // defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
|
||||
template <typename Function, typename Context>
|
||||
inline void invoke(Function& function, Context& context)
|
||||
{
|
||||
#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS)
|
||||
Function tmp(function);
|
||||
tmp();
|
||||
#elif defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
// The asio_handler_invoke hook is no longer used to invoke the function.
|
||||
(void)&error_if_hook_is_defined<Function, Context>;
|
||||
(void)context;
|
||||
function();
|
||||
#else
|
||||
using boost::asio::asio_handler_invoke;
|
||||
asio_handler_invoke(function, boost::asio::detail::addressof(context));
|
||||
@@ -44,6 +61,12 @@ inline void invoke(const Function& function, Context& context)
|
||||
#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS)
|
||||
Function tmp(function);
|
||||
tmp();
|
||||
#elif defined(BOOST_ASIO_NO_DEPRECATED)
|
||||
// The asio_handler_invoke hook is no longer used to invoke the function.
|
||||
(void)&error_if_hook_is_defined<const Function, Context>;
|
||||
(void)context;
|
||||
Function tmp(function);
|
||||
tmp();
|
||||
#else
|
||||
using boost::asio::asio_handler_invoke;
|
||||
asio_handler_invoke(function, boost::asio::detail::addressof(context));
|
||||
|
||||
@@ -90,6 +90,28 @@ public:
|
||||
// Initialise the tracking system.
|
||||
BOOST_ASIO_DECL static void init();
|
||||
|
||||
class location
|
||||
{
|
||||
public:
|
||||
// Constructor adds a location to the stack.
|
||||
BOOST_ASIO_DECL explicit location(const char* file,
|
||||
int line, const char* func);
|
||||
|
||||
// Destructor removes a location from the stack.
|
||||
BOOST_ASIO_DECL ~location();
|
||||
|
||||
private:
|
||||
// Disallow copying and assignment.
|
||||
location(const location&) BOOST_ASIO_DELETED;
|
||||
location& operator=(const location&) BOOST_ASIO_DELETED;
|
||||
|
||||
friend class handler_tracking;
|
||||
const char* file_;
|
||||
int line_;
|
||||
const char* func_;
|
||||
location* next_;
|
||||
};
|
||||
|
||||
// Record the creation of a tracked handler.
|
||||
BOOST_ASIO_DECL static void creation(
|
||||
execution_context& context, tracked_handler& h,
|
||||
@@ -178,6 +200,9 @@ private:
|
||||
# define BOOST_ASIO_HANDLER_TRACKING_INIT \
|
||||
boost::asio::detail::handler_tracking::init()
|
||||
|
||||
# define BOOST_ASIO_HANDLER_LOCATION(args) \
|
||||
boost::asio::detail::handler_tracking::location tracked_location args
|
||||
|
||||
# define BOOST_ASIO_HANDLER_CREATION(args) \
|
||||
boost::asio::detail::handler_tracking::creation args
|
||||
|
||||
@@ -214,6 +239,7 @@ private:
|
||||
# define BOOST_ASIO_INHERIT_TRACKED_HANDLER
|
||||
# define BOOST_ASIO_ALSO_INHERIT_TRACKED_HANDLER
|
||||
# define BOOST_ASIO_HANDLER_TRACKING_INIT (void)0
|
||||
# define BOOST_ASIO_HANDLER_LOCATION(loc) (void)0
|
||||
# define BOOST_ASIO_HANDLER_CREATION(args) (void)0
|
||||
# define BOOST_ASIO_HANDLER_COMPLETION(args) (void)0
|
||||
# define BOOST_ASIO_HANDLER_INVOCATION_BEGIN(args) (void)0
|
||||
|
||||
@@ -18,92 +18,277 @@
|
||||
#include <boost/asio/detail/config.hpp>
|
||||
#include <boost/asio/associated_executor.hpp>
|
||||
#include <boost/asio/detail/handler_invoke_helpers.hpp>
|
||||
#include <boost/asio/detail/type_traits.hpp>
|
||||
#include <boost/asio/execution/allocator.hpp>
|
||||
#include <boost/asio/execution/blocking.hpp>
|
||||
#include <boost/asio/execution/execute.hpp>
|
||||
#include <boost/asio/execution/executor.hpp>
|
||||
#include <boost/asio/execution/outstanding_work.hpp>
|
||||
#include <boost/asio/executor_work_guard.hpp>
|
||||
#include <boost/asio/prefer.hpp>
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
|
||||
class executor;
|
||||
class io_context;
|
||||
|
||||
namespace detail {
|
||||
|
||||
// A helper class template to allow completion handlers to be dispatched
|
||||
// through either the new executors framework or the old invocaton hook. The
|
||||
// primary template uses the new executors framework.
|
||||
template <typename Handler,
|
||||
typename IoExecutor = system_executor, typename HandlerExecutor
|
||||
= typename associated_executor<Handler, IoExecutor>::type>
|
||||
class handler_work
|
||||
template <typename Executor, typename CandidateExecutor = void,
|
||||
typename IoContext = io_context,
|
||||
typename PolymorphicExecutor = executor, typename = void>
|
||||
class handler_work_base
|
||||
{
|
||||
public:
|
||||
explicit handler_work(Handler& handler) BOOST_ASIO_NOEXCEPT
|
||||
: io_executor_(),
|
||||
executor_(boost::asio::get_associated_executor(handler, io_executor_))
|
||||
explicit handler_work_base(const Executor& ex) BOOST_ASIO_NOEXCEPT
|
||||
: executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
|
||||
{
|
||||
}
|
||||
|
||||
handler_work(Handler& handler, const IoExecutor& io_ex) BOOST_ASIO_NOEXCEPT
|
||||
: io_executor_(io_ex),
|
||||
executor_(boost::asio::get_associated_executor(handler, io_executor_))
|
||||
template <typename OtherExecutor>
|
||||
handler_work_base(const Executor& ex,
|
||||
const OtherExecutor&) BOOST_ASIO_NOEXCEPT
|
||||
: executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
|
||||
{
|
||||
}
|
||||
|
||||
static void start(Handler& handler) BOOST_ASIO_NOEXCEPT
|
||||
handler_work_base(const handler_work_base& other) BOOST_ASIO_NOEXCEPT
|
||||
: executor_(other.executor_)
|
||||
{
|
||||
HandlerExecutor ex(boost::asio::get_associated_executor(handler));
|
||||
ex.on_work_started();
|
||||
}
|
||||
|
||||
static void start(Handler& handler,
|
||||
const IoExecutor& io_ex) BOOST_ASIO_NOEXCEPT
|
||||
#if defined(BOOST_ASIO_HAS_MOVE)
|
||||
handler_work_base(handler_work_base&& other) BOOST_ASIO_NOEXCEPT
|
||||
: executor_(BOOST_ASIO_MOVE_CAST(executor_type)(other.executor_))
|
||||
{
|
||||
HandlerExecutor ex(boost::asio::get_associated_executor(handler, io_ex));
|
||||
ex.on_work_started();
|
||||
io_ex.on_work_started();
|
||||
}
|
||||
#endif // defined(BOOST_ASIO_HAS_MOVE)
|
||||
|
||||
bool owns_work() const BOOST_ASIO_NOEXCEPT
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
~handler_work()
|
||||
template <typename Function, typename Handler>
|
||||
void dispatch(Function& function, Handler& handler)
|
||||
{
|
||||
io_executor_.on_work_finished();
|
||||
executor_.on_work_finished();
|
||||
execution::execute(
|
||||
boost::asio::prefer(executor_,
|
||||
execution::blocking.possibly,
|
||||
execution::allocator((get_associated_allocator)(handler))),
|
||||
BOOST_ASIO_MOVE_CAST(Function)(function));
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
void complete(Function& function, Handler& handler)
|
||||
private:
|
||||
typedef typename decay<
|
||||
typename prefer_result_type<Executor,
|
||||
execution::outstanding_work_t::tracked_t
|
||||
>::type
|
||||
>::type executor_type;
|
||||
|
||||
executor_type executor_;
|
||||
};
|
||||
|
||||
template <typename Executor, typename CandidateExecutor,
|
||||
typename IoContext, typename PolymorphicExecutor>
|
||||
class handler_work_base<Executor, CandidateExecutor,
|
||||
IoContext, PolymorphicExecutor,
|
||||
typename enable_if<
|
||||
!execution::is_executor<Executor>::value
|
||||
&& (!is_same<Executor, PolymorphicExecutor>::value
|
||||
|| !is_same<CandidateExecutor, void>::value)
|
||||
>::type>
|
||||
{
|
||||
public:
|
||||
explicit handler_work_base(const Executor& ex) BOOST_ASIO_NOEXCEPT
|
||||
: executor_(ex),
|
||||
owns_work_(true)
|
||||
{
|
||||
executor_.on_work_started();
|
||||
}
|
||||
|
||||
handler_work_base(const Executor& ex,
|
||||
const Executor& candidate) BOOST_ASIO_NOEXCEPT
|
||||
: executor_(ex),
|
||||
owns_work_(ex != candidate)
|
||||
{
|
||||
if (owns_work_)
|
||||
executor_.on_work_started();
|
||||
}
|
||||
|
||||
template <typename OtherExecutor>
|
||||
handler_work_base(const Executor& ex,
|
||||
const OtherExecutor&) BOOST_ASIO_NOEXCEPT
|
||||
: executor_(ex),
|
||||
owns_work_(true)
|
||||
{
|
||||
executor_.on_work_started();
|
||||
}
|
||||
|
||||
handler_work_base(const handler_work_base& other) BOOST_ASIO_NOEXCEPT
|
||||
: executor_(other.executor_),
|
||||
owns_work_(other.owns_work_)
|
||||
{
|
||||
if (owns_work_)
|
||||
executor_.on_work_started();
|
||||
}
|
||||
|
||||
#if defined(BOOST_ASIO_HAS_MOVE)
|
||||
handler_work_base(handler_work_base&& other) BOOST_ASIO_NOEXCEPT
|
||||
: executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)),
|
||||
owns_work_(other.owns_work_)
|
||||
{
|
||||
other.owns_work_ = false;
|
||||
}
|
||||
#endif // defined(BOOST_ASIO_HAS_MOVE)
|
||||
|
||||
~handler_work_base()
|
||||
{
|
||||
if (owns_work_)
|
||||
executor_.on_work_finished();
|
||||
}
|
||||
|
||||
bool owns_work() const BOOST_ASIO_NOEXCEPT
|
||||
{
|
||||
return owns_work_;
|
||||
}
|
||||
|
||||
template <typename Function, typename Handler>
|
||||
void dispatch(Function& function, Handler& handler)
|
||||
{
|
||||
executor_.dispatch(BOOST_ASIO_MOVE_CAST(Function)(function),
|
||||
boost::asio::get_associated_allocator(handler));
|
||||
}
|
||||
|
||||
private:
|
||||
// Disallow copying and assignment.
|
||||
handler_work(const handler_work&);
|
||||
handler_work& operator=(const handler_work&);
|
||||
|
||||
IoExecutor io_executor_;
|
||||
HandlerExecutor executor_;
|
||||
Executor executor_;
|
||||
bool owns_work_;
|
||||
};
|
||||
|
||||
// This specialisation dispatches a handler through the old invocation hook.
|
||||
// The specialisation is not strictly required for correctness, as the
|
||||
// system_executor will dispatch through the hook anyway. However, by doing
|
||||
// this we avoid an extra copy of the handler.
|
||||
template <typename Handler>
|
||||
class handler_work<Handler, system_executor, system_executor>
|
||||
template <typename Executor, typename IoContext, typename PolymorphicExecutor>
|
||||
class handler_work_base<Executor, void, IoContext, PolymorphicExecutor,
|
||||
typename enable_if<
|
||||
is_same<
|
||||
Executor,
|
||||
typename IoContext::executor_type
|
||||
>::value
|
||||
>::type>
|
||||
{
|
||||
public:
|
||||
explicit handler_work(Handler&) BOOST_ASIO_NOEXCEPT {}
|
||||
static void start(Handler&) BOOST_ASIO_NOEXCEPT {}
|
||||
~handler_work() {}
|
||||
explicit handler_work_base(const Executor&)
|
||||
{
|
||||
}
|
||||
|
||||
bool owns_work() const BOOST_ASIO_NOEXCEPT
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Executor, typename IoContext>
|
||||
class handler_work_base<Executor, void, IoContext, Executor>
|
||||
{
|
||||
public:
|
||||
explicit handler_work_base(const Executor& ex) BOOST_ASIO_NOEXCEPT
|
||||
#if !defined(BOOST_ASIO_NO_TYPEID)
|
||||
: executor_(
|
||||
ex.target_type() == typeid(typename IoContext::executor_type)
|
||||
? Executor() : ex)
|
||||
#else // !defined(BOOST_ASIO_NO_TYPEID)
|
||||
: executor_(ex)
|
||||
#endif // !defined(BOOST_ASIO_NO_TYPEID)
|
||||
{
|
||||
if (executor_)
|
||||
executor_.on_work_started();
|
||||
}
|
||||
|
||||
handler_work_base(const Executor& ex,
|
||||
const Executor& candidate) BOOST_ASIO_NOEXCEPT
|
||||
: executor_(ex != candidate ? ex : Executor())
|
||||
{
|
||||
if (executor_)
|
||||
executor_.on_work_started();
|
||||
}
|
||||
|
||||
template <typename OtherExecutor>
|
||||
handler_work_base(const Executor& ex,
|
||||
const OtherExecutor&) BOOST_ASIO_NOEXCEPT
|
||||
: executor_(ex)
|
||||
{
|
||||
executor_.on_work_started();
|
||||
}
|
||||
|
||||
handler_work_base(const handler_work_base& other) BOOST_ASIO_NOEXCEPT
|
||||
: executor_(other.executor_)
|
||||
{
|
||||
if (executor_)
|
||||
executor_.on_work_started();
|
||||
}
|
||||
|
||||
#if defined(BOOST_ASIO_HAS_MOVE)
|
||||
handler_work_base(handler_work_base&& other) BOOST_ASIO_NOEXCEPT
|
||||
: executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_))
|
||||
{
|
||||
}
|
||||
#endif // defined(BOOST_ASIO_HAS_MOVE)
|
||||
|
||||
~handler_work_base()
|
||||
{
|
||||
if (executor_)
|
||||
executor_.on_work_finished();
|
||||
}
|
||||
|
||||
bool owns_work() const BOOST_ASIO_NOEXCEPT
|
||||
{
|
||||
return !!executor_;
|
||||
}
|
||||
|
||||
template <typename Function, typename Handler>
|
||||
void dispatch(Function& function, Handler& handler)
|
||||
{
|
||||
executor_.dispatch(BOOST_ASIO_MOVE_CAST(Function)(function),
|
||||
boost::asio::get_associated_allocator(handler));
|
||||
}
|
||||
|
||||
private:
|
||||
Executor executor_;
|
||||
};
|
||||
|
||||
template <typename Handler, typename IoExecutor,
|
||||
typename HandlerExecutor =
|
||||
typename associated_executor<Handler, IoExecutor>::type>
|
||||
class handler_work :
|
||||
handler_work_base<IoExecutor>,
|
||||
handler_work_base<HandlerExecutor, IoExecutor>
|
||||
{
|
||||
public:
|
||||
handler_work(Handler& handler, const IoExecutor& io_ex) BOOST_ASIO_NOEXCEPT
|
||||
: handler_work_base<IoExecutor>(io_ex),
|
||||
handler_work_base<HandlerExecutor, IoExecutor>(
|
||||
boost::asio::get_associated_executor(handler, io_ex), io_ex)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
void complete(Function& function, Handler& handler)
|
||||
{
|
||||
boost_asio_handler_invoke_helpers::invoke(function, handler);
|
||||
if (!handler_work_base<IoExecutor>::owns_work()
|
||||
&& !handler_work_base<HandlerExecutor, IoExecutor>::owns_work())
|
||||
{
|
||||
// When using a native implementation, I/O completion handlers are
|
||||
// already dispatched according to the execution context's executor's
|
||||
// rules. We can call the function directly.
|
||||
boost_asio_handler_invoke_helpers::invoke(function, handler);
|
||||
}
|
||||
else
|
||||
{
|
||||
handler_work_base<HandlerExecutor,
|
||||
IoExecutor>::dispatch(function, handler);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Disallow copying and assignment.
|
||||
handler_work(const handler_work&);
|
||||
handler_work& operator=(const handler_work&);
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -33,10 +33,8 @@ namespace descriptor_ops {
|
||||
|
||||
int open(const char* path, int flags, boost::system::error_code& ec)
|
||||
{
|
||||
errno = 0;
|
||||
int result = error_wrapper(::open(path, flags), ec);
|
||||
if (result >= 0)
|
||||
ec = boost::system::error_code();
|
||||
int result = ::open(path, flags);
|
||||
get_last_error(ec, result < 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -45,8 +43,8 @@ int close(int d, state_type& state, boost::system::error_code& ec)
|
||||
int result = 0;
|
||||
if (d != -1)
|
||||
{
|
||||
errno = 0;
|
||||
result = error_wrapper(::close(d), ec);
|
||||
result = ::close(d);
|
||||
get_last_error(ec, result < 0);
|
||||
|
||||
if (result != 0
|
||||
&& (ec == boost::asio::error::would_block
|
||||
@@ -68,13 +66,11 @@ int close(int d, state_type& state, boost::system::error_code& ec)
|
||||
#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
|
||||
state &= ~non_blocking;
|
||||
|
||||
errno = 0;
|
||||
result = error_wrapper(::close(d), ec);
|
||||
result = ::close(d);
|
||||
get_last_error(ec, result < 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (result == 0)
|
||||
ec = boost::system::error_code();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -87,23 +83,23 @@ bool set_user_non_blocking(int d, state_type& state,
|
||||
return false;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
#if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
|
||||
int result = error_wrapper(::fcntl(d, F_GETFL, 0), ec);
|
||||
int result = ::fcntl(d, F_GETFL, 0);
|
||||
get_last_error(ec, result < 0);
|
||||
if (result >= 0)
|
||||
{
|
||||
errno = 0;
|
||||
int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
|
||||
result = error_wrapper(::fcntl(d, F_SETFL, flag), ec);
|
||||
result = ::fcntl(d, F_SETFL, flag);
|
||||
get_last_error(ec, result < 0);
|
||||
}
|
||||
#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
|
||||
ioctl_arg_type arg = (value ? 1 : 0);
|
||||
int result = error_wrapper(::ioctl(d, FIONBIO, &arg), ec);
|
||||
int result = ::ioctl(d, FIONBIO, &arg);
|
||||
get_last_error(ec, result < 0);
|
||||
#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
|
||||
|
||||
if (result >= 0)
|
||||
{
|
||||
ec = boost::system::error_code();
|
||||
if (value)
|
||||
state |= user_set_non_blocking;
|
||||
else
|
||||
@@ -137,23 +133,23 @@ bool set_internal_non_blocking(int d, state_type& state,
|
||||
return false;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
#if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
|
||||
int result = error_wrapper(::fcntl(d, F_GETFL, 0), ec);
|
||||
int result = ::fcntl(d, F_GETFL, 0);
|
||||
get_last_error(ec, result < 0);
|
||||
if (result >= 0)
|
||||
{
|
||||
errno = 0;
|
||||
int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
|
||||
result = error_wrapper(::fcntl(d, F_SETFL, flag), ec);
|
||||
result = ::fcntl(d, F_SETFL, flag);
|
||||
get_last_error(ec, result < 0);
|
||||
}
|
||||
#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
|
||||
ioctl_arg_type arg = (value ? 1 : 0);
|
||||
int result = error_wrapper(::ioctl(d, FIONBIO, &arg), ec);
|
||||
int result = ::ioctl(d, FIONBIO, &arg);
|
||||
get_last_error(ec, result < 0);
|
||||
#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
|
||||
|
||||
if (result >= 0)
|
||||
{
|
||||
ec = boost::system::error_code();
|
||||
if (value)
|
||||
state |= internal_non_blocking;
|
||||
else
|
||||
@@ -176,7 +172,7 @@ std::size_t sync_read(int d, state_type state, buf* bufs,
|
||||
// A request to read 0 bytes on a stream is a no-op.
|
||||
if (all_empty)
|
||||
{
|
||||
ec = boost::system::error_code();
|
||||
ec.assign(0, ec.category());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -184,9 +180,54 @@ std::size_t sync_read(int d, state_type state, buf* bufs,
|
||||
for (;;)
|
||||
{
|
||||
// Try to complete the operation without blocking.
|
||||
errno = 0;
|
||||
signed_size_type bytes = error_wrapper(::readv(
|
||||
d, bufs, static_cast<int>(count)), ec);
|
||||
signed_size_type bytes = ::readv(d, bufs, static_cast<int>(count));
|
||||
get_last_error(ec, bytes < 0);
|
||||
|
||||
// Check if operation succeeded.
|
||||
if (bytes > 0)
|
||||
return bytes;
|
||||
|
||||
// Check for EOF.
|
||||
if (bytes == 0)
|
||||
{
|
||||
ec = boost::asio::error::eof;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Operation failed.
|
||||
if ((state & user_set_non_blocking)
|
||||
|| (ec != boost::asio::error::would_block
|
||||
&& ec != boost::asio::error::try_again))
|
||||
return 0;
|
||||
|
||||
// Wait for descriptor to become ready.
|
||||
if (descriptor_ops::poll_read(d, 0, ec) < 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t sync_read1(int d, state_type state, void* data,
|
||||
std::size_t size, boost::system::error_code& ec)
|
||||
{
|
||||
if (d == -1)
|
||||
{
|
||||
ec = boost::asio::error::bad_descriptor;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// A request to read 0 bytes on a stream is a no-op.
|
||||
if (size == 0)
|
||||
{
|
||||
ec.assign(0, ec.category());
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read some data.
|
||||
for (;;)
|
||||
{
|
||||
// Try to complete the operation without blocking.
|
||||
signed_size_type bytes = ::read(d, data, size);
|
||||
get_last_error(ec, bytes < 0);
|
||||
|
||||
// Check if operation succeeded.
|
||||
if (bytes > 0)
|
||||
@@ -217,9 +258,8 @@ bool non_blocking_read(int d, buf* bufs, std::size_t count,
|
||||
for (;;)
|
||||
{
|
||||
// Read some data.
|
||||
errno = 0;
|
||||
signed_size_type bytes = error_wrapper(::readv(
|
||||
d, bufs, static_cast<int>(count)), ec);
|
||||
signed_size_type bytes = ::readv(d, bufs, static_cast<int>(count));
|
||||
get_last_error(ec, bytes < 0);
|
||||
|
||||
// Check for end of stream.
|
||||
if (bytes == 0)
|
||||
@@ -228,6 +268,13 @@ bool non_blocking_read(int d, buf* bufs, std::size_t count,
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if operation succeeded.
|
||||
if (bytes > 0)
|
||||
{
|
||||
bytes_transferred = bytes;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Retry operation if interrupted by signal.
|
||||
if (ec == boost::asio::error::interrupted)
|
||||
continue;
|
||||
@@ -237,15 +284,46 @@ bool non_blocking_read(int d, buf* bufs, std::size_t count,
|
||||
|| ec == boost::asio::error::try_again)
|
||||
return false;
|
||||
|
||||
// Operation is complete.
|
||||
// Operation failed.
|
||||
bytes_transferred = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool non_blocking_read1(int d, void* data, std::size_t size,
|
||||
boost::system::error_code& ec, std::size_t& bytes_transferred)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
// Read some data.
|
||||
signed_size_type bytes = ::read(d, data, size);
|
||||
get_last_error(ec, bytes < 0);
|
||||
|
||||
// Check for end of stream.
|
||||
if (bytes == 0)
|
||||
{
|
||||
ec = boost::asio::error::eof;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if operation succeeded.
|
||||
if (bytes > 0)
|
||||
{
|
||||
ec = boost::system::error_code();
|
||||
bytes_transferred = bytes;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
bytes_transferred = 0;
|
||||
|
||||
// Retry operation if interrupted by signal.
|
||||
if (ec == boost::asio::error::interrupted)
|
||||
continue;
|
||||
|
||||
// Check if we need to run the operation again.
|
||||
if (ec == boost::asio::error::would_block
|
||||
|| ec == boost::asio::error::try_again)
|
||||
return false;
|
||||
|
||||
// Operation failed.
|
||||
bytes_transferred = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -262,7 +340,7 @@ std::size_t sync_write(int d, state_type state, const buf* bufs,
|
||||
// A request to write 0 bytes on a stream is a no-op.
|
||||
if (all_empty)
|
||||
{
|
||||
ec = boost::system::error_code();
|
||||
ec.assign(0, ec.category());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -270,9 +348,47 @@ std::size_t sync_write(int d, state_type state, const buf* bufs,
|
||||
for (;;)
|
||||
{
|
||||
// Try to complete the operation without blocking.
|
||||
errno = 0;
|
||||
signed_size_type bytes = error_wrapper(::writev(
|
||||
d, bufs, static_cast<int>(count)), ec);
|
||||
signed_size_type bytes = ::writev(d, bufs, static_cast<int>(count));
|
||||
get_last_error(ec, bytes < 0);
|
||||
|
||||
// Check if operation succeeded.
|
||||
if (bytes > 0)
|
||||
return bytes;
|
||||
|
||||
// Operation failed.
|
||||
if ((state & user_set_non_blocking)
|
||||
|| (ec != boost::asio::error::would_block
|
||||
&& ec != boost::asio::error::try_again))
|
||||
return 0;
|
||||
|
||||
// Wait for descriptor to become ready.
|
||||
if (descriptor_ops::poll_write(d, 0, ec) < 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t sync_write1(int d, state_type state, const void* data,
|
||||
std::size_t size, boost::system::error_code& ec)
|
||||
{
|
||||
if (d == -1)
|
||||
{
|
||||
ec = boost::asio::error::bad_descriptor;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// A request to write 0 bytes on a stream is a no-op.
|
||||
if (size == 0)
|
||||
{
|
||||
ec.assign(0, ec.category());
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Write some data.
|
||||
for (;;)
|
||||
{
|
||||
// Try to complete the operation without blocking.
|
||||
signed_size_type bytes = ::write(d, data, size);
|
||||
get_last_error(ec, bytes < 0);
|
||||
|
||||
// Check if operation succeeded.
|
||||
if (bytes > 0)
|
||||
@@ -296,9 +412,15 @@ bool non_blocking_write(int d, const buf* bufs, std::size_t count,
|
||||
for (;;)
|
||||
{
|
||||
// Write some data.
|
||||
errno = 0;
|
||||
signed_size_type bytes = error_wrapper(::writev(
|
||||
d, bufs, static_cast<int>(count)), ec);
|
||||
signed_size_type bytes = ::writev(d, bufs, static_cast<int>(count));
|
||||
get_last_error(ec, bytes < 0);
|
||||
|
||||
// Check if operation succeeded.
|
||||
if (bytes >= 0)
|
||||
{
|
||||
bytes_transferred = bytes;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Retry operation if interrupted by signal.
|
||||
if (ec == boost::asio::error::interrupted)
|
||||
@@ -309,15 +431,39 @@ bool non_blocking_write(int d, const buf* bufs, std::size_t count,
|
||||
|| ec == boost::asio::error::try_again)
|
||||
return false;
|
||||
|
||||
// Operation is complete.
|
||||
// Operation failed.
|
||||
bytes_transferred = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool non_blocking_write1(int d, const void* data, std::size_t size,
|
||||
boost::system::error_code& ec, std::size_t& bytes_transferred)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
// Write some data.
|
||||
signed_size_type bytes = ::write(d, data, size);
|
||||
get_last_error(ec, bytes < 0);
|
||||
|
||||
// Check if operation succeeded.
|
||||
if (bytes >= 0)
|
||||
{
|
||||
ec = boost::system::error_code();
|
||||
bytes_transferred = bytes;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
bytes_transferred = 0;
|
||||
|
||||
// Retry operation if interrupted by signal.
|
||||
if (ec == boost::asio::error::interrupted)
|
||||
continue;
|
||||
|
||||
// Check if we need to run the operation again.
|
||||
if (ec == boost::asio::error::would_block
|
||||
|| ec == boost::asio::error::try_again)
|
||||
return false;
|
||||
|
||||
// Operation failed.
|
||||
bytes_transferred = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -331,13 +477,11 @@ int ioctl(int d, state_type& state, long cmd,
|
||||
return -1;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
int result = error_wrapper(::ioctl(d, cmd, arg), ec);
|
||||
int result = ::ioctl(d, cmd, arg);
|
||||
get_last_error(ec, result < 0);
|
||||
|
||||
if (result >= 0)
|
||||
{
|
||||
ec = boost::system::error_code();
|
||||
|
||||
// When updating the non-blocking mode we always perform the ioctl syscall,
|
||||
// even if the flags would otherwise indicate that the descriptor is
|
||||
// already in the correct state. This ensures that the underlying
|
||||
@@ -371,10 +515,8 @@ int fcntl(int d, int cmd, boost::system::error_code& ec)
|
||||
return -1;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
int result = error_wrapper(::fcntl(d, cmd), ec);
|
||||
if (result != -1)
|
||||
ec = boost::system::error_code();
|
||||
int result = ::fcntl(d, cmd);
|
||||
get_last_error(ec, result < 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -386,10 +528,8 @@ int fcntl(int d, int cmd, long arg, boost::system::error_code& ec)
|
||||
return -1;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
int result = error_wrapper(::fcntl(d, cmd, arg), ec);
|
||||
if (result != -1)
|
||||
ec = boost::system::error_code();
|
||||
int result = ::fcntl(d, cmd, arg);
|
||||
get_last_error(ec, result < 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -406,13 +546,11 @@ int poll_read(int d, state_type state, boost::system::error_code& ec)
|
||||
fds.events = POLLIN;
|
||||
fds.revents = 0;
|
||||
int timeout = (state & user_set_non_blocking) ? 0 : -1;
|
||||
errno = 0;
|
||||
int result = error_wrapper(::poll(&fds, 1, timeout), ec);
|
||||
int result = ::poll(&fds, 1, timeout);
|
||||
get_last_error(ec, result < 0);
|
||||
if (result == 0)
|
||||
ec = (state & user_set_non_blocking)
|
||||
? boost::asio::error::would_block : boost::system::error_code();
|
||||
else if (result > 0)
|
||||
ec = boost::system::error_code();
|
||||
if (state & user_set_non_blocking)
|
||||
ec = boost::asio::error::would_block;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -429,13 +567,11 @@ int poll_write(int d, state_type state, boost::system::error_code& ec)
|
||||
fds.events = POLLOUT;
|
||||
fds.revents = 0;
|
||||
int timeout = (state & user_set_non_blocking) ? 0 : -1;
|
||||
errno = 0;
|
||||
int result = error_wrapper(::poll(&fds, 1, timeout), ec);
|
||||
int result = ::poll(&fds, 1, timeout);
|
||||
get_last_error(ec, result < 0);
|
||||
if (result == 0)
|
||||
ec = (state & user_set_non_blocking)
|
||||
? boost::asio::error::would_block : boost::system::error_code();
|
||||
else if (result > 0)
|
||||
ec = boost::system::error_code();
|
||||
if (state & user_set_non_blocking)
|
||||
ec = boost::asio::error::would_block;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -452,13 +588,11 @@ int poll_error(int d, state_type state, boost::system::error_code& ec)
|
||||
fds.events = POLLPRI | POLLERR | POLLHUP;
|
||||
fds.revents = 0;
|
||||
int timeout = (state & user_set_non_blocking) ? 0 : -1;
|
||||
errno = 0;
|
||||
int result = error_wrapper(::poll(&fds, 1, timeout), ec);
|
||||
int result = ::poll(&fds, 1, timeout);
|
||||
get_last_error(ec, result < 0);
|
||||
if (result == 0)
|
||||
ec = (state & user_set_non_blocking)
|
||||
? boost::asio::error::would_block : boost::system::error_code();
|
||||
else if (result > 0)
|
||||
ec = boost::system::error_code();
|
||||
if (state & user_set_non_blocking)
|
||||
ec = boost::asio::error::would_block;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -74,11 +74,12 @@ struct handler_tracking::tracking_state
|
||||
static_mutex mutex_;
|
||||
uint64_t next_id_;
|
||||
tss_ptr<completion>* current_completion_;
|
||||
tss_ptr<location>* current_location_;
|
||||
};
|
||||
|
||||
handler_tracking::tracking_state* handler_tracking::get_state()
|
||||
{
|
||||
static tracking_state state = { BOOST_ASIO_STATIC_MUTEX_INIT, 1, 0 };
|
||||
static tracking_state state = { BOOST_ASIO_STATIC_MUTEX_INIT, 1, 0, 0 };
|
||||
return &state;
|
||||
}
|
||||
|
||||
@@ -91,6 +92,25 @@ void handler_tracking::init()
|
||||
static_mutex::scoped_lock lock(state->mutex_);
|
||||
if (state->current_completion_ == 0)
|
||||
state->current_completion_ = new tss_ptr<completion>;
|
||||
if (state->current_location_ == 0)
|
||||
state->current_location_ = new tss_ptr<location>;
|
||||
}
|
||||
|
||||
handler_tracking::location::location(
|
||||
const char* file, int line, const char* func)
|
||||
: file_(file),
|
||||
line_(line),
|
||||
func_(func),
|
||||
next_(*get_state()->current_location_)
|
||||
{
|
||||
if (file_)
|
||||
*get_state()->current_location_ = this;
|
||||
}
|
||||
|
||||
handler_tracking::location::~location()
|
||||
{
|
||||
if (file_)
|
||||
*get_state()->current_location_ = next_;
|
||||
}
|
||||
|
||||
void handler_tracking::creation(execution_context&,
|
||||
@@ -110,6 +130,24 @@ void handler_tracking::creation(execution_context&,
|
||||
if (completion* current_completion = *state->current_completion_)
|
||||
current_id = current_completion->id_;
|
||||
|
||||
for (location* current_location = *state->current_location_;
|
||||
current_location; current_location = current_location->next_)
|
||||
{
|
||||
write_line(
|
||||
#if defined(BOOST_ASIO_WINDOWS)
|
||||
"@asio|%I64u.%06I64u|%I64u^%I64u|%s%s%.80s%s(%.80s:%d)\n",
|
||||
#else // defined(BOOST_ASIO_WINDOWS)
|
||||
"@asio|%llu.%06llu|%llu^%llu|%s%s%.80s%s(%.80s:%d)\n",
|
||||
#endif // defined(BOOST_ASIO_WINDOWS)
|
||||
timestamp.seconds, timestamp.microseconds,
|
||||
current_id, h.id_,
|
||||
current_location == *state->current_location_ ? "in " : "called from ",
|
||||
current_location->func_ ? "'" : "",
|
||||
current_location->func_ ? current_location->func_ : "",
|
||||
current_location->func_ ? "' " : "",
|
||||
current_location->file_, current_location->line_);
|
||||
}
|
||||
|
||||
write_line(
|
||||
#if defined(BOOST_ASIO_WINDOWS)
|
||||
"@asio|%I64u.%06I64u|%I64u*%I64u|%.20s@%p.%.50s\n",
|
||||
|
||||
@@ -70,8 +70,8 @@ boost::system::error_code reactive_serial_port_service::open(
|
||||
|
||||
// Set up default serial port options.
|
||||
termios ios;
|
||||
errno = 0;
|
||||
s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec);
|
||||
s = ::tcgetattr(fd, &ios);
|
||||
descriptor_ops::get_last_error(ec, s < 0);
|
||||
if (s >= 0)
|
||||
{
|
||||
#if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE)
|
||||
@@ -86,8 +86,8 @@ boost::system::error_code reactive_serial_port_service::open(
|
||||
#endif
|
||||
ios.c_iflag |= IGNPAR;
|
||||
ios.c_cflag |= CREAD | CLOCAL;
|
||||
errno = 0;
|
||||
s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec);
|
||||
s = ::tcsetattr(fd, TCSANOW, &ios);
|
||||
descriptor_ops::get_last_error(ec, s < 0);
|
||||
}
|
||||
if (s < 0)
|
||||
{
|
||||
@@ -112,18 +112,16 @@ boost::system::error_code reactive_serial_port_service::do_set_option(
|
||||
const void* option, boost::system::error_code& ec)
|
||||
{
|
||||
termios ios;
|
||||
errno = 0;
|
||||
descriptor_ops::error_wrapper(::tcgetattr(
|
||||
descriptor_service_.native_handle(impl), &ios), ec);
|
||||
if (ec)
|
||||
int s = ::tcgetattr(descriptor_service_.native_handle(impl), &ios);
|
||||
descriptor_ops::get_last_error(ec, s < 0);
|
||||
if (s < 0)
|
||||
return ec;
|
||||
|
||||
if (store(option, ios, ec))
|
||||
return ec;
|
||||
|
||||
errno = 0;
|
||||
descriptor_ops::error_wrapper(::tcsetattr(
|
||||
descriptor_service_.native_handle(impl), TCSANOW, &ios), ec);
|
||||
s = ::tcsetattr(descriptor_service_.native_handle(impl), TCSANOW, &ios);
|
||||
descriptor_ops::get_last_error(ec, s < 0);
|
||||
return ec;
|
||||
}
|
||||
|
||||
@@ -133,10 +131,9 @@ boost::system::error_code reactive_serial_port_service::do_get_option(
|
||||
void* option, boost::system::error_code& ec) const
|
||||
{
|
||||
termios ios;
|
||||
errno = 0;
|
||||
descriptor_ops::error_wrapper(::tcgetattr(
|
||||
descriptor_service_.native_handle(impl), &ios), ec);
|
||||
if (ec)
|
||||
int s = ::tcgetattr(descriptor_service_.native_handle(impl), &ios);
|
||||
descriptor_ops::get_last_error(ec, s < 0);
|
||||
if (s < 0)
|
||||
return ec;
|
||||
|
||||
return load(option, ios, ec);
|
||||
|
||||
@@ -136,6 +136,10 @@ scheduler::~scheduler()
|
||||
{
|
||||
if (thread_)
|
||||
{
|
||||
mutex::scoped_lock lock(mutex_);
|
||||
shutdown_ = true;
|
||||
stop_all_threads(lock);
|
||||
lock.unlock();
|
||||
thread_->join();
|
||||
delete thread_;
|
||||
}
|
||||
@@ -321,6 +325,12 @@ void scheduler::compensating_work_started()
|
||||
++static_cast<thread_info*>(this_thread)->private_outstanding_work;
|
||||
}
|
||||
|
||||
void scheduler::capture_current_exception()
|
||||
{
|
||||
if (thread_info_base* this_thread = thread_call_stack::contains(this))
|
||||
this_thread->capture_current_exception();
|
||||
}
|
||||
|
||||
void scheduler::post_immediate_completion(
|
||||
scheduler::operation* op, bool is_continuation)
|
||||
{
|
||||
@@ -445,6 +455,7 @@ std::size_t scheduler::do_run_one(mutex::scoped_lock& lock,
|
||||
|
||||
// Complete the operation. May throw an exception. Deletes the object.
|
||||
o->complete(this, ec, task_result);
|
||||
this_thread.rethrow_pending_exception();
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -525,6 +536,7 @@ std::size_t scheduler::do_wait_one(mutex::scoped_lock& lock,
|
||||
|
||||
// Complete the operation. May throw an exception. Deletes the object.
|
||||
o->complete(this, ec, task_result);
|
||||
this_thread.rethrow_pending_exception();
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -579,6 +591,7 @@ std::size_t scheduler::do_poll_one(mutex::scoped_lock& lock,
|
||||
|
||||
// Complete the operation. May throw an exception. Deletes the object.
|
||||
o->complete(this, ec, task_result);
|
||||
this_thread.rethrow_pending_exception();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -90,7 +90,8 @@ class signal_set_service::pipe_read_op : public reactor_op
|
||||
{
|
||||
public:
|
||||
pipe_read_op()
|
||||
: reactor_op(&pipe_read_op::do_perform, pipe_read_op::do_complete)
|
||||
: reactor_op(boost::system::error_code(),
|
||||
&pipe_read_op::do_perform, pipe_read_op::do_complete)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -20,6 +20,9 @@
|
||||
#include <boost/asio/detail/handler_invoke_helpers.hpp>
|
||||
#include <boost/asio/detail/recycling_allocator.hpp>
|
||||
#include <boost/asio/executor_work_guard.hpp>
|
||||
#include <boost/asio/defer.hpp>
|
||||
#include <boost/asio/dispatch.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
@@ -27,8 +30,137 @@ namespace boost {
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
template <typename F, typename Allocator>
|
||||
class strand_executor_service::allocator_binder
|
||||
{
|
||||
public:
|
||||
typedef Allocator allocator_type;
|
||||
|
||||
allocator_binder(BOOST_ASIO_MOVE_ARG(F) f, const Allocator& a)
|
||||
: f_(BOOST_ASIO_MOVE_CAST(F)(f)),
|
||||
allocator_(a)
|
||||
{
|
||||
}
|
||||
|
||||
allocator_binder(const allocator_binder& other)
|
||||
: f_(other.f_),
|
||||
allocator_(other.allocator_)
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(BOOST_ASIO_HAS_MOVE)
|
||||
allocator_binder(allocator_binder&& other)
|
||||
: f_(BOOST_ASIO_MOVE_CAST(F)(other.f_)),
|
||||
allocator_(BOOST_ASIO_MOVE_CAST(allocator_type)(other.allocator_))
|
||||
{
|
||||
}
|
||||
#endif // defined(BOOST_ASIO_HAS_MOVE)
|
||||
|
||||
allocator_type get_allocator() const BOOST_ASIO_NOEXCEPT
|
||||
{
|
||||
return allocator_;
|
||||
}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
f_();
|
||||
}
|
||||
|
||||
private:
|
||||
F f_;
|
||||
allocator_type allocator_;
|
||||
};
|
||||
|
||||
template <typename Executor>
|
||||
class strand_executor_service::invoker
|
||||
class strand_executor_service::invoker<Executor,
|
||||
typename enable_if<
|
||||
execution::is_executor<Executor>::value
|
||||
>::type>
|
||||
{
|
||||
public:
|
||||
invoker(const implementation_type& impl, Executor& ex)
|
||||
: impl_(impl),
|
||||
executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
|
||||
{
|
||||
}
|
||||
|
||||
invoker(const invoker& other)
|
||||
: impl_(other.impl_),
|
||||
executor_(other.executor_)
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(BOOST_ASIO_HAS_MOVE)
|
||||
invoker(invoker&& other)
|
||||
: impl_(BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_)),
|
||||
executor_(BOOST_ASIO_MOVE_CAST(executor_type)(other.executor_))
|
||||
{
|
||||
}
|
||||
#endif // defined(BOOST_ASIO_HAS_MOVE)
|
||||
|
||||
struct on_invoker_exit
|
||||
{
|
||||
invoker* this_;
|
||||
|
||||
~on_invoker_exit()
|
||||
{
|
||||
this_->impl_->mutex_->lock();
|
||||
this_->impl_->ready_queue_.push(this_->impl_->waiting_queue_);
|
||||
bool more_handlers = this_->impl_->locked_ =
|
||||
!this_->impl_->ready_queue_.empty();
|
||||
this_->impl_->mutex_->unlock();
|
||||
|
||||
if (more_handlers)
|
||||
{
|
||||
recycling_allocator<void> allocator;
|
||||
execution::execute(
|
||||
boost::asio::prefer(
|
||||
boost::asio::require(this_->executor_,
|
||||
execution::blocking.never),
|
||||
execution::allocator(allocator)),
|
||||
BOOST_ASIO_MOVE_CAST(invoker)(*this_));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void operator()()
|
||||
{
|
||||
// Indicate that this strand is executing on the current thread.
|
||||
call_stack<strand_impl>::context ctx(impl_.get());
|
||||
|
||||
// Ensure the next handler, if any, is scheduled on block exit.
|
||||
on_invoker_exit on_exit = { this };
|
||||
(void)on_exit;
|
||||
|
||||
// Run all ready handlers. No lock is required since the ready queue is
|
||||
// accessed only within the strand.
|
||||
boost::system::error_code ec;
|
||||
while (scheduler_operation* o = impl_->ready_queue_.front())
|
||||
{
|
||||
impl_->ready_queue_.pop();
|
||||
o->complete(impl_.get(), ec, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
typedef typename decay<
|
||||
typename prefer_result_type<
|
||||
Executor,
|
||||
execution::outstanding_work_t::tracked_t
|
||||
>::type
|
||||
>::type executor_type;
|
||||
|
||||
implementation_type impl_;
|
||||
executor_type executor_;
|
||||
};
|
||||
|
||||
#if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
|
||||
|
||||
template <typename Executor>
|
||||
class strand_executor_service::invoker<Executor,
|
||||
typename enable_if<
|
||||
!execution::is_executor<Executor>::value
|
||||
>::type>
|
||||
{
|
||||
public:
|
||||
invoker(const implementation_type& impl, Executor& ex)
|
||||
@@ -96,6 +228,68 @@ private:
|
||||
executor_work_guard<Executor> work_;
|
||||
};
|
||||
|
||||
#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
|
||||
|
||||
template <typename Executor, typename Function>
|
||||
inline void strand_executor_service::execute(const implementation_type& impl,
|
||||
Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function,
|
||||
typename enable_if<
|
||||
can_query<Executor, execution::allocator_t<void> >::value
|
||||
>::type*)
|
||||
{
|
||||
return strand_executor_service::execute(impl, ex,
|
||||
BOOST_ASIO_MOVE_CAST(Function)(function),
|
||||
boost::asio::query(ex, execution::allocator));
|
||||
}
|
||||
|
||||
template <typename Executor, typename Function>
|
||||
inline void strand_executor_service::execute(const implementation_type& impl,
|
||||
Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function,
|
||||
typename enable_if<
|
||||
!can_query<Executor, execution::allocator_t<void> >::value
|
||||
>::type*)
|
||||
{
|
||||
return strand_executor_service::execute(impl, ex,
|
||||
BOOST_ASIO_MOVE_CAST(Function)(function),
|
||||
std::allocator<void>());
|
||||
}
|
||||
|
||||
template <typename Executor, typename Function, typename Allocator>
|
||||
void strand_executor_service::execute(const implementation_type& impl,
|
||||
Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a)
|
||||
{
|
||||
typedef typename decay<Function>::type function_type;
|
||||
|
||||
// If the executor is not never-blocking, and we are already in the strand,
|
||||
// then the function can run immediately.
|
||||
if (boost::asio::query(ex, execution::blocking) != execution::blocking.never
|
||||
&& call_stack<strand_impl>::contains(impl.get()))
|
||||
{
|
||||
// Make a local, non-const copy of the function.
|
||||
function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(function));
|
||||
|
||||
fenced_block b(fenced_block::full);
|
||||
boost_asio_handler_invoke_helpers::invoke(tmp, tmp);
|
||||
return;
|
||||
}
|
||||
|
||||
// Allocate and construct an operation to wrap the function.
|
||||
typedef executor_op<function_type, Allocator> op;
|
||||
typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
|
||||
p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(function), a);
|
||||
|
||||
BOOST_ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,
|
||||
"strand_executor", impl.get(), 0, "execute"));
|
||||
|
||||
// Add the function to the strand and schedule the strand if required.
|
||||
bool first = enqueue(impl, p.p);
|
||||
p.v = p.p = 0;
|
||||
if (first)
|
||||
{
|
||||
execution::execute(ex, invoker<Executor>(impl, ex));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Executor, typename Function, typename Allocator>
|
||||
void strand_executor_service::dispatch(const implementation_type& impl,
|
||||
Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a)
|
||||
@@ -125,7 +319,11 @@ void strand_executor_service::dispatch(const implementation_type& impl,
|
||||
bool first = enqueue(impl, p.p);
|
||||
p.v = p.p = 0;
|
||||
if (first)
|
||||
ex.dispatch(invoker<Executor>(impl, ex), a);
|
||||
{
|
||||
boost::asio::dispatch(ex,
|
||||
allocator_binder<invoker<Executor>, Allocator>(
|
||||
invoker<Executor>(impl, ex), a));
|
||||
}
|
||||
}
|
||||
|
||||
// Request invocation of the given function and return immediately.
|
||||
@@ -147,7 +345,11 @@ void strand_executor_service::post(const implementation_type& impl,
|
||||
bool first = enqueue(impl, p.p);
|
||||
p.v = p.p = 0;
|
||||
if (first)
|
||||
ex.post(invoker<Executor>(impl, ex), a);
|
||||
{
|
||||
boost::asio::post(ex,
|
||||
allocator_binder<invoker<Executor>, Allocator>(
|
||||
invoker<Executor>(impl, ex), a));
|
||||
}
|
||||
}
|
||||
|
||||
// Request invocation of the given function and return immediately.
|
||||
@@ -169,7 +371,11 @@ void strand_executor_service::defer(const implementation_type& impl,
|
||||
bool first = enqueue(impl, p.p);
|
||||
p.v = p.p = 0;
|
||||
if (first)
|
||||
ex.defer(invoker<Executor>(impl, ex), a);
|
||||
{
|
||||
boost::asio::defer(ex,
|
||||
allocator_binder<invoker<Executor>, Allocator>(
|
||||
invoker<Executor>(impl, ex), a));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -36,7 +36,7 @@ inline strand_service::strand_impl::strand_impl()
|
||||
|
||||
struct strand_service::on_dispatch_exit
|
||||
{
|
||||
io_context_impl* io_context_;
|
||||
io_context_impl* io_context_impl_;
|
||||
strand_impl* impl_;
|
||||
|
||||
~on_dispatch_exit()
|
||||
@@ -47,7 +47,7 @@ struct strand_service::on_dispatch_exit
|
||||
impl_->mutex_.unlock();
|
||||
|
||||
if (more_handlers)
|
||||
io_context_->post_immediate_completion(impl_, false);
|
||||
io_context_impl_->post_immediate_completion(impl_, false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -64,10 +64,10 @@ void strand_service::dispatch(strand_service::implementation_type& impl,
|
||||
}
|
||||
|
||||
// Allocate and construct an operation to wrap the handler.
|
||||
typedef completion_handler<Handler> op;
|
||||
typedef completion_handler<Handler, io_context::executor_type> op;
|
||||
typename op::ptr p = { boost::asio::detail::addressof(handler),
|
||||
op::ptr::allocate(handler), 0 };
|
||||
p.p = new (p.v) op(handler);
|
||||
p.p = new (p.v) op(handler, io_context_.get_executor());
|
||||
|
||||
BOOST_ASIO_HANDLER_CREATION((this->context(),
|
||||
*p.p, "strand", impl, 0, "dispatch"));
|
||||
@@ -82,11 +82,10 @@ void strand_service::dispatch(strand_service::implementation_type& impl,
|
||||
call_stack<strand_impl>::context ctx(impl);
|
||||
|
||||
// Ensure the next handler, if any, is scheduled on block exit.
|
||||
on_dispatch_exit on_exit = { &io_context_, impl };
|
||||
on_dispatch_exit on_exit = { &io_context_impl_, impl };
|
||||
(void)on_exit;
|
||||
|
||||
completion_handler<Handler>::do_complete(
|
||||
&io_context_, o, boost::system::error_code(), 0);
|
||||
op::do_complete(&io_context_impl_, o, boost::system::error_code(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,10 +98,10 @@ void strand_service::post(strand_service::implementation_type& impl,
|
||||
boost_asio_handler_cont_helpers::is_continuation(handler);
|
||||
|
||||
// Allocate and construct an operation to wrap the handler.
|
||||
typedef completion_handler<Handler> op;
|
||||
typedef completion_handler<Handler, io_context::executor_type> op;
|
||||
typename op::ptr p = { boost::asio::detail::addressof(handler),
|
||||
op::ptr::allocate(handler), 0 };
|
||||
p.p = new (p.v) op(handler);
|
||||
p.p = new (p.v) op(handler, io_context_.get_executor());
|
||||
|
||||
BOOST_ASIO_HANDLER_CREATION((this->context(),
|
||||
*p.p, "strand", impl, 0, "post"));
|
||||
|
||||
@@ -44,7 +44,8 @@ struct strand_service::on_do_complete_exit
|
||||
|
||||
strand_service::strand_service(boost::asio::io_context& io_context)
|
||||
: boost::asio::detail::service_base<strand_service>(io_context),
|
||||
io_context_(boost::asio::use_service<io_context_impl>(io_context)),
|
||||
io_context_(io_context),
|
||||
io_context_impl_(boost::asio::use_service<io_context_impl>(io_context)),
|
||||
mutex_(),
|
||||
salt_(0)
|
||||
{
|
||||
@@ -95,7 +96,7 @@ bool strand_service::do_dispatch(implementation_type& impl, operation* op)
|
||||
{
|
||||
// If we are running inside the io_context, and no other handler already
|
||||
// holds the strand lock, then the handler can run immediately.
|
||||
bool can_dispatch = io_context_.can_dispatch();
|
||||
bool can_dispatch = io_context_impl_.can_dispatch();
|
||||
impl->mutex_.lock();
|
||||
if (can_dispatch && !impl->locked_)
|
||||
{
|
||||
@@ -118,7 +119,7 @@ bool strand_service::do_dispatch(implementation_type& impl, operation* op)
|
||||
impl->locked_ = true;
|
||||
impl->mutex_.unlock();
|
||||
impl->ready_queue_.push(op);
|
||||
io_context_.post_immediate_completion(impl, false);
|
||||
io_context_impl_.post_immediate_completion(impl, false);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -141,7 +142,7 @@ void strand_service::do_post(implementation_type& impl,
|
||||
impl->locked_ = true;
|
||||
impl->mutex_.unlock();
|
||||
impl->ready_queue_.push(op);
|
||||
io_context_.post_immediate_completion(impl, is_continuation);
|
||||
io_context_impl_.post_immediate_completion(impl, is_continuation);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -114,6 +114,7 @@ win_iocp_io_context::~win_iocp_io_context()
|
||||
{
|
||||
if (thread_.get())
|
||||
{
|
||||
stop();
|
||||
thread_->join();
|
||||
thread_.reset();
|
||||
}
|
||||
@@ -200,7 +201,7 @@ size_t win_iocp_io_context::run(boost::system::error_code& ec)
|
||||
thread_call_stack::context ctx(this, this_thread);
|
||||
|
||||
size_t n = 0;
|
||||
while (do_one(INFINITE, ec))
|
||||
while (do_one(INFINITE, this_thread, ec))
|
||||
if (n != (std::numeric_limits<size_t>::max)())
|
||||
++n;
|
||||
return n;
|
||||
@@ -218,7 +219,7 @@ size_t win_iocp_io_context::run_one(boost::system::error_code& ec)
|
||||
win_iocp_thread_info this_thread;
|
||||
thread_call_stack::context ctx(this, this_thread);
|
||||
|
||||
return do_one(INFINITE, ec);
|
||||
return do_one(INFINITE, this_thread, ec);
|
||||
}
|
||||
|
||||
size_t win_iocp_io_context::wait_one(long usec, boost::system::error_code& ec)
|
||||
@@ -233,7 +234,7 @@ size_t win_iocp_io_context::wait_one(long usec, boost::system::error_code& ec)
|
||||
win_iocp_thread_info this_thread;
|
||||
thread_call_stack::context ctx(this, this_thread);
|
||||
|
||||
return do_one(usec < 0 ? INFINITE : ((usec - 1) / 1000 + 1), ec);
|
||||
return do_one(usec < 0 ? INFINITE : ((usec - 1) / 1000 + 1), this_thread, ec);
|
||||
}
|
||||
|
||||
size_t win_iocp_io_context::poll(boost::system::error_code& ec)
|
||||
@@ -249,7 +250,7 @@ size_t win_iocp_io_context::poll(boost::system::error_code& ec)
|
||||
thread_call_stack::context ctx(this, this_thread);
|
||||
|
||||
size_t n = 0;
|
||||
while (do_one(0, ec))
|
||||
while (do_one(0, this_thread, ec))
|
||||
if (n != (std::numeric_limits<size_t>::max)())
|
||||
++n;
|
||||
return n;
|
||||
@@ -267,7 +268,7 @@ size_t win_iocp_io_context::poll_one(boost::system::error_code& ec)
|
||||
win_iocp_thread_info this_thread;
|
||||
thread_call_stack::context ctx(this, this_thread);
|
||||
|
||||
return do_one(0, ec);
|
||||
return do_one(0, this_thread, ec);
|
||||
}
|
||||
|
||||
void win_iocp_io_context::stop()
|
||||
@@ -287,6 +288,12 @@ void win_iocp_io_context::stop()
|
||||
}
|
||||
}
|
||||
|
||||
void win_iocp_io_context::capture_current_exception()
|
||||
{
|
||||
if (thread_info_base* this_thread = thread_call_stack::contains(this))
|
||||
this_thread->capture_current_exception();
|
||||
}
|
||||
|
||||
void win_iocp_io_context::post_deferred_completion(win_iocp_operation* op)
|
||||
{
|
||||
// Flag the operation as ready.
|
||||
@@ -396,7 +403,8 @@ void win_iocp_io_context::on_completion(win_iocp_operation* op,
|
||||
}
|
||||
}
|
||||
|
||||
size_t win_iocp_io_context::do_one(DWORD msec, boost::system::error_code& ec)
|
||||
size_t win_iocp_io_context::do_one(DWORD msec,
|
||||
win_iocp_thread_info& this_thread, boost::system::error_code& ec)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
@@ -458,6 +466,7 @@ size_t win_iocp_io_context::do_one(DWORD msec, boost::system::error_code& ec)
|
||||
(void)on_exit;
|
||||
|
||||
op->complete(this, result_ec, bytes_transferred);
|
||||
this_thread.rethrow_pending_exception();
|
||||
ec = boost::system::error_code();
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
//
|
||||
// io_object_executor.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_ASIO_DETAIL_IO_OBJECT_EXECUTOR_HPP
|
||||
#define BOOST_ASIO_DETAIL_IO_OBJECT_EXECUTOR_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
#include <boost/asio/detail/config.hpp>
|
||||
#include <boost/asio/detail/handler_invoke_helpers.hpp>
|
||||
#include <boost/asio/detail/type_traits.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
namespace detail {
|
||||
|
||||
// Wrap the (potentially polymorphic) executor so that we can bypass it when
|
||||
// dispatching on a target executor that has a native I/O implementation.
|
||||
template <typename Executor>
|
||||
class io_object_executor
|
||||
{
|
||||
public:
|
||||
io_object_executor(const Executor& ex,
|
||||
bool native_implementation) BOOST_ASIO_NOEXCEPT
|
||||
: executor_(ex),
|
||||
has_native_impl_(native_implementation)
|
||||
{
|
||||
}
|
||||
|
||||
io_object_executor(const io_object_executor& other) BOOST_ASIO_NOEXCEPT
|
||||
: executor_(other.executor_),
|
||||
has_native_impl_(other.has_native_impl_)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Executor1>
|
||||
io_object_executor(
|
||||
const io_object_executor<Executor1>& other) BOOST_ASIO_NOEXCEPT
|
||||
: executor_(other.inner_executor()),
|
||||
has_native_impl_(other.has_native_implementation())
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(BOOST_ASIO_HAS_MOVE)
|
||||
io_object_executor(io_object_executor&& other) BOOST_ASIO_NOEXCEPT
|
||||
: executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)),
|
||||
has_native_impl_(other.has_native_impl_)
|
||||
{
|
||||
}
|
||||
#endif // defined(BOOST_ASIO_HAS_MOVE)
|
||||
|
||||
const Executor& inner_executor() const BOOST_ASIO_NOEXCEPT
|
||||
{
|
||||
return executor_;
|
||||
}
|
||||
|
||||
bool has_native_implementation() const BOOST_ASIO_NOEXCEPT
|
||||
{
|
||||
return has_native_impl_;
|
||||
}
|
||||
|
||||
execution_context& context() const BOOST_ASIO_NOEXCEPT
|
||||
{
|
||||
return executor_.context();
|
||||
}
|
||||
|
||||
void on_work_started() const BOOST_ASIO_NOEXCEPT
|
||||
{
|
||||
if (is_same<Executor, io_context::executor_type>::value
|
||||
|| has_native_impl_)
|
||||
{
|
||||
// When using a native implementation, work is already counted by the
|
||||
// execution context.
|
||||
}
|
||||
else
|
||||
{
|
||||
executor_.on_work_started();
|
||||
}
|
||||
}
|
||||
|
||||
void on_work_finished() const BOOST_ASIO_NOEXCEPT
|
||||
{
|
||||
if (is_same<Executor, io_context::executor_type>::value
|
||||
|| has_native_impl_)
|
||||
{
|
||||
// When using a native implementation, work is already counted by the
|
||||
// execution context.
|
||||
}
|
||||
else
|
||||
{
|
||||
executor_.on_work_finished();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename F, typename A>
|
||||
void dispatch(BOOST_ASIO_MOVE_ARG(F) f, const A& a) const
|
||||
{
|
||||
if (is_same<Executor, io_context::executor_type>::value
|
||||
|| has_native_impl_)
|
||||
{
|
||||
// When using a native implementation, I/O completion handlers are
|
||||
// already dispatched according to the execution context's executor's
|
||||
// rules. We can call the function directly.
|
||||
#if defined(BOOST_ASIO_HAS_MOVE)
|
||||
if (is_same<F, typename decay<F>::type>::value)
|
||||
{
|
||||
boost_asio_handler_invoke_helpers::invoke(f, f);
|
||||
return;
|
||||
}
|
||||
#endif // defined(BOOST_ASIO_HAS_MOVE)
|
||||
typename decay<F>::type function(BOOST_ASIO_MOVE_CAST(F)(f));
|
||||
boost_asio_handler_invoke_helpers::invoke(function, function);
|
||||
}
|
||||
else
|
||||
{
|
||||
executor_.dispatch(BOOST_ASIO_MOVE_CAST(F)(f), a);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename F, typename A>
|
||||
void post(BOOST_ASIO_MOVE_ARG(F) f, const A& a) const
|
||||
{
|
||||
executor_.post(BOOST_ASIO_MOVE_CAST(F)(f), a);
|
||||
}
|
||||
|
||||
template <typename F, typename A>
|
||||
void defer(BOOST_ASIO_MOVE_ARG(F) f, const A& a) const
|
||||
{
|
||||
executor_.defer(BOOST_ASIO_MOVE_CAST(F)(f), a);
|
||||
}
|
||||
|
||||
friend bool operator==(const io_object_executor& a,
|
||||
const io_object_executor& b) BOOST_ASIO_NOEXCEPT
|
||||
{
|
||||
return a.executor_ == b.executor_
|
||||
&& a.has_native_impl_ == b.has_native_impl_;
|
||||
}
|
||||
|
||||
friend bool operator!=(const io_object_executor& a,
|
||||
const io_object_executor& b) BOOST_ASIO_NOEXCEPT
|
||||
{
|
||||
return a.executor_ != b.executor_
|
||||
|| a.has_native_impl_ != b.has_native_impl_;
|
||||
}
|
||||
|
||||
private:
|
||||
Executor executor_;
|
||||
const bool has_native_impl_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace asio
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/asio/detail/pop_options.hpp>
|
||||
|
||||
#endif // BOOST_ASIO_DETAIL_IO_OBJECT_EXECUTOR_HPP
|
||||
@@ -17,42 +17,18 @@
|
||||
|
||||
#include <new>
|
||||
#include <boost/asio/detail/config.hpp>
|
||||
#include <boost/asio/detail/io_object_executor.hpp>
|
||||
#include <boost/asio/detail/type_traits.hpp>
|
||||
#include <boost/asio/execution/executor.hpp>
|
||||
#include <boost/asio/execution/context.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/query.hpp>
|
||||
|
||||
#include <boost/asio/detail/push_options.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
|
||||
class executor;
|
||||
|
||||
namespace detail {
|
||||
|
||||
inline bool is_native_io_executor(const io_context::executor_type&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Executor>
|
||||
inline bool is_native_io_executor(const Executor&,
|
||||
typename enable_if<!is_same<Executor, executor>::value>::type* = 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename Executor>
|
||||
inline bool is_native_io_executor(const Executor& ex,
|
||||
typename enable_if<is_same<Executor, executor>::value>::type* = 0)
|
||||
{
|
||||
#if !defined (BOOST_ASIO_NO_TYPEID)
|
||||
return ex.target_type() == typeid(io_context::executor_type);
|
||||
#else // !defined (BOOST_ASIO_NO_TYPEID)
|
||||
return false;
|
||||
#endif // !defined (BOOST_ASIO_NO_TYPEID)
|
||||
}
|
||||
|
||||
template <typename IoObjectService,
|
||||
typename Executor = io_context::executor_type>
|
||||
class io_object_impl
|
||||
@@ -67,13 +43,11 @@ public:
|
||||
// The type of the executor associated with the object.
|
||||
typedef Executor executor_type;
|
||||
|
||||
// The type of executor to be used when implementing asynchronous operations.
|
||||
typedef io_object_executor<Executor> implementation_executor_type;
|
||||
|
||||
// Construct an I/O object using an executor.
|
||||
explicit io_object_impl(const executor_type& ex)
|
||||
: service_(&boost::asio::use_service<IoObjectService>(ex.context())),
|
||||
implementation_executor_(ex, (is_native_io_executor)(ex))
|
||||
: service_(&boost::asio::use_service<IoObjectService>(
|
||||
io_object_impl::get_context(ex))),
|
||||
executor_(ex)
|
||||
{
|
||||
service_->construct(implementation_);
|
||||
}
|
||||
@@ -84,8 +58,7 @@ public:
|
||||
typename enable_if<is_convertible<
|
||||
ExecutionContext&, execution_context&>::value>::type* = 0)
|
||||
: service_(&boost::asio::use_service<IoObjectService>(context)),
|
||||
implementation_executor_(context.get_executor(),
|
||||
is_same<ExecutionContext, io_context>::value)
|
||||
executor_(context.get_executor())
|
||||
{
|
||||
service_->construct(implementation_);
|
||||
}
|
||||
@@ -94,7 +67,7 @@ public:
|
||||
// Move-construct an I/O object.
|
||||
io_object_impl(io_object_impl&& other)
|
||||
: service_(&other.get_service()),
|
||||
implementation_executor_(other.get_implementation_executor())
|
||||
executor_(other.get_executor())
|
||||
{
|
||||
service_->move_construct(implementation_, other.implementation_);
|
||||
}
|
||||
@@ -103,8 +76,8 @@ public:
|
||||
template <typename IoObjectService1, typename Executor1>
|
||||
io_object_impl(io_object_impl<IoObjectService1, Executor1>&& other)
|
||||
: service_(&boost::asio::use_service<IoObjectService>(
|
||||
other.get_implementation_executor().context())),
|
||||
implementation_executor_(other.get_implementation_executor())
|
||||
io_object_impl::get_context(other.get_executor()))),
|
||||
executor_(other.get_executor())
|
||||
{
|
||||
service_->converting_move_construct(implementation_,
|
||||
other.get_service(), other.get_implementation());
|
||||
@@ -125,9 +98,9 @@ public:
|
||||
{
|
||||
service_->move_assign(implementation_,
|
||||
*other.service_, other.implementation_);
|
||||
implementation_executor_.~implementation_executor_type();
|
||||
new (&implementation_executor_) implementation_executor_type(
|
||||
std::move(other.implementation_executor_));
|
||||
executor_.~executor_type();
|
||||
new (&executor_) executor_type(
|
||||
std::move(other.executor_));
|
||||
service_ = other.service_;
|
||||
}
|
||||
return *this;
|
||||
@@ -135,16 +108,9 @@ public:
|
||||
#endif // defined(BOOST_ASIO_HAS_MOVE)
|
||||
|
||||
// Get the executor associated with the object.
|
||||
executor_type get_executor() BOOST_ASIO_NOEXCEPT
|
||||
const executor_type& get_executor() BOOST_ASIO_NOEXCEPT
|
||||
{
|
||||
return implementation_executor_.inner_executor();
|
||||
}
|
||||
|
||||
// Get the executor to be used when implementing asynchronous operations.
|
||||
const implementation_executor_type& get_implementation_executor()
|
||||
BOOST_ASIO_NOEXCEPT
|
||||
{
|
||||
return implementation_executor_;
|
||||
return executor_;
|
||||
}
|
||||
|
||||
// Get the service associated with the I/O object.
|
||||
@@ -172,6 +138,22 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
// Helper function to get an executor's context.
|
||||
template <typename T>
|
||||
static execution_context& get_context(const T& t,
|
||||
typename enable_if<execution::is_executor<T>::value>::type* = 0)
|
||||
{
|
||||
return boost::asio::query(t, execution::context);
|
||||
}
|
||||
|
||||
// Helper function to get an executor's context.
|
||||
template <typename T>
|
||||
static execution_context& get_context(const T& t,
|
||||
typename enable_if<!execution::is_executor<T>::value>::type* = 0)
|
||||
{
|
||||
return t.context();
|
||||
}
|
||||
|
||||
// Disallow copying and copy assignment.
|
||||
io_object_impl(const io_object_impl&);
|
||||
io_object_impl& operator=(const io_object_impl&);
|
||||
@@ -183,7 +165,7 @@ private:
|
||||
implementation_type implementation_;
|
||||
|
||||
// The associated executor.
|
||||
implementation_executor_type implementation_executor_;
|
||||
executor_type executor_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <memory>
|
||||
|
||||
#if !defined(BOOST_ASIO_HAS_STD_SHARED_PTR)
|
||||
# include <boost/make_shared.hpp>
|
||||
# include <boost/shared_ptr.hpp>
|
||||
# include <boost/weak_ptr.hpp>
|
||||
#endif // !defined(BOOST_ASIO_HAS_STD_SHARED_PTR)
|
||||
@@ -32,9 +33,11 @@ namespace asio {
|
||||
namespace detail {
|
||||
|
||||
#if defined(BOOST_ASIO_HAS_STD_SHARED_PTR)
|
||||
using std::make_shared;
|
||||
using std::shared_ptr;
|
||||
using std::weak_ptr;
|
||||
#else // defined(BOOST_ASIO_HAS_STD_SHARED_PTR)
|
||||
using boost::make_shared;
|
||||
using boost::shared_ptr;
|
||||
using boost::weak_ptr;
|
||||
#endif // defined(BOOST_ASIO_HAS_STD_SHARED_PTR)
|
||||
|
||||
@@ -56,6 +56,12 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
// Unlock the mutex and signal one waiter who may destroy us.
|
||||
template <typename Lock>
|
||||
void unlock_and_signal_one_for_destruction(Lock&)
|
||||
{
|
||||
}
|
||||
|
||||
// If there's a waiter, unlock the mutex and signal it.
|
||||
template <typename Lock>
|
||||
bool maybe_unlock_and_signal_one(Lock&)
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
|
||||
// Greenhills C++
|
||||
|
||||
#elif defined(__BORLANDC__)
|
||||
#elif defined(__BORLANDC__) && !defined(__clang__)
|
||||
|
||||
// Borland C++
|
||||
|
||||
|
||||
@@ -71,6 +71,18 @@ public:
|
||||
::pthread_cond_signal(&cond_); // Ignore EINVAL.
|
||||
}
|
||||
|
||||
// Unlock the mutex and signal one waiter who may destroy us.
|
||||
template <typename Lock>
|
||||
void unlock_and_signal_one_for_destruction(Lock& lock)
|
||||
{
|
||||
BOOST_ASIO_ASSERT(lock.locked());
|
||||
state_ |= 1;
|
||||
bool have_waiters = (state_ > 1);
|
||||
if (have_waiters)
|
||||
::pthread_cond_signal(&cond_); // Ignore EINVAL.
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
// If there's a waiter, unlock the mutex and signal it.
|
||||
template <typename Lock>
|
||||
bool maybe_unlock_and_signal_one(Lock& lock)
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
|
||||
// Greenhills C++
|
||||
|
||||
#elif defined(__BORLANDC__)
|
||||
#elif defined(__BORLANDC__) && !defined(__clang__)
|
||||
|
||||
// Borland C++
|
||||
|
||||
|
||||
@@ -202,7 +202,7 @@ public:
|
||||
typedef reactive_wait_op<Handler, IoExecutor> op;
|
||||
typename op::ptr p = { boost::asio::detail::addressof(handler),
|
||||
op::ptr::allocate(handler), 0 };
|
||||
p.p = new (p.v) op(handler, io_ex);
|
||||
p.p = new (p.v) op(success_ec_, handler, io_ex);
|
||||
|
||||
BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
|
||||
&impl, impl.descriptor_, "async_wait"));
|
||||
@@ -235,11 +235,22 @@ public:
|
||||
size_t write_some(implementation_type& impl,
|
||||
const ConstBufferSequence& buffers, boost::system::error_code& ec)
|
||||
{
|
||||
buffer_sequence_adapter<boost::asio::const_buffer,
|
||||
ConstBufferSequence> bufs(buffers);
|
||||
typedef buffer_sequence_adapter<boost::asio::const_buffer,
|
||||
ConstBufferSequence> bufs_type;
|
||||
|
||||
return descriptor_ops::sync_write(impl.descriptor_, impl.state_,
|
||||
bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
|
||||
if (bufs_type::is_single_buffer)
|
||||
{
|
||||
return descriptor_ops::sync_write1(impl.descriptor_,
|
||||
impl.state_, bufs_type::first(buffers).data(),
|
||||
bufs_type::first(buffers).size(), ec);
|
||||
}
|
||||
else
|
||||
{
|
||||
bufs_type bufs(buffers);
|
||||
|
||||
return descriptor_ops::sync_write(impl.descriptor_, impl.state_,
|
||||
bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait until data can be written without blocking.
|
||||
@@ -266,7 +277,7 @@ public:
|
||||
typedef descriptor_write_op<ConstBufferSequence, Handler, IoExecutor> op;
|
||||
typename op::ptr p = { boost::asio::detail::addressof(handler),
|
||||
op::ptr::allocate(handler), 0 };
|
||||
p.p = new (p.v) op(impl.descriptor_, buffers, handler, io_ex);
|
||||
p.p = new (p.v) op(success_ec_, impl.descriptor_, buffers, handler, io_ex);
|
||||
|
||||
BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
|
||||
&impl, impl.descriptor_, "async_write_some"));
|
||||
@@ -289,7 +300,7 @@ public:
|
||||
typedef reactive_null_buffers_op<Handler, IoExecutor> op;
|
||||
typename op::ptr p = { boost::asio::detail::addressof(handler),
|
||||
op::ptr::allocate(handler), 0 };
|
||||
p.p = new (p.v) op(handler, io_ex);
|
||||
p.p = new (p.v) op(success_ec_, handler, io_ex);
|
||||
|
||||
BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
|
||||
&impl, impl.descriptor_, "async_write_some(null_buffers)"));
|
||||
@@ -303,11 +314,22 @@ public:
|
||||
size_t read_some(implementation_type& impl,
|
||||
const MutableBufferSequence& buffers, boost::system::error_code& ec)
|
||||
{
|
||||
buffer_sequence_adapter<boost::asio::mutable_buffer,
|
||||
MutableBufferSequence> bufs(buffers);
|
||||
typedef buffer_sequence_adapter<boost::asio::mutable_buffer,
|
||||
MutableBufferSequence> bufs_type;
|
||||
|
||||
return descriptor_ops::sync_read(impl.descriptor_, impl.state_,
|
||||
bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
|
||||
if (bufs_type::is_single_buffer)
|
||||
{
|
||||
return descriptor_ops::sync_read1(impl.descriptor_,
|
||||
impl.state_, bufs_type::first(buffers).data(),
|
||||
bufs_type::first(buffers).size(), ec);
|
||||
}
|
||||
else
|
||||
{
|
||||
bufs_type bufs(buffers);
|
||||
|
||||
return descriptor_ops::sync_read(impl.descriptor_, impl.state_,
|
||||
bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait until data can be read without blocking.
|
||||
@@ -335,7 +357,7 @@ public:
|
||||
typedef descriptor_read_op<MutableBufferSequence, Handler, IoExecutor> op;
|
||||
typename op::ptr p = { boost::asio::detail::addressof(handler),
|
||||
op::ptr::allocate(handler), 0 };
|
||||
p.p = new (p.v) op(impl.descriptor_, buffers, handler, io_ex);
|
||||
p.p = new (p.v) op(success_ec_, impl.descriptor_, buffers, handler, io_ex);
|
||||
|
||||
BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
|
||||
&impl, impl.descriptor_, "async_read_some"));
|
||||
@@ -358,7 +380,7 @@ public:
|
||||
typedef reactive_null_buffers_op<Handler, IoExecutor> op;
|
||||
typename op::ptr p = { boost::asio::detail::addressof(handler),
|
||||
op::ptr::allocate(handler), 0 };
|
||||
p.p = new (p.v) op(handler, io_ex);
|
||||
p.p = new (p.v) op(success_ec_, handler, io_ex);
|
||||
|
||||
BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
|
||||
&impl, impl.descriptor_, "async_read_some(null_buffers)"));
|
||||
@@ -374,6 +396,9 @@ private:
|
||||
|
||||
// The selector that performs event demultiplexing for the service.
|
||||
reactor& reactor_;
|
||||
|
||||
// Cached success value to avoid accessing category singleton.
|
||||
const boost::system::error_code success_ec_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user