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.

195 lines
6.9KB

  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. #if ! (JUCE_MSVC || (JUCE_MAC && defined (__clang__) && defined (MAC_OS_X_VERSION_10_7) \
  21. && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7))
  22. #define JUCE_NO_COMPILER_THREAD_LOCAL 1
  23. #endif
  24. //==============================================================================
  25. /**
  26. Provides cross-platform support for thread-local objects.
  27. This class holds an internal list of objects of the templated type, keeping
  28. an instance for each thread that requests one. The first time a thread attempts
  29. to access its value, an object is created and added to the list for that thread.
  30. Typically, you'll probably want to create a static instance of a ThreadLocalValue
  31. object, or hold one within a singleton.
  32. The templated class for your value could be a primitive type, or any class that
  33. has a default constructor and copy operator.
  34. When a thread no longer needs to use its value, it can call releaseCurrentThreadStorage()
  35. to allow the storage to be re-used by another thread. If a thread exits without calling
  36. this method, the object storage will be left allocated until the ThreadLocalValue object
  37. is deleted.
  38. */
  39. template <typename Type>
  40. class ThreadLocalValue
  41. {
  42. public:
  43. /** */
  44. ThreadLocalValue() noexcept
  45. {
  46. }
  47. /** Destructor.
  48. When this object is deleted, all the value objects for all threads will be deleted.
  49. */
  50. ~ThreadLocalValue()
  51. {
  52. #if JUCE_NO_COMPILER_THREAD_LOCAL
  53. for (ObjectHolder* o = first.value; o != nullptr;)
  54. {
  55. ObjectHolder* const next = o->next;
  56. delete o;
  57. o = next;
  58. }
  59. #endif
  60. }
  61. /** Returns a reference to this thread's instance of the value.
  62. Note that the first time a thread tries to access the value, an instance of the
  63. value object will be created - so if your value's class has a non-trivial
  64. constructor, be aware that this method could invoke it.
  65. */
  66. Type& operator*() const noexcept { return get(); }
  67. /** Returns a pointer to this thread's instance of the value.
  68. Note that the first time a thread tries to access the value, an instance of the
  69. value object will be created - so if your value's class has a non-trivial
  70. constructor, be aware that this method could invoke it.
  71. */
  72. operator Type*() const noexcept { return &get(); }
  73. /** Accesses a method or field of the value object.
  74. Note that the first time a thread tries to access the value, an instance of the
  75. value object will be created - so if your value's class has a non-trivial
  76. constructor, be aware that this method could invoke it.
  77. */
  78. Type* operator->() const noexcept { return &get(); }
  79. /** Assigns a new value to the thread-local object. */
  80. ThreadLocalValue& operator= (const Type& newValue) { get() = newValue; return *this; }
  81. /** Returns a reference to this thread's instance of the value.
  82. Note that the first time a thread tries to access the value, an instance of the
  83. value object will be created - so if your value's class has a non-trivial
  84. constructor, be aware that this method could invoke it.
  85. */
  86. Type& get() const noexcept
  87. {
  88. #if JUCE_NO_COMPILER_THREAD_LOCAL
  89. const Thread::ThreadID threadId = Thread::getCurrentThreadId();
  90. for (ObjectHolder* o = first.get(); o != nullptr; o = o->next)
  91. if (o->threadId == threadId)
  92. return o->object;
  93. for (ObjectHolder* o = first.get(); o != nullptr; o = o->next)
  94. {
  95. if (o->threadId == nullptr)
  96. {
  97. {
  98. SpinLock::ScopedLockType sl (lock);
  99. if (o->threadId != nullptr)
  100. continue;
  101. o->threadId = threadId;
  102. }
  103. o->object = Type();
  104. return o->object;
  105. }
  106. }
  107. ObjectHolder* const newObject = new ObjectHolder (threadId);
  108. do
  109. {
  110. newObject->next = first.get();
  111. }
  112. while (! first.compareAndSetBool (newObject, newObject->next));
  113. return newObject->object;
  114. #elif JUCE_MAC
  115. static __thread Type object;
  116. return object;
  117. #elif JUCE_MSVC
  118. static __declspec(thread) Type object;
  119. return object;
  120. #endif
  121. }
  122. /** Called by a thread before it terminates, to allow this class to release
  123. any storage associated with the thread.
  124. */
  125. void releaseCurrentThreadStorage()
  126. {
  127. #if JUCE_NO_COMPILER_THREAD_LOCAL
  128. const Thread::ThreadID threadId = Thread::getCurrentThreadId();
  129. for (ObjectHolder* o = first.get(); o != nullptr; o = o->next)
  130. {
  131. if (o->threadId == threadId)
  132. {
  133. SpinLock::ScopedLockType sl (lock);
  134. o->threadId = nullptr;
  135. }
  136. }
  137. #endif
  138. }
  139. private:
  140. //==============================================================================
  141. #if JUCE_NO_COMPILER_THREAD_LOCAL
  142. struct ObjectHolder
  143. {
  144. ObjectHolder (const Thread::ThreadID& threadId_)
  145. : threadId (threadId_), object()
  146. {}
  147. Thread::ThreadID threadId;
  148. ObjectHolder* next;
  149. Type object;
  150. JUCE_DECLARE_NON_COPYABLE (ObjectHolder);
  151. };
  152. mutable Atomic<ObjectHolder*> first;
  153. SpinLock lock;
  154. #endif
  155. JUCE_DECLARE_NON_COPYABLE (ThreadLocalValue);
  156. };
  157. #endif // __JUCE_THREADLOCALVALUE_JUCEHEADER__