Use executor_work_guard in composed operations:

fix #1076

As per Asio and Networking TS requirements, composed operations must
maintain an object of type executor_work_guard for the executor associated
with the I/O object, for the lifetime of the asynchronous operation.

This is in addition to the requirement for maintaining an object of type
executor_work_guard for the executor associated with the handler.
This commit is contained in:
Vinnie Falco committed 2018-04-10 08:03:04 -07:00
1 parent b4cb4f1fd3
commit 86342dd72b
18 files changed
+154 -34

No files matched your search

+10
View File
@@ -23,6 +23,7 @@
#include <boost/beast/core.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/executor_work_guard.hpp>
#include <boost/logic/tribool.hpp>
/** Return `true` if a buffer contains a TLS/SSL client handshake.
@@ -319,6 +320,14 @@ class detect_ssl_op : public boost::asio::coroutine
// be cheaply copied as needed by the implementation.
AsyncReadStream& stream_;
// Boost.Asio and the Networking TS require an object of
// type executor_work_guard<T>, where T is the type of
// executor returned by the stream's get_executor function,
// to persist for the duration of the asynchronous operation.
boost::asio::executor_work_guard<
decltype(std::declval<AsyncReadStream&>().get_executor())> work_;
DynamicBuffer& buffer_;
Handler handler_;
boost::tribool result_ = false;
@@ -336,6 +345,7 @@ public:
DynamicBuffer& buffer,
DeducedHandler&& handler)
: stream_(stream)
, work_(stream.get_executor())
, buffer_(buffer)
, handler_(std::forward<DeducedHandler>(handler))
{
+12 -1
View File
@@ -88,6 +88,13 @@ class echo_op
// The stream to read and write to
AsyncStream& stream;
// Boost.Asio and the Networking TS require an object of
// type executor_work_guard<T>, where T is the type of
// executor returned by the stream's get_executor function,
// to persist for the duration of the asynchronous operation.
boost::asio::executor_work_guard<
decltype(std::declval<AsyncStream&>().get_executor())> work;
// Indicates what step in the operation's state machine
// to perform next, starting from zero.
int step = 0;
@@ -109,6 +116,7 @@ class echo_op
//
explicit state(Handler const& handler, AsyncStream& stream_)
: stream(stream_)
, work(stream.get_executor())
, buffer((std::numeric_limits<std::size_t>::max)(),
boost::asio::get_associated_allocator(handler))
{
@@ -215,7 +223,6 @@ operator()(boost::beast::error_code ec, std::size_t bytes_transferred)
p.buffer.consume(bytes_transferred);
break;
}
// Invoke the final handler. The implementation of `handler_ptr`
// will deallocate the storage for the state before the handler
// is invoked. This is necessary to provide the
@@ -226,6 +233,10 @@ operator()(boost::beast::error_code ec, std::size_t bytes_transferred)
// from the `state`, they would have to be moved to the stack
// first or else undefined behavior results.
//
// The work guard is moved to the stack first, otherwise it would
// be destroyed before the handler is invoked.
//
auto work = std::move(p.work);
p_.invoke(ec);
return;
}