From 256c12f1501991704ace2111b83c677bb6e36716 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Sun, 6 Oct 2013 19:46:42 -0700 Subject: [PATCH] Add ScopedWrapperContext --- .../Builds/VisualStudio2012/beast.vcxproj | 1 + .../VisualStudio2012/beast.vcxproj.filters | 3 + src/beast/beast/Threads.h | 1 + .../beast/threads/ScopedWrapperContext.h | 93 +++++++++++++++++++ src/ripple/peerfinder/impl/Manager.cpp | 59 +++++++++--- 5 files changed, 144 insertions(+), 13 deletions(-) create mode 100644 src/beast/beast/threads/ScopedWrapperContext.h diff --git a/src/beast/Builds/VisualStudio2012/beast.vcxproj b/src/beast/Builds/VisualStudio2012/beast.vcxproj index c63d3621da..934a282860 100644 --- a/src/beast/Builds/VisualStudio2012/beast.vcxproj +++ b/src/beast/Builds/VisualStudio2012/beast.vcxproj @@ -172,6 +172,7 @@ + diff --git a/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters b/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters index 6b718eb5c9..171a1a51fe 100644 --- a/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters +++ b/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters @@ -1248,6 +1248,9 @@ beast\utility + + beast\threads + diff --git a/src/beast/beast/Threads.h b/src/beast/beast/Threads.h index 7336bc7771..6c3859d9a6 100644 --- a/src/beast/beast/Threads.h +++ b/src/beast/beast/Threads.h @@ -32,5 +32,6 @@ #include "threads/Thread.h" #include "threads/ThreadLocalValue.h" #include "threads/WaitableEvent.h" +#include "threads/ScopedWrapperContext.h" #endif diff --git a/src/beast/beast/threads/ScopedWrapperContext.h b/src/beast/beast/threads/ScopedWrapperContext.h new file mode 100644 index 0000000000..6a0b88324e --- /dev/null +++ b/src/beast/beast/threads/ScopedWrapperContext.h @@ -0,0 +1,93 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_THREADS_WRAPSCOPED_H_INCLUDED +#define BEAST_THREADS_WRAPSCOPED_H_INCLUDED + +namespace beast { + +/** Wraps a function object so invocation happens during a scoped container lifetime. */ +/** @{ */ +namespace detail { + +template +class ScopedWrapper +{ +public: + ScopedWrapper (Context const& context, Handler const& handler) + : m_context (context) + , m_handler (handler) + { } + + void operator() () + { + ScopedType const scope (m_context); + m_handler(); + } + +private: + Context const& m_context; + Handler m_handler; +}; + +} + +//------------------------------------------------------------------------------ + +/** Helper to eliminate the template argument at call sites. */ +template +class ScopedWrapperContext +{ +public: + typedef Context context_type; + typedef ScopedType scoped_type; + + class Scope + { + public: + explicit Scope (ScopedWrapperContext const& owner) + : m_scope (owner.m_context) + { } + private: + scoped_type m_scope; + }; + + ScopedWrapperContext () + { } + + template + explicit ScopedWrapperContext (Arg& arg) + : m_context (arg) + { } + + template + detail::ScopedWrapper wrap ( + Handler const& handler) + { + return detail::ScopedWrapper ( + m_context, handler); + } + +private: + Context m_context; +}; + +} + +#endif diff --git a/src/ripple/peerfinder/impl/Manager.cpp b/src/ripple/peerfinder/impl/Manager.cpp index 7cf909ce72..93947ea0a8 100644 --- a/src/ripple/peerfinder/impl/Manager.cpp +++ b/src/ripple/peerfinder/impl/Manager.cpp @@ -191,6 +191,14 @@ public: DeadlineTimer m_messageTimer; DeadlineTimer m_cacheTimer; + // Ensures that all Logic member function entry points are + // called while holding a lock on the recursive mutex. + // + typedef ScopedWrapperContext < + RecursiveMutex, RecursiveMutex::ScopedLockType> SerializedContext; + + SerializedContext m_context; + //-------------------------------------------------------------------------- ManagerImp (Stoppable& stoppable, Callback& callback, Journal journal) @@ -226,14 +234,20 @@ public: void setConfig (Config const& config) { - m_queue.dispatch (bind (&Logic::setConfig, &m_logic, config)); + m_queue.dispatch ( + m_context.wrap ( + bind (&Logic::setConfig, &m_logic, + config))); } void addStrings (std::string const& name, std::vector const& strings) { - m_queue.dispatch (bind (&Logic::addStaticSource, &m_logic, - SourceStrings::New (name, strings))); + m_queue.dispatch ( + m_context.wrap ( + bind ( + &Logic::addStaticSource, &m_logic, + SourceStrings::New (name, strings)))); } void addURL (std::string const& name, std::string const& url) @@ -243,26 +257,34 @@ public: void onPeerConnected (PeerID const& id, IPEndpoint const& address, bool incoming) { - m_queue.dispatch (bind (&Logic::onPeerConnected, &m_logic, - id, address, incoming)); + m_queue.dispatch ( + m_context.wrap ( + bind (&Logic::onPeerConnected, &m_logic, + id, address, incoming)));; } void onPeerDisconnected (const PeerID& id) { - m_queue.dispatch (bind (&Logic::onPeerDisconnected, &m_logic, id)); + m_queue.dispatch ( + m_context.wrap ( + bind (&Logic::onPeerDisconnected, &m_logic, + id))); } void onPeerLegacyEndpoint (IPEndpoint const& ep) { - m_queue.dispatch (bind (&Logic::onPeerLegacyEndpoint, &m_logic, - ep)); + m_queue.dispatch ( + m_context.wrap ( + bind (&Logic::onPeerLegacyEndpoint, &m_logic, + ep))); } void onPeerEndpoints (PeerID const& id, std::vector const& endpoints) { - m_queue.dispatch (beast::bind (&Logic::onPeerEndpoints, &m_logic, - id, endpoints)); + m_queue.dispatch ( + beast::bind (&Logic::onPeerEndpoints, &m_logic, + id, endpoints)); } //-------------------------------------------------------------------------- @@ -297,6 +319,8 @@ public: void onWrite (PropertyStream stream) { + SerializedContext::Scope scope (m_context); + // VFALCO NOTE this is not thread safe (yet) stream ["peers"] = m_logic.m_slots.peerCount; @@ -317,17 +341,26 @@ public: { if (timer == m_connectTimer) { - m_queue.dispatch (bind (&Logic::makeOutgoingConnections, &m_logic)); + m_queue.dispatch ( + m_context.wrap ( + bind (&Logic::makeOutgoingConnections, &m_logic))); + m_connectTimer.setExpiration (secondsPerConnect); } else if (timer == m_messageTimer) { - m_queue.dispatch (bind (&Logic::sendEndpoints, &m_logic)); + m_queue.dispatch ( + m_context.wrap ( + bind (&Logic::sendEndpoints, &m_logic))); + m_messageTimer.setExpiration (secondsPerMessage); } else if (timer == m_cacheTimer) { - m_queue.dispatch (bind (&Logic::cycleCache, &m_logic)); + m_queue.dispatch ( + m_context.wrap ( + bind (&Logic::cycleCache, &m_logic))); + m_cacheTimer.setExpiration (cacheSecondsToLive); } }