| @@ -44,6 +44,7 @@ | |||
| #if (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 | |||
| #define JUCE_STDLIB_HAS_STD_FUNCTION_SUPPORT 1 | |||
| #define JUCE_COMPILER_SUPPORTS_THREAD_LOCAL 1 | |||
| #endif | |||
| #ifndef JUCE_EXCEPTIONS_DISABLED | |||
| @@ -67,6 +68,7 @@ | |||
| #if (defined (_LIBCPP_VERSION) || ! (JUCE_MAC || JUCE_IOS)) | |||
| #define JUCE_STDLIB_HAS_STD_FUNCTION_SUPPORT 1 | |||
| #define JUCE_COMPILER_SUPPORTS_THREAD_LOCAL 1 | |||
| #endif | |||
| #if __has_feature (cxx_generalized_initializers) && (defined (_LIBCPP_VERSION) || ! (JUCE_MAC || JUCE_IOS)) | |||
| @@ -106,6 +108,7 @@ | |||
| #define JUCE_COMPILER_SUPPORTS_VARIADIC_TEMPLATES 1 | |||
| #define JUCE_DELETED_FUNCTION = delete | |||
| #define JUCE_STDLIB_HAS_STD_FUNCTION_SUPPORT 1 | |||
| #define JUCE_COMPILER_SUPPORTS_THREAD_LOCAL 1 | |||
| #endif | |||
| #if _MSC_VER >= 1900 | |||
| @@ -277,9 +277,9 @@ bool JUCE_CALLTYPE Process::isRunningUnderDebugger() noexcept | |||
| return juce_isRunningUnderDebugger(); | |||
| } | |||
| //============================================================================== | |||
| #if JUCE_UNIT_TESTS | |||
| //============================================================================== | |||
| class AtomicTests : public UnitTest | |||
| { | |||
| public: | |||
| @@ -401,4 +401,60 @@ public: | |||
| static AtomicTests atomicUnitTests; | |||
| //============================================================================== | |||
| class ThreadLocalValueUnitTest : public UnitTest, private Thread | |||
| { | |||
| public: | |||
| ThreadLocalValueUnitTest() | |||
| : UnitTest ("ThreadLocalValue"), | |||
| Thread ("ThreadLocalValue Thread") | |||
| {} | |||
| void runTest() override | |||
| { | |||
| beginTest ("values are thread local"); | |||
| { | |||
| ThreadLocalValue<int> threadLocal; | |||
| sharedThreadLocal = &threadLocal; | |||
| sharedThreadLocal.get()->get() = 1; | |||
| startThread(); | |||
| signalThreadShouldExit(); | |||
| waitForThreadToExit (-1); | |||
| mainThreadResult = sharedThreadLocal.get()->get(); | |||
| expectEquals (mainThreadResult.get(), 1); | |||
| expectEquals (auxThreadResult.get(), 2); | |||
| } | |||
| beginTest ("values are per-instance"); | |||
| { | |||
| ThreadLocalValue<int> a, b; | |||
| a.get() = 1; | |||
| b.get() = 2; | |||
| expectEquals (a.get(), 1); | |||
| expectEquals (b.get(), 2); | |||
| } | |||
| } | |||
| private: | |||
| Atomic<int> mainThreadResult, auxThreadResult; | |||
| Atomic<ThreadLocalValue<int>*> sharedThreadLocal; | |||
| void run() override | |||
| { | |||
| sharedThreadLocal.get()->get() = 2; | |||
| auxThreadResult = sharedThreadLocal.get()->get(); | |||
| } | |||
| }; | |||
| ThreadLocalValueUnitTest threadLocalValueUnitTest; | |||
| #endif | |||
| @@ -22,13 +22,6 @@ | |||
| #pragma once | |||
| // (NB: on win32, native thread-locals aren't possible in a dynamically loaded DLL in XP). | |||
| #if ! ((JUCE_MSVC && (JUCE_64BIT || ! defined (JucePlugin_PluginCode))) \ | |||
| || (JUCE_MAC && JUCE_CLANG && defined (MAC_OS_X_VERSION_10_7) \ | |||
| && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7)) | |||
| #define JUCE_NO_COMPILER_THREAD_LOCAL 1 | |||
| #endif | |||
| //============================================================================== | |||
| /** | |||
| Provides cross-platform support for thread-local objects. | |||
| @@ -61,7 +54,7 @@ public: | |||
| */ | |||
| ~ThreadLocalValue() | |||
| { | |||
| #if JUCE_NO_COMPILER_THREAD_LOCAL | |||
| #if ! JUCE_COMPILER_SUPPORTS_THREAD_LOCAL | |||
| for (ObjectHolder* o = first.value; o != nullptr;) | |||
| { | |||
| ObjectHolder* const next = o->next; | |||
| @@ -102,7 +95,10 @@ public: | |||
| */ | |||
| Type& get() const noexcept | |||
| { | |||
| #if JUCE_NO_COMPILER_THREAD_LOCAL | |||
| #if JUCE_COMPILER_SUPPORTS_THREAD_LOCAL | |||
| static thread_local HashMap<const void*, Type> holder; | |||
| return holder.getReference (this); | |||
| #else | |||
| const Thread::ThreadID threadId = Thread::getCurrentThreadId(); | |||
| for (ObjectHolder* o = first.get(); o != nullptr; o = o->next) | |||
| @@ -136,12 +132,6 @@ public: | |||
| while (! first.compareAndSetBool (newObject, newObject->next)); | |||
| return newObject->object; | |||
| #elif JUCE_MAC | |||
| static __thread Type object; | |||
| return object; | |||
| #elif JUCE_MSVC | |||
| static __declspec(thread) Type object; | |||
| return object; | |||
| #endif | |||
| } | |||
| @@ -150,7 +140,7 @@ public: | |||
| */ | |||
| void releaseCurrentThreadStorage() | |||
| { | |||
| #if JUCE_NO_COMPILER_THREAD_LOCAL | |||
| #if ! JUCE_COMPILER_SUPPORTS_THREAD_LOCAL | |||
| const Thread::ThreadID threadId = Thread::getCurrentThreadId(); | |||
| for (ObjectHolder* o = first.get(); o != nullptr; o = o->next) | |||
| @@ -166,7 +156,7 @@ public: | |||
| private: | |||
| //============================================================================== | |||
| #if JUCE_NO_COMPILER_THREAD_LOCAL | |||
| #if ! JUCE_COMPILER_SUPPORTS_THREAD_LOCAL | |||
| struct ObjectHolder | |||
| { | |||
| ObjectHolder (const Thread::ThreadID& tid) | |||