diff --git a/src/beast/Builds/VisualStudio2012/Beast.props b/src/beast/Builds/VisualStudio2012/Beast.props
index c7e4aad4d..792f3409c 100644
--- a/src/beast/Builds/VisualStudio2012/Beast.props
+++ b/src/beast/Builds/VisualStudio2012/Beast.props
@@ -1,7 +1,9 @@
-
+
+ ..\..
+
@@ -9,8 +11,12 @@
BEAST_COMPILING_STATIC_LIBARARY=1;_CRTDBG_MAP_ALLOC;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions)
true
false
- %(AdditionalIncludeDirectories)
+ $(RepoDir)\config;%(AdditionalIncludeDirectories)
-
+
+
+ $(RepoDir)
+
+
\ No newline at end of file
diff --git a/src/beast/Builds/VisualStudio2012/beast.vcxproj b/src/beast/Builds/VisualStudio2012/beast.vcxproj
index 3cf894ed2..58e8fb8ec 100644
--- a/src/beast/Builds/VisualStudio2012/beast.vcxproj
+++ b/src/beast/Builds/VisualStudio2012/beast.vcxproj
@@ -78,6 +78,7 @@
+
@@ -119,6 +120,7 @@
+
@@ -143,9 +145,12 @@
+
+
+
@@ -217,13 +222,10 @@
-
-
-
@@ -392,7 +394,6 @@
-
@@ -490,6 +491,18 @@
true
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
true
true
@@ -701,18 +714,6 @@
true
true
-
- true
- true
- true
- true
-
-
- true
- true
- true
- true
-
true
true
diff --git a/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters b/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters
index e83071e18..36e80f17e 100644
--- a/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters
+++ b/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters
@@ -73,6 +73,9 @@
beast\crypto\impl\sha2
+
+ scripts
+
@@ -270,6 +273,9 @@
{39886e0f-1607-4b7a-81cf-011d83dadee3}
+
+ {c65af439-8c23-46c3-9b95-7da15651e5f6}
+
@@ -578,21 +584,12 @@
beast_core\containers
-
- beast_core\diagnostic
-
-
- beast_core\diagnostic
-
beast_core\diagnostic
beast_core\diagnostic
-
- beast_core\diagnostic
-
beast_core\diagnostic
@@ -1178,7 +1175,6 @@
beast\http
-
beast
@@ -1209,6 +1205,16 @@
beast\chrono
+
+ beast
+
+
+
+ beast\utility
+
+
+ beast\utility
+
@@ -1451,12 +1457,6 @@
beast_core\native
-
- beast_core\diagnostic
-
-
- beast_core\diagnostic
-
beast_core\diagnostic
@@ -1781,6 +1781,12 @@
beast\chrono
+
+ beast\utility\impl
+
+
+ beast\utility\impl
+
diff --git a/src/beast/beast/ByteOrder.h b/src/beast/beast/ByteOrder.h
index e574cf29e..0e40616e7 100644
--- a/src/beast/beast/ByteOrder.h
+++ b/src/beast/beast/ByteOrder.h
@@ -34,7 +34,7 @@ namespace beast {
/** Contains static methods for converting the byte order between different
endiannesses.
*/
-class BEAST_API ByteOrder : public Uncopyable
+class ByteOrder : public Uncopyable
{
public:
//==============================================================================
diff --git a/src/beast/modules/beast_core/diagnostic/SafeBool.h b/src/beast/beast/SafeBool.h
similarity index 93%
rename from src/beast/modules/beast_core/diagnostic/SafeBool.h
rename to src/beast/beast/SafeBool.h
index 1b6dfad0e..fbae19592 100644
--- a/src/beast/modules/beast_core/diagnostic/SafeBool.h
+++ b/src/beast/beast/SafeBool.h
@@ -20,23 +20,11 @@
#ifndef BEAST_SAFEBOOL_H_INCLUDED
#define BEAST_SAFEBOOL_H_INCLUDED
-/** Safe evaluation of class as `bool`.
+namespace beast {
- This allows a class to be safely evaluated as a bool without the usual
- harmful side effects of the straightforward operator conversion approach.
- To use it, derive your class from SafeBool and implement `asBoolean()` as:
+namespace detail {
- @code
-
- bool asBoolean () const;
-
- @endcode
-
- Ideas from http://www.artima.com/cppsource/safebool.html
-
- @class SafeBool
-*/
-class BEAST_API SafeBoolBase
+class SafeBoolBase
{
private:
void disallowed () const { }
@@ -56,11 +44,29 @@ protected:
~SafeBoolBase () { }
};
+}
+
+/** Safe evaluation of class as `bool`.
+
+ This allows a class to be safely evaluated as a bool without the usual
+ harmful side effects of the straightforward operator conversion approach.
+ To use it, derive your class from SafeBool and implement `asBoolean()` as:
+
+ @code
+
+ bool asBoolean () const;
+
+ @endcode
+
+ Ideas from http://www.artima.com/cppsource/safebool.html
+
+ @class SafeBool
+*/
template
-class SafeBool : public SafeBoolBase
+class SafeBool : public detail::SafeBoolBase
{
public:
- operator boolean_t () const
+ operator detail::SafeBoolBase::boolean_t () const
{
return (static_cast (this))->asBoolean ()
? &SafeBoolBase::allowed : 0;
@@ -82,6 +88,8 @@ void operator!= (SafeBool const& lhs, SafeBool const& rhs)
lhs.disallowed ();
}
+}
+
#endif
diff --git a/src/beast/beast/Utility.h b/src/beast/beast/Utility.h
index 807a25180..f27cc5947 100644
--- a/src/beast/beast/Utility.h
+++ b/src/beast/beast/Utility.h
@@ -20,7 +20,9 @@
#ifndef BEAST_UTILITY_H_INCLUDED
#define BEAST_UTILITY_H_INCLUDED
+#include "utility/Debug.h"
#include "utility/EnableIf.h"
+#include "utility/Error.h"
#include "utility/Journal.h"
#endif
diff --git a/src/beast/beast/chrono/impl/RelativeTime.cpp b/src/beast/beast/chrono/impl/RelativeTime.cpp
index ca58862b2..ac78d3994 100644
--- a/src/beast/beast/chrono/impl/RelativeTime.cpp
+++ b/src/beast/beast/chrono/impl/RelativeTime.cpp
@@ -21,7 +21,7 @@
*/
//==============================================================================
-#include "RelativeTime.h"
+#include "../RelativeTime.h"
// VFALCO TODO Migrate the localizable strings interfaces for this file
diff --git a/src/beast/modules/beast_core/diagnostic/Debug.h b/src/beast/beast/utility/Debug.h
similarity index 95%
rename from src/beast/modules/beast_core/diagnostic/Debug.h
rename to src/beast/beast/utility/Debug.h
index e80418e04..0a1d5e3e0 100644
--- a/src/beast/modules/beast_core/diagnostic/Debug.h
+++ b/src/beast/beast/utility/Debug.h
@@ -17,8 +17,12 @@
*/
//==============================================================================
-#ifndef BEAST_DEBUG_H_INCLUDED
-#define BEAST_DEBUG_H_INCLUDED
+#ifndef BEAST_UTILITY_DEBUG_H_INCLUDED
+#define BEAST_UTILITY_DEBUG_H_INCLUDED
+
+#include "../strings/String.h"
+
+namespace beast {
// Auxiliary outines for debugging
@@ -83,4 +87,6 @@ extern void checkHeap ();
}
+}
+
#endif
diff --git a/src/beast/modules/beast_core/diagnostic/Error.h b/src/beast/beast/utility/Error.h
similarity index 95%
rename from src/beast/modules/beast_core/diagnostic/Error.h
rename to src/beast/beast/utility/Error.h
index 946270b75..f9b188925 100644
--- a/src/beast/modules/beast_core/diagnostic/Error.h
+++ b/src/beast/beast/utility/Error.h
@@ -17,8 +17,17 @@
*/
//==============================================================================
-#ifndef BEAST_ERROR_H_INCLUDED
-#define BEAST_ERROR_H_INCLUDED
+#ifndef BEAST_UTILITY_ERROR_H_INCLUDED
+#define BEAST_UTILITY_ERROR_H_INCLUDED
+
+#include "../Config.h"
+
+#include "../SafeBool.h"
+#include "../strings/String.h"
+
+#include
+
+namespace beast {
/** A concise error report.
@@ -32,7 +41,7 @@
@ingroup beast_core
*/
-class BEAST_API Error
+class Error
: public std::exception
, public SafeBool
{
@@ -119,4 +128,6 @@ private:
mutable char const* m_szWhat;
};
+}
+
#endif
diff --git a/src/beast/beast/utility/Utility.cpp b/src/beast/beast/utility/Utility.cpp
index fbfc1450a..0eac28256 100644
--- a/src/beast/beast/utility/Utility.cpp
+++ b/src/beast/beast/utility/Utility.cpp
@@ -19,6 +19,10 @@
#include "BeastConfig.h"
-#include "../../modules/beast_core/beast_core.h"
+#include "impl/Error.cpp"
+
+// For Journal and Debug
+#include "../../modules/beast_core/beast_core.h"
#include "impl/Journal.cpp"
+#include "impl/Debug.cpp"
diff --git a/src/beast/modules/beast_core/diagnostic/Debug.cpp b/src/beast/beast/utility/impl/Debug.cpp
similarity index 99%
rename from src/beast/modules/beast_core/diagnostic/Debug.cpp
rename to src/beast/beast/utility/impl/Debug.cpp
index e9e654592..85b8d25a2 100644
--- a/src/beast/modules/beast_core/diagnostic/Debug.cpp
+++ b/src/beast/beast/utility/impl/Debug.cpp
@@ -17,8 +17,9 @@
*/
//==============================================================================
-namespace Debug
-{
+namespace beast {
+
+namespace Debug {
void breakPoint ()
{
@@ -358,3 +359,5 @@ public:
};
static DebugTests debugTests;
+
+}
diff --git a/src/beast/modules/beast_core/diagnostic/Error.cpp b/src/beast/beast/utility/impl/Error.cpp
similarity index 96%
rename from src/beast/modules/beast_core/diagnostic/Error.cpp
rename to src/beast/beast/utility/impl/Error.cpp
index 055d89a09..9083413fe 100644
--- a/src/beast/modules/beast_core/diagnostic/Error.cpp
+++ b/src/beast/beast/utility/impl/Error.cpp
@@ -17,6 +17,19 @@
*/
//==============================================================================
+#include "../Error.h"
+#include "../Debug.h"
+
+#include
+
+// VFALCO TODO Localizable strings
+#ifndef TRANS
+#define TRANS(s) (s)
+#define UNDEF_TRANS
+#endif
+
+namespace beast {
+
Error::Error ()
: m_code (success)
, m_lineNumber (0)
@@ -241,3 +254,11 @@ String const Error::getReasonTextForCode (Code code)
return s;
}
+
+#ifdef UNDEF_TRANS
+#undef TRANs
+#undef UNDEF_TRANS
+#endif
+
+}
+
diff --git a/src/beast/Builds/VisualStudio2012/BeastConfig.h b/src/beast/config/BeastConfig.h
similarity index 100%
rename from src/beast/Builds/VisualStudio2012/BeastConfig.h
rename to src/beast/config/BeastConfig.h
diff --git a/src/beast/modules/beast_core/beast_core.cpp b/src/beast/modules/beast_core/beast_core.cpp
index af54ca760..a24524820 100644
--- a/src/beast/modules/beast_core/beast_core.cpp
+++ b/src/beast/modules/beast_core/beast_core.cpp
@@ -138,8 +138,6 @@ namespace beast
#include "containers/DynamicList.cpp"
#include "containers/HashMap.cpp"
-#include "diagnostic/Debug.cpp"
-#include "diagnostic/Error.cpp"
#include "diagnostic/FatalError.cpp"
#include "diagnostic/FPUFlags.cpp"
#include "diagnostic/LeakChecked.cpp"
diff --git a/src/beast/modules/beast_core/beast_core.h b/src/beast/modules/beast_core/beast_core.h
index e8c4cc911..881856bab 100644
--- a/src/beast/modules/beast_core/beast_core.h
+++ b/src/beast/modules/beast_core/beast_core.h
@@ -54,6 +54,7 @@
#include "../../beast/Memory.h"
#include "../../beast/Intrusive.h"
#include "../../beast/Net.h"
+#include "../../beast/SafeBool.h"
#include "../../beast/Strings.h"
#include "../../beast/TypeTraits.h"
#include "../../beast/Thread.h"
@@ -146,7 +147,6 @@ class FileOutputStream;
#include "memory/MemoryAlignment.h"
#include "memory/CacheLine.h"
#include "threads/ReadWriteMutex.h"
-#include "diagnostic/SafeBool.h"
#include "threads/WaitableEvent.h"
#include "threads/Thread.h"
#include "threads/SpinLock.h"
@@ -154,8 +154,6 @@ class FileOutputStream;
#include "thread/MutexTraits.h"
#include "thread/TrackedMutex.h"
#include "diagnostic/FatalError.h"
-#include "diagnostic/Error.h"
-#include "diagnostic/Debug.h"
#include "text/LexicalCast.h"
#include "memory/ContainerDeletePolicy.h"
#include "maths/Math.h"
diff --git a/src/beast/modules/beast_core/thread/Stoppable.cpp b/src/beast/modules/beast_core/thread/Stoppable.cpp
index e8773f27f..bdb866c84 100644
--- a/src/beast/modules/beast_core/thread/Stoppable.cpp
+++ b/src/beast/modules/beast_core/thread/Stoppable.cpp
@@ -17,84 +17,45 @@
*/
//==============================================================================
-
-Stoppable::Stoppable (char const* name, Stoppable& parent)
+Stoppable::Stoppable (char const* name, RootStoppable& root)
: m_name (name)
- , m_root (false)
+ , m_root (root)
, m_child (this)
- , m_calledStop (false)
, m_stopped (false)
, m_childrenStopped (false)
{
- // must not have had stop called
+}
+
+Stoppable::Stoppable (char const* name, Stoppable& parent)
+ : m_name (name)
+ , m_root (parent.m_root)
+ , m_child (this)
+ , m_stopped (false)
+ , m_childrenStopped (false)
+{
+ // Must not have stopping parent.
bassert (! parent.isStopping());
parent.m_children.push_front (&m_child);
}
-Stoppable::Stoppable (char const* name, Stoppable* parent)
- : m_name (name)
- , m_root (parent == nullptr)
- , m_child (this)
- , m_calledStop (false)
- , m_stopped (false)
- , m_childrenStopped (false)
-{
- if (parent != nullptr)
- {
- // must not have had stop called
- bassert (! parent->isStopping());
-
- parent->m_children.push_front (&m_child);
- }
-}
-
Stoppable::~Stoppable ()
{
- // must be stopped
- bassert (m_stopped);
-
- // children must be stopped
+ // Children must be stopped.
bassert (m_childrenStopped);
}
-void Stoppable::stop (Journal::Stream stream)
+bool Stoppable::isStopping() const
{
- // may only be called once
- if (m_calledStop)
- return;
-
- m_calledStop = true;
-
- // must be called from a root stoppable
- bassert (m_root);
-
- // send the notification
- stopAsync ();
-
- // now block on the tree of Stoppable objects from the leaves up.
- stopRecursive (stream);
+ return m_root.isStopping();
}
-void Stoppable::stopAsync ()
-{
- // must be called from a root stoppable
- bassert (m_root);
-
- stopAsyncRecursive ();
-}
-
-bool Stoppable::isStopping ()
-{
- return m_calledStopAsync.get() != 0;
-}
-
-bool Stoppable::isStopped ()
+bool Stoppable::isStopped () const
{
return m_stopped;
}
-bool Stoppable::areChildrenStopped ()
+bool Stoppable::areChildrenStopped () const
{
return m_childrenStopped;
}
@@ -104,75 +65,134 @@ void Stoppable::stopped ()
m_stoppedEvent.signal();
}
-void Stoppable::onStop()
+void Stoppable::onPrepare (Journal journal)
+{
+}
+
+void Stoppable::onStart (Journal journal)
+{
+}
+
+void Stoppable::onStop (Journal journal)
{
stopped();
}
-void Stoppable::onChildrenStopped ()
+void Stoppable::onChildrenStopped (Journal journal)
{
}
//------------------------------------------------------------------------------
-void Stoppable::stopAsyncRecursive ()
+void Stoppable::prepareRecursive (Journal journal)
{
- // make sure we only do this once
- if (m_root)
- {
- // if this fails, some other thread got to it first
- if (! m_calledStopAsync.compareAndSetBool (1, 0))
- return;
- }
- else
- {
- // can't possibly already be set
- bassert (m_calledStopAsync.get() == 0);
-
- m_calledStopAsync.set (1);
- }
-
- // notify this stoppable
- onStop ();
-
- // notify children
+ onPrepare (journal);
for (Children::const_iterator iter (m_children.cbegin ());
iter != m_children.cend(); ++iter)
- {
- iter->stoppable->stopAsyncRecursive();
- }
+ iter->stoppable->prepareRecursive (journal);
}
-void Stoppable::stopRecursive (Journal::Stream stream)
+void Stoppable::startRecursive (Journal journal)
{
- // Block on each child recursively. Thinking of the Stoppable
- // hierarchy as a tree with the root at the top, we will block
- // first on leaves, and then at each successivly higher level.
+ onStart (journal);
+ for (Children::const_iterator iter (m_children.cbegin ());
+ iter != m_children.cend(); ++iter)
+ iter->stoppable->startRecursive (journal);
+}
+
+void Stoppable::stopAsyncRecursive (Journal journal)
+{
+ onStop (journal);
+ for (Children::const_iterator iter (m_children.cbegin ());
+ iter != m_children.cend(); ++iter)
+ iter->stoppable->stopAsyncRecursive (journal);
+}
+
+void Stoppable::stopRecursive (Journal journal)
+{
+ // Block on each child from the bottom of the tree up.
//
for (Children::const_iterator iter (m_children.cbegin ());
iter != m_children.cend(); ++iter)
- {
- iter->stoppable->stopRecursive (stream);
- }
+ iter->stoppable->stopRecursive (journal);
- // Once we get here, we either have no children, or all of
- // our children have stopped, so update state accordingly.
+ // if we get here then all children have stopped
//
+ memoryBarrier ();
m_childrenStopped = true;
+ onChildrenStopped (journal);
- // Notify derived class that children have stopped.
- onChildrenStopped ();
-
- // Block until this stoppable stops. First we do a timed wait of 1 second, and
- // if that times out we report to the Journal and then do an infinite wait.
+ // Now block on this Stoppable.
//
bool const timedOut (! m_stoppedEvent.wait (1 * 1000)); // milliseconds
if (timedOut)
{
- stream << "Waiting for '" << m_name << "' to stop";
+ journal.warning << "Waiting for '" << m_name << "' to stop";
m_stoppedEvent.wait ();
}
// once we get here, we know the stoppable has stopped.
m_stopped = true;
}
+
+//------------------------------------------------------------------------------
+
+RootStoppable::RootStoppable (char const* name)
+ : Stoppable (name, *this)
+{
+}
+
+RootStoppable::~RootStoppable ()
+{
+}
+
+bool RootStoppable::isStopping() const
+{
+ return m_calledStopAsync.get() != 0;
+}
+
+void RootStoppable::prepare (Journal journal)
+{
+ if (! m_prepared.compareAndSetBool (1, 0))
+ {
+ journal.warning << "Stoppable::prepare called again";
+ return;
+ }
+
+ prepareRecursive (journal);
+}
+
+void RootStoppable::start (Journal journal)
+{
+ // Courtesy call to prepare.
+ if (m_prepared.compareAndSetBool (1, 0))
+ prepareRecursive (journal);
+
+ if (! m_started.compareAndSetBool (1, 0))
+ {
+ journal.warning << "Stoppable::start called again";
+ return;
+ }
+
+ startRecursive (journal);
+}
+
+void RootStoppable::stop (Journal journal)
+{
+ if (! m_calledStop.compareAndSetBool (1, 0))
+ {
+ journal.warning << "Stoppable::stop called again";
+ return;
+ }
+
+ stopAsync (journal);
+ stopRecursive (journal);
+}
+
+void RootStoppable::stopAsync (Journal journal)
+{
+ if (! m_calledStopAsync.compareAndSetBool (1, 0))
+ return;
+
+ stopAsyncRecursive (journal);
+}
diff --git a/src/beast/modules/beast_core/thread/Stoppable.h b/src/beast/modules/beast_core/thread/Stoppable.h
index 5aa2cb1f7..f7f96d982 100644
--- a/src/beast/modules/beast_core/thread/Stoppable.h
+++ b/src/beast/modules/beast_core/thread/Stoppable.h
@@ -20,16 +20,66 @@
#ifndef BEAST_CORE_STOPPABLE_H_INCLUDED
#define BEAST_CORE_STOPPABLE_H_INCLUDED
-/** Provides an interface for stopping.
+class RootStoppable;
+
+/** Provides an interface for starting and stopping.
+
+ A common method of structuring server or peer to peer code is to isolate
+ conceptual portions of functionality into individual classes, aggregated
+ into some larger "application" or "core" object which holds all the parts.
+ Frequently, these components are dependent on each other in unavoidably
+ complex ways. They also often use threads and perform asynchronous i/o
+ operations involving sockets or other operating system objects. The process
+ of starting and stopping such a system can be complex. This interface
+ provides a set of behaviors for ensuring that the start and stop of a
+ composite application-style object is well defined.
+
+ Upon the initialization of the composite object these steps are peformed:
+
+ 1. Construct sub-components.
+
+ These are all typically derived from Stoppable. There can be a deep
+ hierarchy: Stoppable objects may themselves have Stoppable child
+ objects. This captures the relationship of dependencies.
+
+ 2. prepare()
+
+ Because some components may depend on others, preparatory steps require
+ that all objects be first constructed. The prepare step calls all
+ Stoppable objects in the tree starting from the leaves and working up
+ to the root. In this stage we are guaranteed that all objects have been
+ constructed and are in a well-defined state.
+
+ 3. onPrepare()
+
+ This override is called for all Stoppable objects in the hierarchy
+ during the prepare stage. Objects are called from the bottom up.
+ It is guaranteed that all child Stoppable objects have already been
+ prepared when this is called.
+
+ 4. start()
+
+ At this point all sub-components have been constructed and prepared,
+ so it should be safe for them to be started. While some Stoppable
+ objects may do nothing in their start function, others will start
+ threads or call asynchronous i/o initiating functions like timers or
+ sockets.
+
+ 5. onStart()
+
+ This override is called for all Stoppable objects in the hierarchy
+ during the start stage. Objects are called from the bottom up.
+ It is guaranteed that all child Stoppable objects have already been
+ started when this is called.
This is the sequence of events involved in stopping:
- 1. stopAsync() [optional]
+ 6. stopAsync() [optional]
This notifies the root Stoppable and all its children that a stop is
requested.
- 2. stop()
+ 7. stop()
This first calls stopAsync(), and then blocks on each child Stoppable in
the in the tree from the bottom up, until the Stoppable indicates it has
@@ -37,21 +87,21 @@
when some external signal indicates that the process should stop. For
example, an RPC 'stop' command, or a SIGINT POSIX signal.
- 3. onStop()
+ 8. onStop()
This override is called for the root Stoppable and all its children when
stopAsync() is called. Derived classes should cancel pending I/O and
timers, signal that threads should exit, queue cleanup jobs, and perform
any other necessary final actions in preparation for exit.
- 4. onChildrenStopped()
+ 9. onChildrenStopped()
This override is called when all the children have stopped. This informs
the Stoppable that there should not be any more dependents making calls
into its member functions. A Stoppable that has no children will still
have this function called.
- 5. stopped()
+ 10. stopped()
The derived class calls this function to inform the Stoppable API that
it has completed the stop. This unblocks the caller of stop().
@@ -102,85 +152,44 @@
@note A Stoppable may not be restarted.
*/
+/** @{ */
class Stoppable
{
-public:
- /** Create the stoppable.
- A stoppable without a parent is a root stoppable.
- @param name A name used in log output.
- @param parent Optional parent of this stoppable.
- */
- /** @{ */
- Stoppable (char const* name, Stoppable& parent);
- explicit Stoppable (char const* name, Stoppable* parent = nullptr);
- /** @} */
+protected:
+ Stoppable (char const* name, RootStoppable& root);
- /** Destroy the stoppable.
- Undefined behavior results if the object is not stopped first.
- Stoppable objects should not be created and destroyed dynamically during
- the process lifetime. Rather, the set of stoppables should be static and
- well-defined after initialization. If the set of domain-specific objects
- which need to stop is dynamic, use a single parent Stoppable to manage
- those objects. For example, make an HTTP server implementation a
- Stoppable, rather than each of its active connections.
- */
+public:
+ /** Create the Stoppable. */
+ Stoppable (char const* name, Stoppable& parent);
+
+ /** Destroy the Stoppable. */
virtual ~Stoppable ();
- /** Notify a root stoppable and children to stop, and block until stopped.
- Has no effect if the stoppable was already notified.
- This blocks until the stoppable and all of its children have stopped.
- @param stream An optional Journal::Stream on which to log progress.
+ /** Returns `true` if the stoppable should stop. */
+ bool isStopping () const;
- Thread safety:
- Safe to call from any thread not associated with a Stoppable.
- */
- void stop (Journal::Stream stream = Journal::Stream());
+ /** Returns `true` if the requested stop has completed. */
+ bool isStopped () const;
- /** Notify a root stoppable and children to stop, without waiting.
- Has no effect if the stoppable was already notified.
+ /** Returns `true` if all children have stopped. */
+ bool areChildrenStopped () const;
- Thread safety:
- Safe to call from any thread at any time.
- */
- void stopAsync ();
-
- /** Returns `true` if the stoppable should stop.
- Call from the derived class to determine if a long-running operation
- should be canceled. This is not appropriate for either threads, or
- asynchronous I/O. For threads, use the thread-specific facilities
- available to inform the thread that it should exit. For asynchronous
- I/O, cancel all pending operations inside the onStop override.
- @see onStop
-
- Thread safety:
- Safe to call from any thread at any time.
- */
- bool isStopping ();
-
- /** Returns `true` if the stoppable has completed its stop.
- Thread safety:
- Safe to call from any thread at any time.
- */
- bool isStopped ();
-
- /** Returns `true` if all children have stopped.
- For stoppables without children, this returns `true` immediately
- after a stop notification is received.
-
- Thread safety:
- Safe to call from any thread at any time.
- */
- bool areChildrenStopped ();
-
- /** Called by derived classes to indicate that the stoppable has stopped.
- The derived class must call this either after isStopping returns `true`,
- or when onStop is called, or else the call to stop will never unblock.
-
- Thread safety:
- Safe to call from any thread at any time.
- */
+ /** Called by derived classes to indicate that the stoppable has stopped. */
void stopped ();
+ /** Override called during preparation.
+ Since all other Stoppable objects in the tree have already been
+ constructed, this provides an opportunity to perform initialization which
+ depends on calling into other Stoppable objects.
+ This call is made on the same thread that called prepare().
+ The default implementation does nothing.
+ Guaranteed to only be called once.
+ */
+ virtual void onPrepare (Journal journal);
+
+ /** Override called during start. */
+ virtual void onStart (Journal journal);
+
/** Override called when the stop notification is issued.
The call is made on an unspecified, implementation-specific thread.
@@ -202,7 +211,7 @@ public:
Guaranteed only to be called once.
Must be safe to call from any thread at any time.
*/
- virtual void onStop ();
+ virtual void onStop (Journal journal);
/** Override called when all children have stopped.
@@ -222,9 +231,11 @@ public:
Guaranteed only to be called once.
Must be safe to call from any thread at any time.
*/
- virtual void onChildrenStopped ();
+ virtual void onChildrenStopped (Journal journal);
private:
+ friend class RootStoppable;
+
struct Child;
typedef LockFreeStack Children;
@@ -237,28 +248,70 @@ private:
Stoppable* stoppable;
};
- void stopAsyncRecursive ();
- void stopRecursive (Journal::Stream stream);
+ void prepareRecursive (Journal journal);
+ void startRecursive (Journal journal);
+ void stopAsyncRecursive (Journal journal);
+ void stopRecursive (Journal journal);
+protected:
char const* m_name;
- bool m_root;
+ RootStoppable& m_root;
Child m_child;
- Children m_children;
-
- // Flag that we called stop. This is for diagnostics.
- bool m_calledStop;
-
- // Atomic flag to make sure we only call stopAsync once.
- Atomic m_calledStopAsync;
-
- // Flag that this service stopped. Never goes back to false.
bool volatile m_stopped;
-
- // Flag that all children have stopped (recursive). Never goes back to false.
bool volatile m_childrenStopped;
-
- // stop() blocks on this event until stopped() is called.
+ Children m_children;
WaitableEvent m_stoppedEvent;
};
+//------------------------------------------------------------------------------
+
+class RootStoppable : public Stoppable
+{
+public:
+ explicit RootStoppable (char const* name);
+
+ ~RootStoppable ();
+
+ bool isStopping() const;
+
+ /** Prepare all contained Stoppable objects.
+ This calls onPrepare for all Stoppable objects in the tree.
+ Calls made after the first have no effect.
+ Thread safety:
+ May be called from any thread.
+ */
+ void prepare (Journal journal = Journal());
+
+ /** Start all contained Stoppable objects.
+ The default implementation does nothing.
+ Calls made after the first have no effect.
+ Thread safety:
+ May be called from any thread.
+ */
+ void start (Journal journal = Journal());
+
+ /** Notify a root stoppable and children to stop, and block until stopped.
+ Has no effect if the stoppable was already notified.
+ This blocks until the stoppable and all of its children have stopped.
+ Thread safety:
+ Safe to call from any thread not associated with a Stoppable.
+ */
+ void stop (Journal journal = Journal());
+
+ /** Notify a root stoppable and children to stop, without waiting.
+ Has no effect if the stoppable was already notified.
+
+ Thread safety:
+ Safe to call from any thread at any time.
+ */
+ void stopAsync (Journal journal = Journal());
+
+private:
+ Atomic m_prepared;
+ Atomic m_started;
+ Atomic m_calledStop;
+ Atomic m_calledStopAsync;
+};
+/** @} */
+
#endif
diff --git a/src/beast/scripts/compile.sh b/src/beast/scripts/compile.sh
index 7b4eb18a2..bb1f618d3 100755
--- a/src/beast/scripts/compile.sh
+++ b/src/beast/scripts/compile.sh
@@ -23,7 +23,7 @@ for f in $1/*/*.cpp
do
{
echo "Compilng '$f'"
- g++ -xc++ -I$1/../scripts/ "$f" -c -o /dev/null
- g++ -xc++ -std=c++11 -I$1/../scripts/ "$f" -c -o /dev/null
+ g++ -xc++ -I$1/../config/ "$f" -c -o /dev/null
+ g++ -xc++ -std=c++11 -I$1/../config/ "$f" -c -o /dev/null
}
done
diff --git a/src/ripple/validators/impl/Manager.cpp b/src/ripple/validators/impl/Manager.cpp
index 30996eea3..5b9a4e01a 100644
--- a/src/ripple/validators/impl/Manager.cpp
+++ b/src/ripple/validators/impl/Manager.cpp
@@ -145,7 +145,7 @@ public:
// Stoppable
//
- void onStop ()
+ void onStop (Journal)
{
m_queue.dispatch (bind (&Thread::signalThreadShouldExit, this));
}
diff --git a/src/ripple_app/ledger/InboundLedgers.cpp b/src/ripple_app/ledger/InboundLedgers.cpp
index 9aeb7dd61..c202f4171 100644
--- a/src/ripple_app/ledger/InboundLedgers.cpp
+++ b/src/ripple_app/ledger/InboundLedgers.cpp
@@ -366,7 +366,7 @@ Json::Value InboundLedgers::getInfo()
return ret;
}
-void InboundLedgers::onStop ()
+void InboundLedgers::onStop (Journal)
{
ScopedLockType lock (mLock, __FILE__, __LINE__);
diff --git a/src/ripple_app/ledger/InboundLedgers.h b/src/ripple_app/ledger/InboundLedgers.h
index b7388406a..f555d2a50 100644
--- a/src/ripple_app/ledger/InboundLedgers.h
+++ b/src/ripple_app/ledger/InboundLedgers.h
@@ -76,7 +76,7 @@ public:
void gotFetchPack (Job&);
void sweep ();
- void onStop ();
+ void onStop (Journal);
private:
typedef boost::unordered_map MapType;
diff --git a/src/ripple_app/main/Application.cpp b/src/ripple_app/main/Application.cpp
index c93d88404..6bb55d585 100644
--- a/src/ripple_app/main/Application.cpp
+++ b/src/ripple_app/main/Application.cpp
@@ -47,7 +47,7 @@ template <> char const* LogPartition::getPartitionName () { retu
// VFALCO TODO Move the function definitions into the class declaration
class ApplicationImp
: public Application
- , public Stoppable
+ , public RootStoppable
, public DeadlineTimer::Listener
, LeakChecked
, PeerFinder::Callback
@@ -65,7 +65,7 @@ public:
//--------------------------------------------------------------------------
ApplicationImp ()
- : Stoppable ("Application")
+ : RootStoppable ("Application")
, m_journal (LogJournal::get ())
, m_tempNodeCache ("NodeCache", 16384, 90)
, m_sleCache ("LedgerEntryCache", 4096, 120)
@@ -648,7 +648,7 @@ public:
// Stoppable
// Called to indicate shutdown.
- void onStop ()
+ void onStop (Journal)
{
m_sweepTimer.cancel();
@@ -665,6 +665,15 @@ public:
void run ()
{
+ // VFALCO NOTE I put this here in the hopes that when unit tests run (which
+ // tragically require an Application object to exist or else they
+ // crash), the run() function will not get called and we will
+ // avoid doing silly things like contacting the SNTP server, or
+ // running the various logic threads like Validators, PeerFinder, etc.
+ prepare (m_journal);
+ start (m_journal);
+
+
{
if (!getConfig ().RUN_STANDALONE)
{
@@ -724,7 +733,7 @@ public:
m_journal.info << "Received shutdown request";
StopSustain ();
- stop (m_journal.warning);
+ stop (m_journal);
}
void signalStop ()
@@ -1185,8 +1194,7 @@ ApplicationImp* ApplicationImp::s_instance;
Application* Application::New ()
{
- ScopedPointer object (new ApplicationImp);
- return object.release();
+ return new ApplicationImp;
}
Application& getApp ()
diff --git a/src/ripple_app/main/IoServicePool.cpp b/src/ripple_app/main/IoServicePool.cpp
index 6f04e7f63..410886aa2 100644
--- a/src/ripple_app/main/IoServicePool.cpp
+++ b/src/ripple_app/main/IoServicePool.cpp
@@ -90,7 +90,7 @@ IoServicePool::operator boost::asio::io_service& ()
return m_service;
}
-void IoServicePool::onStop ()
+void IoServicePool::onStop (Journal)
{
// VFALCO NOTE This is a hack! We should gracefully
// cancel all pending I/O, and delete the work
@@ -100,7 +100,7 @@ void IoServicePool::onStop ()
m_service.stop ();
}
-void IoServicePool::onChildrenStopped ()
+void IoServicePool::onChildrenStopped (Journal)
{
}
diff --git a/src/ripple_app/main/IoServicePool.h b/src/ripple_app/main/IoServicePool.h
index ad2cdc7f9..7621e4f22 100644
--- a/src/ripple_app/main/IoServicePool.h
+++ b/src/ripple_app/main/IoServicePool.h
@@ -31,8 +31,8 @@ public:
boost::asio::io_service& getService ();
operator boost::asio::io_service& ();
- void onStop ();
- void onChildrenStopped ();
+ void onStop (Journal);
+ void onChildrenStopped (Journal);
private:
class ServiceThread;
diff --git a/src/ripple_app/main/NodeStoreScheduler.cpp b/src/ripple_app/main/NodeStoreScheduler.cpp
index b71882304..4c4709294 100644
--- a/src/ripple_app/main/NodeStoreScheduler.cpp
+++ b/src/ripple_app/main/NodeStoreScheduler.cpp
@@ -25,13 +25,13 @@ NodeStoreScheduler::NodeStoreScheduler (Stoppable& parent, JobQueue& jobQueue)
{
}
-void NodeStoreScheduler::onStop ()
+void NodeStoreScheduler::onStop (Journal)
{
if (--m_taskCount == 0)
stopped();
}
-void NodeStoreScheduler::onChildrenStopped ()
+void NodeStoreScheduler::onChildrenStopped (Journal)
{
}
diff --git a/src/ripple_app/main/NodeStoreScheduler.h b/src/ripple_app/main/NodeStoreScheduler.h
index fe44c410b..1f888438a 100644
--- a/src/ripple_app/main/NodeStoreScheduler.h
+++ b/src/ripple_app/main/NodeStoreScheduler.h
@@ -29,8 +29,8 @@ class NodeStoreScheduler
public:
NodeStoreScheduler (Stoppable& parent, JobQueue& jobQueue);
- void onStop ();
- void onChildrenStopped ();
+ void onStop (Journal);
+ void onChildrenStopped (Journal);
void scheduleTask (NodeStore::Task& task);
private:
diff --git a/src/ripple_app/main/RPCHTTPServer.cpp b/src/ripple_app/main/RPCHTTPServer.cpp
index 57e3718a3..55049add1 100644
--- a/src/ripple_app/main/RPCHTTPServer.cpp
+++ b/src/ripple_app/main/RPCHTTPServer.cpp
@@ -92,12 +92,12 @@ public:
// Stoppable
//
- void onStop()
+ void onStop (Journal)
{
m_server.stopAsync();
}
- void onChildrenStopped()
+ void onChildrenStopped (Journal)
{
}
diff --git a/src/ripple_app/main/RippleMain.cpp b/src/ripple_app/main/RippleMain.cpp
index d56c43a41..337bf0e1f 100644
--- a/src/ripple_app/main/RippleMain.cpp
+++ b/src/ripple_app/main/RippleMain.cpp
@@ -459,7 +459,7 @@ int RippleMain::run (int argc, char const* const* argv)
{
// No arguments. Run server.
ScopedPointer app (Application::New ());
- setupServer ();
+ setupServer ();
startServer ();
}
else
diff --git a/src/ripple_app/misc/NetworkOPs.cpp b/src/ripple_app/misc/NetworkOPs.cpp
index d7fb0bc19..5584a3287 100644
--- a/src/ripple_app/misc/NetworkOPs.cpp
+++ b/src/ripple_app/misc/NetworkOPs.cpp
@@ -376,7 +376,7 @@ public:
//
// Stoppable
- void onStop ()
+ void onStop (Journal)
{
m_heartbeatTimer.cancel();
m_clusterTimer.cancel();
diff --git a/src/ripple_app/peers/PeerDoor.cpp b/src/ripple_app/peers/PeerDoor.cpp
index 85502ae8d..aa9b06ced 100644
--- a/src/ripple_app/peers/PeerDoor.cpp
+++ b/src/ripple_app/peers/PeerDoor.cpp
@@ -107,7 +107,7 @@ public:
//--------------------------------------------------------------------------
- void onStop ()
+ void onStop (Journal)
{
{
boost::system::error_code ec;
diff --git a/src/ripple_app/peers/UniqueNodeList.cpp b/src/ripple_app/peers/UniqueNodeList.cpp
index 1516f17fc..059797643 100644
--- a/src/ripple_app/peers/UniqueNodeList.cpp
+++ b/src/ripple_app/peers/UniqueNodeList.cpp
@@ -115,7 +115,7 @@ public:
//--------------------------------------------------------------------------
- void onStop ()
+ void onStop (Journal)
{
m_fetchTimer.cancel ();
m_scoreTimer.cancel ();
diff --git a/src/ripple_app/websocket/WSDoor.cpp b/src/ripple_app/websocket/WSDoor.cpp
index 6f355f645..69ef88cc2 100644
--- a/src/ripple_app/websocket/WSDoor.cpp
+++ b/src/ripple_app/websocket/WSDoor.cpp
@@ -112,7 +112,7 @@ private:
stopped ();
}
- void onStop ()
+ void onStop (Journal)
{
{
ScopedLockType lock (m_endpointLock, __FILE__, __LINE__);
diff --git a/src/ripple_core/functional/JobQueue.cpp b/src/ripple_core/functional/JobQueue.cpp
index 97083385a..60b9296d4 100644
--- a/src/ripple_core/functional/JobQueue.cpp
+++ b/src/ripple_core/functional/JobQueue.cpp
@@ -648,7 +648,7 @@ private:
//--------------------------------------------------------------------------
- void onStop ()
+ void onStop (Journal)
{
// VFALCO NOTE I wanted to remove all the jobs that are skippable
// but then the Workers count of tasks to process
@@ -700,7 +700,7 @@ private:
*/
}
- void onChildrenStopped ()
+ void onChildrenStopped (Journal)
{
ScopedLock lock (m_mutex);
diff --git a/src/ripple_net/basics/SNTPClient.cpp b/src/ripple_net/basics/SNTPClient.cpp
index 07c81d993..46f1c253c 100644
--- a/src/ripple_net/basics/SNTPClient.cpp
+++ b/src/ripple_net/basics/SNTPClient.cpp
@@ -114,7 +114,7 @@ public:
stopped ();
}
- void onStop ()
+ void onStop (Journal)
{
// HACK!
m_io_service.stop ();