diff --git a/CHANGELOG.md b/CHANGELOG.md index d94d9132..113af4cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ 1.0.0-b22 * Fix broken Intellisense +* Implement the Asio deallocation-before-invocation guarantee -------------------------------------------------------------------------------- diff --git a/doc/quickref.xml b/doc/quickref.xml index 443a55e7..3fe63b3e 100644 --- a/doc/quickref.xml +++ b/doc/quickref.xml @@ -174,6 +174,7 @@ error_code error_condition handler_alloc + handler_ptr static_streambuf static_streambuf_n static_string diff --git a/examples/http_async_server.hpp b/examples/http_async_server.hpp index 350f4a38..bfb5b9ba 100644 --- a/examples/http_async_server.hpp +++ b/examples/http_async_server.hpp @@ -12,6 +12,7 @@ #include "mime_type.hpp" #include +#include #include #include #include @@ -93,24 +94,21 @@ private: struct data { + bool cont; Stream& s; message m; - Handler h; - bool cont; - template - data(DeducedHandler&& h_, Stream& s_, + data(Handler& handler, Stream& s_, message&& m_) - : s(s_) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , s(s_) , m(std::move(m_)) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { } }; - std::shared_ptr d_; + handler_ptr d_; public: write_op(write_op&&) = default; @@ -118,7 +116,7 @@ private: template write_op(DeducedHandler&& h, Stream& s, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), s, std::forward(args)...)) { @@ -135,7 +133,7 @@ private: beast::http::async_write(d.s, d.m, std::move(*this)); return; } - d.h(ec); + d_.invoke(ec); } friend @@ -143,7 +141,7 @@ private: std::size_t size, write_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -151,7 +149,7 @@ private: void* p, std::size_t size, write_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -165,7 +163,7 @@ private: void asio_handler_invoke(Function&& f, write_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; diff --git a/include/beast/core/handler_ptr.hpp b/include/beast/core/handler_ptr.hpp new file mode 100644 index 00000000..175be8bb --- /dev/null +++ b/include/beast/core/handler_ptr.hpp @@ -0,0 +1,173 @@ +// +// Copyright (c) 2013-2016 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) +// + +#ifndef BEAST_HANDLER_PTR_HPP +#define BEAST_HANDLER_PTR_HPP + +#include +#include +#include +#include + +namespace beast { + +/** A smart pointer container. + + This is a smart pointer that retains shared ownership of an + object through a pointer. Memory is managed using the allocation + and deallocation functions associated with a completion handler, + which is also stored in the object. The object is destroyed and + its memory deallocated when one of the following happens: + + @li The function @ref invoke is called. + + @li The function @ref release_handler is called + + @li The last remaining container owning the object is destroyed + + Objects of this type are used in the implementation of + composed operations. Typically the composed operation's shared + state is managed by the @ref handler_ptr and an allocator + associated with the final handler is used to create the managed + object. + + @note The reference count is stored using a 16 bit unsigned + integer. Making more than 2^16 copies of one object results + in undefined behavior. +*/ +template +class handler_ptr +{ + struct P + { + T* t; + std::atomic n; + + // There's no way to put the handler anywhere else + // without exposing ourselves to race conditions + // and all sorts of ugliness. + // See: + // https://github.com/vinniefalco/Beast/issues/215 + Handler handler; + + template + P(DeducedHandler&& handler, Args&&... args); + }; + + P* p_; + + template + handler_ptr(int, DeducedHandler&& handler, Args&&... args); + +public: + /// The type of handler this object stores + using handler_type = Handler; + + /// Copy assignment (disallowed). + handler_ptr& operator=(handler_ptr const&) = delete; + + /** Destructs the owned object if no more @ref handler_ptr link to it. + + If `*this` owns an object and it is the last @ref handler_ptr + owning it, the object is destroyed and the memory deallocated + using the associated deallocator. + */ + ~handler_ptr(); + + /** Move constructor. + + When this call returns, the moved-from container + will have no owned object. + */ + handler_ptr(handler_ptr&& other); + + /// Copy constructor + handler_ptr(handler_ptr const& other); + + /// Returns a reference to the handler + handler_type& + handler() const + { + return p_->handler; + } + + /// Returns a pointer to the owned object + T* + get() const + { + return p_->t; + } + + /// Return a reference to the owned object. + T& + operator*() const + { + return *get(); + } + + /// Return a pointer to the owned object. + T* + operator->() const + { + return get(); + } + + /** Release ownership of the handler + + If `*this` owns an object, it is first destroyed. + + @return The released handler. + */ + handler_type + release_handler(); + + /** Invoke the handler in the owned object. + + This function invokes the handler in the owned object + with a forwarded argument list. Before the invocation, + the owned object is destroyed, satisfying the + deallocation-before-invocation Asio guarantee. All + instances of @ref handler_ptr which refer to the + same owned object will be reset, including this instance. + */ + template + void + invoke(Args&&... args); + + // VFALCO The free function interface works around + // a horrible Visual Studio 15 Update 3 bug + + /** Construct a new `handler_ptr`. + + @param handler The handler. The allocator associated with + the handler will be used to allocate memory for the owned + object. This argument will be forwarded to the owned object's + constructor. + + @param args Optional arguments forwarded to + the owned object's constructor. + */ + /** @{ */ + template + friend + handler_ptr + make_handler_ptr( + CompletionHandler&& handler, Args&&... args); + + template + friend + handler_ptr + make_handler_ptr( + CompletionHandler const& handler, Args&&... args); + /** @} */ +}; + +} // beast + +#include + +#endif diff --git a/include/beast/core/impl/dynabuf_readstream.ipp b/include/beast/core/impl/dynabuf_readstream.ipp index 5403536e..43790f07 100644 --- a/include/beast/core/impl/dynabuf_readstream.ipp +++ b/include/beast/core/impl/dynabuf_readstream.ipp @@ -12,6 +12,7 @@ #include #include #include +#include namespace beast { @@ -23,25 +24,22 @@ class dynabuf_readstream< using alloc_type = handler_alloc; + // VFALCO What about bool cont for is_continuation? struct data { dynabuf_readstream& srs; MutableBufferSequence bs; - Handler h; int state = 0; - template - data(DeducedHandler&& h_, - dynabuf_readstream& srs_, + data(Handler&, dynabuf_readstream& srs_, MutableBufferSequence const& bs_) : srs(srs_) , bs(bs_) - , h(std::forward(h_)) { } }; - std::shared_ptr d_; + handler_ptr d_; public: read_some_op(read_some_op&&) = default; @@ -50,7 +48,7 @@ public: template read_some_op(DeducedHandler&& h, dynabuf_readstream& srs, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), srs, std::forward(args)...)) { @@ -66,7 +64,7 @@ public: std::size_t size, read_some_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -74,14 +72,14 @@ public: void* p, std::size_t size, read_some_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend bool asio_handler_is_continuation(read_some_op* op) { return boost_asio_handler_cont_helpers:: - is_continuation(op->d_->h); + is_continuation(op->d_.handler()); } template @@ -89,7 +87,7 @@ public: void asio_handler_invoke(Function&& f, read_some_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -149,7 +147,7 @@ read_some_op::operator()( break; } } - d.h(ec, bytes_transferred); + d_.invoke(ec, bytes_transferred); } //------------------------------------------------------------------------------ diff --git a/include/beast/core/impl/handler_ptr.ipp b/include/beast/core/impl/handler_ptr.ipp new file mode 100644 index 00000000..152628c4 --- /dev/null +++ b/include/beast/core/impl/handler_ptr.ipp @@ -0,0 +1,137 @@ +// +// Copyright (c) 2013-2016 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) +// + +#ifndef BEAST_IMPL_HANDLER_PTR_HPP +#define BEAST_IMPL_HANDLER_PTR_HPP + +#include +#include +#include + +namespace beast { + +template +template +inline +handler_ptr::P:: +P(DeducedHandler&& h, Args&&... args) + : n(1) + , handler(std::forward(h)) +{ + t = reinterpret_cast( + boost_asio_handler_alloc_helpers:: + allocate(sizeof(T), handler)); + try + { + t = new(t) T{handler, + std::forward(args)...}; + } + catch(...) + { + boost_asio_handler_alloc_helpers:: + deallocate(t, sizeof(T), handler); + throw; + } +} + +template +template +handler_ptr:: +handler_ptr(int, DeducedHandler&& handler, Args&&... args) + : p_(new P(std::forward(handler), + std::forward(args)...)) +{ +} + +template +handler_ptr:: +~handler_ptr() +{ + if(! p_) + return; + if(--p_->n) + return; + if(p_->t) + { + p_->t->~T(); + boost_asio_handler_alloc_helpers:: + deallocate(p_->t, sizeof(T), p_->handler); + } + delete p_; +} + +template +handler_ptr:: +handler_ptr(handler_ptr&& other) + : p_(other.p_) +{ + other.p_ = nullptr; +} + +template +handler_ptr:: +handler_ptr(handler_ptr const& other) + : p_(other.p_) +{ + if(p_) + ++p_->n; +} + +template +auto +handler_ptr:: +release_handler() -> + handler_type +{ + BOOST_ASSERT(p_); + BOOST_ASSERT(p_->t); + p_->t->~T(); + boost_asio_handler_alloc_helpers:: + deallocate(p_->t, sizeof(T), p_->handler); + p_->t = nullptr; + return std::move(p_->handler); +} + +template +template +void +handler_ptr:: +invoke(Args&&... args) +{ + BOOST_ASSERT(p_); + BOOST_ASSERT(p_->t); + p_->t->~T(); + boost_asio_handler_alloc_helpers:: + deallocate(p_->t, sizeof(T), p_->handler); + p_->t = nullptr; + p_->handler(std::forward(args)...); +} + +template< + class T, class CompletionHandler, class... Args> +handler_ptr +make_handler_ptr( + CompletionHandler&& handler, Args&&... args) +{ + return handler_ptr{0, + std::move(handler), + std::forward(args)...}; +} + +template< + class T, class CompletionHandler, class... Args> +handler_ptr +make_handler_ptr( + CompletionHandler const& handler, Args&&... args) +{ + return handler_ptr{0, + handler, std::forward(args)...}; +} + +} // beast + +#endif diff --git a/include/beast/http/impl/parse.ipp b/include/beast/http/impl/parse.ipp index 6a717de5..ab38c143 100644 --- a/include/beast/http/impl/parse.ipp +++ b/include/beast/http/impl/parse.ipp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -23,34 +24,28 @@ template class parse_op { - using alloc_type = - handler_alloc; - struct data { + bool cont; Stream& s; DynamicBuffer& db; Parser& p; - Handler h; bool got_some = false; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, Stream& s_, + data(Handler& handler, Stream& s_, DynamicBuffer& sb_, Parser& p_) - : s(s_) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , s(s_) , db(sb_) , p(p_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { BOOST_ASSERT(! p.complete()); } }; - std::shared_ptr d_; + handler_ptr d_; public: parse_op(parse_op&&) = default; @@ -58,7 +53,7 @@ public: template parse_op(DeducedHandler&& h, Stream& s, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), s, std::forward(args)...)) { @@ -74,7 +69,7 @@ public: std::size_t size, parse_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -82,7 +77,7 @@ public: void* p, std::size_t size, parse_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -96,7 +91,7 @@ public: void asio_handler_invoke(Function&& f, parse_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -214,7 +209,7 @@ operator()(error_code ec, std::size_t bytes_transferred, bool again) } } } - d.h(ec); + d_.invoke(ec); } } // detail diff --git a/include/beast/http/impl/read.ipp b/include/beast/http/impl/read.ipp index 6a96355a..d569c2e8 100644 --- a/include/beast/http/impl/read.ipp +++ b/include/beast/http/impl/read.ipp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -27,9 +28,6 @@ template class read_header_op { - using alloc_type = - handler_alloc; - using parser_type = header_parser_v1; @@ -38,29 +36,26 @@ class read_header_op struct data { + bool cont; Stream& s; DynamicBuffer& db; message_type& m; parser_type p; - Handler h; bool started = false; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, Stream& s_, + data(Handler& handler, Stream& s_, DynamicBuffer& sb_, message_type& m_) - : s(s_) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , s(s_) , db(sb_) , m(m_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { } }; - std::shared_ptr d_; + handler_ptr d_; public: read_header_op(read_header_op&&) = default; @@ -69,7 +64,7 @@ public: template read_header_op( DeducedHandler&& h, Stream& s, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), s, std::forward(args)...)) { @@ -84,7 +79,7 @@ public: std::size_t size, read_header_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -92,7 +87,7 @@ public: void* p, std::size_t size, read_header_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -106,7 +101,7 @@ public: void asio_handler_invoke(Function&& f, read_header_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -135,7 +130,7 @@ operator()(error_code ec, bool again) break; } } - d.h(ec); + d_.invoke(ec); } } // detail @@ -206,9 +201,6 @@ template class read_op { - using alloc_type = - handler_alloc; - using parser_type = parser_v1; @@ -217,29 +209,26 @@ class read_op struct data { + bool cont; Stream& s; DynamicBuffer& db; message_type& m; parser_type p; - Handler h; bool started = false; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, Stream& s_, + data(Handler& handler, Stream& s_, DynamicBuffer& sb_, message_type& m_) - : s(s_) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , s(s_) , db(sb_) , m(m_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { } }; - std::shared_ptr d_; + handler_ptr d_; public: read_op(read_op&&) = default; @@ -247,7 +236,7 @@ public: template read_op(DeducedHandler&& h, Stream& s, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), s, std::forward(args)...)) { @@ -262,7 +251,7 @@ public: std::size_t size, read_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -270,7 +259,7 @@ public: void* p, std::size_t size, read_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -284,7 +273,7 @@ public: void asio_handler_invoke(Function&& f, read_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -313,7 +302,7 @@ operator()(error_code ec, bool again) break; } } - d.h(ec); + d_.invoke(ec); } } // detail diff --git a/include/beast/http/impl/write.ipp b/include/beast/http/impl/write.ipp index e5b83ab2..87e63e1f 100644 --- a/include/beast/http/impl/write.ipp +++ b/include/beast/http/impl/write.ipp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -99,30 +100,24 @@ namespace detail { template class write_streambuf_op { - using alloc_type = - handler_alloc; - struct data { + bool cont; Stream& s; streambuf sb; - Handler h; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, Stream& s_, + data(Handler& handler, Stream& s_, streambuf&& sb_) - : s(s_) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , s(s_) , sb(std::move(sb_)) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { } }; - std::shared_ptr d_; + handler_ptr d_; public: write_streambuf_op(write_streambuf_op&&) = default; @@ -131,19 +126,13 @@ public: template write_streambuf_op(DeducedHandler&& h, Stream& s, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, - std::forward(h), s, - std::forward(args)...)) + : d_(make_handler_ptr( + std::forward(h), + s, std::forward(args)...)) { (*this)(error_code{}, 0, false); } - explicit - write_streambuf_op(std::shared_ptr d) - : d_(std::move(d)) - { - } - void operator()(error_code ec, std::size_t bytes_transferred, bool again = true); @@ -153,7 +142,7 @@ public: std::size_t size, write_streambuf_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -161,7 +150,7 @@ public: void* p, std::size_t size, write_streambuf_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -175,7 +164,7 @@ public: void asio_handler_invoke(Function&& f, write_streambuf_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -199,7 +188,7 @@ operator()(error_code ec, std::size_t, bool again) } } } - d.h(ec); + d_.invoke(ec); } } // detail @@ -301,29 +290,23 @@ template class write_op { - using alloc_type = - handler_alloc; - struct data { + bool cont; Stream& s; // VFALCO How do we use handler_alloc in write_preparation? write_preparation< isRequest, Body, Fields> wp; - Handler h; resume_context resume; resume_context copy; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, Stream& s_, + data(Handler& handler, Stream& s_, message const& m_) - : s(s_) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , s(s_) , wp(m_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { } }; @@ -382,7 +365,7 @@ class write_op } }; - std::shared_ptr d_; + handler_ptr d_; public: write_op(write_op&&) = default; @@ -390,7 +373,7 @@ public: template write_op(DeducedHandler&& h, Stream& s, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), s, std::forward(args)...)) { @@ -410,7 +393,7 @@ public: } explicit - write_op(std::shared_ptr d) + write_op(handler_ptr d) : d_(std::move(d)) { } @@ -424,7 +407,7 @@ public: std::size_t size, write_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -432,7 +415,7 @@ public: void* p, std::size_t size, write_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -446,7 +429,7 @@ public: void asio_handler_invoke(Function&& f, write_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -552,9 +535,9 @@ operator()(error_code ec, std::size_t, bool again) break; } } - d.h(ec); - d.resume = {}; d.copy = {}; + d.resume = {}; + d_.invoke(ec); } template diff --git a/include/beast/websocket/detail/invokable.hpp b/include/beast/websocket/detail/invokable.hpp index fb19d0c9..7fcfc2cf 100644 --- a/include/beast/websocket/detail/invokable.hpp +++ b/include/beast/websocket/detail/invokable.hpp @@ -8,6 +8,7 @@ #ifndef BEAST_WEBSOCKET_DETAIL_INVOKABLE_HPP #define BEAST_WEBSOCKET_DETAIL_INVOKABLE_HPP +#include #include #include #include @@ -64,8 +65,19 @@ class invokable struct exemplar { - std::shared_ptr _; - void operator()(){} + struct H + { + void operator()(); + }; + + struct T + { + using handler_type = H; + }; + + handler_ptr hp; + + void operator()(); }; using buf_type = char[sizeof(holder)]; diff --git a/include/beast/websocket/impl/accept.ipp b/include/beast/websocket/impl/accept.ipp index 1ce54d32..2d0e13d4 100644 --- a/include/beast/websocket/impl/accept.ipp +++ b/include/beast/websocket/impl/accept.ipp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -30,27 +31,21 @@ template template class stream::response_op { - using alloc_type = - handler_alloc; - struct data { + bool cont; stream& ws; http::response resp; - Handler h; error_code final_ec; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, stream& ws_, + template + data(Handler&, stream& ws_, http::request const& req, bool cont_) - : ws(ws_) + : cont(cont_) + , ws(ws_) , resp(ws_.build_response(req)) - , h(std::forward(h_)) - , cont(cont_) { // can't call stream::reset() here // otherwise accept_op will malfunction @@ -60,7 +55,7 @@ class stream::response_op } }; - std::shared_ptr d_; + handler_ptr d_; public: response_op(response_op&&) = default; @@ -69,7 +64,7 @@ public: template response_op(DeducedHandler&& h, stream& ws, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), ws, std::forward(args)...)) { @@ -84,7 +79,7 @@ public: std::size_t size, response_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -92,7 +87,7 @@ public: void* p, std::size_t size, response_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -106,7 +101,7 @@ public: void asio_handler_invoke(Function&& f, response_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -138,7 +133,7 @@ operator()(error_code ec, bool again) break; } } - d.h(ec); + d_.invoke(ec); } //------------------------------------------------------------------------------ @@ -149,24 +144,19 @@ template template class stream::accept_op { - using alloc_type = - handler_alloc; - struct data { + bool cont; stream& ws; http::request req; - Handler h; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, stream& ws_, + template + data(Handler& handler, stream& ws_, Buffers const& buffers) - : ws(ws_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , ws(ws_) { using boost::asio::buffer_copy; using boost::asio::buffer_size; @@ -177,7 +167,7 @@ class stream::accept_op } }; - std::shared_ptr d_; + handler_ptr d_; public: accept_op(accept_op&&) = default; @@ -186,7 +176,7 @@ public: template accept_op(DeducedHandler&& h, stream& ws, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), ws, std::forward(args)...)) { @@ -206,7 +196,7 @@ public: std::size_t size, accept_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -214,7 +204,7 @@ public: void* p, std::size_t size, accept_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -228,7 +218,7 @@ public: void asio_handler_invoke(Function&& f, accept_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -256,19 +246,17 @@ operator()(error_code const& ec, // got message case 1: + { // respond to request -#if 1 - // VFALCO I have no idea why passing std::move(*this) crashes - d.state = 99; - d.ws.async_accept(d.req, *this); -#else + auto& ws = d.ws; + auto req = std::move(d.req); response_op{ - std::move(d.h), d.ws, d.req, true}; -#endif + d_.release_handler(), ws, req, true}; return; } + } } - d.h(ec); + d_.invoke(ec); } template diff --git a/include/beast/websocket/impl/close.ipp b/include/beast/websocket/impl/close.ipp index d426907a..e821e24f 100644 --- a/include/beast/websocket/impl/close.ipp +++ b/include/beast/websocket/impl/close.ipp @@ -9,6 +9,7 @@ #define BEAST_WEBSOCKET_IMPL_CLOSE_IPP #include +#include #include #include #include @@ -30,28 +31,25 @@ class stream::close_op struct data : op { + bool cont; stream& ws; close_reason cr; - Handler h; fb_type fb; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, stream& ws_, + data(Handler& handler, stream& ws_, close_reason const& cr_) - : ws(ws_) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , ws(ws_) , cr(cr_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { ws.template write_close< static_streambuf>(fb, cr); } }; - std::shared_ptr d_; + handler_ptr d_; public: close_op(close_op&&) = default; @@ -60,7 +58,7 @@ public: template close_op(DeducedHandler&& h, stream& ws, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), ws, std::forward(args)...)) { @@ -83,7 +81,7 @@ public: std::size_t size, close_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -91,7 +89,7 @@ public: void* p, std::size_t size, close_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -105,7 +103,7 @@ public: void asio_handler_invoke(Function&& f, close_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -188,7 +186,7 @@ upcall: if(d.ws.wr_block_ == &d) d.ws.wr_block_ = nullptr; d.ws.rd_op_.maybe_invoke(); - d.h(ec); + d_.invoke(ec); } template diff --git a/include/beast/websocket/impl/handshake.ipp b/include/beast/websocket/impl/handshake.ipp index ba96de20..3fc29e32 100644 --- a/include/beast/websocket/impl/handshake.ipp +++ b/include/beast/websocket/impl/handshake.ipp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -33,29 +34,26 @@ class stream::handshake_op struct data { + bool cont; stream& ws; - Handler h; std::string key; http::request req; http::response resp; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, stream& ws_, + data(Handler& handler, stream& ws_, boost::string_ref const& host, boost::string_ref const& resource) - : ws(ws_) - , h(std::forward(h_)) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , ws(ws_) , req(ws.build_request(host, resource, key)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { ws.reset(); } }; - std::shared_ptr d_; + handler_ptr d_; public: handshake_op(handshake_op&&) = default; @@ -64,7 +62,7 @@ public: template handshake_op(DeducedHandler&& h, stream& ws, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), ws, std::forward(args)...)) { @@ -79,7 +77,7 @@ public: std::size_t size, handshake_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -87,7 +85,7 @@ public: void* p, std::size_t size, handshake_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -101,7 +99,7 @@ public: void asio_handler_invoke(Function&& f, handshake_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -147,7 +145,7 @@ operator()(error_code ec, bool again) } } } - d.h(ec); + d_.invoke(ec); } template diff --git a/include/beast/websocket/impl/ping.ipp b/include/beast/websocket/impl/ping.ipp index cfe91277..f81f107b 100644 --- a/include/beast/websocket/impl/ping.ipp +++ b/include/beast/websocket/impl/ping.ipp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -25,24 +26,18 @@ template template class stream::ping_op { - using alloc_type = - handler_alloc; - struct data : op { - stream& ws; - Handler h; - detail::frame_streambuf fb; bool cont; + stream& ws; + detail::frame_streambuf fb; int state = 0; - template - data(DeducedHandler&& h_, stream& ws_, + data(Handler& handler, stream& ws_, opcode op_, ping_data const& payload) - : ws(ws_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , ws(ws_) { using boost::asio::buffer; using boost::asio::buffer_copy; @@ -51,7 +46,7 @@ class stream::ping_op } }; - std::shared_ptr d_; + handler_ptr d_; public: ping_op(ping_op&&) = default; @@ -60,7 +55,7 @@ public: template ping_op(DeducedHandler&& h, stream& ws, Args&&... args) - : d_(std::make_shared( + : d_(make_handler_ptr( std::forward(h), ws, std::forward(args)...)) { @@ -81,7 +76,7 @@ public: std::size_t size, ping_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -89,7 +84,7 @@ public: void* p, std::size_t size, ping_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -103,7 +98,7 @@ public: void asio_handler_invoke(Function&& f, ping_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -187,7 +182,7 @@ upcall: if(d.ws.wr_block_ == &d) d.ws.wr_block_ = nullptr; d.ws.rd_op_.maybe_invoke(); - d.h(ec); + d_.invoke(ec); } template diff --git a/include/beast/websocket/impl/read.ipp b/include/beast/websocket/impl/read.ipp index 02ddd3c2..2469b96f 100644 --- a/include/beast/websocket/impl/read.ipp +++ b/include/beast/websocket/impl/read.ipp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -31,9 +32,6 @@ template template class stream::read_frame_op { - using alloc_type = - handler_alloc; - using fb_type = detail::frame_streambuf; @@ -45,30 +43,27 @@ class stream::read_frame_op struct data : op { + bool cont; stream& ws; frame_info& fi; DynamicBuffer& db; - Handler h; fb_type fb; boost::optional dmb; boost::optional fmb; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, stream& ws_, + data(Handler& handler, stream& ws_, frame_info& fi_, DynamicBuffer& sb_) - : ws(ws_) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , ws(ws_) , fi(fi_) , db(sb_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { } }; - std::shared_ptr d_; + handler_ptr d_; public: read_frame_op(read_frame_op&&) = default; @@ -77,7 +72,7 @@ public: template read_frame_op(DeducedHandler&& h, stream& ws, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), ws, std::forward(args)...)) { @@ -105,7 +100,7 @@ public: std::size_t size, read_frame_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -113,7 +108,7 @@ public: void* p, std::size_t size, read_frame_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -127,7 +122,7 @@ public: void asio_handler_invoke(Function&& f, read_frame_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -545,7 +540,7 @@ upcall: if(d.ws.wr_block_ == &d) d.ws.wr_block_ = nullptr; d.ws.wr_op_.maybe_invoke(); - d.h(ec); + d_.invoke(ec); } template @@ -734,34 +729,28 @@ template template class stream::read_op { - using alloc_type = - handler_alloc; - struct data { + bool cont; stream& ws; opcode& op; DynamicBuffer& db; - Handler h; frame_info fi; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, + data(Handler& handler, stream& ws_, opcode& op_, DynamicBuffer& sb_) - : ws(ws_) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , ws(ws_) , op(op_) , db(sb_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { } }; - std::shared_ptr d_; + handler_ptr d_; public: read_op(read_op&&) = default; @@ -770,7 +759,7 @@ public: template read_op(DeducedHandler&& h, stream& ws, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), ws, std::forward(args)...)) { @@ -785,7 +774,7 @@ public: std::size_t size, read_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -793,7 +782,7 @@ public: void* p, std::size_t size, read_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -807,7 +796,7 @@ public: void asio_handler_invoke(Function&& f, read_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -847,7 +836,7 @@ operator()(error_code const& ec, bool again) } } upcall: - d.h(ec); + d_.invoke(ec); } template diff --git a/include/beast/websocket/impl/ssl.ipp b/include/beast/websocket/impl/ssl.ipp index 07570e5c..09a95cec 100644 --- a/include/beast/websocket/impl/ssl.ipp +++ b/include/beast/websocket/impl/ssl.ipp @@ -9,7 +9,9 @@ #define BEAST_WEBSOCKET_IMPL_SSL_IPP_INCLUDED #include +#include #include +#include namespace beast { namespace websocket { @@ -38,31 +40,28 @@ class teardown_ssl_op struct data { - stream_type& stream; - Handler h; bool cont; + stream_type& stream; int state = 0; - template - data(DeducedHandler&& h_, - stream_type& stream_) - : stream(stream_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) + data(Handler& handler, stream_type& stream_) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , stream(stream_) { } }; - std::shared_ptr d_; + handler_ptr d_; public: template explicit teardown_ssl_op( DeducedHandler&& h, stream_type& stream) - : d_(std::make_shared( - std::forward(h), stream)) + : d_(make_handler_ptr( + std::forward( + h), stream)) { (*this)(error_code{}, false); } @@ -75,7 +74,7 @@ public: teardown_ssl_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -83,7 +82,7 @@ public: std::size_t size, teardown_ssl_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -99,7 +98,7 @@ public: teardown_ssl_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -120,7 +119,7 @@ operator()(error_code ec, bool again) return; } } - d.h(ec); + d_.invoke(ec); } } // detail diff --git a/include/beast/websocket/impl/teardown.ipp b/include/beast/websocket/impl/teardown.ipp index 4de5444b..e757d739 100644 --- a/include/beast/websocket/impl/teardown.ipp +++ b/include/beast/websocket/impl/teardown.ipp @@ -9,7 +9,9 @@ #define BEAST_WEBSOCKET_IMPL_TEARDOWN_IPP #include +#include #include +#include #include namespace beast { @@ -20,37 +22,37 @@ namespace detail { template class teardown_tcp_op { + using alloc_type = + handler_alloc; + using socket_type = boost::asio::ip::tcp::socket; struct data { - socket_type& socket; - Handler h; - char buf[8192]; bool cont; + socket_type& socket; + char buf[2048]; int state = 0; - template - data(DeducedHandler&& h_, socket_type& socket_) - : socket(socket_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) + data(Handler& handler, socket_type& socket_) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , socket(socket_) { } }; - std::shared_ptr d_; + handler_ptr d_; public: template teardown_tcp_op( DeducedHandler&& h, socket_type& socket) - : d_(std::make_shared( - std::forward(h), - socket)) + : d_(make_handler_ptr( + std::forward( + h), socket)) { (*this)(error_code{}, 0, false); } @@ -63,7 +65,7 @@ public: teardown_tcp_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -71,7 +73,7 @@ public: std::size_t size, teardown_tcp_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -86,7 +88,7 @@ public: teardown_tcp_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -119,7 +121,7 @@ operator()(error_code ec, std::size_t, bool again) d.socket.close(ec); ec = error_code{}; } - d.h(ec); + d_.invoke(ec); } } // detail diff --git a/include/beast/websocket/impl/write.ipp b/include/beast/websocket/impl/write.ipp index 0f84692b..884e7c7d 100644 --- a/include/beast/websocket/impl/write.ipp +++ b/include/beast/websocket/impl/write.ipp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -97,31 +98,27 @@ template template class stream::write_frame_op { - using alloc_type = - handler_alloc; - struct data : op { + Handler& handler; + bool cont; stream& ws; consuming_buffers cb; - Handler h; detail::frame_header fh; detail::fh_streambuf fh_buf; detail::prepared_key_type key; void* tmp; std::size_t tmp_size; std::uint64_t remain; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, stream& ws_, + data(Handler& handler_, stream& ws_, bool fin, Buffers const& bs) - : ws(ws_) - , cb(bs) - , h(std::forward(h_)) + : handler(handler_) , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) + is_continuation(handler)) + , ws(ws_) + , cb(bs) { using beast::detail::clamp; fh.op = ws.wr_.cont ? @@ -139,7 +136,7 @@ class stream::write_frame_op detail::prepare_key(key, fh.key); tmp_size = clamp(fh.len, ws.wr_buf_size_); tmp = boost_asio_handler_alloc_helpers:: - allocate(tmp_size, h); + allocate(tmp_size, handler); remain = fh.len; } else @@ -153,11 +150,11 @@ class stream::write_frame_op { if(tmp) boost_asio_handler_alloc_helpers:: - deallocate(tmp, tmp_size, h); + deallocate(tmp, tmp_size, handler); } }; - std::shared_ptr d_; + handler_ptr d_; public: write_frame_op(write_frame_op&&) = default; @@ -166,9 +163,9 @@ public: template write_frame_op(DeducedHandler&& h, stream& ws, Args&&... args) - : d_(std::make_shared( - std::forward(h), ws, - std::forward(args)...)) + : d_(make_handler_ptr( + std::forward(h), + ws, std::forward(args)...)) { (*this)(error_code{}, false); } @@ -187,7 +184,7 @@ public: std::size_t size, write_frame_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -195,7 +192,7 @@ public: void* p, std::size_t size, write_frame_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -209,7 +206,7 @@ public: void asio_handler_invoke(Function&& f, write_frame_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -333,16 +330,10 @@ operator()(error_code ec, bool again) } } upcall: - if(d.tmp) - { - boost_asio_handler_alloc_helpers:: - deallocate(d.tmp, d.tmp_size, d.h); - d.tmp = nullptr; - } if(d.ws.wr_block_ == &d) d.ws.wr_block_ = nullptr; d.ws.rd_op_.maybe_invoke(); - d.h(ec); + d_.invoke(ec); } template @@ -532,32 +523,26 @@ template template class stream::write_op { - using alloc_type = - handler_alloc; - struct data : op { + bool cont; stream& ws; consuming_buffers cb; - Handler h; std::size_t remain; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, - stream& ws_, Buffers const& bs) - : ws(ws_) + data(Handler& handler, stream& ws_, + Buffers const& bs) + : cont(boost_asio_handler_cont_helpers:: + is_continuation(handler)) + , ws(ws_) , cb(bs) - , h(std::forward(h_)) , remain(boost::asio::buffer_size(cb)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { } }; - std::shared_ptr d_; + handler_ptr d_; public: write_op(write_op&&) = default; @@ -567,7 +552,7 @@ public: explicit write_op(DeducedHandler&& h, stream& ws, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), ws, std::forward(args)...)) { @@ -581,7 +566,7 @@ public: std::size_t size, write_op* op) { return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + allocate(size, op->d_.handler()); } friend @@ -589,7 +574,7 @@ public: void* p, std::size_t size, write_op* op) { return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + deallocate(p, size, op->d_.handler()); } friend @@ -603,7 +588,7 @@ public: void asio_handler_invoke(Function&& f, write_op* op) { return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + invoke(f, op->d_.handler()); } }; @@ -637,7 +622,7 @@ operator()(error_code ec, bool again) break; } } - d.h(ec); + d_.invoke(ec); } template diff --git a/test/Jamfile b/test/Jamfile index f05a0922..a023b5fd 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -27,6 +27,7 @@ unit-test core-tests : core/error.cpp core/handler_alloc.cpp core/handler_concepts.cpp + core/handler_ptr.cpp core/placeholders.cpp core/prepare_buffers.cpp core/static_streambuf.cpp diff --git a/test/core/CMakeLists.txt b/test/core/CMakeLists.txt index c0904fd2..d96d5324 100644 --- a/test/core/CMakeLists.txt +++ b/test/core/CMakeLists.txt @@ -22,6 +22,7 @@ add_executable (core-tests error.cpp handler_alloc.cpp handler_concepts.cpp + handler_ptr.cpp placeholders.cpp prepare_buffers.cpp static_streambuf.cpp diff --git a/test/core/handler_ptr.cpp b/test/core/handler_ptr.cpp new file mode 100644 index 00000000..8cd2a8d6 --- /dev/null +++ b/test/core/handler_ptr.cpp @@ -0,0 +1,9 @@ +// +// Copyright (c) 2013-2016 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) +// + +// Test that header file is self-contained. +#include