forked from boostorg/beast
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:
1 parent
b4cb4f1fd3
commit
86342dd72b
18 files changed
+154
-34
No files matched your search
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user