From b6eb988694013b55a6453ef0133c6f24cbac3ff2 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Sun, 9 Dec 2018 19:00:04 -0800 Subject: [PATCH] saved_handler maintains a work_guard (websocket): * Tidy up and comment asserts * `pausation` is renamed to saved_handler * A work guard on the handler's associated executor is maintained for the lifetime of the store handler. --- CHANGELOG.md | 1 + .../beast/websocket/detail/pausation.hpp | 162 ----------------- .../beast/websocket/detail/saved_handler.hpp | 170 ++++++++++++++++++ include/boost/beast/websocket/stream.hpp | 14 +- 4 files changed, 178 insertions(+), 169 deletions(-) delete mode 100644 include/boost/beast/websocket/detail/pausation.hpp create mode 100644 include/boost/beast/websocket/detail/saved_handler.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 171c3a1f..fd938636 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Version 198: * multi_buffer improvements * static_buffer improvements * flat_static_buffer_improvements +* saved_handler maintains a work_guard (websocket) API Changes: diff --git a/include/boost/beast/websocket/detail/pausation.hpp b/include/boost/beast/websocket/detail/pausation.hpp deleted file mode 100644 index 64d2a7ed..00000000 --- a/include/boost/beast/websocket/detail/pausation.hpp +++ /dev/null @@ -1,162 +0,0 @@ -// -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// Official repository: https://github.com/boostorg/beast -// - -#ifndef BOOST_BEAST_WEBSOCKET_DETAIL_PAUSATION_HPP -#define BOOST_BEAST_WEBSOCKET_DETAIL_PAUSATION_HPP - -#include -#include -#include -#include -#include - -namespace boost { -namespace beast { -namespace websocket { -namespace detail { - -// A container that holds a suspended, asynchronous composed -// operation. The contained object may be invoked later to -// resume the operation, or the container may be destroyed. -// -class pausation -{ - struct handler - { - handler() = default; - handler(handler &&) = delete; - handler(handler const&) = delete; - virtual ~handler() = default; - virtual void destroy() = 0; - virtual void invoke() = 0; - }; - - template - class impl : public handler - { - Handler h_; - - public: - template - impl(DeducedHandler&& h) - : h_(std::forward(h)) - { - } - - void - destroy() override - { - Handler h(std::move(h_)); - typename beast::detail::allocator_traits< - net::associated_allocator_t< - Handler>>::template rebind_alloc alloc{ - net::get_associated_allocator(h)}; - beast::detail::allocator_traits< - decltype(alloc)>::destroy(alloc, this); - beast::detail::allocator_traits< - decltype(alloc)>::deallocate(alloc, this, 1); - } - - void - invoke() override - { - Handler h(std::move(h_)); - typename beast::detail::allocator_traits< - net::associated_allocator_t< - Handler>>::template rebind_alloc alloc{ - net::get_associated_allocator(h)}; - beast::detail::allocator_traits< - decltype(alloc)>::destroy(alloc, this); - beast::detail::allocator_traits< - decltype(alloc)>::deallocate(alloc, this, 1); - h(); - } - }; - - handler* h_ = nullptr; - -public: - pausation() = default; - pausation(pausation const&) = delete; - pausation& operator=(pausation const&) = delete; - - ~pausation() - { - if(h_) - h_->destroy(); - } - - pausation(pausation&& other) - { - boost::ignore_unused(other); - BOOST_ASSERT(! other.h_); - } - - pausation& - operator=(pausation&& other) - { - boost::ignore_unused(other); - BOOST_ASSERT(! h_); - BOOST_ASSERT(! other.h_); - return *this; - } - - template - void - emplace(CompletionHandler&& handler); - - explicit - operator bool() const - { - return h_ != nullptr; - } - - bool - maybe_invoke() - { - if(h_) - { - auto const h = h_; - h_ = nullptr; - h->invoke(); - return true; - } - return false; - } -}; - -template -void -pausation::emplace(CompletionHandler&& handler) -{ - BOOST_ASSERT(! h_); - typename beast::detail::allocator_traits< - net::associated_allocator_t< - CompletionHandler>>::template rebind_alloc< - impl> alloc{ - net::get_associated_allocator(handler)}; - using A = decltype(alloc); - auto const d = - [&alloc](impl* p) - { - beast::detail::allocator_traits::deallocate(alloc, p, 1); - }; - std::unique_ptr, decltype(d)> p{ - beast::detail::allocator_traits::allocate(alloc, 1), d}; - beast::detail::allocator_traits::construct( - alloc, p.get(), std::forward(handler)); - h_ = p.release(); -} - -} // detail -} // websocket -} // beast -} // boost - -#endif diff --git a/include/boost/beast/websocket/detail/saved_handler.hpp b/include/boost/beast/websocket/detail/saved_handler.hpp new file mode 100644 index 00000000..02fadfbb --- /dev/null +++ b/include/boost/beast/websocket/detail/saved_handler.hpp @@ -0,0 +1,170 @@ +// +// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/boostorg/beast +// + +#ifndef BOOST_BEAST_WEBSOCKET_DETAIL_SAVED_HANDLER_HPP +#define BOOST_BEAST_WEBSOCKET_DETAIL_SAVED_HANDLER_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace beast { +namespace websocket { +namespace detail { + +// A container that holds a suspended, asynchronous composed +// operation. The contained object may be invoked later to +// resume the operation, or the container may be destroyed. +// +class saved_handler +{ + struct base + { + base() = default; + base(base &&) = delete; + base(base const&) = delete; + virtual void destroy() = 0; + virtual void invoke() = 0; + + protected: + ~base() = default; + }; + + template + class impl : public base + { + Handler h_; + net::executor_work_guard< + net::associated_executor_t> wg_; + + public: + template + impl(DeducedHandler&& h) + : h_(std::forward(h)) + , wg_(net::get_associated_executor(h_)) + { + } + + void + destroy() override + { + using A = typename beast::detail::allocator_traits< + net::associated_allocator_t< + Handler>>::template rebind_alloc; + using alloc_traits = + beast::detail::allocator_traits; + Handler h(std::move(h_)); + A alloc(net::get_associated_allocator(h)); + alloc_traits::destroy(alloc, this); + alloc_traits::deallocate(alloc, this, 1); + } + + void + invoke() override + { + using A = typename beast::detail::allocator_traits< + net::associated_allocator_t< + Handler>>::template rebind_alloc; + using alloc_traits = + beast::detail::allocator_traits; + Handler h(std::move(h_)); + A alloc(net::get_associated_allocator(h)); + alloc_traits::destroy(alloc, this); + alloc_traits::deallocate(alloc, this, 1); + h(); + } + }; + + base* p_ = nullptr; + +public: + saved_handler() = default; + saved_handler(saved_handler const&) = delete; + saved_handler& operator=(saved_handler const&) = delete; + + ~saved_handler() + { + if(p_) + p_->destroy(); + } + + saved_handler(saved_handler&& other) + { + boost::ignore_unused(other); + // Moving a saved handler that + // owns an object is illegal + BOOST_ASSERT(! other.p_); + } + + saved_handler& + operator=(saved_handler&& other) + { + boost::ignore_unused(other); + // Moving a saved handler that + // owns an object is illegal + BOOST_ASSERT(! p_); + BOOST_ASSERT(! other.p_); + return *this; + } + + template + void + emplace(Handler&& handler) + { + // Can't emplace twice without invoke + BOOST_ASSERT(! p_); + using A = typename beast::detail::allocator_traits< + net::associated_allocator_t>::template + rebind_alloc>; + using alloc_traits = + beast::detail::allocator_traits; + A alloc(net::get_associated_allocator(handler)); + auto const d = + [&alloc](impl* p) + { + alloc_traits::deallocate(alloc, p, 1); + }; + std::unique_ptr, decltype(d)> p( + alloc_traits::allocate(alloc, 1), d); + alloc_traits::construct(alloc, p.get(), + std::forward(handler)); + p_ = p.release(); + } + + explicit + operator bool() const noexcept + { + return p_ != nullptr; + } + + bool + maybe_invoke() + { + if(p_) + { + auto const h = p_; + p_ = nullptr; + h->invoke(); + return true; + } + return false; + } +}; + +} // detail +} // websocket +} // beast +} // boost + +#endif diff --git a/include/boost/beast/websocket/stream.hpp b/include/boost/beast/websocket/stream.hpp index 47b38b0e..b4b1a1b9 100644 --- a/include/boost/beast/websocket/stream.hpp +++ b/include/boost/beast/websocket/stream.hpp @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include @@ -204,12 +204,12 @@ class stream = 4096; detail::fh_buffer wr_fb_; // header buffer used for writes - detail::pausation paused_rd_; // paused read op - detail::pausation paused_wr_; // paused write op - detail::pausation paused_ping_; // paused ping op - detail::pausation paused_close_; // paused close op - detail::pausation paused_r_rd_; // paused read op (async read) - detail::pausation paused_r_close_;// paused close op (async read) + detail::saved_handler paused_rd_; // paused read op + detail::saved_handler paused_wr_; // paused write op + detail::saved_handler paused_ping_; // paused ping op + detail::saved_handler paused_close_; // paused close op + detail::saved_handler paused_r_rd_; // paused read op (async read) + detail::saved_handler paused_r_close_;// paused close op (async read) public: /// Indicates if the permessage-deflate extension is supported