The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

197 lines
7.0KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #ifndef __JUCE_THREADLOCALVALUE_JUCEHEADER__
  19. #define __JUCE_THREADLOCALVALUE_JUCEHEADER__
  20. // (NB: on win32, native thread-locals aren't possible in a dynamically loaded DLL in XP).
  21. #if ! ((JUCE_MSVC && (defined (_WIN64) || ! defined (JucePlugin_PluginCode))) \
  22. || (JUCE_MAC && defined (__clang__) && defined (MAC_OS_X_VERSION_10_7) \
  23. && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7))
  24. #define JUCE_NO_COMPILER_THREAD_LOCAL 1
  25. #endif
  26. //==============================================================================
  27. /**
  28. Provides cross-platform support for thread-local objects.
  29. This class holds an internal list of objects of the templated type, keeping
  30. an instance for each thread that requests one. The first time a thread attempts
  31. to access its value, an object is created and added to the list for that thread.
  32. Typically, you'll probably want to create a static instance of a ThreadLocalValue
  33. object, or hold one within a singleton.
  34. The templated class for your value could be a primitive type, or any class that
  35. has a default constructor and copy operator.
  36. When a thread no longer needs to use its value, it can call releaseCurrentThreadStorage()
  37. to allow the storage to be re-used by another thread. If a thread exits without calling
  38. this method, the object storage will be left allocated until the ThreadLocalValue object
  39. is deleted.
  40. */
  41. template <typename Type>
  42. class ThreadLocalValue
  43. {
  44. public:
  45. /** */
  46. ThreadLocalValue() noexcept
  47. {
  48. }
  49. /** Destructor.
  50. When this object is deleted, all the value objects for all threads will be deleted.
  51. */
  52. ~ThreadLocalValue()
  53. {
  54. #if JUCE_NO_COMPILER_THREAD_LOCAL
  55. for (ObjectHolder* o = first.value; o != nullptr;)
  56. {
  57. ObjectHolder* const next = o->next;
  58. delete o;
  59. o = next;
  60. }
  61. #endif
  62. }
  63. /** Returns a reference to this thread's instance of the value.
  64. Note that the first time a thread tries to access the value, an instance of the
  65. value object will be created - so if your value's class has a non-trivial
  66. constructor, be aware that this method could invoke it.
  67. */
  68. Type& operator*() const noexcept { return get(); }
  69. /** Returns a pointer to this thread's instance of the value.
  70. Note that the first time a thread tries to access the value, an instance of the
  71. value object will be created - so if your value's class has a non-trivial
  72. constructor, be aware that this method could invoke it.
  73. */
  74. operator Type*() const noexcept { return &get(); }
  75. /** Accesses a method or field of the value object.
  76. Note that the first time a thread tries to access the value, an instance of the
  77. value object will be created - so if your value's class has a non-trivial
  78. constructor, be aware that this method could invoke it.
  79. */
  80. Type* operator->() const noexcept { return &get(); }
  81. /** Assigns a new value to the thread-local object. */
  82. ThreadLocalValue& operator= (const Type& newValue) { get() = newValue; return *this; }
  83. /** Returns a reference to this thread's instance of the value.
  84. Note that the first time a thread tries to access the value, an instance of the
  85. value object will be created - so if your value's class has a non-trivial
  86. constructor, be aware that this method could invoke it.
  87. */
  88. Type& get() const noexcept
  89. {
  90. #if JUCE_NO_COMPILER_THREAD_LOCAL
  91. const Thread::ThreadID threadId = Thread::getCurrentThreadId();
  92. for (ObjectHolder* o = first.get(); o != nullptr; o = o->next)
  93. if (o->threadId == threadId)
  94. return o->object;
  95. for (ObjectHolder* o = first.get(); o != nullptr; o = o->next)
  96. {
  97. if (o->threadId == nullptr)
  98. {
  99. {
  100. SpinLock::ScopedLockType sl (lock);
  101. if (o->threadId != nullptr)
  102. continue;
  103. o->threadId = threadId;
  104. }
  105. o->object = Type();
  106. return o->object;
  107. }
  108. }
  109. ObjectHolder* const newObject = new ObjectHolder (threadId);
  110. do
  111. {
  112. newObject->next = first.get();
  113. }
  114. while (! first.compareAndSetBool (newObject, newObject->next));
  115. return newObject->object;
  116. #elif JUCE_MAC
  117. static __thread Type object;
  118. return object;
  119. #elif JUCE_MSVC
  120. static __declspec(thread) Type object;
  121. return object;
  122. #endif
  123. }
  124. /** Called by a thread before it terminates, to allow this class to release
  125. any storage associated with the thread.
  126. */
  127. void releaseCurrentThreadStorage()
  128. {
  129. #if JUCE_NO_COMPILER_THREAD_LOCAL
  130. const Thread::ThreadID threadId = Thread::getCurrentThreadId();
  131. for (ObjectHolder* o = first.get(); o != nullptr; o = o->next)
  132. {
  133. if (o->threadId == threadId)
  134. {
  135. SpinLock::ScopedLockType sl (lock);
  136. o->threadId = nullptr;
  137. }
  138. }
  139. #endif
  140. }
  141. private:
  142. //==============================================================================
  143. #if JUCE_NO_COMPILER_THREAD_LOCAL
  144. struct ObjectHolder
  145. {
  146. ObjectHolder (const Thread::ThreadID& threadId_)
  147. : threadId (threadId_), object()
  148. {}
  149. Thread::ThreadID threadId;
  150. ObjectHolder* next;
  151. Type object;
  152. JUCE_DECLARE_NON_COPYABLE (ObjectHolder);
  153. };
  154. mutable Atomic<ObjectHolder*> first;
  155. SpinLock lock;
  156. #endif
  157. JUCE_DECLARE_NON_COPYABLE (ThreadLocalValue);
  158. };
  159. #endif // __JUCE_THREADLOCALVALUE_JUCEHEADER__