diff --git a/Builds/QtCreator/rippled.pro b/Builds/QtCreator/rippled.pro index 957370a493..d90b383b5c 100644 --- a/Builds/QtCreator/rippled.pro +++ b/Builds/QtCreator/rippled.pro @@ -61,6 +61,7 @@ UI_HEADERS_DIR += ../../modules/ripple_basics SOURCES += \ ../../Subtrees/beast/modules/beast_asio/beast_asio.cpp \ ../../Subtrees/beast/modules/beast_basics/beast_basics.cpp \ + ../../Subtrees/beast/modules/beast_boost/beast_boost.cpp \ ../../Subtrees/beast/modules/beast_core/beast_core.cpp \ ../../Subtrees/beast/modules/beast_crypto/beast_crypto.cpp \ ../../Subtrees/beast/modules/beast_db/beast_db.cpp \ diff --git a/Builds/VisualStudio2012/RippleD.vcxproj b/Builds/VisualStudio2012/RippleD.vcxproj index 9a79dacd89..203b29f495 100644 --- a/Builds/VisualStudio2012/RippleD.vcxproj +++ b/Builds/VisualStudio2012/RippleD.vcxproj @@ -1021,6 +1021,7 @@ + diff --git a/Builds/VisualStudio2012/RippleD.vcxproj.filters b/Builds/VisualStudio2012/RippleD.vcxproj.filters index cbc15ab178..470020139f 100644 --- a/Builds/VisualStudio2012/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2012/RippleD.vcxproj.filters @@ -891,6 +891,9 @@ [1] Ripple\ripple_app\boost + + [0] Subtrees\beast + diff --git a/SConstruct b/SConstruct index 443fb52733..37cd9e0fd9 100644 --- a/SConstruct +++ b/SConstruct @@ -133,7 +133,7 @@ else: COMPILED_FILES.extend([ 'Subtrees/beast/modules/beast_asio/beast_asio.cpp', 'Subtrees/beast/modules/beast_basics/beast_basics.cpp', - # 'Subtrees/beast/modules/beast_core/beast_core.cpp', + 'Subtrees/beast/modules/beast_boost/beast_boost.cpp', 'Subtrees/beast/modules/beast_crypto/beast_crypto.cpp', 'Subtrees/beast/modules/beast_db/beast_db.cpp', 'Subtrees/beast/modules/beast_sqdb/beast_sqdb.cpp', diff --git a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj index 23b9c40448..36b1a50a48 100644 --- a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj +++ b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj @@ -116,17 +116,17 @@ - - + + @@ -159,6 +159,7 @@ + @@ -235,7 +236,6 @@ - @@ -248,9 +248,11 @@ + + @@ -258,6 +260,13 @@ + + + + + + + @@ -466,12 +475,6 @@ true true - - true - true - true - true - true true @@ -496,6 +499,7 @@ true true + true @@ -915,12 +919,6 @@ true true - - true - true - true - true - true true @@ -969,6 +967,12 @@ true true + + true + true + true + true + true true @@ -993,6 +997,12 @@ true true + + true + true + true + true + true true diff --git a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters index 08346ee209..28f89bd5a9 100644 --- a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters +++ b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters @@ -161,6 +161,21 @@ {beb81776-4aad-401d-8826-81478dbbf30b} + + {0eac8b8d-7049-4eda-b6b4-53194d336a97} + + + {1e6959ed-fcb9-4a3b-ac5a-eb26973e21f6} + + + {493db217-b3e4-4b08-97b2-a2d753cc8c35} + + + {1b2e8962-c087-4453-8107-7077c2de5846} + + + {91538dcf-b219-4c80-9861-bb4949089775} + @@ -545,9 +560,6 @@ beast_basics\threads - - beast_basics\threads - beast_basics\threads @@ -632,9 +644,6 @@ beast_core\time - - beast_basics\threads - beast_basics\events @@ -869,8 +878,41 @@ beast_asio\handshake - - beast_core\text + + beast_core\diagnostic + + + beast_boost + + + beast_core\threads + + + beast_core\threads + + + beast_boost\traits + + + beast_core\thread + + + beast_core\thread + + + beast_core\thread\detail + + + beast_core\thread\detail + + + beast_core\thread\impl + + + beast_core\thread\impl + + + beast_core\thread\impl @@ -1150,9 +1192,6 @@ beast_basics\threads - - beast_basics\threads - beast_basics\threads @@ -1339,8 +1378,14 @@ beast_asio\async - - beast_core\text + + beast_boost + + + beast_core\threads + + + beast_core\thread\impl diff --git a/Subtrees/beast/modules/beast_basics/beast_basics.cpp b/Subtrees/beast/modules/beast_basics/beast_basics.cpp index 099cbe6027..18f7a73774 100644 --- a/Subtrees/beast/modules/beast_basics/beast_basics.cpp +++ b/Subtrees/beast/modules/beast_basics/beast_basics.cpp @@ -53,7 +53,6 @@ namespace beast #include "threads/beast_Listeners.cpp" #include "threads/beast_ManualCallQueue.cpp" #include "threads/beast_ParallelFor.cpp" -#include "threads/beast_ReadWriteMutex.cpp" #include "threads/beast_ThreadGroup.cpp" #include "threads/beast_ThreadWithCallQueue.cpp" #include "threads/beast_Workers.cpp" diff --git a/Subtrees/beast/modules/beast_basics/beast_basics.h b/Subtrees/beast/modules/beast_basics/beast_basics.h index d9a5b78ba7..940732e9a7 100644 --- a/Subtrees/beast/modules/beast_basics/beast_basics.h +++ b/Subtrees/beast/modules/beast_basics/beast_basics.h @@ -259,10 +259,8 @@ namespace beast #include "threads/beast_Semaphore.h" #include "threads/beast_SerialFor.h" #include "threads/beast_InterruptibleThread.h" -#include "threads/beast_ReadWriteMutex.h" #include "threads/beast_ThreadGroup.h" #include "threads/beast_CallQueue.h" -#include "threads/beast_SharedData.h" #include "threads/beast_GlobalThreadGroup.h" #include "threads/beast_Listeners.h" #include "threads/beast_ManualCallQueue.h" diff --git a/Subtrees/beast/modules/beast_boost/.gitignore b/Subtrees/beast/modules/beast_boost/.gitignore index 4d99b61908..5a31723b02 100644 --- a/Subtrees/beast/modules/beast_boost/.gitignore +++ b/Subtrees/beast/modules/beast_boost/.gitignore @@ -1,2 +1 @@ /boost-subtree -*.cpp diff --git a/Subtrees/beast/modules/beast_boost/beast_boost.cpp b/Subtrees/beast/modules/beast_boost/beast_boost.cpp new file mode 100644 index 0000000000..7a58ced01f --- /dev/null +++ b/Subtrees/beast/modules/beast_boost/beast_boost.cpp @@ -0,0 +1,29 @@ +//------------------------------------------------------------------------------ +/* + 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. +*/ +//============================================================================== + +#include "BeastConfig.h" + +#include "beast_boost.h" + +namespace beast +{ + + + +} diff --git a/Subtrees/beast/modules/beast_boost/beast_boost.h b/Subtrees/beast/modules/beast_boost/beast_boost.h new file mode 100644 index 0000000000..6e49a8a358 --- /dev/null +++ b/Subtrees/beast/modules/beast_boost/beast_boost.h @@ -0,0 +1,43 @@ +//------------------------------------------------------------------------------ +/* + 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_BOOST_H_INCLUDED +#define BEAST_BOOST_H_INCLUDED + +// Adds boost-specific features to beast. + +#include + +// lockable_traits was added in 1.53.0 +#ifndef BEAST_BOOST_HAS_LOCKABLES +# if BOOST_VERSION >= 105300 +# define BEAST_BOOST_HAS_LOCKABLES 1 +# else +# define BEAST_BOOST_HAS_LOCKABLES 0 +# endif +#endif +#if BEAST_BOOST_HAS_LOCKABLES +# include +#endif + +#if BEAST_BOOST_HAS_LOCKABLES +# include "traits/beast_BoostLockableTraits.h" +#endif + +#endif diff --git a/Subtrees/beast/modules/beast_boost/traits/beast_BoostLockableTraits.h b/Subtrees/beast/modules/beast_boost/traits/beast_BoostLockableTraits.h new file mode 100644 index 0000000000..7e9803b510 --- /dev/null +++ b/Subtrees/beast/modules/beast_boost/traits/beast_BoostLockableTraits.h @@ -0,0 +1,125 @@ +//------------------------------------------------------------------------------ +/* + 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_BOOSTLOCKABLERAITS_H_INCLUDED +#define BEAST_BOOSTLOCKABLERAITS_H_INCLUDED + +// Adds beast specializations for boost lockables. + +// beast forward declarations + +namespace beast +{ + +class CriticalSection; + +template +class TrackedMutex; + +template +class UntrackedMutex; + +} + +//------------------------------------------------------------------------------ + +// boost Mutex concepts +// +// http://www.boost.org/doc/libs/1_54_0/doc/html/thread/synchronization.html#thread.synchronization.mutex_concepts + +namespace boost +{ + +namespace sync +{ + +//------------------------------------------------------------------------------ +// +// CriticalSection +// + +// BasicLockable +// +template <> +struct is_basic_lockable + : public boost::true_type { }; + +// Lockable +// +template <> +struct is_lockable + : public boost::true_type { }; + +// RecursiveLockable +// +template <> +struct is_recursive_mutex_sur_parole + : public boost::true_type { }; + +//------------------------------------------------------------------------------ +// +// TrackedMutex <> +// + +// BasicLockable +// +template +class is_basic_lockable > + : public boost::sync::is_basic_lockable { }; + +// Lockable +// +template +class is_lockable > + : public boost::sync::is_lockable { }; + +// RecursiveLockable +// +template +struct is_recursive_mutex_sur_parole > + : public boost::true_type { }; + +//------------------------------------------------------------------------------ +// +// UntrackedMutex <> +// + +// BasicLockable +// +template +class is_basic_lockable > + : public boost::sync::is_basic_lockable { }; + +// Lockable +// +template +class is_lockable > + : public boost::sync::is_lockable { }; + +// RecursiveLockable +// +template +struct is_recursive_mutex_sur_parole > + : public boost::true_type { }; + +} + +} + +#endif diff --git a/Subtrees/beast/modules/beast_core/beast_core.cpp b/Subtrees/beast/modules/beast_core/beast_core.cpp index b90b480d03..346adf76df 100644 --- a/Subtrees/beast/modules/beast_core/beast_core.cpp +++ b/Subtrees/beast/modules/beast_core/beast_core.cpp @@ -204,8 +204,11 @@ namespace beast #include "text/beast_StringPool.cpp" #include "text/beast_TextDiff.cpp" +#include "thread/impl/TrackedMutex.cpp" + #include "threads/beast_ChildProcess.cpp" #include "threads/beast_ReadWriteLock.cpp" +#include "threads/beast_ReadWriteMutex.cpp" #include "threads/beast_SpinDelay.cpp" #include "threads/beast_Thread.cpp" #include "threads/beast_ThreadPool.cpp" diff --git a/Subtrees/beast/modules/beast_core/beast_core.h b/Subtrees/beast/modules/beast_core/beast_core.h index 5cc6d85086..c70f009db1 100644 --- a/Subtrees/beast/modules/beast_core/beast_core.h +++ b/Subtrees/beast/modules/beast_core/beast_core.h @@ -198,6 +198,8 @@ namespace beast #include "system/beast_PlatformDefs.h" #include "system/beast_TargetPlatform.h" + +#include "diagnostic/beast_Throw.h" #include "system/beast_Functional.h" #include "maths/beast_MathsFunctions.h" @@ -206,6 +208,7 @@ namespace beast #include "memory/beast_AtomicFlag.h" #include "memory/beast_AtomicPointer.h" #include "memory/beast_AtomicState.h" +#include "containers/beast_List.h" #include "containers/beast_LockFreeStack.h" #include "threads/beast_SpinDelay.h" #include "memory/beast_StaticObject.h" @@ -213,12 +216,26 @@ namespace beast #include "text/beast_String.h" +#include "memory/beast_MemoryAlignment.h" +#include "memory/beast_CacheLine.h" #include "threads/beast_CriticalSection.h" -#include "diagnostic/beast_FatalError.h" +#include "threads/beast_ReadWriteMutex.h" +#include "threads/beast_SharedData.h" #include "diagnostic/beast_SafeBool.h" +#include "time/beast_PerformedAtExit.h" +#include "diagnostic/beast_LeakChecked.h" +#include "threads/beast_WaitableEvent.h" +#include "threads/beast_Thread.h" +#include "threads/beast_SpinLock.h" +#include "threads/beast_ThreadLocalValue.h" + +#include "thread/MutexTraits.h" +#include "containers/beast_Array.h" +#include "text/beast_StringArray.h" +#include "thread/TrackedMutex.h" +#include "diagnostic/beast_FatalError.h" #include "diagnostic/beast_Error.h" #include "diagnostic/beast_Debug.h" -#include "diagnostic/beast_Throw.h" #include "text/beast_CharacterFunctions.h" #include "text/beast_CharPointer_ASCII.h" @@ -228,23 +245,18 @@ namespace beast #include "text/beast_LexicalCast.h" #include "memory/beast_ContainerDeletePolicy.h" -#include "time/beast_PerformedAtExit.h" -#include "diagnostic/beast_LeakChecked.h" #include "memory/beast_ByteOrder.h" #include "memory/beast_ByteSwap.h" #include "maths/beast_uint24.h" #include "logging/beast_Logger.h" -#include "threads/beast_Thread.h" #include "diagnostic/beast_FPUFlags.h" #include "diagnostic/beast_ProtectedCall.h" #include "containers/beast_AbstractFifo.h" -#include "containers/beast_Array.h" #include "containers/beast_ArrayAllocationBase.h" #include "containers/beast_DynamicObject.h" #include "containers/beast_ElementComparator.h" #include "maths/beast_Random.h" #include "containers/beast_HashMap.h" -#include "containers/beast_List.h" #include "containers/beast_LinkedListPointer.h" #include "containers/beast_LockFreeQueue.h" #include "containers/beast_NamedValueSet.h" @@ -281,11 +293,8 @@ namespace beast #include "memory/beast_OptionalScopedPointer.h" #include "memory/beast_SharedObject.h" #include "memory/beast_ScopedPointer.h" -#include "threads/beast_SpinLock.h" #include "memory/beast_SharedSingleton.h" #include "memory/beast_WeakReference.h" -#include "memory/beast_MemoryAlignment.h" -#include "memory/beast_CacheLine.h" #include "memory/beast_RecycledObjectPool.h" #include "misc/beast_Main.h" #include "misc/beast_Result.h" @@ -309,7 +318,6 @@ namespace beast #include "text/beast_Identifier.h" #include "text/beast_LocalisedStrings.h" #include "text/beast_NewLine.h" -#include "text/beast_StringArray.h" #include "diagnostic/beast_SemanticVersion.h" #include "text/beast_StringPairArray.h" #include "text/beast_StringPool.h" @@ -323,10 +331,8 @@ namespace beast #include "threads/beast_ScopedLock.h" #include "threads/beast_ScopedReadLock.h" #include "threads/beast_ScopedWriteLock.h" -#include "threads/beast_ThreadLocalValue.h" #include "threads/beast_ThreadPool.h" #include "threads/beast_TimeSliceThread.h" -#include "threads/beast_WaitableEvent.h" #include "time/beast_PerformanceCounter.h" #include "time/beast_RelativeTime.h" #include "time/beast_Time.h" @@ -338,6 +344,8 @@ namespace beast #include "zip/beast_GZIPDecompressorInputStream.h" #include "zip/beast_ZipFile.h" +#include "diagnostic/MeasureFunctionCallTime.h" + } #ifdef _CRTDBG_MAP_ALLOC diff --git a/Subtrees/beast/modules/beast_core/diagnostic/MeasureFunctionCallTime.h b/Subtrees/beast/modules/beast_core/diagnostic/MeasureFunctionCallTime.h new file mode 100644 index 0000000000..99efe3412b --- /dev/null +++ b/Subtrees/beast/modules/beast_core/diagnostic/MeasureFunctionCallTime.h @@ -0,0 +1,80 @@ +//------------------------------------------------------------------------------ +/* + 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_DIAGNOSTIC_MEASUREFUNCTIONCALLTIME_H_INCLUDED +#define BEAST_CORE_DIAGNOSTIC_MEASUREFUNCTIONCALLTIME_H_INCLUDED + +/** Measures the speed of invoking a function. */ +/** @{ */ +template +double measureFunctionCallTime (Function f) +{ + int64 const startTime (Time::getHighResolutionTicks ()); + f (); + return Time::highResolutionTicksToSeconds ( + Time::getHighResolutionTicks () - startTime); +} + +#if 0 +template +double measureFunctionCallTime (Function f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) +{ + int64 const startTime (Time::getHighResolutionTicks ()); + f (p1, p2, p3, p4, p5 ,p6 ,p7 ,p8); + return Time::highResolutionTicksToSeconds ( + Time::getHighResolutionTicks () - startTime); +} + +template +double measureFunctionCallTime (Function f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) +{ + int64 const startTime (Time::getHighResolutionTicks ()); + f (p1, p2, p3, p4, p5 ,p6 ,p7 ,p8); + return Time::highResolutionTicksToSeconds ( + Time::getHighResolutionTicks () - startTime); +} + +template +double measureFunctionCallTime (Function f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) +{ + int64 const startTime (Time::getHighResolutionTicks ()); + f (p1, p2, p3, p4, p5 ,p6 ,p7 ,p8); + return Time::highResolutionTicksToSeconds ( + Time::getHighResolutionTicks () - startTime); +} + +template +double measureFunctionCallTime (Function f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) +{ + int64 const startTime (Time::getHighResolutionTicks ()); + f (p1, p2, p3, p4, p5 ,p6 ,p7 ,p8); + return Time::highResolutionTicksToSeconds ( + Time::getHighResolutionTicks () - startTime); +} +#endif + +#endif diff --git a/Subtrees/beast/modules/beast_core/diagnostic/beast_Debug.cpp b/Subtrees/beast/modules/beast_core/diagnostic/beast_Debug.cpp index e52ea11a67..488e030d31 100644 --- a/Subtrees/beast/modules/beast_core/diagnostic/beast_Debug.cpp +++ b/Subtrees/beast/modules/beast_core/diagnostic/beast_Debug.cpp @@ -118,9 +118,36 @@ void checkHeap () //------------------------------------------------------------------------------ -const String getFileNameFromPath (const char* sourceFileName) +String getSourceLocation (char const* fileName, int lineNumber, + int numberOfParents) { - return File::createFileWithoutCheckingPath (sourceFileName).getFileName (); + return getFileNameFromPath (fileName, numberOfParents) + + "(" + String::fromNumber (lineNumber) + ")"; +} + +String getFileNameFromPath (const char* sourceFileName, int numberOfParents) +{ + String fullPath (sourceFileName); + +#if BEAST_WINDOWS + // Convert everything to forward slash + fullPath = fullPath.replaceCharacter ('\\', '/'); +#endif + + String path; + + int chopPoint = fullPath.lastIndexOfChar ('/'); + path = fullPath.substring (chopPoint + 1); + + while (chopPoint >= 0 && numberOfParents > 0) + { + --numberOfParents; + fullPath = fullPath.substring (0, chopPoint); + chopPoint = fullPath.lastIndexOfChar ('/'); + path = fullPath.substring (chopPoint + 1) + '/' + path; + } + + return path; } // Returns a String with double quotes escaped diff --git a/Subtrees/beast/modules/beast_core/diagnostic/beast_Debug.h b/Subtrees/beast/modules/beast_core/diagnostic/beast_Debug.h index c6013d46c5..e80418e042 100644 --- a/Subtrees/beast/modules/beast_core/diagnostic/beast_Debug.h +++ b/Subtrees/beast/modules/beast_core/diagnostic/beast_Debug.h @@ -31,11 +31,16 @@ namespace Debug */ extern void breakPoint (); -// VFALCO NOTE IS THIS REALLY THE RIGHT PLACE FOR THESE?? -// -// Return only the filename portion of sourceFileName -// This hides the programmer's directory structure from end-users. -const String getFileNameFromPath (const char* sourceFileName); +/** Given a file and line number this formats a suitable string. + Usually you will pass __FILE__ and __LINE__ here. +*/ +String getSourceLocation (char const* fileName, int lineNumber, + int numberOfParents = 0); + +/** Retrieve the file name from a full path. + The nubmer of parents can be chosen +*/ +String getFileNameFromPath (const char* sourceFileName, int numberOfParents = 0); // Convert a String that may contain double quotes and newlines // into a String with double quotes escaped as \" and each diff --git a/Subtrees/beast/modules/beast_core/diagnostic/beast_Throw.h b/Subtrees/beast/modules/beast_core/diagnostic/beast_Throw.h index 58b6e8ae70..314c5b1047 100644 --- a/Subtrees/beast/modules/beast_core/diagnostic/beast_Throw.h +++ b/Subtrees/beast/modules/beast_core/diagnostic/beast_Throw.h @@ -25,6 +25,11 @@ This provides an opportunity to utilize the debugger before the stack is unwound. */ +namespace Debug +{ +extern void breakPoint (); +}; + template inline void Throw (Exception const& e, char const* = "", int = 0) { diff --git a/Subtrees/beast/modules/beast_core/thread/MutexTraits.h b/Subtrees/beast/modules/beast_core/thread/MutexTraits.h new file mode 100644 index 0000000000..9de13e042a --- /dev/null +++ b/Subtrees/beast/modules/beast_core/thread/MutexTraits.h @@ -0,0 +1,75 @@ +//------------------------------------------------------------------------------ +/* + 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_THREAD_MUTEXTRAITS_H_INCLUDED +#define BEAST_CORE_THREAD_MUTEXTRAITS_H_INCLUDED + +/** Adapt a Mutex type to meet the boost::Mutex concept requirements. + The default implementation assumes adherance to the boost::Mutex concepts, + with one important exception. We make the member functions const, for + convenience. +*/ +template +struct MutexTraits +{ + // BasicLockable + // http://www.boost.org/doc/libs/1_54_0/doc/html/thread/synchronization.html#thread.synchronization.mutex_concepts.basic_lockable + // + static inline void lock (Mutex const& mutex) noexcept + { + (const_cast (mutex)).lock (); + } + + static inline void unlock (Mutex const& mutex) noexcept + { + (const_cast (mutex)).unlock (); + } + + // Lockable + // http://www.boost.org/doc/libs/1_54_0/doc/html/thread/synchronization.html#thread.synchronization.mutex_concepts.basic_lockable + // + static inline bool try_lock (Mutex const& mutex) noexcept + { + return (const_cast (mutex)).try_lock (); + } +}; + +//------------------------------------------------------------------------------ + +/** MutexTraits Specialization for a beast CriticalSection. */ +template <> +struct MutexTraits +{ + static inline void lock (CriticalSection const& mutex) noexcept + { + mutex.lock (); + } + + static inline void unlock (CriticalSection const& mutex) noexcept + { + mutex.unlock (); + } + + static inline bool try_lock (CriticalSection const& mutex) noexcept + { + return mutex.try_lock (); + } +}; + +#endif diff --git a/Subtrees/beast/modules/beast_core/thread/TrackedMutex.h b/Subtrees/beast/modules/beast_core/thread/TrackedMutex.h new file mode 100644 index 0000000000..e41dc0b1d4 --- /dev/null +++ b/Subtrees/beast/modules/beast_core/thread/TrackedMutex.h @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +/* + 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_THREAD_TRACKEDMUTEX_H_INCLUDED +#define BEAST_CORE_THREAD_TRACKEDMUTEX_H_INCLUDED + +#include "detail/TrackedMutex.h" +#include "detail/ScopedLock.h" + +#include "impl/TrackedMutex.h" +#include "impl/TrackedMutexType.h" +#include "impl/UntrackedMutexType.h" + +#endif diff --git a/Subtrees/beast/modules/beast_core/thread/detail/ScopedLock.h b/Subtrees/beast/modules/beast_core/thread/detail/ScopedLock.h new file mode 100644 index 0000000000..97045032d0 --- /dev/null +++ b/Subtrees/beast/modules/beast_core/thread/detail/ScopedLock.h @@ -0,0 +1,251 @@ +//------------------------------------------------------------------------------ +/* + 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_THREAD_DETAIL_SCOPEDLOCK_H_INCLUDED +#define BEAST_CORE_THREAD_DETAIL_SCOPEDLOCK_H_INCLUDED + +#include "../MutexTraits.h" + +namespace detail +{ + +template +class TrackedScopedLock : public Uncopyable +{ +public: + inline explicit TrackedScopedLock (Mutex const& mutex, + char const* fileName, int lineNumber) noexcept + : m_mutex (mutex) + , m_lock_count (0) + { + lock (fileName, lineNumber); + } + + inline ~TrackedScopedLock () noexcept + { + if (m_lock_count > 0) + unlock (); + } + + inline void lock (char const* fileName, int lineNumber) noexcept + { + ++m_lock_count; + m_mutex.lock (fileName, lineNumber); + } + + inline void unlock () noexcept + { + m_mutex.unlock (); + --m_lock_count; + } + +private: + Mutex const& m_mutex; + int m_lock_count; +}; + +//-------------------------------------------------------------------------- + +template +class TrackedScopedTryLock : public Uncopyable +{ +public: + inline explicit TrackedScopedTryLock (Mutex const& mutex, + char const* fileName, int lineNumber) noexcept + : m_mutex (mutex) + , m_lock_count (0) + { + try_lock (fileName, lineNumber); + } + + inline ~TrackedScopedTryLock () noexcept + { + if (m_lock_count > 0) + unlock (); + } + + inline bool owns_lock () const noexcept + { + return m_lock_count > 0; + } + + inline bool try_lock (char const* fileName, int lineNumber) noexcept + { + bool const success = m_mutex.try_lock (fileName, lineNumber); + if (success) + ++m_lock_count; + return success; + } + + inline void unlock () noexcept + { + m_mutex.unlock (); + --m_lock_count; + } + +private: + Mutex const& m_mutex; + int m_lock_count; +}; + +//-------------------------------------------------------------------------- + +template +class TrackedScopedUnlock : public Uncopyable +{ +public: + inline explicit TrackedScopedUnlock (Mutex const& mutex, + char const* fileName, int lineNumber) noexcept + : m_mutex (mutex) + , m_fileName (fileName) + , m_lineNumber (lineNumber) + { + m_mutex.unlock (); + } + + inline ~TrackedScopedUnlock () noexcept + { + m_mutex.lock (m_fileName, m_lineNumber); + } + +private: + Mutex const& m_mutex; + char const* const m_fileName; + int const m_lineNumber; +}; + +//-------------------------------------------------------------------------- + +template +class UntrackedScopedLock : public Uncopyable +{ +public: + inline explicit UntrackedScopedLock (Mutex const& mutex, + char const*, int) noexcept + : m_mutex (mutex) + , m_lock_count (0) + { + lock (); + } + + inline ~UntrackedScopedLock () noexcept + { + if (m_lock_count > 0) + unlock (); + } + + inline void lock () noexcept + { + ++m_lock_count; + m_mutex.lock (); + } + + inline void lock (char const*, int) noexcept + { + lock (); + } + + inline void unlock () noexcept + { + m_mutex.unlock (); + --m_lock_count; + } + +private: + Mutex const& m_mutex; + int m_lock_count; +}; + +//-------------------------------------------------------------------------- + +template +class UntrackedScopedTryLock : public Uncopyable +{ +public: + inline explicit UntrackedScopedTryLock (Mutex const& mutex, + char const*, int) noexcept + : m_mutex (mutex) + { + try_lock (); + } + + inline ~UntrackedScopedTryLock () noexcept + { + if (m_lock_count > 0) + unlock (); + } + + inline bool owns_lock () const noexcept + { + return m_lock_count > 0; + } + + inline bool try_lock () noexcept + { + bool const success = m_mutex.try_lock (); + if (success) + ++m_lock_count; + return success; + } + + inline bool try_lock (char const*, int) noexcept + { + return try_lock (); + } + + inline void unlock () noexcept + { + m_mutex.unlock (); + --m_lock_count; + } + +private: + Mutex const& m_mutex; + int m_lock_count; +}; + +//-------------------------------------------------------------------------- + +template +class UntrackedScopedUnlock : public Uncopyable +{ +public: + UntrackedScopedUnlock (Mutex const& mutex, + char const*, int) noexcept + : m_mutex (mutex) + , m_owns_lock (true) + { + MutexTraits ::unlock (m_mutex); + m_owns_lock = false; + } + + ~UntrackedScopedUnlock () noexcept + { + MutexTraits ::lock (m_mutex); + m_owns_lock = true; + } + +private: + Mutex const& m_mutex; + bool m_owns_lock; +}; + +} // namespace detail + +#endif diff --git a/Subtrees/beast/modules/beast_core/thread/detail/TrackedMutex.h b/Subtrees/beast/modules/beast_core/thread/detail/TrackedMutex.h new file mode 100644 index 0000000000..e291749776 --- /dev/null +++ b/Subtrees/beast/modules/beast_core/thread/detail/TrackedMutex.h @@ -0,0 +1,100 @@ +//------------------------------------------------------------------------------ +/* + 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_THREAD_DETAIL_TRACKEDMUTEX_H_INCLUDED +#define BEAST_CORE_THREAD_DETAIL_TRACKEDMUTEX_H_INCLUDED + +#include "../../containers/beast_List.h" +#include "../../memory/beast_Atomic.h" +#include "../../threads/beast_ThreadLocalValue.h" + +class TrackedMutex; + +namespace detail +{ + +struct TrackedMutexBasics +{ + struct PerThreadData; + + typedef List ThreadLockList; + typedef List GlobalThreadList; + + // Retrieve an atomic counter unique to class Object + template + static Atomic & getCounter () noexcept + { + static Atomic counter; + return counter; + } + + template + inline static String createName (String name, + char const* fileName, int lineNumber) + { + return createName (name, fileName, lineNumber, + ++getCounter ()); + } + + static String createName (String name, + char const* fileName, int lineNumber, int instanceNumber = 0); + + struct PerThreadData + : GlobalThreadList::Node + { + PerThreadData (); + + int id; + int refCount; + ThreadLockList list; + CriticalSection mutex; + + TrackedMutex const* blocked; + String threadName; // at the time of the block + String sourceLocation; // at the time of the block + }; + + // This turns the thread local into a POD which will be + // initialized to all zeroes. We use the 'id' flag to + // know to initialize. + // + struct PerThreadDataStorage + { + BEAST_ALIGN(8) + unsigned char bytes [sizeof (PerThreadData)]; + }; + + static Atomic lastThreadId; + + static ThreadLocalValue threadLocal; + + static PerThreadData& getPerThreadData (); + + struct Lists + { + GlobalThreadList allThreads; + }; + + static CriticalSection& getGlobalMutex (); + static Lists& getLists (); +}; + +} // namespace detail + +#endif diff --git a/Subtrees/beast/modules/beast_core/thread/impl/TrackedMutex.cpp b/Subtrees/beast/modules/beast_core/thread/impl/TrackedMutex.cpp new file mode 100644 index 0000000000..1b0a44f741 --- /dev/null +++ b/Subtrees/beast/modules/beast_core/thread/impl/TrackedMutex.cpp @@ -0,0 +1,476 @@ +//------------------------------------------------------------------------------ +/* + 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. +*/ +//============================================================================== + +namespace detail +{ + +// Example: +// +// m_mutex[2] @ beast_deadlineTimer.cpp(25) +// +String detail::TrackedMutexBasics::createName (String name, + char const* fileName, int lineNumber, int instanceNumber) +{ + return name + + ((instanceNumber > 1) ? + (String ("[") + String::fromNumber (instanceNumber) + "] (") : " (") + + Debug::getFileNameFromPath (fileName) + "," + + String::fromNumber (lineNumber) + ")"; +} + +Atomic TrackedMutexBasics::lastThreadId; + +ThreadLocalValue TrackedMutexBasics::threadLocal; + +TrackedMutexBasics::PerThreadData::PerThreadData () + : id (++lastThreadId) +{ +} + +TrackedMutexBasics::PerThreadData& TrackedMutexBasics::getPerThreadData () +{ + PerThreadData& thread (*reinterpret_cast (&threadLocal.get ())); + + // Manually call the constructor with placement new if needed + if (! thread.id) + { + ::new (&thread) PerThreadData (); + bassert (thread.id != 0); + } + + return thread; +} + +CriticalSection& TrackedMutexBasics::getGlobalMutex () +{ + static CriticalSection mutex; + return mutex; +} + +TrackedMutexBasics::Lists& TrackedMutexBasics::getLists () +{ + static Lists lists; + return lists; +} + +//------------------------------------------------------------------------------ + +} // namespace detail + +//============================================================================== + +TrackedMutex::Record::Record (String mutexName, + String threadName, String sourceLocation) + : m_mutexName (mutexName) + , m_threadName (threadName) + , m_sourceLocation (sourceLocation) +{ +} + +TrackedMutex::Record::Record () noexcept +{ +} + +TrackedMutex::Record::Record (Record const& other) noexcept + : m_mutexName (other.m_mutexName) + , m_threadName (other.m_threadName) + , m_sourceLocation (other.m_sourceLocation) +{ +} + +TrackedMutex::Record& TrackedMutex::Record::operator= (Record const& other) noexcept +{ + m_mutexName = other.m_mutexName; + m_threadName = other.m_threadName; + m_sourceLocation = other.m_sourceLocation; + return *this; +} + +bool TrackedMutex::Record::isNull () const noexcept +{ + return m_mutexName == ""; +} + +bool TrackedMutex::Record::isNotNull () const noexcept +{ + return m_mutexName != ""; +} + +bool TrackedMutex::Record::asBoolean () const noexcept +{ + return isNotNull (); +} + +String TrackedMutex::Record::getMutexName () const noexcept +{ + return m_mutexName; +} + +String TrackedMutex::Record::getThreadName () const noexcept +{ + return m_threadName; +} + +String TrackedMutex::Record::getSourceLocation () const noexcept +{ + return m_sourceLocation; +} + +//------------------------------------------------------------------------------ + +TrackedMutex::Agent::Agent (detail::TrackedMutexBasics::PerThreadData* thread) + : m_thread (thread) + , m_threadName (thread->threadName) +{ +} + +TrackedMutex::Agent::Agent () noexcept + : m_thread (nullptr) +{ +} + +TrackedMutex::Agent::Agent (Agent const& other) noexcept + : m_thread (other.m_thread) + , m_threadName (other.m_threadName) + , m_blocked (other.m_blocked) +{ +} + +TrackedMutex::Agent& TrackedMutex::Agent::operator= (Agent const& other) noexcept +{ + m_thread = other.m_thread; + m_threadName = other.m_threadName; + m_blocked = other.m_blocked; + return *this; +} + +bool TrackedMutex::Agent::isNull () const noexcept +{ + return m_thread == nullptr; +} + +bool TrackedMutex::Agent::isNotNull () const noexcept +{ + return m_thread != nullptr; +} + +bool TrackedMutex::Agent::asBoolean () const noexcept +{ + return isNotNull (); +} + +String TrackedMutex::Agent::getThreadName () const noexcept +{ + return m_threadName; +} + +TrackedMutex::Record TrackedMutex::Agent::getBlockedRecord () const noexcept +{ + return m_blocked; +} + +bool TrackedMutex::Agent::getLockedList (Array & output) +{ + bassert (isNotNull ()); + + output.clearQuick (); + + typedef detail::TrackedMutexBasics::ThreadLockList ListType; + + { + CriticalSection::ScopedLockType lock (m_thread->mutex); + + ListType const& list (m_thread->list); + + output.ensureStorageAllocated (list.size ()); + + for (ListType::const_iterator iter = list.begin (); + iter != list.end (); ++iter) + { + TrackedMutex const& mutex = *iter; + { + TrackedMutex::SharedState::ReadAccess state (mutex.m_state); + output.add (state->owner); + } + } + } + + return output.size () > 0; +} + +//------------------------------------------------------------------------------ + +TrackedMutex::State::State () + : thread (nullptr) +{ +} + +//------------------------------------------------------------------------------ + +TrackedMutex::TrackedMutex (String const& name) noexcept + : m_name (name) + , m_count (0) +{ +} + +String TrackedMutex::getName () const noexcept +{ + return m_name; +} + +TrackedMutex::Record TrackedMutex::getOwnerRecord () const noexcept +{ + { + SharedState::ReadAccess state (m_state); + return state->owner; + } +} + +TrackedMutex::Agent TrackedMutex::getOwnerAgent () const noexcept +{ + { + SharedState::ReadAccess state (m_state); + if (state->thread != nullptr) + return Agent (state->thread); + } + + return Agent (); +} + +//------------------------------------------------------------------------------ + +void TrackedMutex::generateGlobalBlockedReport (StringArray& report) +{ + report.clear (); + + { + CriticalSection::ScopedLockType lock ( + detail::TrackedMutexBasics::getGlobalMutex ()); + + typedef detail::TrackedMutexBasics::GlobalThreadList ListType; + + ListType const& list (detail::TrackedMutexBasics::getLists ().allThreads); + + for (ListType::const_iterator iter = list.begin (); iter != list.end (); ++iter) + { + detail::TrackedMutexBasics::PerThreadData const* thread ( + &(*iter)); + + typedef detail::TrackedMutexBasics::ThreadLockList LockedList; + LockedList const& owned (thread->list); + + if (thread->blocked) + { + String s; + s << thread->threadName << " blocked on " << + thread->blocked->getName () << " at " << + thread->sourceLocation; + if (owned.size () > 0) + s << " and owns these locks:"; + report.add (s); + } + else if (owned.size () > 0) + { + String s; + s << thread->threadName << " owns these locks:"; + report.add (s); + } + + if (owned.size () > 0) + { + for (LockedList::const_iterator iter = owned.begin (); iter != owned.end (); ++iter) + { + String s; + TrackedMutex const& mutex (*iter); + TrackedMutex::SharedState::ReadAccess state (mutex.m_state); + s << " " << mutex.getName () << + " from " << state->owner.getSourceLocation (); + report.add (s); + } + } + } + } +} + +//------------------------------------------------------------------------------ + +// Called before we attempt to acquire the mutex. +// +void TrackedMutex::block (char const* fileName, int lineNumber) const noexcept +{ + // Get calling thread data. + detail::TrackedMutexBasics::PerThreadData& thread + (detail::TrackedMutexBasics::getPerThreadData ()); + + ++thread.refCount; + + String const sourceLocation (makeSourceLocation (fileName, lineNumber)); + + { + // Take a global lock. + CriticalSection::ScopedLockType globalLock ( + detail::TrackedMutexBasics::getGlobalMutex ()); + + { + // Take a thread lock. + CriticalSection::ScopedLockType threadLock (thread.mutex); + + // Set the thread's blocked record + thread.blocked = this; + thread.threadName = makeThreadName (thread); + thread.sourceLocation = sourceLocation; + + // Add this thread to threads list. + if (thread.refCount == 1) + detail::TrackedMutexBasics::getLists().allThreads.push_back (thread); + } + } +} + +//------------------------------------------------------------------------------ + +// Called after we already have ownership of the mutex +// +void TrackedMutex::acquired (char const* fileName, int lineNumber) const noexcept +{ + // Retrieve the per-thread data for the calling thread. + detail::TrackedMutexBasics::PerThreadData& thread + (detail::TrackedMutexBasics::getPerThreadData ()); + + // If this goes off it means block() wasn't called. + bassert (thread.refCount > 0); + + ++m_count; + + // Take ownership on the first count. + if (m_count == 1) + { + // Thread is a new owner of the mutex. + String const sourceLocation (makeSourceLocation (fileName, lineNumber)); + String const threadName (makeThreadName (thread)); + + { + // Take a global lock. + CriticalSection::ScopedLockType globalLock ( + detail::TrackedMutexBasics::getGlobalMutex ()); + + { + // Take a state lock. + SharedState::WriteAccess state (m_state); + + // Set the mutex ownership record + state->owner = Record (getName (), threadName, sourceLocation); + state->thread = &thread; + + { + // Take a thread lock. + CriticalSection::ScopedLockType threadLock (thread.mutex); + + // Add the mutex to the thread's list. + thread.list.push_back (const_cast (*this)); + + // Unblock the thread record. + thread.blocked = nullptr; + thread.sourceLocation = ""; + } + } + } + } + else + { + // Thread already had ownership of the mutex. + bassert (SharedState::UnlockedAccess (m_state)->thread == &thread); + + // If this goes off it means we counted wrong. + bassert (thread.refCount >= m_count); + } +} + +//------------------------------------------------------------------------------ + +void TrackedMutex::release () const noexcept +{ + // If this goes off it means we don't own the mutex! + bassert (m_count > 0); + + // Retrieve the per-thread data for the calling thread. + detail::TrackedMutexBasics::PerThreadData& thread + (detail::TrackedMutexBasics::getPerThreadData ()); + + // If this goes off it means we counted wrong. + bassert (thread.refCount >= m_count); + + --m_count; + --thread.refCount; + + // Give up ownership when the count drops to zero. + if (m_count == 0) + { + // Take the global mutex + CriticalSection::ScopedLockType globalLock ( + detail::TrackedMutexBasics::getGlobalMutex ()); + + { + // Take the mutex' state lock + SharedState::WriteAccess state (m_state); + + // Clear the mutex ownership record + state->owner = Record (); + state->thread = nullptr; + + { + // Take the thread mutex + CriticalSection::ScopedLockType threadLock (thread.mutex); + + // Remove this mutex from the list of the thread's owned locks. + thread.list.erase (thread.list.iterator_to ( + const_cast (*this))); + + // Remove this thread from the threads list. + if (thread.refCount == 0) + { + typedef detail::TrackedMutexBasics::GlobalThreadList ListType; + ListType& list (detail::TrackedMutexBasics::getLists().allThreads); + list.erase (list.iterator_to (thread)); + } + } + } + } +} + +//------------------------------------------------------------------------------ + +String TrackedMutex::makeThreadName ( + detail::TrackedMutexBasics::PerThreadData const& thread) noexcept +{ + String threadName; + Thread const* const currentThread (Thread::getCurrentThread ()); + if (currentThread != nullptr) + threadName = currentThread->getThreadName (); + threadName = threadName + "[" + String::fromNumber (thread.id) + "]"; + return threadName; +} + +String TrackedMutex::makeSourceLocation (char const* fileName, int lineNumber) noexcept +{ + String const sourceLocation (Debug::getFileNameFromPath (fileName, 1) + "(" + + String::fromNumber (lineNumber) + ")"); + + return sourceLocation; +} diff --git a/Subtrees/beast/modules/beast_core/thread/impl/TrackedMutex.h b/Subtrees/beast/modules/beast_core/thread/impl/TrackedMutex.h new file mode 100644 index 0000000000..783c2014d4 --- /dev/null +++ b/Subtrees/beast/modules/beast_core/thread/impl/TrackedMutex.h @@ -0,0 +1,168 @@ +//------------------------------------------------------------------------------ +/* + 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_THREAD_IMPL_TRACKEDMUTEX_H_INCLUDED +#define BEAST_CORE_THREAD_IMPL_TRACKEDMUTEX_H_INCLUDED + +/** Common types and member functions for a TrackedMutex */ +class TrackedMutex + : public detail::TrackedMutexBasics::ThreadLockList::Node +{ +public: + class Agent; + class Location; + + //-------------------------------------------------------------------------- + + /** A triplet identifying a mutex, a thread, and source code location. + */ + class Record : public SafeBool + { + public: + Record () noexcept; + Record (Record const& other) noexcept; + Record& operator= (Record const& other) noexcept; + + bool isNull () const noexcept; + bool isNotNull () const noexcept; + bool asBoolean () const noexcept; + + /** Returns the name of the mutex. + Since the Mutex may not exist after the Record record is + created, we only provide a String, which is always valid. + */ + String getMutexName () const noexcept; + + /** Returns the name of the associated thread. + The name is generated at the time the record is created, + and might have changed since that time, or may no longer exist. + */ + String getThreadName () const noexcept; + + /** Returns the position within the source code. + This will either be the place a lock was acquired, or the place + where a thread is trying to acquire a lock. The vaue is only + meaningful at the time the Record is created. Since then, the + thread may have changed its state. + */ + String getSourceLocation () const noexcept; + + private: + friend class TrackedMutex; + + Record (String mutexName, String threadName, String sourceLocation); + + String m_mutexName; + String m_threadName; + String m_sourceLocation; + }; + + //-------------------------------------------------------------------------- + + /** Describes a thread that can acquire mutexes. */ + class Agent : public SafeBool + { + public: + Agent () noexcept; + Agent (Agent const& other) noexcept; + Agent& operator= (Agent const& other) noexcept; + + bool isNull () const noexcept; + bool isNotNull () const noexcept; + bool asBoolean () const noexcept; + + /** Returns the name of the thread. + The name is generated at the time the Agent record is created, + and might have changed since that time. + */ + String getThreadName () const noexcept; + + /** Returns a Record indicating where the thread is blocked on a mutex. + If the thread is not blocked, a null Record is returned. + The value is only meaningful at the moment of the call as conditions + can change. + */ + Record getBlockedRecord () const noexcept; + + /** Retrieve a list of other locks that this thread holds. + Each lock is represented by a Location indicating the place + The value is only meaningful at the moment of the call as conditions + can change. + @return `true` if the list is not empty. + */ + bool getLockedList (Array & list); + + private: + friend class TrackedMutex; + explicit Agent (detail::TrackedMutexBasics::PerThreadData* thread); + + detail::TrackedMutexBasics::PerThreadData* m_thread; + String m_threadName; + Record m_blocked; + }; + + //-------------------------------------------------------------------------- + + /** Retrieve the name of this mutex. + Thread safety: May be called from any thread. + */ + String getName () const noexcept; + + /** Retrieve a Record for the current owner. + It is only valid at the one instant in time, as the person holding it + might have released it shortly afterwards. If there is no owner, + a null Record is returned. + */ + Record getOwnerRecord () const noexcept; + + /** Retrieve the Agent for the current owner. + It is only valid at the one instant in time, as the person holding it + might have released it shortly afterwards. If there is no owner, + a null Agent is returned. + */ + Agent getOwnerAgent () const noexcept; + + /** Produce a report on the state of all blocked threads. */ + static void generateGlobalBlockedReport (StringArray& report); + +protected: + static String makeThreadName (detail::TrackedMutexBasics::PerThreadData const&) noexcept; + static String makeSourceLocation (char const* fileName, int lineNumber) noexcept; + + TrackedMutex (String const& name) noexcept; + void block (char const* fileName, int lineNumber) const noexcept; + void acquired (char const* fileName, int lineNumber) const noexcept; + void release () const noexcept; + +private: + struct State + { + State (); + Record owner; + detail::TrackedMutexBasics::PerThreadData* thread; + }; + + typedef SharedData SharedState; + + String const m_name; + int mutable m_count; + SharedState mutable m_state; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_core/thread/impl/TrackedMutexType.h b/Subtrees/beast/modules/beast_core/thread/impl/TrackedMutexType.h new file mode 100644 index 0000000000..654ffe52b0 --- /dev/null +++ b/Subtrees/beast/modules/beast_core/thread/impl/TrackedMutexType.h @@ -0,0 +1,95 @@ +//------------------------------------------------------------------------------ +/* + 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_THREAD_TRACKEDMUTEXTYPE_H_INCLUDED +#define BEAST_CORE_THREAD_TRACKEDMUTEXTYPE_H_INCLUDED + +/** A template that gives a Mutex diagnostic tracking capabilities. */ +template +class TrackedMutexType + : public TrackedMutex +{ +public: + /** The type of ScopedLock to use with this TrackedMutexType object. */ + typedef detail::TrackedScopedLock > ScopedLockType; + + /** The type of ScopedTrylock to use with this TrackedMutexType object. */ + typedef detail::TrackedScopedTryLock > ScopedTryLockType; + + /** The type of ScopedUnlock to use with this TrackedMutexType object. */ + typedef detail::TrackedScopedUnlock > ScopedUnlockType; + + /** Construct a mutex, keyed to a particular class. + Just pass 'this' for owner and give it the name of the data member + of your class. + */ + template + TrackedMutexType (Object const* object, + String name, + char const* fileName, + int lineNumber) + : TrackedMutex (detail::TrackedMutexBasics::createName ( + name, fileName, lineNumber)) + { + } + + /** Construct a mutex, without a class association. + These will all get numbered together as a group. + */ + TrackedMutexType (String name, char const* fileName, int lineNumber) + : TrackedMutex (detail::TrackedMutexBasics::createName (name, + fileName, lineNumber)) + { + } + + ~TrackedMutexType () noexcept + { + } + + inline void lock (char const* fileName, int lineNumber) const noexcept + { + block (fileName, lineNumber); + MutexTraits ::lock (m_mutex); + acquired (fileName, lineNumber); + } + + inline void unlock () const noexcept + { + release (); + MutexTraits ::unlock (m_mutex); + } + + // VFALCO NOTE: We could use enable_if here... + inline bool try_lock (char const* fileName, int lineNumber) const noexcept + { + bool const success = MutexTraits ::try_lock (m_mutex); + if (success) + { + // Hack, call block to prevent counts from going wrong. + block (fileName, lineNumber); + acquired (fileName, lineNumber); + } + return success; + } + +private: + Mutex const m_mutex; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_core/thread/impl/UntrackedMutexType.h b/Subtrees/beast/modules/beast_core/thread/impl/UntrackedMutexType.h new file mode 100644 index 0000000000..3768bb66a5 --- /dev/null +++ b/Subtrees/beast/modules/beast_core/thread/impl/UntrackedMutexType.h @@ -0,0 +1,82 @@ +//------------------------------------------------------------------------------ +/* + 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_THREAD_IMPL_UNTRACKEDMUTEX_H_INCLUDED +#define BEAST_CORE_THREAD_IMPL_UNTRACKEDMUTEX_H_INCLUDED + +/** A drop-in replacement for TrackedMutex without the tracking. +*/ +template +class UntrackedMutexType + : public Uncopyable +{ +public: + typedef detail::UntrackedScopedLock > ScopedLockType; + typedef detail::UntrackedScopedTryLock > ScopedTryLockType; + typedef detail::UntrackedScopedUnlock > ScopedUnlockType; + + template + inline UntrackedMutexType (Object const*, String name, char const*, int) noexcept + { + } + + inline UntrackedMutexType (String, char const*, int) noexcept + { + } + + inline UntrackedMutexType () noexcept + { + } + + inline ~UntrackedMutexType () noexcept + { + } + + inline void lock () const noexcept + { + MutexTraits ::lock (m_mutex); + } + + inline void lock (char const*, int) const noexcept + { + MutexTraits ::lock (m_mutex); + } + + inline void unlock () const noexcept + { + MutexTraits ::unlock (m_mutex); + } + + // VFALCO NOTE: We could use enable_if here... + + inline bool try_lock () const noexcept + { + return MutexTraits ::try_lock (m_mutex); + } + + inline bool try_lock (char const*, int) const noexcept + { + return MutexTraits ::try_lock (m_mutex); + } + +private: + Mutex mutable m_mutex; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_core/threads/beast_CriticalSection.h b/Subtrees/beast/modules/beast_core/threads/beast_CriticalSection.h index 45e8055cb4..23d27cc620 100644 --- a/Subtrees/beast/modules/beast_core/threads/beast_CriticalSection.h +++ b/Subtrees/beast/modules/beast_core/threads/beast_CriticalSection.h @@ -96,6 +96,20 @@ public: /** Provides the type of scoped try-locker to use with a CriticalSection. */ typedef GenericScopedTryLock ScopedTryLockType; + //-------------------------------------------------------------------------- + // + // Boost concept compatibility + // http://www.boost.org/doc/libs/1_54_0/doc/html/thread/synchronization.html#thread.synchronization.mutex_concepts + // + + // BasicLockable + inline void lock () const noexcept { enter (); } + inline void unlock () const noexcept { exit (); } + + // Lockable + inline bool try_lock () const noexcept { return tryEnter (); } + + //-------------------------------------------------------------------------- private: //============================================================================== diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_ReadWriteMutex.cpp b/Subtrees/beast/modules/beast_core/threads/beast_ReadWriteMutex.cpp similarity index 100% rename from Subtrees/beast/modules/beast_basics/threads/beast_ReadWriteMutex.cpp rename to Subtrees/beast/modules/beast_core/threads/beast_ReadWriteMutex.cpp diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_ReadWriteMutex.h b/Subtrees/beast/modules/beast_core/threads/beast_ReadWriteMutex.h similarity index 100% rename from Subtrees/beast/modules/beast_basics/threads/beast_ReadWriteMutex.h rename to Subtrees/beast/modules/beast_core/threads/beast_ReadWriteMutex.h diff --git a/Subtrees/beast/modules/beast_core/threads/beast_ScopedLock.h b/Subtrees/beast/modules/beast_core/threads/beast_ScopedLock.h index 5ba0960b1d..5d09a59802 100644 --- a/Subtrees/beast/modules/beast_core/threads/beast_ScopedLock.h +++ b/Subtrees/beast/modules/beast_core/threads/beast_ScopedLock.h @@ -24,7 +24,6 @@ #ifndef BEAST_SCOPEDLOCK_BEASTHEADER #define BEAST_SCOPEDLOCK_BEASTHEADER - //============================================================================== /** Automatically locks and unlocks a mutex object. @@ -64,21 +63,27 @@ public: otherwise there are no guarantees what will happen! Best just to use it as a local stack object, rather than creating one with the new() operator. */ - inline explicit GenericScopedLock (const LockType& lock) noexcept : lock_ (lock) { lock.enter(); } + inline explicit GenericScopedLock (const LockType& lock) noexcept + : lock_ (lock) + { + lock.enter(); + } /** Destructor. The lock will be released when the destructor is called. Make sure this object is created and deleted by the same thread, otherwise there are no guarantees what will happen! */ - inline ~GenericScopedLock() noexcept { lock_.exit(); } + inline ~GenericScopedLock() noexcept + { + lock_.exit(); + } private: //============================================================================== const LockType& lock_; }; - //============================================================================== /** Automatically unlocks and re-locks a mutex object. @@ -132,7 +137,11 @@ public: otherwise there are no guarantees what will happen! Best just to use it as a local stack object, rather than creating one with the new() operator. */ - inline explicit GenericScopedUnlock (const LockType& lock) noexcept : lock_ (lock) { lock.exit(); } + inline explicit GenericScopedUnlock (const LockType& lock) noexcept + : lock_ (lock) + { + lock.exit(); + } /** Destructor. @@ -141,7 +150,10 @@ public: Make sure this object is created and deleted by the same thread, otherwise there are no guarantees what will happen! */ - inline ~GenericScopedUnlock() noexcept { lock_.enter(); } + inline ~GenericScopedUnlock() noexcept + { + lock_.enter(); + } private: @@ -149,7 +161,6 @@ private: const LockType& lock_; }; - //============================================================================== /** Automatically locks and unlocks a mutex object. @@ -211,10 +222,17 @@ public: Make sure this object is created and deleted by the same thread, otherwise there are no guarantees what will happen! */ - inline ~GenericScopedTryLock() noexcept { if (lockWasSuccessful) lock_.exit(); } + inline ~GenericScopedTryLock() noexcept + { + if (lockWasSuccessful) + lock_.exit(); + } /** Returns true if the mutex was successfully locked. */ - bool isLocked() const noexcept { return lockWasSuccessful; } + bool isLocked() const noexcept + { + return lockWasSuccessful; + } private: //============================================================================== @@ -222,5 +240,5 @@ private: const bool lockWasSuccessful; }; +#endif -#endif // BEAST_SCOPEDLOCK_BEASTHEADER diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_SharedData.h b/Subtrees/beast/modules/beast_core/threads/beast_SharedData.h similarity index 100% rename from Subtrees/beast/modules/beast_basics/threads/beast_SharedData.h rename to Subtrees/beast/modules/beast_core/threads/beast_SharedData.h