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);
}
}