@@ -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) | |||