From 942336c4541c833a9e785ebff83144a45825547f Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Fri, 4 Oct 2013 13:49:24 -0700 Subject: [PATCH] Move many Thread related classes --- .../Builds/VisualStudio2012/beast.vcxproj | 126 ++-- .../VisualStudio2012/beast.vcxproj.filters | 181 +++--- src/beast/TODO.txt | 7 - src/beast/beast/SmartPtr.h | 2 + src/beast/beast/Threads.h | 36 ++ src/beast/beast/Utility.h | 2 + src/beast/beast/chrono/CPUMeter.h | 2 +- src/beast/beast/smart_ptr/ScopedPointer.h | 32 +- .../memory => beast/smart_ptr}/SharedObject.h | 8 + .../memory => beast/smart_ptr}/SharedPtr.h | 11 +- .../{Thread.h => smart_ptr/SmartPtr.cpp} | 19 +- .../beast/{thread => threads}/LockGuard.h | 4 +- .../{thread => threads}/RecursiveMutex.h | 4 +- .../beast/{thread => threads}/ServiceQueue.h | 4 +- .../beast/{thread => threads}/SharedData.h | 4 +- .../{thread => threads}/SharedLockGuard.h | 4 +- .../{thread => threads}/SharedMutexAdapter.h | 4 +- .../beast/{thread => threads}/SpinLock.h | 4 +- .../thread => beast/threads}/Stoppable.h | 14 +- .../beast_core => beast}/threads/Thread.h | 17 +- .../{thread => threads}/ThreadLocalValue.h | 6 +- .../Thread.cpp => threads/Threads.cpp} | 3 + .../beast/{thread => threads}/TryLockGuard.h | 4 +- .../beast/{thread => threads}/UnlockGuard.h | 4 +- .../beast/{thread => threads}/WaitableEvent.h | 4 +- src/beast/beast/threads/impl/Atomic.cpp | 133 ++++ .../impl/RecursiveMutex.cpp | 0 .../{thread => threads}/impl/ServiceQueue.cpp | 0 .../threads/impl}/Stoppable.cpp | 6 + src/beast/beast/threads/impl/Thread.cpp | 599 ++++++++++++++++++ .../impl/WaitableEvent.cpp | 0 .../utility}/LeakChecked.h | 16 +- .../memory => beast/utility}/StaticObject.h | 8 +- src/beast/beast/utility/Utility.cpp | 6 +- .../utility/impl}/LeakChecked.cpp | 6 + .../utility/impl}/StaticObject.cpp | 7 + src/beast/modules/beast_core/beast_core.cpp | 7 - src/beast/modules/beast_core/beast_core.h | 11 +- .../modules/beast_core/diagnostic/UnitTest.h | 3 +- .../beast_core/native/posix_SharedCode.h | 146 ----- .../beast_core/native/win32_Threads.cpp | 139 ---- .../beast_core/threads/ReadWriteMutex.cpp | 98 --- .../beast_core/threads/ReadWriteMutex.h | 150 ----- .../modules/beast_core/threads/Thread.cpp | 376 ----------- .../modules/beast_core/threads/ThreadPool.cpp | 371 ----------- .../modules/beast_core/threads/ThreadPool.h | 304 --------- .../beast_core/threads/TimeSliceThread.cpp | 166 ----- .../beast_core/threads/TimeSliceThread.h | 143 ----- src/ripple/beast/ripple_beast.cpp | 3 +- 49 files changed, 1045 insertions(+), 2159 deletions(-) create mode 100644 src/beast/beast/Threads.h rename src/beast/{modules/beast_core/memory => beast/smart_ptr}/SharedObject.h (98%) rename src/beast/{modules/beast_core/memory => beast/smart_ptr}/SharedPtr.h (98%) rename src/beast/beast/{Thread.h => smart_ptr/SmartPtr.cpp} (72%) rename src/beast/beast/{thread => threads}/LockGuard.h (94%) rename src/beast/beast/{thread => threads}/RecursiveMutex.h (96%) rename src/beast/beast/{thread => threads}/ServiceQueue.h (99%) rename src/beast/beast/{thread => threads}/SharedData.h (99%) rename src/beast/beast/{thread => threads}/SharedLockGuard.h (93%) rename src/beast/beast/{thread => threads}/SharedMutexAdapter.h (94%) rename src/beast/beast/{thread => threads}/SpinLock.h (97%) rename src/beast/{modules/beast_core/thread => beast/threads}/Stoppable.h (98%) rename src/beast/{modules/beast_core => beast}/threads/Thread.h (97%) rename src/beast/beast/{thread => threads}/ThreadLocalValue.h (97%) rename src/beast/beast/{thread/Thread.cpp => threads/Threads.cpp} (93%) rename src/beast/beast/{thread => threads}/TryLockGuard.h (94%) rename src/beast/beast/{thread => threads}/UnlockGuard.h (94%) rename src/beast/beast/{thread => threads}/WaitableEvent.h (98%) create mode 100644 src/beast/beast/threads/impl/Atomic.cpp rename src/beast/beast/{thread => threads}/impl/RecursiveMutex.cpp (100%) rename src/beast/beast/{thread => threads}/impl/ServiceQueue.cpp (100%) rename src/beast/{modules/beast_core/thread => beast/threads/impl}/Stoppable.cpp (98%) create mode 100644 src/beast/beast/threads/impl/Thread.cpp rename src/beast/beast/{thread => threads}/impl/WaitableEvent.cpp (100%) rename src/beast/{modules/beast_core/diagnostic => beast/utility}/LeakChecked.h (94%) rename src/beast/{modules/beast_core/memory => beast/utility}/StaticObject.h (96%) rename src/beast/{modules/beast_core/diagnostic => beast/utility/impl}/LeakChecked.cpp (98%) rename src/beast/{modules/beast_core/memory => beast/utility/impl}/StaticObject.cpp (93%) delete mode 100644 src/beast/modules/beast_core/threads/ReadWriteMutex.cpp delete mode 100644 src/beast/modules/beast_core/threads/ReadWriteMutex.h delete mode 100644 src/beast/modules/beast_core/threads/Thread.cpp delete mode 100644 src/beast/modules/beast_core/threads/ThreadPool.cpp delete mode 100644 src/beast/modules/beast_core/threads/ThreadPool.h delete mode 100644 src/beast/modules/beast_core/threads/TimeSliceThread.cpp delete mode 100644 src/beast/modules/beast_core/threads/TimeSliceThread.h diff --git a/src/beast/Builds/VisualStudio2012/beast.vcxproj b/src/beast/Builds/VisualStudio2012/beast.vcxproj index e89b435e5d..19fbebb492 100644 --- a/src/beast/Builds/VisualStudio2012/beast.vcxproj +++ b/src/beast/Builds/VisualStudio2012/beast.vcxproj @@ -140,6 +140,8 @@ + + @@ -151,19 +153,21 @@ - - - - - - - + - - - - - + + + + + + + + + + + + + @@ -175,6 +179,8 @@ + + @@ -245,7 +251,6 @@ - @@ -280,11 +285,8 @@ - - - @@ -327,17 +329,12 @@ - - - - - @@ -492,6 +489,7 @@ true + true true @@ -505,25 +503,43 @@ true - + true true true true - + true true true true - + true true true true - + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + true true @@ -542,6 +558,18 @@ true true + + true + true + true + true + + + true + true + true + true + true @@ -729,12 +757,6 @@ true true - - true - true - true - true - true true @@ -745,12 +767,6 @@ true true - - true - true - true - true - true true @@ -859,12 +875,6 @@ true true - - true - true - true - true - true true @@ -1147,36 +1157,12 @@ true true - - true - true - true - true - true true true true - - true - true - true - true - - - true - true - true - true - - - true - true - true - true - true true @@ -1189,12 +1175,6 @@ true true - - true - true - true - true - true true diff --git a/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters b/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters index ac32658afc..5a0913d2e3 100644 --- a/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters +++ b/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters @@ -234,9 +234,6 @@ {775ab0d6-aa5f-43d7-ab3b-3c01652a9ef1} - - {da8084c0-491b-4eb0-b750-97182a9deed4} - {56ef157f-ad92-4da7-8fbf-00723f769732} @@ -291,8 +288,11 @@ {4e9c54da-1581-41d7-ac75-48140e4a13d4} - - {96d46096-0e7d-4ca8-9d81-72f6834f88f8} + + {f864ff58-1055-4c56-805f-9f181c4f0aa1} + + + {386a8cd8-6be3-4cac-9bca-7a01fdb5327a} @@ -497,15 +497,6 @@ beast_core\threads - - beast_core\threads - - - beast_core\threads - - - beast_core\threads - beast_core\time @@ -587,9 +578,6 @@ beast_core\diagnostic - - beast_core\diagnostic - beast_core\diagnostic @@ -704,9 +692,6 @@ beast_core\diagnostic - - beast_core\threads - beast_core\thread @@ -800,12 +785,6 @@ beast\mpl - - beast_core\memory - - - beast_core\memory - beast_asio\async @@ -938,9 +917,6 @@ beast_core\diagnostic - - beast_core\memory - beast_crypto\math @@ -995,21 +971,6 @@ beast\mpl - - beast - - - beast\thread - - - beast\thread - - - beast\thread - - - beast\thread - beast @@ -1037,9 +998,6 @@ beast\mpl - - beast_core\thread - beast\http\impl\http-parser @@ -1212,32 +1170,65 @@ beast_asio\http - - beast\thread - - - beast\thread - - - beast\thread - beast\chrono beast\chrono - - beast\thread + + beast\smart_ptr - - beast\thread + + beast\smart_ptr - - beast\thread + + beast - - beast\thread + + beast\threads + + + beast\threads + + + beast\threads + + + beast\threads + + + beast\threads + + + beast\threads + + + beast\threads + + + beast\threads + + + beast\threads + + + beast\threads + + + beast\threads + + + beast\threads + + + beast\utility + + + beast\utility + + + beast\threads @@ -1406,15 +1397,6 @@ beast_core\threads - - beast_core\threads - - - beast_core\threads - - - beast_core\threads - beast_core\time @@ -1484,9 +1466,6 @@ beast_core\diagnostic - - beast_core\diagnostic - beast_core\threads @@ -1565,9 +1544,6 @@ beast_core\diagnostic - - beast_core\threads - beast_core\thread\impl @@ -1673,12 +1649,6 @@ beast_core\diagnostic - - beast_core\memory - - - beast_core\diagnostic - beast_crypto\math @@ -1703,9 +1673,6 @@ beast_asio\http - - beast_core\thread - beast\http\impl\http-parser @@ -1775,20 +1742,38 @@ beast_asio\http - - beast\thread\impl - - - beast\thread - beast\chrono\impl - - beast\thread\impl + + beast\smart_ptr - - beast\thread\impl + + beast\threads\impl + + + beast\threads\impl + + + beast\threads\impl + + + beast\threads\impl + + + beast\threads + + + beast\threads\impl + + + beast\utility\impl + + + beast\utility\impl + + + beast\threads\impl diff --git a/src/beast/TODO.txt b/src/beast/TODO.txt index 7ba271bd1e..965d1721e4 100644 --- a/src/beast/TODO.txt +++ b/src/beast/TODO.txt @@ -2,13 +2,6 @@ BEAST TODO -------------------------------------------------------------------------------- -- Remove ReadWriteMutex and replace it with a CriticalSection - since the implementation is broken. - -- Rewrite SharedData to work with a CriticalSection - -- Use new file naming convention - - Use SemanticVersion for beast version numbers to replace BEAST_VERSION - add support for a __PRETTY_FUNCTION__ equivalent for all environments diff --git a/src/beast/beast/SmartPtr.h b/src/beast/beast/SmartPtr.h index 1bdf1d918a..13aab726a8 100644 --- a/src/beast/beast/SmartPtr.h +++ b/src/beast/beast/SmartPtr.h @@ -23,6 +23,8 @@ #include "Config.h" #include "smart_ptr/ContainerDeletePolicy.h" +#include "smart_ptr/SharedObject.h" +#include "smart_ptr/SharedPtr.h" #include "smart_ptr/ScopedPointer.h" #endif diff --git a/src/beast/beast/Threads.h b/src/beast/beast/Threads.h new file mode 100644 index 0000000000..7336bc7771 --- /dev/null +++ b/src/beast/beast/Threads.h @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_THREADS_H_INCLUDED +#define BEAST_THREADS_H_INCLUDED + +#include "threads/LockGuard.h" +#include "threads/UnlockGuard.h" +#include "threads/TryLockGuard.h" +#include "threads/SharedLockGuard.h" +#include "threads/SharedMutexAdapter.h" +#include "threads/SharedData.h" +#include "threads/ServiceQueue.h" +#include "threads/SpinLock.h" +#include "threads/Stoppable.h" +#include "threads/Thread.h" +#include "threads/ThreadLocalValue.h" +#include "threads/WaitableEvent.h" + +#endif diff --git a/src/beast/beast/Utility.h b/src/beast/beast/Utility.h index f27cc5947c..403f78ee31 100644 --- a/src/beast/beast/Utility.h +++ b/src/beast/beast/Utility.h @@ -24,6 +24,8 @@ #include "utility/EnableIf.h" #include "utility/Error.h" #include "utility/Journal.h" +#include "utility/LeakChecked.h" +#include "utility/StaticObject.h" #endif diff --git a/src/beast/beast/chrono/CPUMeter.h b/src/beast/beast/chrono/CPUMeter.h index fd728a54e5..b78da25d74 100644 --- a/src/beast/beast/chrono/CPUMeter.h +++ b/src/beast/beast/chrono/CPUMeter.h @@ -22,7 +22,7 @@ #include "RelativeTime.h" #include "ScopedTimeInterval.h" -#include "../thread/SharedData.h" +#include "../threads/SharedData.h" #include "../Atomic.h" namespace beast { diff --git a/src/beast/beast/smart_ptr/ScopedPointer.h b/src/beast/beast/smart_ptr/ScopedPointer.h index 51d214d65e..5e16c64511 100644 --- a/src/beast/beast/smart_ptr/ScopedPointer.h +++ b/src/beast/beast/smart_ptr/ScopedPointer.h @@ -24,9 +24,11 @@ #ifndef BEAST_SMARTPTR_SCOPEDPOINTER_H_INCLUDED #define BEAST_SMARTPTR_SCOPEDPOINTER_H_INCLUDED -#include "ContainerDeletePolicy.h" +#include "../Config.h" #include "../Uncopyable.h" #include "../StaticAssert.h" + +#include "ContainerDeletePolicy.h" namespace beast { @@ -73,13 +75,13 @@ class ScopedPointer : public Uncopyable public: //============================================================================== /** Creates a ScopedPointer containing a null pointer. */ - inline ScopedPointer() noexcept + inline ScopedPointer() : object (nullptr) { } /** Creates a ScopedPointer that owns the specified object. */ - inline ScopedPointer (ObjectType* const objectToTakePossessionOf) noexcept + inline ScopedPointer (ObjectType* const objectToTakePossessionOf) : object (objectToTakePossessionOf) { } @@ -90,7 +92,7 @@ public: the pointer from the other object to this one, and the other object is reset to be a null pointer. */ - ScopedPointer (ScopedPointer& objectToTransferFrom) noexcept + ScopedPointer (ScopedPointer& objectToTransferFrom) : object (objectToTransferFrom.object) { objectToTransferFrom.object = nullptr; @@ -150,13 +152,13 @@ public: } #if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS - ScopedPointer (ScopedPointer&& other) noexcept + ScopedPointer (ScopedPointer&& other) : object (other.object) { other.object = nullptr; } - ScopedPointer& operator= (ScopedPointer&& other) noexcept + ScopedPointer& operator= (ScopedPointer&& other) { object = other.object; other.object = nullptr; @@ -166,28 +168,28 @@ public: //============================================================================== /** Returns the object that this ScopedPointer refers to. */ - inline operator ObjectType*() const noexcept { return object; } + inline operator ObjectType*() const { return object; } /** Returns the object that this ScopedPointer refers to. */ - inline ObjectType* get() const noexcept { return object; } + inline ObjectType* get() const { return object; } /** Returns the object that this ScopedPointer refers to. */ - inline ObjectType& operator*() const noexcept { return *object; } + inline ObjectType& operator*() const { return *object; } /** Lets you access methods and properties of the object that this ScopedPointer refers to. */ - inline ObjectType* operator->() const noexcept { return object; } + inline ObjectType* operator->() const { return object; } //============================================================================== /** Removes the current object from this ScopedPointer without deleting it. This will return the current object, and set the ScopedPointer to a null pointer. */ - ObjectType* release() noexcept { ObjectType* const o = object; object = nullptr; return o; } + ObjectType* release() { ObjectType* const o = object; object = nullptr; return o; } //============================================================================== /** Swaps this object with that of another ScopedPointer. The two objects simply exchange their pointers. */ - void swapWith (ScopedPointer & other) noexcept + void swapWith (ScopedPointer & other) { // Two ScopedPointers should never be able to refer to the same object - if // this happens, you must have done something dodgy! @@ -206,7 +208,7 @@ private: ObjectType* object; // (Required as an alternative to the overloaded & operator). - const ScopedPointer* getAddress() const noexcept { return this; } + const ScopedPointer* getAddress() const { return this; } #if ! BEAST_MSVC // (MSVC can't deal with multiple copy constructors) /* The copy constructors are private to stop people accidentally copying a const ScopedPointer @@ -233,7 +235,7 @@ private: This can be handy for checking whether this is a null pointer. */ template -bool operator== (const ScopedPointer& pointer1, ObjectType* const pointer2) noexcept +bool operator== (const ScopedPointer& pointer1, ObjectType* const pointer2) { return static_cast (pointer1) == pointer2; } @@ -242,7 +244,7 @@ bool operator== (const ScopedPointer& pointer1, ObjectType* const po This can be handy for checking whether this is a null pointer. */ template -bool operator!= (const ScopedPointer& pointer1, ObjectType* const pointer2) noexcept +bool operator!= (const ScopedPointer& pointer1, ObjectType* const pointer2) { return static_cast (pointer1) != pointer2; } diff --git a/src/beast/modules/beast_core/memory/SharedObject.h b/src/beast/beast/smart_ptr/SharedObject.h similarity index 98% rename from src/beast/modules/beast_core/memory/SharedObject.h rename to src/beast/beast/smart_ptr/SharedObject.h index 8efd00aeb0..53de02c7a7 100644 --- a/src/beast/modules/beast_core/memory/SharedObject.h +++ b/src/beast/beast/smart_ptr/SharedObject.h @@ -24,6 +24,12 @@ #ifndef BEAST_SHAREDOBJECT_H_INCLUDED #define BEAST_SHAREDOBJECT_H_INCLUDED +#include "../Config.h" +#include "../Atomic.h" +#include "../Uncopyable.h" + +namespace beast { + //============================================================================== /** Adds reference-counting to an object. @@ -194,4 +200,6 @@ private: int refCount; }; +} + #endif diff --git a/src/beast/modules/beast_core/memory/SharedPtr.h b/src/beast/beast/smart_ptr/SharedPtr.h similarity index 98% rename from src/beast/modules/beast_core/memory/SharedPtr.h rename to src/beast/beast/smart_ptr/SharedPtr.h index f69431c5a9..f1ce3754ce 100644 --- a/src/beast/modules/beast_core/memory/SharedPtr.h +++ b/src/beast/beast/smart_ptr/SharedPtr.h @@ -21,8 +21,13 @@ */ //============================================================================== -#ifndef BEAST_CORE_SHAREDPTR_H_INCLUDED -#define BEAST_CORE_SHAREDPTR_H_INCLUDED +#ifndef BEAST_SMARTPTR_SHAREDPTR_H_INCLUDED +#define BEAST_SMARTPTR_SHAREDPTR_H_INCLUDED + +#include "../Config.h" +#include "SharedObject.h" + +namespace beast { // Visual Studio doesn't seem to do very well when it comes // to templated constructors and assignments so we provide @@ -317,4 +322,6 @@ bool operator!= (T const* lhs, SharedPtr const& rhs) noexcept } /** @} */ +} + #endif diff --git a/src/beast/beast/Thread.h b/src/beast/beast/smart_ptr/SmartPtr.cpp similarity index 72% rename from src/beast/beast/Thread.h rename to src/beast/beast/smart_ptr/SmartPtr.cpp index 72e83d69f0..02700c5642 100644 --- a/src/beast/beast/Thread.h +++ b/src/beast/beast/smart_ptr/SmartPtr.cpp @@ -17,18 +17,9 @@ */ //============================================================================== -#ifndef BEAST_THREAD_H_INCLUDED -#define BEAST_THREAD_H_INCLUDED +#include "BeastConfig.h" -#include "thread/LockGuard.h" -#include "thread/UnlockGuard.h" -#include "thread/TryLockGuard.h" -#include "thread/SharedLockGuard.h" -#include "thread/SharedMutexAdapter.h" -#include "thread/SharedData.h" -#include "thread/ServiceQueue.h" -#include "thread/SpinLock.h" -#include "thread/ThreadLocalValue.h" -#include "thread/WaitableEvent.h" - -#endif +#include "ContainerDeletePolicy.h" +#include "ScopedPointer.h" +#include "SharedObject.h" +#include "SharedPtr.h" diff --git a/src/beast/beast/thread/LockGuard.h b/src/beast/beast/threads/LockGuard.h similarity index 94% rename from src/beast/beast/thread/LockGuard.h rename to src/beast/beast/threads/LockGuard.h index 44463df53e..a90895ae05 100644 --- a/src/beast/beast/thread/LockGuard.h +++ b/src/beast/beast/threads/LockGuard.h @@ -17,8 +17,8 @@ */ //============================================================================== -#ifndef BEAST_THREAD_LOCKGUARD_H_INCLUDED -#define BEAST_THREAD_LOCKGUARD_H_INCLUDED +#ifndef BEAST_THREADS_LOCKGUARD_H_INCLUDED +#define BEAST_THREADS_LOCKGUARD_H_INCLUDED #include "../Uncopyable.h" diff --git a/src/beast/beast/thread/RecursiveMutex.h b/src/beast/beast/threads/RecursiveMutex.h similarity index 96% rename from src/beast/beast/thread/RecursiveMutex.h rename to src/beast/beast/threads/RecursiveMutex.h index b1d45adcf1..15a2330589 100644 --- a/src/beast/beast/thread/RecursiveMutex.h +++ b/src/beast/beast/threads/RecursiveMutex.h @@ -21,8 +21,8 @@ */ //============================================================================== -#ifndef BEAST_THREAD_RECURSIVEMUTEX_H_INCLUDED -#define BEAST_THREAD_RECURSIVEMUTEX_H_INCLUDED +#ifndef BEAST_THREADS_RECURSIVEMUTEX_H_INCLUDED +#define BEAST_THREADS_RECURSIVEMUTEX_H_INCLUDED #include "../Config.h" #include "LockGuard.h" diff --git a/src/beast/beast/thread/ServiceQueue.h b/src/beast/beast/threads/ServiceQueue.h similarity index 99% rename from src/beast/beast/thread/ServiceQueue.h rename to src/beast/beast/threads/ServiceQueue.h index a9f337ec11..2199615e7b 100644 --- a/src/beast/beast/thread/ServiceQueue.h +++ b/src/beast/beast/threads/ServiceQueue.h @@ -17,8 +17,8 @@ */ //============================================================================== -#ifndef BEAST_THREAD_SERVICEQUEUE_H_INCLUDED -#define BEAST_THREAD_SERVICEQUEUE_H_INCLUDED +#ifndef BEAST_THREADS_SERVICEQUEUE_H_INCLUDED +#define BEAST_THREADS_SERVICEQUEUE_H_INCLUDED #include "../chrono/CPUMeter.h" #include "../intrusive/List.h" diff --git a/src/beast/beast/thread/SharedData.h b/src/beast/beast/threads/SharedData.h similarity index 99% rename from src/beast/beast/thread/SharedData.h rename to src/beast/beast/threads/SharedData.h index 5420540797..62e1defe72 100644 --- a/src/beast/beast/thread/SharedData.h +++ b/src/beast/beast/threads/SharedData.h @@ -17,8 +17,8 @@ */ //============================================================================== -#ifndef BEAST_THREAD_SHAREDDATA_H_INCLUDED -#define BEAST_THREAD_SHAREDDATA_H_INCLUDED +#ifndef BEAST_THREADS_SHAREDDATA_H_INCLUDED +#define BEAST_THREADS_SHAREDDATA_H_INCLUDED #include "RecursiveMutex.h" #include "SharedMutexAdapter.h" diff --git a/src/beast/beast/thread/SharedLockGuard.h b/src/beast/beast/threads/SharedLockGuard.h similarity index 93% rename from src/beast/beast/thread/SharedLockGuard.h rename to src/beast/beast/threads/SharedLockGuard.h index 07fd7ab097..82fdbd0812 100644 --- a/src/beast/beast/thread/SharedLockGuard.h +++ b/src/beast/beast/threads/SharedLockGuard.h @@ -17,8 +17,8 @@ */ //============================================================================== -#ifndef BEAST_THREAD_SHAREDLOCKGUARD_H_INCLUDED -#define BEAST_THREAD_SHAREDLOCKGUARD_H_INCLUDED +#ifndef BEAST_THREADS_SHAREDLOCKGUARD_H_INCLUDED +#define BEAST_THREADS_SHAREDLOCKGUARD_H_INCLUDED #include "../Uncopyable.h" diff --git a/src/beast/beast/thread/SharedMutexAdapter.h b/src/beast/beast/threads/SharedMutexAdapter.h similarity index 94% rename from src/beast/beast/thread/SharedMutexAdapter.h rename to src/beast/beast/threads/SharedMutexAdapter.h index b6fea18907..cb28ea51ab 100644 --- a/src/beast/beast/thread/SharedMutexAdapter.h +++ b/src/beast/beast/threads/SharedMutexAdapter.h @@ -17,8 +17,8 @@ */ //============================================================================== -#ifndef BEAST_THREAD_SHAREDMUTEXADAPTER_H_INCLUDED -#define BEAST_THREAD_SHAREDMUTEXADAPTER_H_INCLUDED +#ifndef BEAST_THREADS_SHAREDMUTEXADAPTER_H_INCLUDED +#define BEAST_THREADS_SHAREDMUTEXADAPTER_H_INCLUDED #include "LockGuard.h" #include "SharedLockGuard.h" diff --git a/src/beast/beast/thread/SpinLock.h b/src/beast/beast/threads/SpinLock.h similarity index 97% rename from src/beast/beast/thread/SpinLock.h rename to src/beast/beast/threads/SpinLock.h index 37501659c8..cbc6e0e959 100644 --- a/src/beast/beast/thread/SpinLock.h +++ b/src/beast/beast/threads/SpinLock.h @@ -21,8 +21,8 @@ */ //============================================================================== -#ifndef BEAST_THREAD_SPINLOCK_H_INCLUDED -#define BEAST_THREAD_SPINLOCK_H_INCLUDED +#ifndef BEAST_THREADS_SPINLOCK_H_INCLUDED +#define BEAST_THREADS_SPINLOCK_H_INCLUDED #include "../Atomic.h" #include "LockGuard.h" diff --git a/src/beast/modules/beast_core/thread/Stoppable.h b/src/beast/beast/threads/Stoppable.h similarity index 98% rename from src/beast/modules/beast_core/thread/Stoppable.h rename to src/beast/beast/threads/Stoppable.h index c556df5d4e..637b078c0f 100644 --- a/src/beast/modules/beast_core/thread/Stoppable.h +++ b/src/beast/beast/threads/Stoppable.h @@ -17,8 +17,16 @@ */ //============================================================================== -#ifndef BEAST_CORE_STOPPABLE_H_INCLUDED -#define BEAST_CORE_STOPPABLE_H_INCLUDED +#ifndef BEAST_THREADS_STOPPABLE_H_INCLUDED +#define BEAST_THREADS_STOPPABLE_H_INCLUDED + +#include "../Atomic.h" +#include "../intrusive/LockFreeStack.h" +#include "../utility/Journal.h" + +#include "WaitableEvent.h" + +namespace beast { class RootStoppable; @@ -314,4 +322,6 @@ private: }; /** @} */ +} + #endif diff --git a/src/beast/modules/beast_core/threads/Thread.h b/src/beast/beast/threads/Thread.h similarity index 97% rename from src/beast/modules/beast_core/threads/Thread.h rename to src/beast/beast/threads/Thread.h index 8cf8cf1510..1ea34f7c14 100644 --- a/src/beast/modules/beast_core/threads/Thread.h +++ b/src/beast/beast/threads/Thread.h @@ -21,8 +21,14 @@ */ //============================================================================== -#ifndef BEAST_JUCE_THREAD_H_INCLUDED -#define BEAST_JUCE_THREAD_H_INCLUDED +#ifndef BEAST_THREADS_THREAD_H_INCLUDED +#define BEAST_THREADS_THREAD_H_INCLUDED + +#include "../utility/LeakChecked.h" +#include "RecursiveMutex.h" +#include "WaitableEvent.h" + +namespace beast { //============================================================================== /** @@ -265,7 +271,7 @@ private: const String threadName; void* volatile threadHandle; ThreadID threadId; - CriticalSection startStopLock; + RecursiveMutex startStopLock; WaitableEvent startSuspensionEvent, defaultEvent; int threadPriority; uint32 affinityMask; @@ -282,4 +288,7 @@ private: static bool setThreadPriority (void*, int); }; -#endif // BEAST_THREAD_H_INCLUDED +} + +#endif + diff --git a/src/beast/beast/thread/ThreadLocalValue.h b/src/beast/beast/threads/ThreadLocalValue.h similarity index 97% rename from src/beast/beast/thread/ThreadLocalValue.h rename to src/beast/beast/threads/ThreadLocalValue.h index 4b7e4908d5..751062efe4 100644 --- a/src/beast/beast/thread/ThreadLocalValue.h +++ b/src/beast/beast/threads/ThreadLocalValue.h @@ -21,10 +21,12 @@ */ //============================================================================== -#ifndef BEAST_THREAD_THREADLOCALVALUE_H_INCLUDED -#define BEAST_THREAD_THREADLOCALVALUE_H_INCLUDED +#ifndef BEAST_THREADS_THREADLOCALVALUE_H_INCLUDED +#define BEAST_THREADS_THREADLOCALVALUE_H_INCLUDED #include "../Config.h" +#include "SpinLock.h" +#include "Thread.h" namespace beast { diff --git a/src/beast/beast/thread/Thread.cpp b/src/beast/beast/threads/Threads.cpp similarity index 93% rename from src/beast/beast/thread/Thread.cpp rename to src/beast/beast/threads/Threads.cpp index 7bd7438ec9..a941c1e848 100644 --- a/src/beast/beast/thread/Thread.cpp +++ b/src/beast/beast/threads/Threads.cpp @@ -19,6 +19,9 @@ #include "BeastConfig.h" +#include "impl/Atomic.cpp" #include "impl/RecursiveMutex.cpp" #include "impl/ServiceQueue.cpp" +#include "impl/Stoppable.cpp" +#include "impl/Thread.cpp" #include "impl/WaitableEvent.cpp" diff --git a/src/beast/beast/thread/TryLockGuard.h b/src/beast/beast/threads/TryLockGuard.h similarity index 94% rename from src/beast/beast/thread/TryLockGuard.h rename to src/beast/beast/threads/TryLockGuard.h index 0f9d65c14c..f61f8bb6e1 100644 --- a/src/beast/beast/thread/TryLockGuard.h +++ b/src/beast/beast/threads/TryLockGuard.h @@ -17,8 +17,8 @@ */ //============================================================================== -#ifndef BEAST_THREAD_TRYLOCKGUARD_H_INCLUDED -#define BEAST_THREAD_TRYLOCKGUARD_H_INCLUDED +#ifndef BEAST_THREADS_TRYLOCKGUARD_H_INCLUDED +#define BEAST_THREADS_TRYLOCKGUARD_H_INCLUDED #include "../Uncopyable.h" diff --git a/src/beast/beast/thread/UnlockGuard.h b/src/beast/beast/threads/UnlockGuard.h similarity index 94% rename from src/beast/beast/thread/UnlockGuard.h rename to src/beast/beast/threads/UnlockGuard.h index c53b4d06a7..ea412765f6 100644 --- a/src/beast/beast/thread/UnlockGuard.h +++ b/src/beast/beast/threads/UnlockGuard.h @@ -17,8 +17,8 @@ */ //============================================================================== -#ifndef BEAST_THREAD_UNLOCKGUARD_H_INCLUDED -#define BEAST_THREAD_UNLOCKGUARD_H_INCLUDED +#ifndef BEAST_THREADS_UNLOCKGUARD_H_INCLUDED +#define BEAST_THREADS_UNLOCKGUARD_H_INCLUDED #include "../Uncopyable.h" diff --git a/src/beast/beast/thread/WaitableEvent.h b/src/beast/beast/threads/WaitableEvent.h similarity index 98% rename from src/beast/beast/thread/WaitableEvent.h rename to src/beast/beast/threads/WaitableEvent.h index e4f4191046..1e8b2a2cba 100644 --- a/src/beast/beast/thread/WaitableEvent.h +++ b/src/beast/beast/threads/WaitableEvent.h @@ -21,8 +21,8 @@ */ //============================================================================== -#ifndef BEAST_WAITABLEEVENT_H_INCLUDED -#define BEAST_WAITABLEEVENT_H_INCLUDED +#ifndef BEAST_THREADS_WAITABLEEVENT_H_INCLUDED +#define BEAST_THREADS_WAITABLEEVENT_H_INCLUDED #include "../Config.h" #include "../Uncopyable.h" diff --git a/src/beast/beast/threads/impl/Atomic.cpp b/src/beast/beast/threads/impl/Atomic.cpp new file mode 100644 index 0000000000..5f1790fd48 --- /dev/null +++ b/src/beast/beast/threads/impl/Atomic.cpp @@ -0,0 +1,133 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Portions of this file are from JUCE. + Copyright (c) 2013 - Raw Material Software Ltd. + Please visit http://www.juce.com + + 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 "../../../modules/beast_core/beast_core.h" // for UnitTest + +namespace beast { + +class AtomicTests : public UnitTest +{ +public: + AtomicTests() : UnitTest ("Atomic", "beast") {} + + template + void testFloat () + { + Atomic a, b; + a = (Type) 21; + memoryBarrier(); + + /* These are some simple test cases to check the atomics - let me know + if any of these assertions fail on your system! + */ + expect (a.get() == (Type) 21); + expect (a.compareAndSetValue ((Type) 100, (Type) 50) == (Type) 21); + expect (a.get() == (Type) 21); + expect (a.compareAndSetValue ((Type) 101, a.get()) == (Type) 21); + expect (a.get() == (Type) 101); + expect (! a.compareAndSetBool ((Type) 300, (Type) 200)); + expect (a.get() == (Type) 101); + expect (a.compareAndSetBool ((Type) 200, a.get())); + expect (a.get() == (Type) 200); + + expect (a.exchange ((Type) 300) == (Type) 200); + expect (a.get() == (Type) 300); + + b = a; + expect (b.get() == a.get()); + } + + template + void testInteger () + { + Atomic a, b; + a.set ((Type) 10); + expect (a.value == (Type) 10); + expect (a.get() == (Type) 10); + a += (Type) 15; + expect (a.get() == (Type) 25); + memoryBarrier(); + a -= (Type) 5; + expect (a.get() == (Type) 20); + expect (++a == (Type) 21); + ++a; + expect (--a == (Type) 21); + expect (a.get() == (Type) 21); + memoryBarrier(); + + testFloat (); + } + + void runTest() + { + beginTestCase ("Misc"); + + char a1[7]; + expect (numElementsInArray(a1) == 7); + int a2[3]; + expect (numElementsInArray(a2) == 3); + + expect (ByteOrder::swap ((uint16) 0x1122) == 0x2211); + expect (ByteOrder::swap ((uint32) 0x11223344) == 0x44332211); + expect (ByteOrder::swap ((uint64) literal64bit (0x1122334455667788)) == literal64bit (0x8877665544332211)); + + beginTestCase ("int"); + testInteger (); + + beginTestCase ("unsigned int"); + testInteger (); + + beginTestCase ("int32"); + testInteger (); + + beginTestCase ("uint32"); + testInteger (); + + beginTestCase ("long"); + testInteger (); + + beginTestCase ("void*"); + testInteger (); + + beginTestCase ("int*"); + testInteger (); + + beginTestCase ("float"); + testFloat (); + + #if ! BEAST_64BIT_ATOMICS_UNAVAILABLE // 64-bit intrinsics aren't available on some old platforms + beginTestCase ("int64"); + testInteger (); + + beginTestCase ("uint64"); + testInteger (); + + beginTestCase ("double"); + testFloat (); + #endif + } +}; + +static AtomicTests atomicTests; + +} diff --git a/src/beast/beast/thread/impl/RecursiveMutex.cpp b/src/beast/beast/threads/impl/RecursiveMutex.cpp similarity index 100% rename from src/beast/beast/thread/impl/RecursiveMutex.cpp rename to src/beast/beast/threads/impl/RecursiveMutex.cpp diff --git a/src/beast/beast/thread/impl/ServiceQueue.cpp b/src/beast/beast/threads/impl/ServiceQueue.cpp similarity index 100% rename from src/beast/beast/thread/impl/ServiceQueue.cpp rename to src/beast/beast/threads/impl/ServiceQueue.cpp diff --git a/src/beast/modules/beast_core/thread/Stoppable.cpp b/src/beast/beast/threads/impl/Stoppable.cpp similarity index 98% rename from src/beast/modules/beast_core/thread/Stoppable.cpp rename to src/beast/beast/threads/impl/Stoppable.cpp index fc6f57cdfc..75e01986aa 100644 --- a/src/beast/modules/beast_core/thread/Stoppable.cpp +++ b/src/beast/beast/threads/impl/Stoppable.cpp @@ -17,6 +17,10 @@ */ //============================================================================== +#include "../Stoppable.h" + +namespace beast { + Stoppable::Stoppable (char const* name, RootStoppable& root) : m_name (name) , m_root (root) @@ -190,3 +194,5 @@ void RootStoppable::stopAsync () stopAsyncRecursive (); } + +} diff --git a/src/beast/beast/threads/impl/Thread.cpp b/src/beast/beast/threads/impl/Thread.cpp new file mode 100644 index 0000000000..d6969552b5 --- /dev/null +++ b/src/beast/beast/threads/impl/Thread.cpp @@ -0,0 +1,599 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Portions of this file are from JUCE. + Copyright (c) 2013 - Raw Material Software Ltd. + Please visit http://www.juce.com + + 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 "../Thread.h" + +namespace beast { + +Thread::Thread (const String& threadName_) + : threadName (threadName_), + threadHandle (nullptr), + threadId (0), + threadPriority (5), + affinityMask (0), + shouldExit (false) +{ +} + +Thread::~Thread() +{ + /* If your thread class's destructor has been called without first stopping the thread, that + means that this partially destructed object is still performing some work - and that's + probably a Bad Thing! + + To avoid this type of nastiness, always make sure you call stopThread() before or during + your subclass's destructor. + */ + check_precondition (! isThreadRunning()); + + stopThread (); +} + +//============================================================================== +// Use a ref-counted object to hold this shared data, so that it can outlive its static +// shared pointer when threads are still running during static shutdown. +struct CurrentThreadHolder : public SharedObject +{ + CurrentThreadHolder() noexcept {} + + typedef SharedPtr Ptr; + ThreadLocalValue value; +}; + +static char currentThreadHolderLock [sizeof (SpinLock)]; // (statically initialised to zeros). + +static SpinLock* castToSpinLockWithoutAliasingWarning (void* s) +{ + return static_cast (s); +} + +static CurrentThreadHolder::Ptr getCurrentThreadHolder() +{ + static CurrentThreadHolder::Ptr currentThreadHolder; + SpinLock::ScopedLockType lock (*castToSpinLockWithoutAliasingWarning (currentThreadHolderLock)); + + if (currentThreadHolder == nullptr) + currentThreadHolder = new CurrentThreadHolder(); + + return currentThreadHolder; +} + +void Thread::threadEntryPoint() +{ + const CurrentThreadHolder::Ptr currentThreadHolder (getCurrentThreadHolder()); + currentThreadHolder->value = this; + + if (threadName.isNotEmpty()) + setCurrentThreadName (threadName); + + if (startSuspensionEvent.wait (10000)) + { + bassert (getCurrentThreadId() == threadId); + + if (affinityMask != 0) + setCurrentThreadAffinityMask (affinityMask); + + run(); + } + + currentThreadHolder->value.releaseCurrentThreadStorage(); + closeThreadHandle(); +} + +// used to wrap the incoming call from the platform-specific code +void BEAST_API beast_threadEntryPoint (void* userData) +{ + static_cast (userData)->threadEntryPoint(); +} + +//============================================================================== +void Thread::startThread() +{ + const RecursiveMutex::ScopedLockType sl (startStopLock); + + shouldExit = false; + + if (threadHandle == nullptr) + { + launchThread(); + setThreadPriority (threadHandle, threadPriority); + startSuspensionEvent.signal(); + } +} + +void Thread::startThread (const int priority) +{ + const RecursiveMutex::ScopedLockType sl (startStopLock); + + if (threadHandle == nullptr) + { + threadPriority = priority; + startThread(); + } + else + { + setPriority (priority); + } +} + +bool Thread::isThreadRunning() const +{ + return threadHandle != nullptr; +} + +Thread* Thread::getCurrentThread() +{ + return getCurrentThreadHolder()->value.get(); +} + +//============================================================================== +void Thread::signalThreadShouldExit() +{ + shouldExit = true; +} + +bool Thread::waitForThreadToExit (const int timeOutMilliseconds) const +{ + // Doh! So how exactly do you expect this thread to wait for itself to stop?? + bassert (getThreadId() != getCurrentThreadId() || getCurrentThreadId() == 0); + + const uint32 timeoutEnd = Time::getMillisecondCounter() + (uint32) timeOutMilliseconds; + + while (isThreadRunning()) + { + if (timeOutMilliseconds >= 0 && Time::getMillisecondCounter() > timeoutEnd) + return false; + + sleep (2); + } + + return true; +} + +bool Thread::stopThread (const int timeOutMilliseconds) +{ + bool cleanExit = true; + + // agh! You can't stop the thread that's calling this method! How on earth + // would that work?? + bassert (getCurrentThreadId() != getThreadId()); + + const RecursiveMutex::ScopedLockType sl (startStopLock); + + if (isThreadRunning()) + { + signalThreadShouldExit(); + notify(); + + if (timeOutMilliseconds != 0) + { + cleanExit = waitForThreadToExit (timeOutMilliseconds); + } + + if (isThreadRunning()) + { + bassert (! cleanExit); + + // very bad karma if this point is reached, as there are bound to be + // locks and events left in silly states when a thread is killed by force.. + killThread(); + + threadHandle = nullptr; + threadId = 0; + + cleanExit = false; + } + else + { + cleanExit = true; + } + } + + return cleanExit; +} + +void Thread::stopThreadAsync () +{ + const RecursiveMutex::ScopedLockType sl (startStopLock); + + if (isThreadRunning()) + { + signalThreadShouldExit(); + notify(); + } +} + +//============================================================================== +bool Thread::setPriority (const int newPriority) +{ + // NB: deadlock possible if you try to set the thread prio from the thread itself, + // so using setCurrentThreadPriority instead in that case. + if (getCurrentThreadId() == getThreadId()) + return setCurrentThreadPriority (newPriority); + + const RecursiveMutex::ScopedLockType sl (startStopLock); + + if (setThreadPriority (threadHandle, newPriority)) + { + threadPriority = newPriority; + return true; + } + + return false; +} + +bool Thread::setCurrentThreadPriority (const int newPriority) +{ + return setThreadPriority (0, newPriority); +} + +void Thread::setAffinityMask (const uint32 newAffinityMask) +{ + affinityMask = newAffinityMask; +} + +//============================================================================== +bool Thread::wait (const int timeOutMilliseconds) const +{ + return defaultEvent.wait (timeOutMilliseconds); +} + +void Thread::notify() const +{ + defaultEvent.signal(); +} + +//============================================================================== + +// This is here so we dont have circular includes +// +void SpinLock::enter() const noexcept +{ + if (! tryEnter()) + { + for (int i = 20; --i >= 0;) + if (tryEnter()) + return; + + while (! tryEnter()) + Thread::yield(); + } +} + +} + +//------------------------------------------------------------------------------ + +#if BEAST_WINDOWS + +#include +#include +#include + +namespace beast { + +HWND beast_messageWindowHandle = 0; // (this is used by other parts of the codebase) + +void BEAST_API beast_threadEntryPoint (void*); + +static unsigned int __stdcall threadEntryProc (void* userData) +{ + if (beast_messageWindowHandle != 0) + AttachThreadInput (GetWindowThreadProcessId (beast_messageWindowHandle, 0), + GetCurrentThreadId(), TRUE); + + beast_threadEntryPoint (userData); + + _endthreadex (0); + return 0; +} + +void Thread::launchThread() +{ + unsigned int newThreadId; + threadHandle = (void*) _beginthreadex (0, 0, &threadEntryProc, this, 0, &newThreadId); + threadId = (ThreadID) newThreadId; +} + +void Thread::closeThreadHandle() +{ + CloseHandle ((HANDLE) threadHandle); + threadId = 0; + threadHandle = 0; +} + +void Thread::killThread() +{ + if (threadHandle != 0) + { + #if BEAST_DEBUG + OutputDebugStringA ("** Warning - Forced thread termination **\n"); + #endif + TerminateThread (threadHandle, 0); + } +} + +void Thread::setCurrentThreadName (const String& name) +{ + #if BEAST_DEBUG && BEAST_MSVC + struct + { + DWORD dwType; + LPCSTR szName; + DWORD dwThreadID; + DWORD dwFlags; + } info; + + info.dwType = 0x1000; + info.szName = name.toUTF8(); + info.dwThreadID = GetCurrentThreadId(); + info.dwFlags = 0; + + __try + { + RaiseException (0x406d1388 /*MS_VC_EXCEPTION*/, 0, sizeof (info) / sizeof (ULONG_PTR), (ULONG_PTR*) &info); + } + __except (EXCEPTION_CONTINUE_EXECUTION) + {} + #else + (void) name; + #endif +} + +Thread::ThreadID Thread::getCurrentThreadId() +{ + return (ThreadID) (pointer_sized_int) GetCurrentThreadId(); +} + +bool Thread::setThreadPriority (void* handle, int priority) +{ + int pri = THREAD_PRIORITY_TIME_CRITICAL; + + if (priority < 1) pri = THREAD_PRIORITY_IDLE; + else if (priority < 2) pri = THREAD_PRIORITY_LOWEST; + else if (priority < 5) pri = THREAD_PRIORITY_BELOW_NORMAL; + else if (priority < 7) pri = THREAD_PRIORITY_NORMAL; + else if (priority < 9) pri = THREAD_PRIORITY_ABOVE_NORMAL; + else if (priority < 10) pri = THREAD_PRIORITY_HIGHEST; + + if (handle == 0) + handle = GetCurrentThread(); + + return SetThreadPriority (handle, pri) != FALSE; +} + +void Thread::setCurrentThreadAffinityMask (const uint32 affinityMask) +{ + SetThreadAffinityMask (GetCurrentThread(), affinityMask); +} + +struct SleepEvent +{ + SleepEvent() noexcept + : handle (CreateEvent (nullptr, FALSE, FALSE, + #if BEAST_DEBUG + _T("BEAST Sleep Event"))) + #else + nullptr)) + #endif + {} + + ~SleepEvent() noexcept + { + CloseHandle (handle); + handle = 0; + } + + HANDLE handle; +}; + +static SleepEvent sleepEvent; + +void BEAST_CALLTYPE Thread::sleep (const int millisecs) +{ + if (millisecs >= 10 || sleepEvent.handle == 0) + { + Sleep ((DWORD) millisecs); + } + else + { + // unlike Sleep() this is guaranteed to return to the current thread after + // the time expires, so we'll use this for short waits, which are more likely + // to need to be accurate + WaitForSingleObject (sleepEvent.handle, (DWORD) millisecs); + } +} + +void Thread::yield() +{ + Sleep (0); +} + +} + +//------------------------------------------------------------------------------ + +#else + +#include +#if BEAST_BSD + // ??? +#else +# include +#endif + +namespace beast { + +void BEAST_CALLTYPE Thread::sleep (int millisecs) +{ + struct timespec time; + time.tv_sec = millisecs / 1000; + time.tv_nsec = (millisecs % 1000) * 1000000; + nanosleep (&time, nullptr); +} + +void BEAST_API beast_threadEntryPoint (void*); + +extern "C" void* threadEntryProc (void*); +extern "C" void* threadEntryProc (void* userData) +{ + BEAST_AUTORELEASEPOOL + { + #if BEAST_ANDROID + struct AndroidThreadScope + { + AndroidThreadScope() { threadLocalJNIEnvHolder.attach(); } + ~AndroidThreadScope() { threadLocalJNIEnvHolder.detach(); } + }; + + const AndroidThreadScope androidEnv; + #endif + + beast_threadEntryPoint (userData); + } + + return nullptr; +} + +void Thread::launchThread() +{ + threadHandle = 0; + pthread_t handle = 0; + + if (pthread_create (&handle, 0, threadEntryProc, this) == 0) + { + pthread_detach (handle); + threadHandle = (void*) handle; + threadId = (ThreadID) threadHandle; + } +} + +void Thread::closeThreadHandle() +{ + threadId = 0; + threadHandle = 0; +} + +void Thread::killThread() +{ + if (threadHandle != 0) + { + #if BEAST_ANDROID + bassertfalse; // pthread_cancel not available! + #else + pthread_cancel ((pthread_t) threadHandle); + #endif + } +} + +void Thread::setCurrentThreadName (const String& name) +{ + #if BEAST_IOS || (BEAST_MAC && defined (MAC_OS_X_VERSION_10_5) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) + BEAST_AUTORELEASEPOOL + { + [[NSThread currentThread] setName: beastStringToNS (name)]; + } + #elif BEAST_LINUX + #if (__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2012 + pthread_setname_np (pthread_self(), name.toRawUTF8()); + #else + prctl (PR_SET_NAME, name.toRawUTF8(), 0, 0, 0); + #endif + #endif +} + +bool Thread::setThreadPriority (void* handle, int priority) +{ + struct sched_param param; + int policy; + priority = blimit (0, 10, priority); + + if (handle == nullptr) + handle = (void*) pthread_self(); + + if (pthread_getschedparam ((pthread_t) handle, &policy, ¶m) != 0) + return false; + + policy = priority == 0 ? SCHED_OTHER : SCHED_RR; + + const int minPriority = sched_get_priority_min (policy); + const int maxPriority = sched_get_priority_max (policy); + + param.sched_priority = ((maxPriority - minPriority) * priority) / 10 + minPriority; + return pthread_setschedparam ((pthread_t) handle, policy, ¶m) == 0; +} + +Thread::ThreadID Thread::getCurrentThreadId() +{ + return (ThreadID) pthread_self(); +} + +void Thread::yield() +{ + sched_yield(); +} + +//============================================================================== +/* Remove this macro if you're having problems compiling the cpu affinity + calls (the API for these has changed about quite a bit in various Linux + versions, and a lot of distros seem to ship with obsolete versions) +*/ +#if defined (CPU_ISSET) && ! defined (SUPPORT_AFFINITIES) + #define SUPPORT_AFFINITIES 1 +#endif + +void Thread::setCurrentThreadAffinityMask (const uint32 affinityMask) +{ + #if SUPPORT_AFFINITIES + cpu_set_t affinity; + CPU_ZERO (&affinity); + + for (int i = 0; i < 32; ++i) + if ((affinityMask & (1 << i)) != 0) + CPU_SET (i, &affinity); + + /* + N.B. If this line causes a compile error, then you've probably not got the latest + version of glibc installed. + + If you don't want to update your copy of glibc and don't care about cpu affinities, + then you can just disable all this stuff by setting the SUPPORT_AFFINITIES macro to 0. + */ + sched_setaffinity (getpid(), sizeof (cpu_set_t), &affinity); + sched_yield(); + + #else + /* affinities aren't supported because either the appropriate header files weren't found, + or the SUPPORT_AFFINITIES macro was turned off + */ + bassertfalse; + (void) affinityMask; + #endif +} + +} + +//------------------------------------------------------------------------------ + +#endif + diff --git a/src/beast/beast/thread/impl/WaitableEvent.cpp b/src/beast/beast/threads/impl/WaitableEvent.cpp similarity index 100% rename from src/beast/beast/thread/impl/WaitableEvent.cpp rename to src/beast/beast/threads/impl/WaitableEvent.cpp diff --git a/src/beast/modules/beast_core/diagnostic/LeakChecked.h b/src/beast/beast/utility/LeakChecked.h similarity index 94% rename from src/beast/modules/beast_core/diagnostic/LeakChecked.h rename to src/beast/beast/utility/LeakChecked.h index 6e63f9fe55..296d315efb 100644 --- a/src/beast/modules/beast_core/diagnostic/LeakChecked.h +++ b/src/beast/beast/utility/LeakChecked.h @@ -17,11 +17,17 @@ */ //============================================================================== -#ifndef BEAST_LEAKCHECKED_H_INCLUDED -#define BEAST_LEAKCHECKED_H_INCLUDED +#ifndef BEAST_UTILITY_LEAKCHECKED_H_INCLUDED +#define BEAST_UTILITY_LEAKCHECKED_H_INCLUDED -namespace detail -{ +#include "../Config.h" +#include "../Atomic.h" +#include "../intrusive/LockFreeStack.h" +#include "StaticObject.h" + +namespace beast { + +namespace detail { class LeakCheckedBase { @@ -169,4 +175,6 @@ using detail::disabled::LeakChecked; using detail::disabled::LeakCheckedBase; #endif +} + #endif diff --git a/src/beast/modules/beast_core/memory/StaticObject.h b/src/beast/beast/utility/StaticObject.h similarity index 96% rename from src/beast/modules/beast_core/memory/StaticObject.h rename to src/beast/beast/utility/StaticObject.h index 8b0d5a93f7..30ab11cb9d 100644 --- a/src/beast/modules/beast_core/memory/StaticObject.h +++ b/src/beast/beast/utility/StaticObject.h @@ -17,8 +17,10 @@ */ //============================================================================== -#ifndef BEAST_STATICOBJECT_H_INCLUDED -#define BEAST_STATICOBJECT_H_INCLUDED +#ifndef BEAST_UTILITY_STATICOBJECT_H_INCLUDED +#define BEAST_UTILITY_STATICOBJECT_H_INCLUDED + +namespace beast { // Spec: N2914=09-0104 // @@ -106,4 +108,6 @@ private: }; }; +} + #endif diff --git a/src/beast/beast/utility/Utility.cpp b/src/beast/beast/utility/Utility.cpp index 0eac282565..f66ea5a69a 100644 --- a/src/beast/beast/utility/Utility.cpp +++ b/src/beast/beast/utility/Utility.cpp @@ -21,8 +21,10 @@ #include "impl/Error.cpp" - // For Journal and Debug #include "../../modules/beast_core/beast_core.h" -#include "impl/Journal.cpp" + #include "impl/Debug.cpp" +#include "impl/Journal.cpp" +#include "impl/LeakChecked.cpp" +#include "impl/StaticObject.cpp" diff --git a/src/beast/modules/beast_core/diagnostic/LeakChecked.cpp b/src/beast/beast/utility/impl/LeakChecked.cpp similarity index 98% rename from src/beast/modules/beast_core/diagnostic/LeakChecked.cpp rename to src/beast/beast/utility/impl/LeakChecked.cpp index 7f7d51b64a..2209995e68 100644 --- a/src/beast/modules/beast_core/diagnostic/LeakChecked.cpp +++ b/src/beast/beast/utility/impl/LeakChecked.cpp @@ -17,6 +17,10 @@ */ //============================================================================== +#include "../LeakChecked.h" + +namespace beast { + namespace detail { @@ -124,3 +128,5 @@ void LeakCheckedBase::checkForLeaks () } } + +} diff --git a/src/beast/modules/beast_core/memory/StaticObject.cpp b/src/beast/beast/utility/impl/StaticObject.cpp similarity index 93% rename from src/beast/modules/beast_core/memory/StaticObject.cpp rename to src/beast/beast/utility/impl/StaticObject.cpp index 7482b0a172..5b44bb0dd7 100644 --- a/src/beast/modules/beast_core/memory/StaticObject.cpp +++ b/src/beast/beast/utility/impl/StaticObject.cpp @@ -17,6 +17,11 @@ */ //============================================================================== +#include "../StaticObject.h" +#include "../../threads/Thread.h" + +namespace beast { + namespace detail { @@ -32,3 +37,5 @@ void staticObjectWait (std::size_t n) } } + +} diff --git a/src/beast/modules/beast_core/beast_core.cpp b/src/beast/modules/beast_core/beast_core.cpp index da04f4dbe1..8608e180d1 100644 --- a/src/beast/modules/beast_core/beast_core.cpp +++ b/src/beast/modules/beast_core/beast_core.cpp @@ -137,7 +137,6 @@ namespace beast #include "diagnostic/FatalError.cpp" #include "diagnostic/FPUFlags.cpp" -#include "diagnostic/LeakChecked.cpp" #include "diagnostic/SemanticVersion.cpp" #include "diagnostic/UnitTest.cpp" #include "diagnostic/UnitTestUtilities.cpp" @@ -161,7 +160,6 @@ namespace beast #include "maths/Random.cpp" #include "memory/MemoryBlock.cpp" -#include "memory/StaticObject.cpp" #include "misc/Main.cpp" #include "misc/Result.cpp" @@ -192,17 +190,12 @@ namespace beast #include "thread/impl/TrackedMutex.cpp" #include "thread/DeadlineTimer.cpp" -#include "thread/Stoppable.cpp" #include "thread/Semaphore.cpp" #include "thread/Workers.cpp" #include "threads/ChildProcess.cpp" #include "threads/ReadWriteLock.cpp" -#include "threads/ReadWriteMutex.cpp" #include "threads/SpinDelay.cpp" -#include "threads/Thread.cpp" -#include "threads/ThreadPool.cpp" -#include "threads/TimeSliceThread.cpp" #include "time/PerformanceCounter.cpp" #include "time/AtExitHook.cpp" diff --git a/src/beast/modules/beast_core/beast_core.h b/src/beast/modules/beast_core/beast_core.h index aa34fde6cb..fff039ba9f 100644 --- a/src/beast/modules/beast_core/beast_core.h +++ b/src/beast/modules/beast_core/beast_core.h @@ -58,7 +58,7 @@ #include "../../beast/SafeBool.h" #include "../../beast/Strings.h" #include "../../beast/TypeTraits.h" -#include "../../beast/Thread.h" +#include "../../beast/Threads.h" #include "../../beast/Utility.h" #include "../../beast/Chrono.h" @@ -81,10 +81,8 @@ class FileOutputStream; #include "memory/AtomicPointer.h" #include "memory/AtomicState.h" #include "threads/SpinDelay.h" -#include "memory/StaticObject.h" #include "time/AtExitHook.h" -#include "diagnostic/LeakChecked.h" #include "time/Time.h" #include "threads/ScopedLock.h" #include "threads/CriticalSection.h" @@ -147,8 +145,6 @@ class FileOutputStream; #include "memory/MemoryAlignment.h" #include "memory/CacheLine.h" -#include "threads/ReadWriteMutex.h" -#include "threads/Thread.h" #include "thread/MutexTraits.h" #include "thread/TrackedMutex.h" #include "diagnostic/FatalError.h" @@ -157,8 +153,6 @@ class FileOutputStream; #include "maths/uint24.h" #include "logging/Logger.h" #include "diagnostic/FPUFlags.h" -#include "memory/SharedObject.h" -#include "memory/SharedPtr.h" #include "memory/SharedFunction.h" #include "containers/AbstractFifo.h" #include "text/Identifier.h" @@ -223,8 +217,6 @@ class FileOutputStream; #include "threads/Process.h" #include "threads/ScopedReadLock.h" #include "threads/ScopedWriteLock.h" -#include "threads/ThreadPool.h" -#include "threads/TimeSliceThread.h" #include "diagnostic/UnitTest.h" #include "xml/XmlDocument.h" #include "xml/XmlElement.h" @@ -238,7 +230,6 @@ class FileOutputStream; #include "thread/DeadlineTimer.h" #include "thread/Semaphore.h" -#include "thread/Stoppable.h" #include "thread/Workers.h" } diff --git a/src/beast/modules/beast_core/diagnostic/UnitTest.h b/src/beast/modules/beast_core/diagnostic/UnitTest.h index 7f1d671751..72b9140f8f 100644 --- a/src/beast/modules/beast_core/diagnostic/UnitTest.h +++ b/src/beast/modules/beast_core/diagnostic/UnitTest.h @@ -170,8 +170,7 @@ public: } }; - /** The type of a list of tests. - */ + /** The type of a list of tests. */ typedef Array TestList; //-------------------------------------------------------------------------- diff --git a/src/beast/modules/beast_core/native/posix_SharedCode.h b/src/beast/modules/beast_core/native/posix_SharedCode.h index 95e72f9c33..4d72928d40 100644 --- a/src/beast/modules/beast_core/native/posix_SharedCode.h +++ b/src/beast/modules/beast_core/native/posix_SharedCode.h @@ -39,13 +39,6 @@ bool CriticalSection::tryEnter() const noexcept { return pthread_mutex_trylock ( void CriticalSection::exit() const noexcept { pthread_mutex_unlock (&mutex); } //============================================================================== -void BEAST_CALLTYPE Thread::sleep (int millisecs) -{ - struct timespec time; - time.tv_sec = millisecs / 1000; - time.tv_nsec = (millisecs % 1000) * 1000000; - nanosleep (&time, nullptr); -} void Process::terminate() { @@ -913,146 +906,7 @@ void InterProcessLock::exit() } //============================================================================== -void BEAST_API beast_threadEntryPoint (void*); -extern "C" void* threadEntryProc (void*); -extern "C" void* threadEntryProc (void* userData) -{ - BEAST_AUTORELEASEPOOL - { - #if BEAST_ANDROID - struct AndroidThreadScope - { - AndroidThreadScope() { threadLocalJNIEnvHolder.attach(); } - ~AndroidThreadScope() { threadLocalJNIEnvHolder.detach(); } - }; - - const AndroidThreadScope androidEnv; - #endif - - beast_threadEntryPoint (userData); - } - - return nullptr; -} - -void Thread::launchThread() -{ - threadHandle = 0; - pthread_t handle = 0; - - if (pthread_create (&handle, 0, threadEntryProc, this) == 0) - { - pthread_detach (handle); - threadHandle = (void*) handle; - threadId = (ThreadID) threadHandle; - } -} - -void Thread::closeThreadHandle() -{ - threadId = 0; - threadHandle = 0; -} - -void Thread::killThread() -{ - if (threadHandle != 0) - { - #if BEAST_ANDROID - bassertfalse; // pthread_cancel not available! - #else - pthread_cancel ((pthread_t) threadHandle); - #endif - } -} - -void Thread::setCurrentThreadName (const String& name) -{ - #if BEAST_IOS || (BEAST_MAC && defined (MAC_OS_X_VERSION_10_5) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) - BEAST_AUTORELEASEPOOL - { - [[NSThread currentThread] setName: beastStringToNS (name)]; - } - #elif BEAST_LINUX - #if (__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2012 - pthread_setname_np (pthread_self(), name.toRawUTF8()); - #else - prctl (PR_SET_NAME, name.toRawUTF8(), 0, 0, 0); - #endif - #endif -} - -bool Thread::setThreadPriority (void* handle, int priority) -{ - struct sched_param param; - int policy; - priority = blimit (0, 10, priority); - - if (handle == nullptr) - handle = (void*) pthread_self(); - - if (pthread_getschedparam ((pthread_t) handle, &policy, ¶m) != 0) - return false; - - policy = priority == 0 ? SCHED_OTHER : SCHED_RR; - - const int minPriority = sched_get_priority_min (policy); - const int maxPriority = sched_get_priority_max (policy); - - param.sched_priority = ((maxPriority - minPriority) * priority) / 10 + minPriority; - return pthread_setschedparam ((pthread_t) handle, policy, ¶m) == 0; -} - -Thread::ThreadID Thread::getCurrentThreadId() -{ - return (ThreadID) pthread_self(); -} - -void Thread::yield() -{ - sched_yield(); -} - -//============================================================================== -/* Remove this macro if you're having problems compiling the cpu affinity - calls (the API for these has changed about quite a bit in various Linux - versions, and a lot of distros seem to ship with obsolete versions) -*/ -#if defined (CPU_ISSET) && ! defined (SUPPORT_AFFINITIES) - #define SUPPORT_AFFINITIES 1 -#endif - -void Thread::setCurrentThreadAffinityMask (const uint32 affinityMask) -{ - #if SUPPORT_AFFINITIES - cpu_set_t affinity; - CPU_ZERO (&affinity); - - for (int i = 0; i < 32; ++i) - if ((affinityMask & (1 << i)) != 0) - CPU_SET (i, &affinity); - - /* - N.B. If this line causes a compile error, then you've probably not got the latest - version of glibc installed. - - If you don't want to update your copy of glibc and don't care about cpu affinities, - then you can just disable all this stuff by setting the SUPPORT_AFFINITIES macro to 0. - */ - sched_setaffinity (getpid(), sizeof (cpu_set_t), &affinity); - sched_yield(); - - #else - /* affinities aren't supported because either the appropriate header files weren't found, - or the SUPPORT_AFFINITIES macro was turned off - */ - bassertfalse; - (void) affinityMask; - #endif -} - -//============================================================================== bool DynamicLibrary::open (const String& name) { close(); diff --git a/src/beast/modules/beast_core/native/win32_Threads.cpp b/src/beast/modules/beast_core/native/win32_Threads.cpp index 6c77427878..019a6d900e 100644 --- a/src/beast/modules/beast_core/native/win32_Threads.cpp +++ b/src/beast/modules/beast_core/native/win32_Threads.cpp @@ -21,8 +21,6 @@ */ //============================================================================== -HWND beast_messageWindowHandle = 0; // (this is used by other parts of the codebase) - void* getUser32Function (const char* functionName) { HMODULE module = GetModuleHandleA ("user32.dll"); @@ -72,143 +70,6 @@ void CriticalSection::enter() const noexcept { EnterCriticalSection ((CRITICAL_S bool CriticalSection::tryEnter() const noexcept { return TryEnterCriticalSection ((CRITICAL_SECTION*) section) != FALSE; } void CriticalSection::exit() const noexcept { LeaveCriticalSection ((CRITICAL_SECTION*) section); } -//============================================================================== -void BEAST_API beast_threadEntryPoint (void*); - -static unsigned int __stdcall threadEntryProc (void* userData) -{ - if (beast_messageWindowHandle != 0) - AttachThreadInput (GetWindowThreadProcessId (beast_messageWindowHandle, 0), - GetCurrentThreadId(), TRUE); - - beast_threadEntryPoint (userData); - - _endthreadex (0); - return 0; -} - -void Thread::launchThread() -{ - unsigned int newThreadId; - threadHandle = (void*) _beginthreadex (0, 0, &threadEntryProc, this, 0, &newThreadId); - threadId = (ThreadID) newThreadId; -} - -void Thread::closeThreadHandle() -{ - CloseHandle ((HANDLE) threadHandle); - threadId = 0; - threadHandle = 0; -} - -void Thread::killThread() -{ - if (threadHandle != 0) - { - #if BEAST_DEBUG - OutputDebugStringA ("** Warning - Forced thread termination **\n"); - #endif - TerminateThread (threadHandle, 0); - } -} - -void Thread::setCurrentThreadName (const String& name) -{ - #if BEAST_DEBUG && BEAST_MSVC - struct - { - DWORD dwType; - LPCSTR szName; - DWORD dwThreadID; - DWORD dwFlags; - } info; - - info.dwType = 0x1000; - info.szName = name.toUTF8(); - info.dwThreadID = GetCurrentThreadId(); - info.dwFlags = 0; - - __try - { - RaiseException (0x406d1388 /*MS_VC_EXCEPTION*/, 0, sizeof (info) / sizeof (ULONG_PTR), (ULONG_PTR*) &info); - } - __except (EXCEPTION_CONTINUE_EXECUTION) - {} - #else - (void) name; - #endif -} - -Thread::ThreadID Thread::getCurrentThreadId() -{ - return (ThreadID) (pointer_sized_int) GetCurrentThreadId(); -} - -bool Thread::setThreadPriority (void* handle, int priority) -{ - int pri = THREAD_PRIORITY_TIME_CRITICAL; - - if (priority < 1) pri = THREAD_PRIORITY_IDLE; - else if (priority < 2) pri = THREAD_PRIORITY_LOWEST; - else if (priority < 5) pri = THREAD_PRIORITY_BELOW_NORMAL; - else if (priority < 7) pri = THREAD_PRIORITY_NORMAL; - else if (priority < 9) pri = THREAD_PRIORITY_ABOVE_NORMAL; - else if (priority < 10) pri = THREAD_PRIORITY_HIGHEST; - - if (handle == 0) - handle = GetCurrentThread(); - - return SetThreadPriority (handle, pri) != FALSE; -} - -void Thread::setCurrentThreadAffinityMask (const uint32 affinityMask) -{ - SetThreadAffinityMask (GetCurrentThread(), affinityMask); -} - -//============================================================================== -struct SleepEvent -{ - SleepEvent() noexcept - : handle (CreateEvent (nullptr, FALSE, FALSE, - #if BEAST_DEBUG - _T("BEAST Sleep Event"))) - #else - nullptr)) - #endif - {} - - ~SleepEvent() noexcept - { - CloseHandle (handle); - handle = 0; - } - - HANDLE handle; -}; - -static SleepEvent sleepEvent; - -void BEAST_CALLTYPE Thread::sleep (const int millisecs) -{ - if (millisecs >= 10 || sleepEvent.handle == 0) - { - Sleep ((DWORD) millisecs); - } - else - { - // unlike Sleep() this is guaranteed to return to the current thread after - // the time expires, so we'll use this for short waits, which are more likely - // to need to be accurate - WaitForSingleObject (sleepEvent.handle, (DWORD) millisecs); - } -} - -void Thread::yield() -{ - Sleep (0); -} - //============================================================================== static int lastProcessPriority = -1; diff --git a/src/beast/modules/beast_core/threads/ReadWriteMutex.cpp b/src/beast/modules/beast_core/threads/ReadWriteMutex.cpp deleted file mode 100644 index 6118e4e26a..0000000000 --- a/src/beast/modules/beast_core/threads/ReadWriteMutex.cpp +++ /dev/null @@ -1,98 +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. -*/ -//============================================================================== - -ReadWriteMutex::ReadWriteMutex () noexcept -{ -} - -ReadWriteMutex::~ReadWriteMutex () noexcept -{ -} - -void ReadWriteMutex::enterRead () const noexcept -{ - for (;;) - { - // attempt the lock optimistically - // THIS IS NOT CACHE-FRIENDLY! - m_readers->addref (); - - // is there a writer? - // THIS IS NOT CACHE-FRIENDLY! - if (m_writes->isSignaled ()) - { - // a writer exists, give up the read lock - m_readers->release (); - - // block until the writer is done - { - CriticalSection::ScopedLockType lock (m_mutex); - } - - // now try the loop again - } - else - { - break; - } - } -} - -void ReadWriteMutex::exitRead () const noexcept -{ - m_readers->release (); -} - -void ReadWriteMutex::enterWrite () const noexcept -{ - // Optimistically acquire the write lock. - m_writes->addref (); - - // Go for the mutex. - // Another writer might block us here. - m_mutex.enter (); - - // Only one competing writer will get here, - // but we don't know who, so we have to drain - // readers no matter what. New readers will be - // blocked by the mutex. - // - if (m_readers->isSignaled ()) - { - SpinDelay delay; - - do - { - delay.pause (); - } - while (m_readers->isSignaled ()); - } -} - -void ReadWriteMutex::exitWrite () const noexcept -{ - // Releasing the mutex first and then decrementing the - // writer count allows another waiting writer to atomically - // acquire the lock, thus starving readers. This fulfills - // the write-preferencing requirement. - - m_mutex.exit (); - - m_writes->release (); -} diff --git a/src/beast/modules/beast_core/threads/ReadWriteMutex.h b/src/beast/modules/beast_core/threads/ReadWriteMutex.h deleted file mode 100644 index 05b87750ce..0000000000 --- a/src/beast/modules/beast_core/threads/ReadWriteMutex.h +++ /dev/null @@ -1,150 +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. -*/ -//============================================================================== - -#ifndef BEAST_READWRITEMUTEX_H_INCLUDED -#define BEAST_READWRITEMUTEX_H_INCLUDED - -/*============================================================================*/ -/** - Multiple consumer, single producer (MCSP) synchronization. - - This is an optimized lock for the multiple reader, single writer - scenario. It provides only a subset of features of the more general - traditional read/write lock. Specifically, these rules apply: - - - A caller cannot hold a read lock while acquiring a write lock. - - - Write locks are only recursive with respect to write locks. - - - Read locks are only recursive with respect to read locks. - - - A write lock cannot be downgraded. - - - Writes are preferenced over reads. - - For real-time applications, these restrictions are often not an issue. - - The implementation is wait-free in the fast path: acquiring read access - for a lock without contention - just one interlocked increment! - - @class ReadWriteMutex - @ingroup beast_concurrent -*/ - -//------------------------------------------------------------------------------ - -/** - Scoped read lock for ReadWriteMutex. - - @ingroup beast_concurrent -*/ -template -struct GenericScopedReadLock : public Uncopyable -{ - inline explicit GenericScopedReadLock (LockType const& lock) noexcept -: - m_lock (lock) - { - m_lock.enterRead (); - } - - inline ~GenericScopedReadLock () noexcept - { - m_lock.exitRead (); - } - -private: - LockType const& m_lock; -}; - -//------------------------------------------------------------------------------ - -/** - Scoped write lock for ReadWriteMutex. - - @ingroup beast_concurrent -*/ -template -struct GenericScopedWriteLock : public Uncopyable -{ - inline explicit GenericScopedWriteLock (LockType const& lock) noexcept -: - m_lock (lock) - { - m_lock.enterWrite (); - } - - inline ~GenericScopedWriteLock () noexcept - { - m_lock.exitWrite (); - } - -private: - LockType const& m_lock; -}; - -//------------------------------------------------------------------------------ - -class BEAST_API ReadWriteMutex -{ -public: - /** Provides the type of scoped read lock to use with a ReadWriteMutex. */ - typedef GenericScopedReadLock ScopedReadLockType; - - /** Provides the type of scoped write lock to use with a ReadWriteMutex. */ - typedef GenericScopedWriteLock ScopedWriteLockType; - - /** Create a ReadWriteMutex */ - ReadWriteMutex () noexcept; - - /** Destroy a ReadWriteMutex - - If the object is destroyed while a lock is held, the result is - undefined behavior. - */ - ~ReadWriteMutex () noexcept; - - /** Acquire a read lock. - - This is recursive with respect to other read locks. Calling this while - holding a write lock is undefined. - */ - void enterRead () const noexcept; - - /** Release a previously acquired read lock */ - void exitRead () const noexcept; - - /** Acquire a write lock. - - This is recursive with respect to other write locks. Calling this while - holding a read lock is undefined. - */ - void enterWrite () const noexcept; - - /** Release a previously acquired write lock */ - void exitWrite () const noexcept; - -private: - CriticalSection m_mutex; - - mutable CacheLine::Padded m_writes; - mutable CacheLine::Padded m_readers; -}; - -#endif diff --git a/src/beast/modules/beast_core/threads/Thread.cpp b/src/beast/modules/beast_core/threads/Thread.cpp deleted file mode 100644 index f3ab1eb2b1..0000000000 --- a/src/beast/modules/beast_core/threads/Thread.cpp +++ /dev/null @@ -1,376 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Portions of this file are from JUCE. - Copyright (c) 2013 - Raw Material Software Ltd. - Please visit http://www.juce.com - - 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. -*/ -//============================================================================== - -Thread::Thread (const String& threadName_) - : threadName (threadName_), - threadHandle (nullptr), - threadId (0), - threadPriority (5), - affinityMask (0), - shouldExit (false) -{ -} - -Thread::~Thread() -{ - /* If your thread class's destructor has been called without first stopping the thread, that - means that this partially destructed object is still performing some work - and that's - probably a Bad Thing! - - To avoid this type of nastiness, always make sure you call stopThread() before or during - your subclass's destructor. - */ - check_precondition (! isThreadRunning()); - - stopThread (); -} - -//============================================================================== -// Use a ref-counted object to hold this shared data, so that it can outlive its static -// shared pointer when threads are still running during static shutdown. -struct CurrentThreadHolder : public SharedObject -{ - CurrentThreadHolder() noexcept {} - - typedef SharedPtr Ptr; - ThreadLocalValue value; -}; - -static char currentThreadHolderLock [sizeof (SpinLock)]; // (statically initialised to zeros). - -static SpinLock* castToSpinLockWithoutAliasingWarning (void* s) -{ - return static_cast (s); -} - -static CurrentThreadHolder::Ptr getCurrentThreadHolder() -{ - static CurrentThreadHolder::Ptr currentThreadHolder; - SpinLock::ScopedLockType lock (*castToSpinLockWithoutAliasingWarning (currentThreadHolderLock)); - - if (currentThreadHolder == nullptr) - currentThreadHolder = new CurrentThreadHolder(); - - return currentThreadHolder; -} - -void Thread::threadEntryPoint() -{ - const CurrentThreadHolder::Ptr currentThreadHolder (getCurrentThreadHolder()); - currentThreadHolder->value = this; - - if (threadName.isNotEmpty()) - setCurrentThreadName (threadName); - - if (startSuspensionEvent.wait (10000)) - { - bassert (getCurrentThreadId() == threadId); - - if (affinityMask != 0) - setCurrentThreadAffinityMask (affinityMask); - - run(); - } - - currentThreadHolder->value.releaseCurrentThreadStorage(); - closeThreadHandle(); -} - -// used to wrap the incoming call from the platform-specific code -void BEAST_API beast_threadEntryPoint (void* userData) -{ - static_cast (userData)->threadEntryPoint(); -} - -//============================================================================== -void Thread::startThread() -{ - const ScopedLock sl (startStopLock); - - shouldExit = false; - - if (threadHandle == nullptr) - { - launchThread(); - setThreadPriority (threadHandle, threadPriority); - startSuspensionEvent.signal(); - } -} - -void Thread::startThread (const int priority) -{ - const ScopedLock sl (startStopLock); - - if (threadHandle == nullptr) - { - threadPriority = priority; - startThread(); - } - else - { - setPriority (priority); - } -} - -bool Thread::isThreadRunning() const -{ - return threadHandle != nullptr; -} - -Thread* Thread::getCurrentThread() -{ - return getCurrentThreadHolder()->value.get(); -} - -//============================================================================== -void Thread::signalThreadShouldExit() -{ - shouldExit = true; -} - -bool Thread::waitForThreadToExit (const int timeOutMilliseconds) const -{ - // Doh! So how exactly do you expect this thread to wait for itself to stop?? - bassert (getThreadId() != getCurrentThreadId() || getCurrentThreadId() == 0); - - const uint32 timeoutEnd = Time::getMillisecondCounter() + (uint32) timeOutMilliseconds; - - while (isThreadRunning()) - { - if (timeOutMilliseconds >= 0 && Time::getMillisecondCounter() > timeoutEnd) - return false; - - sleep (2); - } - - return true; -} - -bool Thread::stopThread (const int timeOutMilliseconds) -{ - bool cleanExit = true; - - // agh! You can't stop the thread that's calling this method! How on earth - // would that work?? - bassert (getCurrentThreadId() != getThreadId()); - - const ScopedLock sl (startStopLock); - - if (isThreadRunning()) - { - signalThreadShouldExit(); - notify(); - - if (timeOutMilliseconds != 0) - { - cleanExit = waitForThreadToExit (timeOutMilliseconds); - } - - if (isThreadRunning()) - { - bassert (! cleanExit); - - // very bad karma if this point is reached, as there are bound to be - // locks and events left in silly states when a thread is killed by force.. - killThread(); - - threadHandle = nullptr; - threadId = 0; - - cleanExit = false; - } - else - { - cleanExit = true; - } - } - - return cleanExit; -} - -void Thread::stopThreadAsync () -{ - const ScopedLock sl (startStopLock); - - if (isThreadRunning()) - { - signalThreadShouldExit(); - notify(); - } -} - -//============================================================================== -bool Thread::setPriority (const int newPriority) -{ - // NB: deadlock possible if you try to set the thread prio from the thread itself, - // so using setCurrentThreadPriority instead in that case. - if (getCurrentThreadId() == getThreadId()) - return setCurrentThreadPriority (newPriority); - - const ScopedLock sl (startStopLock); - - if (setThreadPriority (threadHandle, newPriority)) - { - threadPriority = newPriority; - return true; - } - - return false; -} - -bool Thread::setCurrentThreadPriority (const int newPriority) -{ - return setThreadPriority (0, newPriority); -} - -void Thread::setAffinityMask (const uint32 newAffinityMask) -{ - affinityMask = newAffinityMask; -} - -//============================================================================== -bool Thread::wait (const int timeOutMilliseconds) const -{ - return defaultEvent.wait (timeOutMilliseconds); -} - -void Thread::notify() const -{ - defaultEvent.signal(); -} - -//============================================================================== -void SpinLock::enter() const noexcept -{ - if (! tryEnter()) - { - for (int i = 20; --i >= 0;) - if (tryEnter()) - return; - - while (! tryEnter()) - Thread::yield(); - } -} - -//============================================================================== - -class AtomicTests : public UnitTest -{ -public: - AtomicTests() : UnitTest ("Atomic", "beast") {} - - void runTest() - { - beginTestCase ("Misc"); - - char a1[7]; - expect (numElementsInArray(a1) == 7); - int a2[3]; - expect (numElementsInArray(a2) == 3); - - expect (ByteOrder::swap ((uint16) 0x1122) == 0x2211); - expect (ByteOrder::swap ((uint32) 0x11223344) == 0x44332211); - expect (ByteOrder::swap ((uint64) literal64bit (0x1122334455667788)) == literal64bit (0x8877665544332211)); - - beginTestCase ("int"); - AtomicTester ::testInteger (*this); - beginTestCase ("unsigned int"); - AtomicTester ::testInteger (*this); - beginTestCase ("int32"); - AtomicTester ::testInteger (*this); - beginTestCase ("uint32"); - AtomicTester ::testInteger (*this); - beginTestCase ("long"); - AtomicTester ::testInteger (*this); - beginTestCase ("void*"); - AtomicTester ::testInteger (*this); - beginTestCase ("int*"); - AtomicTester ::testInteger (*this); - beginTestCase ("float"); - AtomicTester ::testFloat (*this); - #if ! BEAST_64BIT_ATOMICS_UNAVAILABLE // 64-bit intrinsics aren't available on some old platforms - beginTestCase ("int64"); - AtomicTester ::testInteger (*this); - beginTestCase ("uint64"); - AtomicTester ::testInteger (*this); - beginTestCase ("double"); - AtomicTester ::testFloat (*this); - #endif - } - - template - class AtomicTester - { - public: - AtomicTester() {} - - static void testInteger (UnitTest& test) - { - Atomic a, b; - a.set ((Type) 10); - test.expect (a.value == (Type) 10); - test.expect (a.get() == (Type) 10); - a += (Type) 15; - test.expect (a.get() == (Type) 25); - memoryBarrier(); - a -= (Type) 5; - test.expect (a.get() == (Type) 20); - test.expect (++a == (Type) 21); - ++a; - test.expect (--a == (Type) 21); - test.expect (a.get() == (Type) 21); - memoryBarrier(); - - testFloat (test); - } - - static void testFloat (UnitTest& test) - { - Atomic a, b; - a = (Type) 21; - memoryBarrier(); - - /* These are some simple test cases to check the atomics - let me know - if any of these assertions fail on your system! - */ - test.expect (a.get() == (Type) 21); - test.expect (a.compareAndSetValue ((Type) 100, (Type) 50) == (Type) 21); - test.expect (a.get() == (Type) 21); - test.expect (a.compareAndSetValue ((Type) 101, a.get()) == (Type) 21); - test.expect (a.get() == (Type) 101); - test.expect (! a.compareAndSetBool ((Type) 300, (Type) 200)); - test.expect (a.get() == (Type) 101); - test.expect (a.compareAndSetBool ((Type) 200, a.get())); - test.expect (a.get() == (Type) 200); - - test.expect (a.exchange ((Type) 300) == (Type) 200); - test.expect (a.get() == (Type) 300); - - b = a; - test.expect (b.get() == a.get()); - } - }; -}; - -static AtomicTests atomicTests; diff --git a/src/beast/modules/beast_core/threads/ThreadPool.cpp b/src/beast/modules/beast_core/threads/ThreadPool.cpp deleted file mode 100644 index 71354bad00..0000000000 --- a/src/beast/modules/beast_core/threads/ThreadPool.cpp +++ /dev/null @@ -1,371 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Portions of this file are from JUCE. - Copyright (c) 2013 - Raw Material Software Ltd. - Please visit http://www.juce.com - - 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. -*/ -//============================================================================== - -ThreadPoolJob::ThreadPoolJob (const String& name) - : jobName (name), - pool (nullptr), - shouldStop (false), - isActive (false), - shouldBeDeleted (false) -{ -} - -ThreadPoolJob::~ThreadPoolJob() -{ - // you mustn't delete a job while it's still in a pool! Use ThreadPool::removeJob() - // to remove it first! - bassert (pool == nullptr || ! pool->contains (this)); -} - -String ThreadPoolJob::getJobName() const -{ - return jobName; -} - -void ThreadPoolJob::setJobName (const String& newName) -{ - jobName = newName; -} - -void ThreadPoolJob::signalJobShouldExit() -{ - shouldStop = true; -} - -//============================================================================== -class ThreadPool::ThreadPoolThread - : public Thread - , LeakChecked -{ -public: - ThreadPoolThread (ThreadPool& pool_) - : Thread ("Pool"), - pool (pool_) - { - } - - void run() override - { - while (! threadShouldExit()) - { - if (! pool.runNextJob()) - wait (500); - } - } - -private: - ThreadPool& pool; -}; - -//============================================================================== -ThreadPool::ThreadPool (const int numThreads) -{ - bassert (numThreads > 0); // not much point having a pool without any threads! - - createThreads (numThreads); -} - -ThreadPool::ThreadPool() -{ - createThreads (SystemStats::getNumCpus()); -} - -ThreadPool::~ThreadPool() -{ - removeAllJobs (true, 5000); - stopThreads(); -} - -void ThreadPool::createThreads (int numThreads) -{ - for (int i = bmax (1, numThreads); --i >= 0;) - threads.add (new ThreadPoolThread (*this)); - - for (int i = threads.size(); --i >= 0;) - threads.getUnchecked(i)->startThread(); -} - -void ThreadPool::stopThreads() -{ - for (int i = threads.size(); --i >= 0;) - threads.getUnchecked(i)->signalThreadShouldExit(); - - for (int i = threads.size(); --i >= 0;) - threads.getUnchecked(i)->stopThread (500); -} - -void ThreadPool::addJob (ThreadPoolJob* const job, const bool deleteJobWhenFinished) -{ - bassert (job != nullptr); - bassert (job->pool == nullptr); - - if (job->pool == nullptr) - { - job->pool = this; - job->shouldStop = false; - job->isActive = false; - job->shouldBeDeleted = deleteJobWhenFinished; - - { - const ScopedLock sl (lock); - jobs.add (job); - } - - for (int i = threads.size(); --i >= 0;) - threads.getUnchecked(i)->notify(); - } -} - -int ThreadPool::getNumJobs() const -{ - return jobs.size(); -} - -ThreadPoolJob* ThreadPool::getJob (const int index) const -{ - const ScopedLock sl (lock); - return jobs [index]; -} - -bool ThreadPool::contains (const ThreadPoolJob* const job) const -{ - const ScopedLock sl (lock); - return jobs.contains (const_cast (job)); -} - -bool ThreadPool::isJobRunning (const ThreadPoolJob* const job) const -{ - const ScopedLock sl (lock); - return jobs.contains (const_cast (job)) && job->isActive; -} - -bool ThreadPool::waitForJobToFinish (const ThreadPoolJob* const job, - const int timeOutMs) const -{ - if (job != nullptr) - { - const uint32 start = Time::getMillisecondCounter(); - - while (contains (job)) - { - if (timeOutMs >= 0 && Time::getMillisecondCounter() >= start + (uint32) timeOutMs) - return false; - - jobFinishedSignal.wait (2); - } - } - - return true; -} - -bool ThreadPool::removeJob (ThreadPoolJob* const job, - const bool interruptIfRunning, - const int timeOutMs) -{ - bool dontWait = true; - OwnedArray deletionList; - - if (job != nullptr) - { - const ScopedLock sl (lock); - - if (jobs.contains (job)) - { - if (job->isActive) - { - if (interruptIfRunning) - job->signalJobShouldExit(); - - dontWait = false; - } - else - { - jobs.removeFirstMatchingValue (job); - addToDeleteList (deletionList, job); - } - } - } - - return dontWait || waitForJobToFinish (job, timeOutMs); -} - -bool ThreadPool::removeAllJobs (const bool interruptRunningJobs, const int timeOutMs, - ThreadPool::JobSelector* selectedJobsToRemove) -{ - Array jobsToWaitFor; - - { - OwnedArray deletionList; - - { - const ScopedLock sl (lock); - - for (int i = jobs.size(); --i >= 0;) - { - ThreadPoolJob* const job = jobs.getUnchecked(i); - - if (selectedJobsToRemove == nullptr || selectedJobsToRemove->isJobSuitable (job)) - { - if (job->isActive) - { - jobsToWaitFor.add (job); - - if (interruptRunningJobs) - job->signalJobShouldExit(); - } - else - { - jobs.remove (i); - addToDeleteList (deletionList, job); - } - } - } - } - } - - const uint32 start = Time::getMillisecondCounter(); - - for (;;) - { - for (int i = jobsToWaitFor.size(); --i >= 0;) - { - ThreadPoolJob* const job = jobsToWaitFor.getUnchecked (i); - - if (! isJobRunning (job)) - jobsToWaitFor.remove (i); - } - - if (jobsToWaitFor.size() == 0) - break; - - if (timeOutMs >= 0 && Time::getMillisecondCounter() >= start + (uint32) timeOutMs) - return false; - - jobFinishedSignal.wait (20); - } - - return true; -} - -StringArray ThreadPool::getNamesOfAllJobs (const bool onlyReturnActiveJobs) const -{ - StringArray s; - const ScopedLock sl (lock); - - for (int i = 0; i < jobs.size(); ++i) - { - const ThreadPoolJob* const job = jobs.getUnchecked(i); - if (job->isActive || ! onlyReturnActiveJobs) - s.add (job->getJobName()); - } - - return s; -} - -bool ThreadPool::setThreadPriorities (const int newPriority) -{ - bool ok = true; - - for (int i = threads.size(); --i >= 0;) - if (! threads.getUnchecked(i)->setPriority (newPriority)) - ok = false; - - return ok; -} - -ThreadPoolJob* ThreadPool::pickNextJobToRun() -{ - OwnedArray deletionList; - - { - const ScopedLock sl (lock); - - for (int i = 0; i < jobs.size(); ++i) - { - ThreadPoolJob* job = jobs[i]; - - if (job != nullptr && ! job->isActive) - { - if (job->shouldStop) - { - jobs.remove (i); - addToDeleteList (deletionList, job); - --i; - continue; - } - - job->isActive = true; - return job; - } - } - } - - return nullptr; -} - -bool ThreadPool::runNextJob() -{ - ThreadPoolJob* const job = pickNextJobToRun(); - - if (job == nullptr) - return false; - - ThreadPoolJob::JobStatus result = ThreadPoolJob::jobHasFinished; - - result = job->runJob(); - - OwnedArray deletionList; - - { - const ScopedLock sl (lock); - - if (jobs.contains (job)) - { - job->isActive = false; - - if (result != ThreadPoolJob::jobNeedsRunningAgain || job->shouldStop) - { - jobs.removeFirstMatchingValue (job); - addToDeleteList (deletionList, job); - - jobFinishedSignal.signal(); - } - else - { - // move the job to the end of the queue if it wants another go - jobs.move (jobs.indexOf (job), -1); - } - } - } - - return true; -} - -void ThreadPool::addToDeleteList (OwnedArray& deletionList, ThreadPoolJob* const job) const -{ - job->shouldStop = true; - job->pool = nullptr; - - if (job->shouldBeDeleted) - deletionList.add (job); -} diff --git a/src/beast/modules/beast_core/threads/ThreadPool.h b/src/beast/modules/beast_core/threads/ThreadPool.h deleted file mode 100644 index c2c27783a8..0000000000 --- a/src/beast/modules/beast_core/threads/ThreadPool.h +++ /dev/null @@ -1,304 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Portions of this file are from JUCE. - Copyright (c) 2013 - Raw Material Software Ltd. - Please visit http://www.juce.com - - 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_THREADPOOL_H_INCLUDED -#define BEAST_THREADPOOL_H_INCLUDED - -class ThreadPool; -class ThreadPoolThread; - -//============================================================================== -/** - A task that is executed by a ThreadPool object. - - A ThreadPool keeps a list of ThreadPoolJob objects which are executed by - its threads. - - The runJob() method needs to be implemented to do the task, and if the code that - does the work takes a significant time to run, it must keep checking the shouldExit() - method to see if something is trying to interrupt the job. If shouldExit() returns - true, the runJob() method must return immediately. - - @see ThreadPool, Thread -*/ -class BEAST_API ThreadPoolJob : LeakChecked , public Uncopyable -{ -public: - //============================================================================== - /** Creates a thread pool job object. - After creating your job, add it to a thread pool with ThreadPool::addJob(). - */ - explicit ThreadPoolJob (const String& name); - - /** Destructor. */ - virtual ~ThreadPoolJob(); - - //============================================================================== - /** Returns the name of this job. - @see setJobName - */ - String getJobName() const; - - /** Changes the job's name. - @see getJobName - */ - void setJobName (const String& newName); - - //============================================================================== - /** These are the values that can be returned by the runJob() method. - */ - enum JobStatus - { - jobHasFinished = 0, /**< indicates that the job has finished and can be - removed from the pool. */ - - jobNeedsRunningAgain /**< indicates that the job would like to be called - again when a thread is free. */ - }; - - /** Peforms the actual work that this job needs to do. - - Your subclass must implement this method, in which is does its work. - - If the code in this method takes a significant time to run, it must repeatedly check - the shouldExit() method to see if something is trying to interrupt the job. - If shouldExit() ever returns true, the runJob() method must return immediately. - - If this method returns jobHasFinished, then the job will be removed from the pool - immediately. If it returns jobNeedsRunningAgain, then the job will be left in the - pool and will get a chance to run again as soon as a thread is free. - - @see shouldExit() - */ - virtual JobStatus runJob() = 0; - - - //============================================================================== - /** Returns true if this job is currently running its runJob() method. */ - bool isRunning() const noexcept { return isActive; } - - /** Returns true if something is trying to interrupt this job and make it stop. - - Your runJob() method must call this whenever it gets a chance, and if it ever - returns true, the runJob() method must return immediately. - - @see signalJobShouldExit() - */ - bool shouldExit() const noexcept { return shouldStop; } - - /** Calling this will cause the shouldExit() method to return true, and the job - should (if it's been implemented correctly) stop as soon as possible. - - @see shouldExit() - */ - void signalJobShouldExit(); - - //============================================================================== -private: - friend class ThreadPool; - friend class ThreadPoolThread; - String jobName; - ThreadPool* pool; - bool shouldStop, isActive, shouldBeDeleted; -}; - - -//============================================================================== -/** - A set of threads that will run a list of jobs. - - When a ThreadPoolJob object is added to the ThreadPool's list, its runJob() method - will be called by the next pooled thread that becomes free. - - @see ThreadPoolJob, Thread -*/ -class BEAST_API ThreadPool : LeakChecked , public Uncopyable -{ -public: - //============================================================================== - /** Creates a thread pool. - Once you've created a pool, you can give it some jobs by calling addJob(). - @param numberOfThreads the number of threads to run. These will be started - immediately, and will run until the pool is deleted. - */ - ThreadPool (int numberOfThreads); - - /** Creates a thread pool with one thread per CPU core. - Once you've created a pool, you can give it some jobs by calling addJob(). - If you want to specify the number of threads, use the other constructor; this - one creates a pool which has one thread for each CPU core. - @see SystemStats::getNumCpus() - */ - ThreadPool(); - - /** Destructor. - - This will attempt to remove all the jobs before deleting, but if you want to - specify a timeout, you should call removeAllJobs() explicitly before deleting - the pool. - */ - ~ThreadPool(); - - //============================================================================== - /** A callback class used when you need to select which ThreadPoolJob objects are suitable - for some kind of operation. - @see ThreadPool::removeAllJobs - */ - class BEAST_API JobSelector - { - public: - virtual ~JobSelector() {} - - /** Should return true if the specified thread matches your criteria for whatever - operation that this object is being used for. - - Any implementation of this method must be extremely fast and thread-safe! - */ - virtual bool isJobSuitable (ThreadPoolJob* job) = 0; - }; - - //============================================================================== - /** Adds a job to the queue. - - Once a job has been added, then the next time a thread is free, it will run - the job's ThreadPoolJob::runJob() method. Depending on the return value of the - runJob() method, the pool will either remove the job from the pool or add it to - the back of the queue to be run again. - - If deleteJobWhenFinished is true, then the job object will be owned and deleted by - the pool when not needed - if you do this, make sure that your object's destructor - is thread-safe. - - If deleteJobWhenFinished is false, the pointer will be used but not deleted, and - the caller is responsible for making sure the object is not deleted before it has - been removed from the pool. - */ - void addJob (ThreadPoolJob* job, - bool deleteJobWhenFinished); - - /** Tries to remove a job from the pool. - - If the job isn't yet running, this will simply remove it. If it is running, it - will wait for it to finish. - - If the timeout period expires before the job finishes running, then the job will be - left in the pool and this will return false. It returns true if the job is sucessfully - stopped and removed. - - @param job the job to remove - @param interruptIfRunning if true, then if the job is currently busy, its - ThreadPoolJob::signalJobShouldExit() method will be called to try - to interrupt it. If false, then if the job will be allowed to run - until it stops normally (or the timeout expires) - @param timeOutMilliseconds the length of time this method should wait for the job to finish - before giving up and returning false - */ - bool removeJob (ThreadPoolJob* job, - bool interruptIfRunning, - int timeOutMilliseconds); - - /** Tries to remove all jobs from the pool. - - @param interruptRunningJobs if true, then all running jobs will have their ThreadPoolJob::signalJobShouldExit() - methods called to try to interrupt them - @param timeOutMilliseconds the length of time this method should wait for all the jobs to finish - before giving up and returning false - @param selectedJobsToRemove if this is non-zero, the JobSelector object is asked to decide which - jobs should be removed. If it is zero, all jobs are removed - @returns true if all jobs are successfully stopped and removed; false if the timeout period - expires while waiting for one or more jobs to stop - */ - bool removeAllJobs (bool interruptRunningJobs, - int timeOutMilliseconds, - JobSelector* selectedJobsToRemove = nullptr); - - /** Returns the number of jobs currently running or queued. - */ - int getNumJobs() const; - - /** Returns one of the jobs in the queue. - - Note that this can be a very volatile list as jobs might be continuously getting shifted - around in the list, and this method may return 0 if the index is currently out-of-range. - */ - ThreadPoolJob* getJob (int index) const; - - /** Returns true if the given job is currently queued or running. - - @see isJobRunning() - */ - bool contains (const ThreadPoolJob* job) const; - - /** Returns true if the given job is currently being run by a thread. - */ - bool isJobRunning (const ThreadPoolJob* job) const; - - /** Waits until a job has finished running and has been removed from the pool. - - This will wait until the job is no longer in the pool - i.e. until its - runJob() method returns ThreadPoolJob::jobHasFinished. - - If the timeout period expires before the job finishes, this will return false; - it returns true if the job has finished successfully. - */ - bool waitForJobToFinish (const ThreadPoolJob* job, - int timeOutMilliseconds) const; - - /** Returns a list of the names of all the jobs currently running or queued. - If onlyReturnActiveJobs is true, only the ones currently running are returned. - */ - StringArray getNamesOfAllJobs (bool onlyReturnActiveJobs) const; - - /** Changes the priority of all the threads. - - This will call Thread::setPriority() for each thread in the pool. - May return false if for some reason the priority can't be changed. - */ - bool setThreadPriorities (int newPriority); - - -private: - //============================================================================== - Array jobs; - - class ThreadPoolThread; - friend class ThreadPoolThread; - friend class OwnedArray ; - OwnedArray threads; - - CriticalSection lock; - WaitableEvent jobFinishedSignal; - - bool runNextJob(); - ThreadPoolJob* pickNextJobToRun(); - void addToDeleteList (OwnedArray&, ThreadPoolJob*) const; - void createThreads (int numThreads); - void stopThreads(); - - // Note that this method has changed, and no longer has a parameter to indicate - // whether the jobs should be deleted - see the new method for details. - void removeAllJobs (bool, int, bool); -}; - - -#endif // BEAST_THREADPOOL_H_INCLUDED diff --git a/src/beast/modules/beast_core/threads/TimeSliceThread.cpp b/src/beast/modules/beast_core/threads/TimeSliceThread.cpp deleted file mode 100644 index 106e7084db..0000000000 --- a/src/beast/modules/beast_core/threads/TimeSliceThread.cpp +++ /dev/null @@ -1,166 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Portions of this file are from JUCE. - Copyright (c) 2013 - Raw Material Software Ltd. - Please visit http://www.juce.com - - 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. -*/ -//============================================================================== - -TimeSliceThread::TimeSliceThread (const String& name) - : Thread (name), - clientBeingCalled (nullptr) -{ -} - -TimeSliceThread::~TimeSliceThread() -{ - stopThread (2000); -} - -//============================================================================== -void TimeSliceThread::addTimeSliceClient (TimeSliceClient* const client, int millisecondsBeforeStarting) -{ - if (client != nullptr) - { - const ScopedLock sl (listLock); - client->nextCallTime = Time::getCurrentTime() + RelativeTime::milliseconds (millisecondsBeforeStarting); - clients.addIfNotAlreadyThere (client); - notify(); - } -} - -void TimeSliceThread::removeTimeSliceClient (TimeSliceClient* const client) -{ - const ScopedLock sl1 (listLock); - - // if there's a chance we're in the middle of calling this client, we need to - // also lock the outer lock.. - if (clientBeingCalled == client) - { - const ScopedUnlock ul (listLock); // unlock first to get the order right.. - - const ScopedLock sl2 (callbackLock); - const ScopedLock sl3 (listLock); - - clients.removeFirstMatchingValue (client); - } - else - { - clients.removeFirstMatchingValue (client); - } -} - -void TimeSliceThread::moveToFrontOfQueue (TimeSliceClient* client) -{ - const ScopedLock sl (listLock); - - if (clients.contains (client)) - { - client->nextCallTime = Time::getCurrentTime(); - notify(); - } -} - -int TimeSliceThread::getNumClients() const -{ - return clients.size(); -} - -TimeSliceClient* TimeSliceThread::getClient (const int i) const -{ - const ScopedLock sl (listLock); - return clients [i]; -} - -//============================================================================== -TimeSliceClient* TimeSliceThread::getNextClient (int index) const -{ - Time soonest; - TimeSliceClient* client = nullptr; - - for (int i = clients.size(); --i >= 0;) - { - TimeSliceClient* const c = clients.getUnchecked ((i + index) % clients.size()); - - if (client == nullptr || c->nextCallTime < soonest) - { - client = c; - soonest = c->nextCallTime; - } - } - - return client; -} - -void TimeSliceThread::run() -{ - int index = 0; - - while (! threadShouldExit()) - { - int timeToWait = 500; - - { - Time nextClientTime; - - { - const ScopedLock sl2 (listLock); - - index = clients.size() > 0 ? ((index + 1) % clients.size()) : 0; - - if (TimeSliceClient* const firstClient = getNextClient (index)) - nextClientTime = firstClient->nextCallTime; - } - - const Time now (Time::getCurrentTime()); - - if (nextClientTime > now) - { - timeToWait = (int) bmin ((int64) 500, (nextClientTime - now).inMilliseconds()); - } - else - { - timeToWait = index == 0 ? 1 : 0; - - const ScopedLock sl (callbackLock); - - { - const ScopedLock sl2 (listLock); - clientBeingCalled = getNextClient (index); - } - - if (clientBeingCalled != nullptr) - { - const int msUntilNextCall = clientBeingCalled->useTimeSlice(); - - const ScopedLock sl2 (listLock); - - if (msUntilNextCall >= 0) - clientBeingCalled->nextCallTime = now + RelativeTime::milliseconds (msUntilNextCall); - else - clients.removeFirstMatchingValue (clientBeingCalled); - - clientBeingCalled = nullptr; - } - } - } - - if (timeToWait > 0) - wait (timeToWait); - } -} diff --git a/src/beast/modules/beast_core/threads/TimeSliceThread.h b/src/beast/modules/beast_core/threads/TimeSliceThread.h deleted file mode 100644 index 566b398c20..0000000000 --- a/src/beast/modules/beast_core/threads/TimeSliceThread.h +++ /dev/null @@ -1,143 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Portions of this file are from JUCE. - Copyright (c) 2013 - Raw Material Software Ltd. - Please visit http://www.juce.com - - 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_TIMESLICETHREAD_H_INCLUDED -#define BEAST_TIMESLICETHREAD_H_INCLUDED - -class TimeSliceThread; - -//============================================================================== -/** - Used by the TimeSliceThread class. - - To register your class with a TimeSliceThread, derive from this class and - use the TimeSliceThread::addTimeSliceClient() method to add it to the list. - - Make sure you always call TimeSliceThread::removeTimeSliceClient() before - deleting your client! - - @see TimeSliceThread -*/ -class BEAST_API TimeSliceClient -{ -public: - /** Destructor. */ - virtual ~TimeSliceClient() {} - - /** Called back by a TimeSliceThread. - - When you register this class with it, a TimeSliceThread will repeatedly call - this method. - - The implementation of this method should use its time-slice to do something that's - quick - never block for longer than absolutely necessary. - - @returns Your method should return the number of milliseconds which it would like to wait before being called - again. Returning 0 will make the thread call again as soon as possible (after possibly servicing - other busy clients). If you return a value below zero, your client will be removed from the list of clients, - and won't be called again. The value you specify isn't a guaranteee, and is only used as a hint by the - thread - the actual time before the next callback may be more or less than specified. - You can force the TimeSliceThread to wake up and poll again immediately by calling its notify() method. - */ - virtual int useTimeSlice() = 0; - - -private: - friend class TimeSliceThread; - Time nextCallTime; -}; - - -//============================================================================== -/** - A thread that keeps a list of clients, and calls each one in turn, giving them - all a chance to run some sort of short task. - - @see TimeSliceClient, Thread -*/ -class BEAST_API TimeSliceThread - : public Thread - , LeakChecked -{ -public: - //============================================================================== - /** - Creates a TimeSliceThread. - - When first created, the thread is not running. Use the startThread() - method to start it. - */ - explicit TimeSliceThread (const String& threadName); - - /** Destructor. - - Deleting a Thread object that is running will only give the thread a - brief opportunity to stop itself cleanly, so it's recommended that you - should always call stopThread() with a decent timeout before deleting, - to avoid the thread being forcibly killed (which is a Bad Thing). - */ - ~TimeSliceThread(); - - //============================================================================== - /** Adds a client to the list. - - The client's callbacks will start after the number of milliseconds specified - by millisecondsBeforeStarting (and this may happen before this method has returned). - */ - void addTimeSliceClient (TimeSliceClient* client, int millisecondsBeforeStarting = 0); - - /** Removes a client from the list. - - This method will make sure that all callbacks to the client have completely - finished before the method returns. - */ - void removeTimeSliceClient (TimeSliceClient* client); - - /** If the given client is waiting in the queue, it will be moved to the front - and given a time-slice as soon as possible. - If the specified client has not been added, nothing will happen. - */ - void moveToFrontOfQueue (TimeSliceClient* client); - - /** Returns the number of registered clients. */ - int getNumClients() const; - - /** Returns one of the registered clients. */ - TimeSliceClient* getClient (int index) const; - - //============================================================================== - #ifndef DOXYGEN - void run() override; - #endif - - //============================================================================== -private: - CriticalSection callbackLock, listLock; - Array clients; - TimeSliceClient* clientBeingCalled; - - TimeSliceClient* getNextClient (int index) const; -}; - - -#endif // BEAST_TIMESLICETHREAD_H_INCLUDED diff --git a/src/ripple/beast/ripple_beast.cpp b/src/ripple/beast/ripple_beast.cpp index 1510cda2fc..8766494671 100644 --- a/src/ripple/beast/ripple_beast.cpp +++ b/src/ripple/beast/ripple_beast.cpp @@ -42,6 +42,7 @@ #include "../beast/beast/crypto/Crypto.cpp" #include "../beast/beast/http/HTTP.cpp" #include "../beast/beast/net/Net.cpp" +#include "../beast/beast/smart_ptr/SmartPtr.cpp" #include "../beast/beast/strings/Strings.cpp" -#include "../beast/beast/thread/Thread.cpp" +#include "../beast/beast/threads/Threads.cpp" #include "../beast/beast/utility/Utility.cpp"