Fixes to test::stream::async_read:

- Call the completion handler with the correct signature
- Replicate ASIO socket behavior of async operation completions
- Fix a data race between read_op and a call to stream::nread()

Signed-off-by: Damian Jarek <damian.jarek93@gmail.com>
This commit is contained in:
Damian Jarek
2019-02-04 15:43:41 +01:00
committed by Vinnie Falco
parent adcd4bc0c9
commit 34362256c0
3 changed files with 34 additions and 37 deletions

View File

@ -7,6 +7,7 @@ Version 210:
* Add executor_type trait * Add executor_type trait
* Fix hexadecimal string conversion table * Fix hexadecimal string conversion table
* is_completion_handler, type_traits.hpp are deprecated * is_completion_handler, type_traits.hpp are deprecated
* Fixes to test::stream::async_read
API Changes: API Changes:

View File

@ -210,13 +210,16 @@ New websocket-chat-multi example
* `ostream` * `ostream`
does not overflow or exceed the dynamic buffer's maximum size does not overflow or exceed the dynamic buffer's maximum size
* A handler work guard is maintained on paused websocket operations * Fixes to
`test::stream::async_read`
* All behavior of default-constructed iterators is conforming
* `file_mode::append_existing` * `file_mode::append_existing`
works correctly works correctly
* A handler work guard is maintained on paused websocket operations
* All behavior of default-constructed iterators is conforming
[/-----------------------------------------------------------------------------] [/-----------------------------------------------------------------------------]
[heading Boost 1.69] [heading Boost 1.69]

View File

@ -427,7 +427,8 @@ TeardownHandler&& handler)
s.in_->fc->fail(ec)) s.in_->fc->fail(ec))
return net::post( return net::post(
s.get_executor(), s.get_executor(),
beast::bind_front_handler(std::move(handler), ec)); beast::bind_front_handler(
std::move(handler), ec));
s.close(); s.close();
if( s.in_->fc && if( s.in_->fc &&
s.in_->fc->fail(ec)) s.in_->fc->fail(ec))
@ -437,7 +438,8 @@ TeardownHandler&& handler)
net::post( net::post(
s.get_executor(), s.get_executor(),
beast::bind_front_handler(std::move(handler), ec)); beast::bind_front_handler(
std::move(handler), ec));
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -445,15 +447,16 @@ TeardownHandler&& handler)
template<class Handler, class Buffers> template<class Handler, class Buffers>
class stream::read_op : public stream::read_op_base class stream::read_op : public stream::read_op_base
{ {
using ex1_type = net::io_context::executor_type; using ex1_type =
using ex2_type = net::associated_executor_t<Handler, ex1_type>; net::io_context::executor_type;
using ex2_type
= net::associated_executor_t<Handler, ex1_type>;
class lambda class lambda
{ {
state& s_; state& s_;
Buffers b_; Buffers b_;
Handler h_; Handler h_;
net::executor_work_guard<ex1_type> wg1_;
net::executor_work_guard<ex2_type> wg2_; net::executor_work_guard<ex2_type> wg2_;
public: public:
@ -465,76 +468,66 @@ class stream::read_op : public stream::read_op_base
: s_(s) : s_(s)
, b_(b) , b_(b)
, h_(std::forward<DeducedHandler>(h)) , h_(std::forward<DeducedHandler>(h))
, wg1_(s_.ioc.get_executor())
, wg2_(net::get_associated_executor( , wg2_(net::get_associated_executor(
h_, s_.ioc.get_executor())) h_, s_.ioc.get_executor()))
{ {
} }
void
post()
{
net::post(
s_.ioc.get_executor(),
std::move(*this));
wg1_.reset();
wg2_.reset();
}
void void
operator()() operator()()
{ {
std::unique_lock<std::mutex> lock{s_.m}; std::unique_lock<std::mutex> lock{s_.m};
error_code ec;
std::size_t bytes_transferred = 0;
BOOST_ASSERT(! s_.op); BOOST_ASSERT(! s_.op);
if(s_.b.size() > 0) if(s_.b.size() > 0)
{ {
auto const bytes_transferred = bytes_transferred =
net::buffer_copy( net::buffer_copy(
b_, s_.b.data(), s_.read_max); b_, s_.b.data(), s_.read_max);
s_.b.consume(bytes_transferred); s_.b.consume(bytes_transferred);
auto& s = s_; ++s_.nread;
Handler h{std::move(h_)};
lock.unlock();
++s.nread;
net::post(
s.ioc.get_executor(),
beast::bind_front_handler(
std::move(h),
error_code{},
bytes_transferred));
} }
else else
{ {
BOOST_ASSERT(s_.code != status::ok); BOOST_ASSERT(s_.code != status::ok);
auto& s = s_; auto& s = s_;
Handler h{std::move(h_)};
lock.unlock();
++s.nread; ++s.nread;
error_code ec;
if(s.code == status::eof) if(s.code == status::eof)
ec = net::error::eof; ec = net::error::eof;
else if(s.code == status::reset) else if(s.code == status::reset)
ec = net::error::connection_reset; ec = net::error::connection_reset;
net::post(
s.ioc.get_executor(),
beast::bind_front_handler(std::move(h), ec, 0));
} }
lock.unlock();
auto alloc = net::get_associated_allocator(h_);
wg2_.get_executor().dispatch(
beast::bind_front_handler(
std::move(h_),
ec,
bytes_transferred), alloc);
wg2_.reset();
} }
}; };
lambda fn_; lambda fn_;
net::executor_work_guard<ex1_type> wg1_;
public: public:
template<class DeducedHandler> template<class DeducedHandler>
read_op(state& s, Buffers const& b, DeducedHandler&& h) read_op(state& s, Buffers const& b, DeducedHandler&& h)
: fn_(s, b, std::forward<DeducedHandler>(h)) : fn_(s, b, std::forward<DeducedHandler>(h))
, wg1_(s.ioc.get_executor())
{ {
} }
void void
operator()() override operator()() override
{ {
fn_.post(); net::post(
wg1_.get_executor(),
std::move(fn_));
wg1_.reset();
} }
}; };