From 02acf7d6d03d6550bd02ae70ddaaa6dfee5dc90e Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Thu, 12 Sep 2013 08:26:25 -0700 Subject: [PATCH] General refactoring of beast framework classes --- Builds/VisualStudio2012/beast.vcxproj | 30 ++-- Builds/VisualStudio2012/beast.vcxproj.filters | 60 ++++---- modules/beast_core/beast_core.cpp | 9 +- modules/beast_core/beast_core.h | 18 +-- .../{beast_FatalError.cpp => FatalError.cpp} | 15 +- .../{beast_FatalError.h => FatalError.h} | 20 ++- ...st_ProtectedCall.cpp => ProtectedCall.cpp} | 7 +- ...{beast_ProtectedCall.h => ProtectedCall.h} | 6 +- modules/beast_core/diagnostic/beast_Debug.cpp | 50 ++++++- .../diagnostic/beast_LeakChecked.cpp | 2 +- .../beast_core/diagnostic/beast_LeakChecked.h | 62 ++++---- modules/beast_core/memory/SharedSingleton.h | 28 ++-- .../StaticObject.cpp} | 42 ++---- .../{beast_StaticObject.h => StaticObject.h} | 89 +++++++----- .../misc/{beast_Main.cpp => Main.cpp} | 33 +++-- .../beast_core/misc/{beast_Main.h => Main.h} | 13 +- modules/beast_core/system/BeastConfigCheck.h | 4 +- modules/beast_core/system/BeforeBoost.h | 8 +- modules/beast_core/system/BoostIncludes.h | 4 +- modules/beast_core/system/PlatformDefs.h | 10 +- modules/beast_core/system/StandardHeader.h | 4 +- modules/beast_core/system/TargetPlatform.h | 7 +- .../thread/beast_ConcurrentObject.cpp | 2 +- modules/beast_core/time/AtExitHook.cpp | 135 ++++++++++++++++++ modules/beast_core/time/AtExitHook.h | 88 ++++++++++++ .../beast_core/time/beast_PerformedAtExit.cpp | 74 ---------- 26 files changed, 514 insertions(+), 306 deletions(-) rename modules/beast_core/diagnostic/{beast_FatalError.cpp => FatalError.cpp} (91%) rename modules/beast_core/diagnostic/{beast_FatalError.h => FatalError.h} (93%) rename modules/beast_core/diagnostic/{beast_ProtectedCall.cpp => ProtectedCall.cpp} (98%) rename modules/beast_core/diagnostic/{beast_ProtectedCall.h => ProtectedCall.h} (96%) rename modules/beast_core/{time/beast_PerformedAtExit.h => memory/StaticObject.cpp} (53%) rename modules/beast_core/memory/{beast_StaticObject.h => StaticObject.h} (68%) rename modules/beast_core/misc/{beast_Main.cpp => Main.cpp} (85%) rename modules/beast_core/misc/{beast_Main.h => Main.h} (89%) create mode 100644 modules/beast_core/time/AtExitHook.cpp create mode 100644 modules/beast_core/time/AtExitHook.h delete mode 100644 modules/beast_core/time/beast_PerformedAtExit.cpp diff --git a/Builds/VisualStudio2012/beast.vcxproj b/Builds/VisualStudio2012/beast.vcxproj index 1fbc577a85..a7ef873432 100644 --- a/Builds/VisualStudio2012/beast.vcxproj +++ b/Builds/VisualStudio2012/beast.vcxproj @@ -153,8 +153,8 @@ - - + + @@ -211,11 +211,11 @@ - - + + @@ -302,7 +302,7 @@ - + @@ -557,6 +557,12 @@ true true + + true + true + true + true + true true @@ -569,11 +575,11 @@ true true - + true true - + true true true @@ -723,7 +729,13 @@ true true - + + true + true + true + true + + true true true @@ -1131,7 +1143,7 @@ true true - + true true true diff --git a/Builds/VisualStudio2012/beast.vcxproj.filters b/Builds/VisualStudio2012/beast.vcxproj.filters index 7e8967d03e..3a99643827 100644 --- a/Builds/VisualStudio2012/beast.vcxproj.filters +++ b/Builds/VisualStudio2012/beast.vcxproj.filters @@ -527,9 +527,6 @@ beast_core\threads - - beast_core\memory - beast_core\containers @@ -560,9 +557,6 @@ beast_core\maths - - beast_core\time - beast_core\diagnostic @@ -662,18 +656,9 @@ beast_core\maths - - beast_core\diagnostic - - - beast_core\misc - beast_core\text - - beast_core\diagnostic - beast_core\diagnostic @@ -1025,6 +1010,21 @@ beast_core\memory + + beast_core\time + + + beast_core\misc + + + beast_core\diagnostic + + + beast_core\diagnostic + + + beast_core\memory + @@ -1300,9 +1300,6 @@ beast_core\native - - beast_core\time - beast_core\diagnostic @@ -1369,18 +1366,9 @@ beast_core\maths - - beast_core\diagnostic - - - beast_core\misc - beast_core\text - - beast_core\diagnostic - beast_core\diagnostic @@ -1540,6 +1528,24 @@ beast_asio + + beast_core\time + + + beast_core\misc + + + beast_core\diagnostic + + + beast_core\diagnostic + + + beast_core\memory + + + beast_core\diagnostic + diff --git a/modules/beast_core/beast_core.cpp b/modules/beast_core/beast_core.cpp index e837f976d7..b238839f30 100644 --- a/modules/beast_core/beast_core.cpp +++ b/modules/beast_core/beast_core.cpp @@ -149,10 +149,10 @@ namespace beast #include "diagnostic/beast_Debug.cpp" #include "diagnostic/beast_Error.cpp" -#include "diagnostic/beast_FatalError.cpp" +#include "diagnostic/FatalError.cpp" #include "diagnostic/beast_FPUFlags.cpp" #include "diagnostic/beast_LeakChecked.cpp" -#include "diagnostic/beast_ProtectedCall.cpp" +#include "diagnostic/ProtectedCall.cpp" #include "diagnostic/beast_SemanticVersion.cpp" #include "diagnostic/beast_UnitTest.cpp" #include "diagnostic/beast_UnitTestUtilities.cpp" @@ -180,8 +180,9 @@ namespace beast #include "memory/beast_FifoFreeStoreWithoutTLS.cpp" #include "memory/beast_GlobalPagedFreeStore.cpp" #include "memory/beast_PagedFreeStore.cpp" +#include "memory/StaticObject.cpp" -#include "misc/beast_Main.cpp" +#include "misc/Main.cpp" #include "misc/beast_Result.cpp" #include "misc/beast_Uuid.cpp" @@ -232,7 +233,7 @@ namespace beast #include "threads/beast_TimeSliceThread.cpp" #include "time/beast_PerformanceCounter.cpp" -#include "time/beast_PerformedAtExit.cpp" +#include "time/AtExitHook.cpp" #include "time/beast_RelativeTime.cpp" #include "time/beast_Time.cpp" diff --git a/modules/beast_core/beast_core.h b/modules/beast_core/beast_core.h index cb65de75c4..2b19116d64 100644 --- a/modules/beast_core/beast_core.h +++ b/modules/beast_core/beast_core.h @@ -172,10 +172,14 @@ Some files contain portions of these external projects, licensed separately: @copyright Provided under the [ISC LIcense][11] */ +// TargetPlatform.h should not use anything from BeastConfig.h +#include "system/TargetPlatform.h" +#include "system/BeastConfigCheck.h" + # include "system/BeforeBoost.h" # include "system/BoostIncludes.h" #include "system/FunctionalIncludes.h" - +#include "system/PlatformDefs.h" #include "system/StandardHeader.h" #if BEAST_MSVC @@ -261,8 +265,6 @@ extern BEAST_API void BEAST_CALLTYPE logAssertion (char const* file, int line) n # include "containers/detail/removecv.h" #include "containers/detail/copyconst.h" -#include "system/PlatformDefs.h" -#include "system/TargetPlatform.h" #include "diagnostic/beast_Throw.h" #include "system/Functional.h" #include "memory/beast_AtomicCounter.h" @@ -272,12 +274,12 @@ extern BEAST_API void BEAST_CALLTYPE logAssertion (char const* file, int line) n #include "containers/List.h" #include "containers/beast_LockFreeStack.h" #include "threads/beast_SpinDelay.h" -#include "memory/beast_StaticObject.h" +#include "memory/StaticObject.h" #include "text/StringCharPointerType.h" #include "text/StringFromNumber.h" #include "text/beast_String.h" -#include "time/beast_PerformedAtExit.h" +#include "time/AtExitHook.h" #include "diagnostic/beast_LeakChecked.h" #include "time/beast_RelativeTime.h" #include "time/beast_Time.h" @@ -304,7 +306,7 @@ extern BEAST_API void BEAST_CALLTYPE logAssertion (char const* file, int line) n #include "threads/beast_ThreadLocalValue.h" #include "thread/MutexTraits.h" #include "thread/TrackedMutex.h" -#include "diagnostic/beast_FatalError.h" +#include "diagnostic/FatalError.h" #include "diagnostic/beast_Error.h" #include "diagnostic/beast_Debug.h" #include "text/beast_LexicalCast.h" @@ -317,7 +319,7 @@ extern BEAST_API void BEAST_CALLTYPE logAssertion (char const* file, int line) n #include "memory/SharedObject.h" #include "memory/SharedPtr.h" #include "functional/SharedFunction.h" -#include "diagnostic/beast_ProtectedCall.h" +#include "diagnostic/ProtectedCall.h" #include "containers/beast_AbstractFifo.h" #include "text/beast_Identifier.h" #include "containers/beast_Variant.h" @@ -366,7 +368,7 @@ extern BEAST_API void BEAST_CALLTYPE logAssertion (char const* file, int line) n #include "memory/SharedSingleton.h" #include "memory/beast_WeakReference.h" #include "memory/beast_RecycledObjectPool.h" -#include "misc/beast_Main.h" +#include "misc/Main.h" #include "misc/beast_Uuid.h" #include "misc/beast_WindowsRegistry.h" #include "network/beast_IPAddress.h" diff --git a/modules/beast_core/diagnostic/beast_FatalError.cpp b/modules/beast_core/diagnostic/FatalError.cpp similarity index 91% rename from modules/beast_core/diagnostic/beast_FatalError.cpp rename to modules/beast_core/diagnostic/FatalError.cpp index 393e744327..4ad792b9ee 100644 --- a/modules/beast_core/diagnostic/beast_FatalError.cpp +++ b/modules/beast_core/diagnostic/FatalError.cpp @@ -66,16 +66,19 @@ String FatalError::Reporter::formatFilePath (char const* filePath) //------------------------------------------------------------------------------ -Static::Storage , FatalError> FatalError::s_reporter; +FatalError::Reporter *FatalError::s_reporter; -void FatalError::setReporter (Reporter& reporter) +/** Returns the current fatal error reporter. */ +FatalError::Reporter* FatalError::getReporter () { - s_reporter->compareAndSetBool (&reporter, nullptr); + return s_reporter; } -void FatalError::resetReporter (Reporter& reporter) +FatalError::Reporter* FatalError::setReporter (Reporter* reporter) { - s_reporter->compareAndSetBool (nullptr, &reporter); + Reporter* const previous (s_reporter); + s_reporter = reporter; + return previous; } FatalError::FatalError (char const* message, char const* fileName, int lineNumber) @@ -94,7 +97,7 @@ FatalError::FatalError (char const* message, char const* fileName, int lineNumbe char const* const szFileName = fileNameString.toRawUTF8 (); - Reporter* const reporter = s_reporter->get (); + Reporter* const reporter (s_reporter); if (reporter != nullptr) { diff --git a/modules/beast_core/diagnostic/beast_FatalError.h b/modules/beast_core/diagnostic/FatalError.h similarity index 93% rename from modules/beast_core/diagnostic/beast_FatalError.h rename to modules/beast_core/diagnostic/FatalError.h index 87222d244c..fe25d51a37 100644 --- a/modules/beast_core/diagnostic/beast_FatalError.h +++ b/modules/beast_core/diagnostic/FatalError.h @@ -17,8 +17,8 @@ */ //============================================================================== -#ifndef BEAST_FATALERROR_H_INCLUDED -#define BEAST_FATALERROR_H_INCLUDED +#ifndef BEAST_CORE_FATALERROR_H_INCLUDED +#define BEAST_CORE_FATALERROR_H_INCLUDED /** Signal a fatal error. @@ -109,6 +109,9 @@ public: virtual String formatFilePath (char const* filePath); }; + /** Returns the current fatal error reporter. */ + static Reporter* getReporter (); + /** Set the fatal error reporter. Note that if a fatal error is raised during the construction of @@ -122,16 +125,11 @@ public: If a reporter was previously set, this routine will do nothing. + @return The previous Reporter (Which may be null). + @see SharedSingleton, Reporter */ - static void setReporter (Reporter& reporter); - - /** Clear the fatal error reporter. - - If the current reporter is the same as the one passed in, this - will remove the reporter. - */ - static void resetReporter (Reporter& reporter); + static Reporter* setReporter (Reporter* reporter); /** Raise a fatal error. @@ -145,7 +143,7 @@ public: FatalError (char const* message, char const* filePath, int lineNumber); private: - static Static::Storage , FatalError> s_reporter; + static Reporter* s_reporter; }; //------------------------------------------------------------------------------ diff --git a/modules/beast_core/diagnostic/beast_ProtectedCall.cpp b/modules/beast_core/diagnostic/ProtectedCall.cpp similarity index 98% rename from modules/beast_core/diagnostic/beast_ProtectedCall.cpp rename to modules/beast_core/diagnostic/ProtectedCall.cpp index 6b40d4bbb0..b1aab675e0 100644 --- a/modules/beast_core/diagnostic/beast_ProtectedCall.cpp +++ b/modules/beast_core/diagnostic/ProtectedCall.cpp @@ -297,19 +297,18 @@ ProtectedCall::DefaultHandler::LockType ProtectedCall::DefaultHandler::s_mutex; //------------------------------------------------------------------------------ -Static::Storage , ProtectedCall> - ProtectedCall::s_handler; +ProtectedCall::Handler const* ProtectedCall::s_handler; void ProtectedCall::setHandler (Handler const& handler) { - s_handler->set (&handler); + s_handler = &handler; } void ProtectedCall::call (Call& c) { static DefaultHandler defaultHandler; - Handler const* handler = s_handler->get (); + Handler const* handler = s_handler; if (handler == nullptr) handler = &defaultHandler; diff --git a/modules/beast_core/diagnostic/beast_ProtectedCall.h b/modules/beast_core/diagnostic/ProtectedCall.h similarity index 96% rename from modules/beast_core/diagnostic/beast_ProtectedCall.h rename to modules/beast_core/diagnostic/ProtectedCall.h index 8d5533633d..491da78742 100644 --- a/modules/beast_core/diagnostic/beast_ProtectedCall.h +++ b/modules/beast_core/diagnostic/ProtectedCall.h @@ -17,8 +17,8 @@ */ //============================================================================== -#ifndef BEAST_PROTECTEDCALL_H_INCLUDED -#define BEAST_PROTECTEDCALL_H_INCLUDED +#ifndef BEAST_CORE_PROTECTEDCALL_H_INCLUDED +#define BEAST_CORE_PROTECTEDCALL_H_INCLUDED /** Call a function in a protected exception context. @@ -141,7 +141,7 @@ private: void call (Call& call); private: - static Static::Storage , ProtectedCall> s_handler; + static Handler const* s_handler; }; #endif diff --git a/modules/beast_core/diagnostic/beast_Debug.cpp b/modules/beast_core/diagnostic/beast_Debug.cpp index 3580b04540..e9e6545926 100644 --- a/modules/beast_core/diagnostic/beast_Debug.cpp +++ b/modules/beast_core/diagnostic/beast_Debug.cpp @@ -296,19 +296,65 @@ String commandLineToString (const String& commandLine) //------------------------------------------------------------------------------ +// A simple unit test to determine the diagnostic settings in a build. +// class DebugTests : public UnitTest { public: - DebugTests () : UnitTest ("Debug", "beast", runManual) + static int envDebug () { + #ifdef _DEBUG + return 1; + #else + return 0; + #endif + } + + static int beastDebug () + { + #ifdef BEAST_DEBUG + return BEAST_DEBUG; + #else + return 0; + #endif + } + + static int beastForceDebug () + { + #ifdef BEAST_FORCE_DEBUG + return BEAST_FORCE_DEBUG; + #else + return 0; + #endif + } + + static int beastCatchExceptions () + { + #ifdef BEAST_CATCH_UNHANDLED_EXCEPTIONS + return BEAST_CATCH_UNHANDLED_EXCEPTIONS; + #else + return 0; + #endif } void runTest () { - beginTestCase ("bassert"); + beginTestCase ("diagnostics"); + + logMessage ("operatingSystemName = '" + SystemStats::getOperatingSystemName () + "'"); + logMessage ("_DEBUG = " + String::fromNumber (envDebug ())); + logMessage ("BEAST_DEBUG = " + String::fromNumber (beastDebug ())); + logMessage ("BEAST_FORCE_DEBUG = " + String::fromNumber (beastForceDebug ())); + logMessage ("BEAST_CATCH_UNHANDLED_EXCEPTIONS = " + String::fromNumber (beastCatchExceptions ())); + bassertfalse; + fail (); } + + DebugTests () : UnitTest ("Debug", "beast", runManual) + { + } }; static DebugTests debugTests; diff --git a/modules/beast_core/diagnostic/beast_LeakChecked.cpp b/modules/beast_core/diagnostic/beast_LeakChecked.cpp index b70e41697a..075069e644 100644 --- a/modules/beast_core/diagnostic/beast_LeakChecked.cpp +++ b/modules/beast_core/diagnostic/beast_LeakChecked.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -namespace Implemented +namespace detail { class LeakCheckedBase::CounterBase::Singleton diff --git a/modules/beast_core/diagnostic/beast_LeakChecked.h b/modules/beast_core/diagnostic/beast_LeakChecked.h index 4d84722422..254a7208fe 100644 --- a/modules/beast_core/diagnostic/beast_LeakChecked.h +++ b/modules/beast_core/diagnostic/beast_LeakChecked.h @@ -20,18 +20,23 @@ #ifndef BEAST_LEAKCHECKED_H_INCLUDED #define BEAST_LEAKCHECKED_H_INCLUDED -namespace Implemented +namespace detail { -class BEAST_API LeakCheckedBase +class LeakCheckedBase { +public: + static void checkForLeaks (); + protected: class CounterBase : public LockFreeStack ::Node { public: CounterBase (); - virtual ~CounterBase () { } + virtual ~CounterBase () + { + } inline int increment () { @@ -47,24 +52,15 @@ protected: private: void checkForLeaks (); - virtual void checkPureVirtual () const = 0; - private: - friend class LeakCheckedBase; - class Singleton; + friend class LeakCheckedBase; Atomic m_count; }; -protected: static void reportDanglingPointer (char const* objectName); - -private: - friend class PerformedAtExit::ExitHook; - - static void checkForLeaks (); }; //------------------------------------------------------------------------------ @@ -129,18 +125,7 @@ private: // static Counter& getCounter () noexcept { - static Counter* volatile s_instance; - static Static::Initializer s_initializer; - - if (s_initializer.beginConstruction ()) - { - static char s_storage [sizeof (Counter)]; - s_instance = new (s_storage) Counter; - - s_initializer.endConstruction (); - } - - return *s_instance; + return StaticObject ::get(); } }; @@ -148,35 +133,40 @@ private: //------------------------------------------------------------------------------ -namespace Dummy +namespace detail { -class BEAST_API LeakCheckedBase +namespace disabled { -private: - friend class PerformedAtExit; +class LeakCheckedBase +{ public: - static void checkForLeaks () { } + static void checkForLeaks () + { + } }; template -struct LeakChecked : LeakCheckedBase +class LeakChecked : public LeakCheckedBase { +public: }; } +} + //------------------------------------------------------------------------------ -// Lift the corresponding implementation +// Lift the appropriate implementation into our namespace // #if BEAST_CHECK_MEMORY_LEAKS -using Implemented::LeakChecked; -using Implemented::LeakCheckedBase; +using detail::LeakChecked; +using detail::LeakCheckedBase; #else -using Dummy::LeakChecked; -using Dummy::LeakCheckedBase; +using detail::disabled::LeakChecked; +using detail::disabled::LeakCheckedBase; #endif #endif diff --git a/modules/beast_core/memory/SharedSingleton.h b/modules/beast_core/memory/SharedSingleton.h index b46ad67620..14b2a8dffb 100644 --- a/modules/beast_core/memory/SharedSingleton.h +++ b/modules/beast_core/memory/SharedSingleton.h @@ -86,6 +86,7 @@ public: instance = staticData.instance; if (instance == nullptr) { + bassert (lifetime == SingletonLifetime::createOnDemand || ! staticData.destructorCalled); staticData.instance = &staticData.object; ::new (staticData.instance) SharedSingleton (lifetime); instance = staticData.instance; @@ -107,7 +108,7 @@ private: { } - void performAtExit () + void onExit () { if (m_lifetime == SingletonLifetime::persistAfterCreation) this->decReferenceCount (); @@ -132,6 +133,7 @@ private: { callDestructor = true; staticData.instance = nullptr; + staticData.destructorCalled = true; } } @@ -145,31 +147,16 @@ private: typedef SpinLock LockType; - class ExitHook : public PerformedAtExit - { - public: - explicit ExitHook (SharedSingleton* owner) - : m_owner (owner) - { - } - - void performAtExit () - { - m_owner->performAtExit(); - } - - private: - SharedSingleton* m_owner; - }; - // This structure gets zero-filled at static initialization time. // No constructors are called. // - struct StaticData + class StaticData : public Uncopyable { + public: LockType mutex; SharedSingleton* instance; SharedSingleton object; + bool destructorCalled; private: StaticData(); @@ -183,9 +170,10 @@ private: } friend class SharedPtr ; + friend class AtExitMemberHook ; SingletonLifetime::Lifetime m_lifetime; - ExitHook m_exitHook; + AtExitMemberHook m_exitHook; }; //------------------------------------------------------------------------------ diff --git a/modules/beast_core/time/beast_PerformedAtExit.h b/modules/beast_core/memory/StaticObject.cpp similarity index 53% rename from modules/beast_core/time/beast_PerformedAtExit.h rename to modules/beast_core/memory/StaticObject.cpp index 9cde4ff713..7482b0a172 100644 --- a/modules/beast_core/time/beast_PerformedAtExit.h +++ b/modules/beast_core/memory/StaticObject.cpp @@ -17,36 +17,18 @@ */ //============================================================================== -#ifndef BEAST_PERFORMEDATEXIT_H_INCLUDED -#define BEAST_PERFORMEDATEXIT_H_INCLUDED - -/*============================================================================*/ -/** - Perform an action at program exit - - To use, derive your class from PerformedAtExit, and override `performAtExit()`. - The call will be made during the destruction of objects with static storage - duration, before LeakChecked performs its diagnostics. - - @ingroup beast_core -*/ -// VFALCO TODO Make the linked list element a private type and use composition -// instead of inheritance, so that PerformedAtExit doesn't expose -// lock free stack node interfaces. -// -class BEAST_API PerformedAtExit : public LockFreeStack ::Node +namespace detail { -public: - class ExitHook; -protected: - PerformedAtExit (); - virtual ~PerformedAtExit () { } +// This is here so we don't need the Thread class declaration +void staticObjectWait (std::size_t n) +{ + // Wait for initialization + Thread::yield (); + if (n > 10) + Thread::sleep (1); + else if (n > 100) + Thread::sleep (10); +} -protected: - /** Called at program exit. - */ - virtual void performAtExit () = 0; -}; - -#endif +} diff --git a/modules/beast_core/memory/beast_StaticObject.h b/modules/beast_core/memory/StaticObject.h similarity index 68% rename from modules/beast_core/memory/beast_StaticObject.h rename to modules/beast_core/memory/StaticObject.h index 4019245a9f..c602e57386 100644 --- a/modules/beast_core/memory/beast_StaticObject.h +++ b/modules/beast_core/memory/StaticObject.h @@ -112,61 +112,86 @@ private: template char Storage ::s_storage [sizeof (ObjectType)]; +} + //------------------------------------------------------------------------------ -// Provides a thread safe flag for indicating if and when -// initialization is required for an object with static storage duration. -// -class Initializer +namespace detail +{ + +extern void staticObjectWait (std::size_t n); + +} + +/** Wrapper to produce an object with static storage duration. + + The object is constructed in a thread-safe fashion when the get function + is first called. Note that the destructor for Object is never called. To + invoke the destructor, use the AtExitHook facility (with caution). + + The Tag parameter allows multiple instances of the same Object type, by + using different tags. + + Object must meet these requirements: + DefaultConstructible + + @see AtExitHook +*/ +template +class StaticObject { public: - // If the condition is not initialized, the first caller will - // receive true, while concurrent callers get blocked until - // initialization completes. - // - bool beginConstruction () + static Object& get () { - bool needsInitialization = false; + StaticData& staticData (StaticData::get()); - if (m_state.get () != stateInitialized) + if (staticData.state.get() != initialized) { - if (m_state.compareAndSetBool (stateInitializing, stateUninitialized)) + if (staticData.state.compareAndSetBool (initializing, uninitialized)) { - needsInitialization = true; + // Initialize the object. + ::new (&staticData.object) Object; + staticData.state = initialized; } else { - SpinDelay delay; - - do + for (std::size_t n = 0; staticData.state.get() != initialized; ++n) { - delay.pause (); + detail::staticObjectWait (n); } - while (m_state.get () != stateInitialized); } } - return needsInitialization; - } - - // Called to signal that the initialization is complete - // - void endConstruction () - { - m_state.set (stateInitialized); + return staticData.object; } private: enum { - stateUninitialized = 0, // must be zero - stateInitializing, - stateInitialized + uninitialized = 0, // must be zero to function properly + initializing, + initialized }; - Atomic m_state; + // This structure gets zero-filled at static initialization time. + // No constructors are called. + // + class StaticData : public Uncopyable + { + public: + Atomic state; + Object object; + + static StaticData& get () + { + static uint8 storage [sizeof (StaticData)]; + return *(reinterpret_cast (&storage [0])); + } + + private: + StaticData(); + ~StaticData(); + }; }; -} - #endif diff --git a/modules/beast_core/misc/beast_Main.cpp b/modules/beast_core/misc/Main.cpp similarity index 85% rename from modules/beast_core/misc/beast_Main.cpp rename to modules/beast_core/misc/Main.cpp index 029e480b29..e9ccaf4d8b 100644 --- a/modules/beast_core/misc/beast_Main.cpp +++ b/modules/beast_core/misc/Main.cpp @@ -17,31 +17,33 @@ */ //============================================================================== -Static::Storage , Main> Main::s_instance; +Main* Main::s_instance; Main::Main () { - bool const replaced = s_instance->compareAndSetBool (this, nullptr); - // If this happens it means there are two instances of Main! - if (! replaced) - FatalError ("Multiple instances of Main", __FILE__, __LINE__); + check_precondition (s_instance == nullptr); + + s_instance = this; + } Main::~Main () { - s_instance->set (nullptr); + s_instance = nullptr; } Main& Main::getInstance () { - bassert (s_instance->get () != nullptr); + bassert (s_instance != nullptr); - return *s_instance->get (); + return *s_instance; } -void Main::runStartupUnitTests () +int Main::runStartupUnitTests () { + int exitCode = EXIT_SUCCESS; + struct StartupUnitTests : UnitTests { void logMessage (String const&) @@ -105,15 +107,20 @@ void Main::runStartupUnitTests () { tests.reportResults (); - tests.log ("Terminating due to failed startup tests"); + tests.log ("Terminating with an error due to failed startup tests."); - Process::terminate (); + exitCode = EXIT_FAILURE; } + + return exitCode; } int Main::runFromMain (int argc, char const* const* argv) { - runStartupUnitTests (); + int exitCode (runStartupUnitTests ()); - return run (argc, argv); + if (exitCode == EXIT_SUCCESS) + exitCode = run (argc, argv); + + return exitCode; } diff --git a/modules/beast_core/misc/beast_Main.h b/modules/beast_core/misc/Main.h similarity index 89% rename from modules/beast_core/misc/beast_Main.h rename to modules/beast_core/misc/Main.h index f167116855..0059b9cc92 100644 --- a/modules/beast_core/misc/beast_Main.h +++ b/modules/beast_core/misc/Main.h @@ -17,15 +17,14 @@ */ //============================================================================== -#ifndef BEAST_MAIN_H_INCLUDED -#define BEAST_MAIN_H_INCLUDED - -/** Represents a command line program's entry point. +#ifndef BEAST_CORE_MAIN_H_INCLUDED +#define BEAST_CORE_MAIN_H_INCLUDED +/** Represents a command line program's entry point To use this, derive your class from @ref Main and implement the function run (); */ -class BEAST_API Main : public Uncopyable +class Main : public Uncopyable { public: Main (); @@ -70,10 +69,10 @@ protected: virtual int run (int argc, char const* const* argv) = 0; private: - void runStartupUnitTests (); + int runStartupUnitTests (); private: - static Static::Storage , Main> s_instance; + static Main* s_instance; }; #endif diff --git a/modules/beast_core/system/BeastConfigCheck.h b/modules/beast_core/system/BeastConfigCheck.h index 2ce310578d..172ac0f00e 100644 --- a/modules/beast_core/system/BeastConfigCheck.h +++ b/modules/beast_core/system/BeastConfigCheck.h @@ -17,8 +17,8 @@ */ //============================================================================== -#ifndef BEAST_CORE_SYSTEM_BEASTCONFIGCHECK_H_INCLUDED -#define BEAST_CORE_SYSTEM_BEASTCONFIGCHECK_H_INCLUDED +#ifndef BEAST_CORE_BEASTCONFIGCHECK_H_INCLUDED +#define BEAST_CORE_BEASTCONFIGCHECK_H_INCLUDED // This file makes sure that BeastConfig.h was included. // It also sets defaults for all config options. diff --git a/modules/beast_core/system/BeforeBoost.h b/modules/beast_core/system/BeforeBoost.h index eb26e5f9c3..a314cc6677 100644 --- a/modules/beast_core/system/BeforeBoost.h +++ b/modules/beast_core/system/BeforeBoost.h @@ -20,14 +20,14 @@ #ifndef BEAST_CORE_SYSTEM_BEFOREBOOST_H_INCLUDED #define BEAST_CORE_SYSTEM_BEFOREBOOST_H_INCLUDED +// TargetPlatform.h should not use anything from BeastConfig.h +#include "TargetPlatform.h" +#include "BeastConfigCheck.h" + // This file should be included before including any boost headers. // If you don't include this file, and you include boost headers, // Beast will generate a compile error with an explanation of why. -#include "TargetPlatform.h" - -#include "BeastConfigCheck.h" - #if BEAST_USE_BOOST_FEATURES // Prevent from being included diff --git a/modules/beast_core/system/BoostIncludes.h b/modules/beast_core/system/BoostIncludes.h index 1d4862490a..dc4416feb9 100644 --- a/modules/beast_core/system/BoostIncludes.h +++ b/modules/beast_core/system/BoostIncludes.h @@ -17,8 +17,8 @@ */ //============================================================================== -#ifndef BEAST_CORE_SYSTEM_BOOSTINCLUDES_H_INCLUDED -#define BEAST_CORE_SYSTEM_BOOSTINCLUDES_H_INCLUDED +#ifndef BEAST_CORE_BOOSTINCLUDES_H_INCLUDED +#define BEAST_CORE_BOOSTINCLUDES_H_INCLUDED #if BEAST_USE_BOOST_FEATURES diff --git a/modules/beast_core/system/PlatformDefs.h b/modules/beast_core/system/PlatformDefs.h index f9bd910a1d..63774dce99 100644 --- a/modules/beast_core/system/PlatformDefs.h +++ b/modules/beast_core/system/PlatformDefs.h @@ -21,16 +21,14 @@ */ //============================================================================== -#ifndef BEAST_PLATFORMDEFS_H_INCLUDED -#define BEAST_PLATFORMDEFS_H_INCLUDED +#ifndef BEAST_CORE_PLATFORMDEFS_H_INCLUDED +#define BEAST_CORE_PLATFORMDEFS_H_INCLUDED // This file defines miscellaneous macros for debugging, assertions, etc. -#ifdef BEAST_FORCE_DEBUG +#if BEAST_FORCE_DEBUG # undef BEAST_DEBUG -# if BEAST_FORCE_DEBUG -# define BEAST_DEBUG 1 -# endif +# define BEAST_DEBUG 1 #endif /** This macro defines the C calling convention used as the standard for Beast calls. diff --git a/modules/beast_core/system/StandardHeader.h b/modules/beast_core/system/StandardHeader.h index 43415b9659..4172ed1c2d 100644 --- a/modules/beast_core/system/StandardHeader.h +++ b/modules/beast_core/system/StandardHeader.h @@ -47,7 +47,9 @@ //------------------------------------------------------------------------------ -#include "PlatformDefs.h" +#ifndef BEAST_CORE_PLATFORMDEFS_H_INCLUDED +#error "PlatformDefs.h must be included first" +#endif // Now we'll include some common OS headers.. #if BEAST_MSVC diff --git a/modules/beast_core/system/TargetPlatform.h b/modules/beast_core/system/TargetPlatform.h index 4e60bf1d6d..2cb46c333e 100644 --- a/modules/beast_core/system/TargetPlatform.h +++ b/modules/beast_core/system/TargetPlatform.h @@ -21,8 +21,8 @@ */ //============================================================================== -#ifndef BEAST_TARGETPLATFORM_H_INCLUDED -#define BEAST_TARGETPLATFORM_H_INCLUDED +#ifndef BEAST_CORE_TARGETPLATFORM_H_INCLUDED +#define BEAST_CORE_TARGETPLATFORM_H_INCLUDED //============================================================================== /* This file figures out which platform is being built, and defines some macros @@ -213,4 +213,5 @@ #define BEAST_PP_STR1_(x) BEAST_PP_STR2_(x) #define BEAST_FILEANDLINE_ __FILE__ "(" BEAST_PP_STR1_(__LINE__) "): warning:" -#endif // BEAST_TARGETPLATFORM_H_INCLUDED +#endif + diff --git a/modules/beast_core/thread/beast_ConcurrentObject.cpp b/modules/beast_core/thread/beast_ConcurrentObject.cpp index 91c0c53e30..56ace3e98a 100644 --- a/modules/beast_core/thread/beast_ConcurrentObject.cpp +++ b/modules/beast_core/thread/beast_ConcurrentObject.cpp @@ -30,7 +30,7 @@ private: m_thread.stop (true); } - void performAtExit () + void onExit () { //delete this; } diff --git a/modules/beast_core/time/AtExitHook.cpp b/modules/beast_core/time/AtExitHook.cpp new file mode 100644 index 0000000000..e983b7f28d --- /dev/null +++ b/modules/beast_core/time/AtExitHook.cpp @@ -0,0 +1,135 @@ +//------------------------------------------------------------------------------ +/* + 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. +*/ +//============================================================================== + +// Manages the list of hooks, and calls +// whoever is in the list at exit time. +// +class AtExitHook::Manager +{ +public: + Manager () + : m_didStaticDestruction (false) + { + } + + static inline Manager& get () + { + return StaticObject ::get(); + } + + void insert (Item& item) + { + ScopedLockType lock (m_mutex); + + // Adding a new AtExitHook during or after the destruction + // of objects with static storage duration has taken place? + // Surely something has gone wrong. + // + bassert (! m_didStaticDestruction); + m_list.push_front (item); + } + + void erase (Item& item) + { + ScopedLockType lock (m_mutex); + + m_list.erase (m_list.iterator_to (item)); + } + +private: + // Called at program exit when destructors for objects + // with static storage duration are invoked. + // + void doStaticDetruction () + { + // In theory this shouldn't be needed (?) + ScopedLockType lock (m_mutex); + + bassert (! m_didStaticDestruction); + + for (List ::iterator iter (m_list.begin()); iter != m_list.end();) + { + Item& item (*iter++); + AtExitHook* const hook (item.hook ()); + hook->onExit (); + } + + // Now do the leak checking + // + LeakCheckedBase::checkForLeaks (); + } + + struct StaticDestructor + { + ~StaticDestructor () + { + Manager::get().doStaticDetruction(); + } + }; + + typedef CriticalSection MutexType; + typedef MutexType::ScopedLockType ScopedLockType; + + static StaticDestructor s_staticDestructor; + + MutexType m_mutex; + List m_list; + bool m_didStaticDestruction; +}; + +// This is an object with static storage duration. +// When it gets destroyed, we will call into the Manager to +// call all of the AtExitHook items in the list. +// +AtExitHook::Manager::StaticDestructor AtExitHook::Manager::s_staticDestructor; + +//------------------------------------------------------------------------------ + +AtExitHook::Item::Item (AtExitHook* hook) + : m_hook (hook) +{ +} + +AtExitHook* AtExitHook::Item::hook () +{ + return m_hook; +} + +//------------------------------------------------------------------------------ + +AtExitHook::AtExitHook () + : m_item (this) +{ +#if BEAST_IOS + // Patrick Dehne: + // AtExitHook::Manager::insert crashes on iOS + // if the storage is not accessed before it is used. + // + // VFALCO TODO Figure out why and fix it cleanly if needed. + // + char* hack = AtExitHook::Manager::s_list.s_storage; +#endif + + Manager::get().insert (m_item); +} + +AtExitHook::~AtExitHook () +{ + Manager::get().erase (m_item); +} diff --git a/modules/beast_core/time/AtExitHook.h b/modules/beast_core/time/AtExitHook.h new file mode 100644 index 0000000000..26801d23d9 --- /dev/null +++ b/modules/beast_core/time/AtExitHook.h @@ -0,0 +1,88 @@ +//------------------------------------------------------------------------------ +/* + 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_CORE_ATEXITHOOK_H_INCLUDED +#define BEAST_CORE_ATEXITHOOK_H_INCLUDED + +/** Hook for performing activity on program exit. + + These hooks execute when objects with static storage duration are + destroyed. The hooks are called in the reverse order that they were + created. + + To use, derive your class from AtExitHook and implement onExit. + Alternatively, add AtExitMemberHook as a data member of your class and + then provide your own onExit function with this signature: + + @code + + void onExit () + + @endcode + + @see AtExitMemberHook +*/ +/** @{ */ +class AtExitHook +{ +protected: + AtExitHook (); + virtual ~AtExitHook (); + +protected: + /** Called at program exit. */ + virtual void onExit () = 0; + +private: + class Manager; + + class Item : public List ::Node + { + public: + explicit Item (AtExitHook* hook); + AtExitHook* hook (); + + private: + AtExitHook* m_hook; + }; + + Item m_item; +}; + +/** Helper for utilizing the AtExitHook as a data member. +*/ +template +class AtExitMemberHook : public AtExitHook +{ +public: + explicit AtExitMemberHook (Object* owner) : m_owner (owner) + { + } + +private: + void onExit () + { + m_owner->onExit (); + } + + Object* m_owner; +}; +/** @} */ + +#endif diff --git a/modules/beast_core/time/beast_PerformedAtExit.cpp b/modules/beast_core/time/beast_PerformedAtExit.cpp deleted file mode 100644 index 7babb0d2dd..0000000000 --- a/modules/beast_core/time/beast_PerformedAtExit.cpp +++ /dev/null @@ -1,74 +0,0 @@ -//------------------------------------------------------------------------------ -/* - 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. -*/ -//============================================================================== - -class PerformedAtExit::ExitHook -{ -public: - typedef Static::Storage , PerformedAtExit> StackType; - -private: - ~ExitHook () - { - // Call all PerformedAtExit objects - // - PerformedAtExit* object = s_list->pop_front (); - - while (object != nullptr) - { - object->performAtExit (); - - object = s_list->pop_front (); - } - - // Now do the leak checking - // - LeakCheckedBase::checkForLeaks (); - } - -public: - static void push_front (PerformedAtExit* object) - { - s_list->push_front (object); - } - -private: - friend class PerformedAtExit; - - static StackType s_list; - - static ExitHook s_performer; -}; - -PerformedAtExit::ExitHook PerformedAtExit::ExitHook::s_performer; -PerformedAtExit::ExitHook::StackType PerformedAtExit::ExitHook::s_list; - -PerformedAtExit::PerformedAtExit () -{ -#if BEAST_IOS - // Patrick Dehne: - // PerformedAtExit::ExitHook::push_front crashes on iOS - // if s_storage is not accessed before used - // - // VFALCO TODO Figure out why and fix it cleanly if needed. - // - char* hack = PerformedAtExit::ExitHook::s_list.s_storage; -#endif - - ExitHook::push_front (this); -}