diff --git a/include/libtorrent/Makefile.am b/include/libtorrent/Makefile.am index e927b7eb5..08fa595c0 100644 --- a/include/libtorrent/Makefile.am +++ b/include/libtorrent/Makefile.am @@ -8,6 +8,7 @@ nobase_include_HEADERS = \ alert_observer.hpp \ alert_types.hpp \ alloca.hpp \ + allocating_handler.hpp \ allocator.hpp \ assert.hpp \ bandwidth_limit.hpp \ diff --git a/include/libtorrent/aux_/allocating_handler.hpp b/include/libtorrent/aux_/allocating_handler.hpp new file mode 100644 index 000000000..0c012cef9 --- /dev/null +++ b/include/libtorrent/aux_/allocating_handler.hpp @@ -0,0 +1,151 @@ +/* + +Copyright (c) 2015, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef TORRENT_ALLOCATING_HANDLER_HPP_INCLUDED +#define TORRENT_ALLOCATING_HANDLER_HPP_INCLUDED + +#include +#include "libtorrent/config.hpp" + +#include "libtorrent/aux_/disable_warnings_push.hpp" + +#include + +#include "libtorrent/aux_/disable_warnings_pop.hpp" + +namespace libtorrent { namespace aux +{ + // this is meant to provide the actual storage for the handler allocator. + // There's only a single slot, so the allocator is only supposed to be used + // for handlers where there's only a single outstanding operation at a time, + // per storage object. For instance, peers only ever have one outstanding + // read operation at a time, so it can reuse its storage for read handlers. + template + struct handler_storage + { +#ifdef TORRENT_DEBUG + handler_storage() + : used(false) + {} + + bool used; +#else + handler_storage() {} +#endif + boost::aligned_storage bytes; + private: + handler_storage(handler_storage const&); + }; + + // this class is a wrapper for an asio handler object. Its main purpose + // is to pass along additional parameters to the asio handler allocator + // function, as well as providing a distinct type for the handler + // allocator function to overload on + template + struct allocating_handler + { +#if !defined BOOST_NO_CXX11_RVALUE_REFERENCES + allocating_handler( + Handler&& h, handler_storage& s) + : handler(std::move(h)) + , storage(s) + {} +#else + allocating_handler( + Handler const& h, handler_storage& s) + : handler(h) + , storage(s) + {} +#endif + +#if !deffined BOOST_NO_CXX11_VARIADIC_TEMPLATES \ + && !defined BOOST_NO_CXX11_RVALUE_REFERENCES + template + void operator()(A&&... a) const + { + handler(std::forward(a)...); + } +#else + template + void operator()(A0 const& a0) const + { + handler(a0); + } + + template + void operator()(A0 const& a0, A1 const& a1) const + { + handler(a0, a1); + } + + template + void operator()(A0 const& a0, A1 const& a1, A2 const& a2) const + { + handler(a0, a1, a2); + } +#endif + + friend void* asio_handler_allocate( + std::size_t size, allocating_handler* ctx) + { + TORRENT_UNUSED(size); + TORRENT_ASSERT(size <= Size); +#ifdef TORRENT_DEBUG + TORRENT_ASSERT(!ctx->storage.used); + ctx->storage.used = true; +#endif + return &ctx->storage.bytes; + } + + friend void asio_handler_deallocate( + void* ptr, std::size_t size, allocating_handler* ctx) + { + TORRENT_UNUSED(ptr); + TORRENT_UNUSED(size); + TORRENT_UNUSED(ctx); + + TORRENT_ASSERT(size <= Size); + TORRENT_ASSERT(ptr == &ctx->storage.bytes); +#ifdef TORRENT_DEBUG + ctx->storage.used = false; +#endif + } + + Handler handler; + handler_storage& storage; + }; + +} +} + +#endif + diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index aaa8384b9..8dac3e8bd 100644 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -59,6 +59,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket.hpp" // for tcp::endpoint #include "libtorrent/io_service_fwd.hpp" #include "libtorrent/receive_buffer.hpp" +#include "libtorrent/aux_/allocating_handler.hpp" #ifndef TORRENT_DISABLE_LOGGING #include "libtorrent/debug.hpp" @@ -79,7 +80,6 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include #include "libtorrent/aux_/disable_warnings_pop.hpp" @@ -983,25 +983,9 @@ namespace libtorrent // have sent to it int m_outstanding_bytes; - template - struct handler_storage - { -#ifdef TORRENT_DEBUG - handler_storage() - : used(false) - {} - - bool used; -#else - handler_storage() {} -#endif - boost::aligned_storage bytes; - private: - handler_storage(handler_storage const&); - }; - - handler_storage m_read_handler_storage; - handler_storage m_write_handler_storage; + // TODO: 3 use handler storage for second_tick and udp_packet handler too + aux::handler_storage m_read_handler_storage; + aux::handler_storage m_write_handler_storage; // we have suggested these pieces to the peer // don't suggest it again @@ -1246,89 +1230,20 @@ namespace libtorrent // outstanding requests need to increase at the same pace to keep up. bool m_slow_start:1; - // TODO: 3 factor this out into its own header and use it for UDP socket - // and maybe second_timer as well - template - struct allocating_handler - { - // TODO: 3 if move semantics is supported, move the handler into this - // wrapper - allocating_handler( - Handler const& h, handler_storage& s) - : handler(h) - , storage(s) - {} - -#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES - template - void operator()(A&&... a) const - { - handler(std::forward(a)...); - } -#else - template - void operator()(A0 const& a0) const - { - handler(a0); - } - - template - void operator()(A0 const& a0, A1 const& a1) const - { - handler(a0, a1); - } - - template - void operator()(A0 const& a0, A1 const& a1, A2 const& a2) const - { - handler(a0, a1, a2); - } -#endif - - friend void* asio_handler_allocate( - std::size_t size, allocating_handler* ctx) - { - TORRENT_UNUSED(size); - TORRENT_ASSERT(size <= Size); -#ifdef TORRENT_DEBUG - TORRENT_ASSERT(!ctx->storage.used); - ctx->storage.used = true; -#endif - return &ctx->storage.bytes; - } - - friend void asio_handler_deallocate( - void* ptr, std::size_t size, allocating_handler* ctx) - { - TORRENT_UNUSED(ptr); - TORRENT_UNUSED(size); - TORRENT_UNUSED(ctx); - - TORRENT_ASSERT(size <= Size); - TORRENT_ASSERT(ptr == &ctx->storage.bytes); -#ifdef TORRENT_DEBUG - ctx->storage.used = false; -#endif - } - - Handler handler; - handler_storage& storage; - }; - template - allocating_handler + aux::allocating_handler make_read_handler(Handler const& handler) { - return allocating_handler( + return aux::allocating_handler( handler, m_read_handler_storage ); } template - allocating_handler + aux::allocating_handler make_write_handler(Handler const& handler) { - return allocating_handler( + return aux::allocating_handler( handler, m_write_handler_storage ); }