From 2e62f25701b6fe52e0d2cfd2d3b7672c0f936ddb Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Fri, 15 Feb 2019 15:47:36 -0800 Subject: [PATCH] Use async_op_base::invoke --- example/echo-op/echo_op.cpp | 20 ++++--------- include/boost/beast/core/async_op_base.hpp | 28 +++++++++---------- include/boost/beast/core/detail/impl/read.hpp | 18 ++---------- include/boost/beast/websocket/impl/close.hpp | 9 +----- include/boost/beast/websocket/impl/read.hpp | 10 +------ include/boost/beast/websocket/impl/write.hpp | 11 +------- test/beast/core/async_op_base.cpp | 15 ++++------ 7 files changed, 30 insertions(+), 81 deletions(-) diff --git a/example/echo-op/echo_op.cpp b/example/echo-op/echo_op.cpp index 802544b0..c4b39560 100644 --- a/example/echo-op/echo_op.cpp +++ b/example/echo-op/echo_op.cpp @@ -302,21 +302,13 @@ async_echo( // directly invoke the completion handler otherwise it could // lead to unfairness, starvation, or stack overflow. Therefore, // if cont == false (meaning, that the call stack still includes - // the frame of the initiating function) then use `net::post` - // to cause us to be called again after the initiating function - // returns. The function `bind_handler` works similarly to - // `std::bind`, allowing bound arguments to be passed to our - // completion handler during the dispatch, but also takes care - // of forwarding the allocator and executor customization points - // in the returned call wrapper. + // the frame of the initiating function) then we need to use + // `net::post` to cause us to be called again after the initiating + // function. The function `async_op_base::invoke` takes care of + // calling the final completion handler, using post if the + // first argument is false, otherwise invoking it directly. - if(! cont) - 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); + this->invoke(cont, ec); } } }; diff --git a/include/boost/beast/core/async_op_base.hpp b/include/boost/beast/core/async_op_base.hpp index f33fb350..6188e710 100644 --- a/include/boost/beast/core/async_op_base.hpp +++ b/include/boost/beast/core/async_op_base.hpp @@ -84,13 +84,13 @@ namespace beast { using handler_type = BOOST_ASIO_HANDLER_TYPE(ReadHandler, void(error_code, std::size_t)); using base_type = async_op_base; - struct read_op : base_type + struct op : base_type { AsyncReadStream& stream_; net::mutable_buffer buffer_; std::size_t total_bytes_transferred_; - read_op( + op( AsyncReadStream& stream, net::mutable_buffer buffer, handler_type& handler) @@ -112,22 +112,17 @@ namespace beast { if(! ec && buffer_.size() > 0) return stream_.async_read_some(buffer_, std::move(*this)); - // If this is first invocation, we have to post to the executor. Otherwise the - // handler would be invoked before the call to async_read returns, which is disallowed. - if(! is_continuation) - { - // 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. If `is_continuation` is + // false, which happens on the first time through this function, then + // `net::post` will be used to call the completion handler, otherwise + // the completion handler will be invoked directly. - // Call the completion handler with the result - this->invoke_now(ec, total_bytes_transferred_); + this->invoke(is_continuation, ec, total_bytes_transferred_); } }; net::async_completion init{handler}; - read_op(stream, buffer, init.completion_handler); + op(stream, buffer, init.completion_handler); return init.result.get(); } @@ -341,15 +336,20 @@ public: invoke(bool is_continuation, Args&&... args) { this->before_invoke_hook(); - wg1_.reset(); if(! is_continuation) + { net::post(net::bind_executor( wg1_.get_executor(), beast::bind_front_handler( std::move(h_), std::forward(args)...))); + wg1_.reset(); + } else + { + wg1_.reset(); h_(std::forward(args)...); + } } /** Invoke the final completion handler. diff --git a/include/boost/beast/core/detail/impl/read.hpp b/include/boost/beast/core/detail/impl/read.hpp index 1933c9e5..66bab82a 100644 --- a/include/boost/beast/core/detail/impl/read.hpp +++ b/include/boost/beast/core/detail/impl/read.hpp @@ -89,14 +89,7 @@ public: b_.commit(bytes_transferred); total_ += bytes_transferred; } - if(! cont) - { - BOOST_ASIO_CORO_YIELD - net::post(s_.get_executor(), - beast::bind_front_handler( - std::move(*this), ec, total_)); - } - this->invoke_now(ec, total_); + this->invoke(cont, ec, total_); } } }; @@ -197,14 +190,7 @@ public: limit_ = cond_(ec, total_, b_); } } - if(! cont) - { - BOOST_ASIO_CORO_YIELD - net::post(s_.get_executor(), - beast::bind_front_handler( - std::move(*this), ec, total_)); - } - this->invoke_now(ec, total_); + this->invoke(cont, ec, total_); } } diff --git a/include/boost/beast/websocket/impl/close.hpp b/include/boost/beast/websocket/impl/close.hpp index dc5dfc64..81ef98b3 100644 --- a/include/boost/beast/websocket/impl/close.hpp +++ b/include/boost/beast/websocket/impl/close.hpp @@ -246,14 +246,7 @@ public: d_.ws.impl_->paused_rd.maybe_invoke() || d_.ws.impl_->paused_ping.maybe_invoke() || d_.ws.impl_->paused_wr.maybe_invoke(); - if(! d_.cont) - { - BOOST_ASIO_CORO_YIELD - net::post( - d_.ws.get_executor(), - beast::bind_front_handler(std::move(*this), ec)); - } - this->invoke_now(ec); + this->invoke(d_.cont, ec); } } }; diff --git a/include/boost/beast/websocket/impl/read.hpp b/include/boost/beast/websocket/impl/read.hpp index 2c08dadf..1860ef87 100644 --- a/include/boost/beast/websocket/impl/read.hpp +++ b/include/boost/beast/websocket/impl/read.hpp @@ -609,15 +609,7 @@ public: impl.paused_close.maybe_invoke() || impl.paused_ping.maybe_invoke() || impl.paused_wr.maybe_invoke(); - if(! cont_) - { - 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_); + this->invoke(cont_, ec, bytes_written_); } } }; diff --git a/include/boost/beast/websocket/impl/write.hpp b/include/boost/beast/websocket/impl/write.hpp index 88389c5b..2a9d822d 100644 --- a/include/boost/beast/websocket/impl/write.hpp +++ b/include/boost/beast/websocket/impl/write.hpp @@ -422,16 +422,7 @@ operator()( ws_.impl_->paused_close.maybe_invoke() || ws_.impl_->paused_rd.maybe_invoke() || ws_.impl_->paused_ping.maybe_invoke(); - if(! cont_) - { - 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_); + this->invoke(cont_, ec, bytes_transferred_); } } diff --git a/test/beast/core/async_op_base.cpp b/test/beast/core/async_op_base.cpp index c5abdcd7..6dbe8e0e 100644 --- a/test/beast/core/async_op_base.cpp +++ b/test/beast/core/async_op_base.cpp @@ -615,17 +615,12 @@ public: if(! ec && buffer_.size() > 0) return stream_.async_read_some(buffer_, std::move(*this)); - // If this is first invocation, we have to post to the executor. Otherwise the - // handler would be invoked before the call to async_read returns, which is disallowed. - if(! is_continuation) - { - // 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. If `is_continuation` is + // false, which happens on the first time through this function, then + // `net::post` will be used to call the completion handler, otherwise + // the completion handler will be invoked directly. - // Call the completion handler with the result - this->invoke_now(ec, total_bytes_transferred_); + this->invoke(is_continuation, ec, total_bytes_transferred_); } };