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