Use async_op_base::invoke

This commit is contained in:
Vinnie Falco
2019-02-15 15:47:36 -08:00
parent f41363c60c
commit 2e62f25701
7 changed files with 30 additions and 81 deletions

View File

@ -302,21 +302,13 @@ async_echo(
// directly invoke the completion handler otherwise it could // directly invoke the completion handler otherwise it could
// lead to unfairness, starvation, or stack overflow. Therefore, // lead to unfairness, starvation, or stack overflow. Therefore,
// if cont == false (meaning, that the call stack still includes // if cont == false (meaning, that the call stack still includes
// the frame of the initiating function) then use `net::post` // the frame of the initiating function) then we need to use
// to cause us to be called again after the initiating function // `net::post` to cause us to be called again after the initiating
// returns. The function `bind_handler` works similarly to // function. The function `async_op_base::invoke` takes care of
// `std::bind`, allowing bound arguments to be passed to our // calling the final completion handler, using post if the
// completion handler during the dispatch, but also takes care // first argument is false, otherwise invoking it directly.
// of forwarding the allocator and executor customization points
// in the returned call wrapper.
if(! cont) this->invoke(cont, ec);
yield net::post(beast::bind_handler(std::move(*this), ec));
// The function `async_op_base::invoke` takes care of calling
// the final completion handler.
this->invoke_now(ec);
} }
} }
}; };

View File

@ -84,13 +84,13 @@ namespace beast {
using handler_type = BOOST_ASIO_HANDLER_TYPE(ReadHandler, void(error_code, std::size_t)); using handler_type = BOOST_ASIO_HANDLER_TYPE(ReadHandler, void(error_code, std::size_t));
using base_type = async_op_base<handler_type, typename AsyncReadStream::executor_type>; using base_type = async_op_base<handler_type, typename AsyncReadStream::executor_type>;
struct read_op : base_type struct op : base_type
{ {
AsyncReadStream& stream_; AsyncReadStream& stream_;
net::mutable_buffer buffer_; net::mutable_buffer buffer_;
std::size_t total_bytes_transferred_; std::size_t total_bytes_transferred_;
read_op( op(
AsyncReadStream& stream, AsyncReadStream& stream,
net::mutable_buffer buffer, net::mutable_buffer buffer,
handler_type& handler) handler_type& handler)
@ -112,22 +112,17 @@ namespace beast {
if(! ec && buffer_.size() > 0) if(! ec && buffer_.size() > 0)
return stream_.async_read_some(buffer_, std::move(*this)); return stream_.async_read_some(buffer_, std::move(*this));
// If this is first invocation, we have to post to the executor. Otherwise the // Call the completion handler with the result. If `is_continuation` is
// handler would be invoked before the call to async_read returns, which is disallowed. // false, which happens on the first time through this function, then
if(! is_continuation) // `net::post` will be used to call the completion handler, otherwise
{ // the completion handler will be invoked directly.
// Issue a zero-sized read so our handler runs "as-if" posted using net::post().
// This technique is used to reduce the number of function template instantiations.
return stream_.async_read_some(net::mutable_buffer(buffer_.data(), 0), std::move(*this));
}
// Call the completion handler with the result this->invoke(is_continuation, ec, total_bytes_transferred_);
this->invoke_now(ec, total_bytes_transferred_);
} }
}; };
net::async_completion<ReadHandler, void(error_code, std::size_t)> init{handler}; net::async_completion<ReadHandler, void(error_code, std::size_t)> init{handler};
read_op(stream, buffer, init.completion_handler); op(stream, buffer, init.completion_handler);
return init.result.get(); return init.result.get();
} }
@ -341,15 +336,20 @@ public:
invoke(bool is_continuation, Args&&... args) invoke(bool is_continuation, Args&&... args)
{ {
this->before_invoke_hook(); this->before_invoke_hook();
wg1_.reset();
if(! is_continuation) if(! is_continuation)
{
net::post(net::bind_executor( net::post(net::bind_executor(
wg1_.get_executor(), wg1_.get_executor(),
beast::bind_front_handler( beast::bind_front_handler(
std::move(h_), std::move(h_),
std::forward<Args>(args)...))); std::forward<Args>(args)...)));
wg1_.reset();
}
else else
{
wg1_.reset();
h_(std::forward<Args>(args)...); h_(std::forward<Args>(args)...);
}
} }
/** Invoke the final completion handler. /** Invoke the final completion handler.

View File

@ -89,14 +89,7 @@ public:
b_.commit(bytes_transferred); b_.commit(bytes_transferred);
total_ += bytes_transferred; total_ += bytes_transferred;
} }
if(! cont) this->invoke(cont, ec, total_);
{
BOOST_ASIO_CORO_YIELD
net::post(s_.get_executor(),
beast::bind_front_handler(
std::move(*this), ec, total_));
}
this->invoke_now(ec, total_);
} }
} }
}; };
@ -197,14 +190,7 @@ public:
limit_ = cond_(ec, total_, b_); limit_ = cond_(ec, total_, b_);
} }
} }
if(! cont) this->invoke(cont, ec, total_);
{
BOOST_ASIO_CORO_YIELD
net::post(s_.get_executor(),
beast::bind_front_handler(
std::move(*this), ec, total_));
}
this->invoke_now(ec, total_);
} }
} }

View File

@ -246,14 +246,7 @@ public:
d_.ws.impl_->paused_rd.maybe_invoke() || d_.ws.impl_->paused_rd.maybe_invoke() ||
d_.ws.impl_->paused_ping.maybe_invoke() || d_.ws.impl_->paused_ping.maybe_invoke() ||
d_.ws.impl_->paused_wr.maybe_invoke(); d_.ws.impl_->paused_wr.maybe_invoke();
if(! d_.cont) this->invoke(d_.cont, ec);
{
BOOST_ASIO_CORO_YIELD
net::post(
d_.ws.get_executor(),
beast::bind_front_handler(std::move(*this), ec));
}
this->invoke_now(ec);
} }
} }
}; };

View File

@ -609,15 +609,7 @@ public:
impl.paused_close.maybe_invoke() || impl.paused_close.maybe_invoke() ||
impl.paused_ping.maybe_invoke() || impl.paused_ping.maybe_invoke() ||
impl.paused_wr.maybe_invoke(); impl.paused_wr.maybe_invoke();
if(! cont_) this->invoke(cont_, ec, bytes_written_);
{
BOOST_ASIO_CORO_YIELD
net::post(
ws_.get_executor(),
beast::bind_front_handler(std::move(*this),
ec, bytes_written_));
}
this->invoke_now(ec, bytes_written_);
} }
} }
}; };

View File

@ -422,16 +422,7 @@ operator()(
ws_.impl_->paused_close.maybe_invoke() || ws_.impl_->paused_close.maybe_invoke() ||
ws_.impl_->paused_rd.maybe_invoke() || ws_.impl_->paused_rd.maybe_invoke() ||
ws_.impl_->paused_ping.maybe_invoke(); ws_.impl_->paused_ping.maybe_invoke();
if(! cont_) this->invoke(cont_, ec, bytes_transferred_);
{
BOOST_ASIO_CORO_YIELD
net::post(
ws_.get_executor(),
beast::bind_front_handler(
std::move(*this),
ec, bytes_transferred_));
}
this->invoke_now(ec, bytes_transferred_);
} }
} }

View File

@ -615,17 +615,12 @@ public:
if(! ec && buffer_.size() > 0) if(! ec && buffer_.size() > 0)
return stream_.async_read_some(buffer_, std::move(*this)); return stream_.async_read_some(buffer_, std::move(*this));
// If this is first invocation, we have to post to the executor. Otherwise the // Call the completion handler with the result. If `is_continuation` is
// handler would be invoked before the call to async_read returns, which is disallowed. // false, which happens on the first time through this function, then
if(! is_continuation) // `net::post` will be used to call the completion handler, otherwise
{ // the completion handler will be invoked directly.
// Issue a zero-sized read so our handler runs "as-if" posted using net::post().
// This technique is used to reduce the number of function template instantiations.
return stream_.async_read_some(net::mutable_buffer(buffer_.data(), 0), std::move(*this));
}
// Call the completion handler with the result this->invoke(is_continuation, ec, total_bytes_transferred_);
this->invoke_now(ec, total_bytes_transferred_);
} }
}; };