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.

194 lines
6.8KB

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