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.

357 lines
11KB

  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. Thread::Thread (const String& threadName_)
  19. : threadName (threadName_),
  20. threadHandle (nullptr),
  21. threadId (0),
  22. threadPriority (5),
  23. affinityMask (0),
  24. shouldExit (false)
  25. {
  26. }
  27. Thread::~Thread()
  28. {
  29. /* If your thread class's destructor has been called without first stopping the thread, that
  30. means that this partially destructed object is still performing some work - and that's
  31. probably a Bad Thing!
  32. To avoid this type of nastiness, always make sure you call stopThread() before or during
  33. your subclass's destructor.
  34. */
  35. jassert (! isThreadRunning());
  36. stopThread (100);
  37. }
  38. //==============================================================================
  39. // Use a ref-counted object to hold this shared data, so that it can outlive its static
  40. // shared pointer when threads are still running during static shutdown.
  41. struct CurrentThreadHolder : public ReferenceCountedObject
  42. {
  43. CurrentThreadHolder() noexcept {}
  44. typedef ReferenceCountedObjectPtr <CurrentThreadHolder> Ptr;
  45. ThreadLocalValue<Thread*> value;
  46. JUCE_DECLARE_NON_COPYABLE (CurrentThreadHolder);
  47. };
  48. static char currentThreadHolderLock [sizeof (SpinLock)]; // (statically initialised to zeros).
  49. static CurrentThreadHolder::Ptr getCurrentThreadHolder()
  50. {
  51. static CurrentThreadHolder::Ptr currentThreadHolder;
  52. SpinLock::ScopedLockType lock (*reinterpret_cast <SpinLock*> (currentThreadHolderLock));
  53. if (currentThreadHolder == nullptr)
  54. currentThreadHolder = new CurrentThreadHolder();
  55. return currentThreadHolder;
  56. }
  57. void Thread::threadEntryPoint()
  58. {
  59. const CurrentThreadHolder::Ptr currentThreadHolder (getCurrentThreadHolder());
  60. currentThreadHolder->value = this;
  61. JUCE_TRY
  62. {
  63. if (threadName.isNotEmpty())
  64. setCurrentThreadName (threadName);
  65. if (startSuspensionEvent.wait (10000))
  66. {
  67. jassert (getCurrentThreadId() == threadId);
  68. if (affinityMask != 0)
  69. setCurrentThreadAffinityMask (affinityMask);
  70. run();
  71. }
  72. }
  73. JUCE_CATCH_ALL_ASSERT
  74. currentThreadHolder->value.releaseCurrentThreadStorage();
  75. closeThreadHandle();
  76. }
  77. // used to wrap the incoming call from the platform-specific code
  78. void JUCE_API juce_threadEntryPoint (void* userData)
  79. {
  80. static_cast <Thread*> (userData)->threadEntryPoint();
  81. }
  82. //==============================================================================
  83. void Thread::startThread()
  84. {
  85. const ScopedLock sl (startStopLock);
  86. shouldExit = false;
  87. if (threadHandle == nullptr)
  88. {
  89. launchThread();
  90. setThreadPriority (threadHandle, threadPriority);
  91. startSuspensionEvent.signal();
  92. }
  93. }
  94. void Thread::startThread (const int priority)
  95. {
  96. const ScopedLock sl (startStopLock);
  97. if (threadHandle == nullptr)
  98. {
  99. threadPriority = priority;
  100. startThread();
  101. }
  102. else
  103. {
  104. setPriority (priority);
  105. }
  106. }
  107. bool Thread::isThreadRunning() const
  108. {
  109. return threadHandle != nullptr;
  110. }
  111. Thread* Thread::getCurrentThread()
  112. {
  113. return getCurrentThreadHolder()->value.get();
  114. }
  115. //==============================================================================
  116. void Thread::signalThreadShouldExit()
  117. {
  118. shouldExit = true;
  119. }
  120. bool Thread::waitForThreadToExit (const int timeOutMilliseconds) const
  121. {
  122. // Doh! So how exactly do you expect this thread to wait for itself to stop??
  123. jassert (getThreadId() != getCurrentThreadId() || getCurrentThreadId() == 0);
  124. const int sleepMsPerIteration = 5;
  125. int count = timeOutMilliseconds / sleepMsPerIteration;
  126. while (isThreadRunning())
  127. {
  128. if (timeOutMilliseconds >= 0 && --count < 0)
  129. return false;
  130. sleep (sleepMsPerIteration);
  131. }
  132. return true;
  133. }
  134. void Thread::stopThread (const int timeOutMilliseconds)
  135. {
  136. // agh! You can't stop the thread that's calling this method! How on earth
  137. // would that work??
  138. jassert (getCurrentThreadId() != getThreadId());
  139. const ScopedLock sl (startStopLock);
  140. if (isThreadRunning())
  141. {
  142. signalThreadShouldExit();
  143. notify();
  144. if (timeOutMilliseconds != 0)
  145. waitForThreadToExit (timeOutMilliseconds);
  146. if (isThreadRunning())
  147. {
  148. // very bad karma if this point is reached, as there are bound to be
  149. // locks and events left in silly states when a thread is killed by force..
  150. jassertfalse;
  151. Logger::writeToLog ("!! killing thread by force !!");
  152. killThread();
  153. threadHandle = nullptr;
  154. threadId = 0;
  155. }
  156. }
  157. }
  158. //==============================================================================
  159. bool Thread::setPriority (const int newPriority)
  160. {
  161. const ScopedLock sl (startStopLock);
  162. if (setThreadPriority (threadHandle, newPriority))
  163. {
  164. threadPriority = newPriority;
  165. return true;
  166. }
  167. return false;
  168. }
  169. bool Thread::setCurrentThreadPriority (const int newPriority)
  170. {
  171. return setThreadPriority (0, newPriority);
  172. }
  173. void Thread::setAffinityMask (const uint32 newAffinityMask)
  174. {
  175. affinityMask = newAffinityMask;
  176. }
  177. //==============================================================================
  178. bool Thread::wait (const int timeOutMilliseconds) const
  179. {
  180. return defaultEvent.wait (timeOutMilliseconds);
  181. }
  182. void Thread::notify() const
  183. {
  184. defaultEvent.signal();
  185. }
  186. //==============================================================================
  187. void SpinLock::enter() const noexcept
  188. {
  189. if (! tryEnter())
  190. {
  191. for (int i = 20; --i >= 0;)
  192. if (tryEnter())
  193. return;
  194. while (! tryEnter())
  195. Thread::yield();
  196. }
  197. }
  198. //==============================================================================
  199. #if JUCE_UNIT_TESTS
  200. class AtomicTests : public UnitTest
  201. {
  202. public:
  203. AtomicTests() : UnitTest ("Atomics") {}
  204. void runTest()
  205. {
  206. beginTest ("Misc");
  207. char a1[7];
  208. expect (numElementsInArray(a1) == 7);
  209. int a2[3];
  210. expect (numElementsInArray(a2) == 3);
  211. expect (ByteOrder::swap ((uint16) 0x1122) == 0x2211);
  212. expect (ByteOrder::swap ((uint32) 0x11223344) == 0x44332211);
  213. expect (ByteOrder::swap ((uint64) literal64bit (0x1122334455667788)) == literal64bit (0x8877665544332211));
  214. beginTest ("Atomic int");
  215. AtomicTester <int>::testInteger (*this);
  216. beginTest ("Atomic unsigned int");
  217. AtomicTester <unsigned int>::testInteger (*this);
  218. beginTest ("Atomic int32");
  219. AtomicTester <int32>::testInteger (*this);
  220. beginTest ("Atomic uint32");
  221. AtomicTester <uint32>::testInteger (*this);
  222. beginTest ("Atomic long");
  223. AtomicTester <long>::testInteger (*this);
  224. beginTest ("Atomic void*");
  225. AtomicTester <void*>::testInteger (*this);
  226. beginTest ("Atomic int*");
  227. AtomicTester <int*>::testInteger (*this);
  228. beginTest ("Atomic float");
  229. AtomicTester <float>::testFloat (*this);
  230. #if ! JUCE_64BIT_ATOMICS_UNAVAILABLE // 64-bit intrinsics aren't available on some old platforms
  231. beginTest ("Atomic int64");
  232. AtomicTester <int64>::testInteger (*this);
  233. beginTest ("Atomic uint64");
  234. AtomicTester <uint64>::testInteger (*this);
  235. beginTest ("Atomic double");
  236. AtomicTester <double>::testFloat (*this);
  237. #endif
  238. }
  239. template <typename Type>
  240. class AtomicTester
  241. {
  242. public:
  243. AtomicTester() {}
  244. static void testInteger (UnitTest& test)
  245. {
  246. Atomic<Type> a, b;
  247. a.set ((Type) 10);
  248. test.expect (a.value == (Type) 10);
  249. test.expect (a.get() == (Type) 10);
  250. a += (Type) 15;
  251. test.expect (a.get() == (Type) 25);
  252. a.memoryBarrier();
  253. a -= (Type) 5;
  254. test.expect (a.get() == (Type) 20);
  255. test.expect (++a == (Type) 21);
  256. ++a;
  257. test.expect (--a == (Type) 21);
  258. test.expect (a.get() == (Type) 21);
  259. a.memoryBarrier();
  260. testFloat (test);
  261. }
  262. static void testFloat (UnitTest& test)
  263. {
  264. Atomic<Type> a, b;
  265. a = (Type) 21;
  266. a.memoryBarrier();
  267. /* These are some simple test cases to check the atomics - let me know
  268. if any of these assertions fail on your system!
  269. */
  270. test.expect (a.get() == (Type) 21);
  271. test.expect (a.compareAndSetValue ((Type) 100, (Type) 50) == (Type) 21);
  272. test.expect (a.get() == (Type) 21);
  273. test.expect (a.compareAndSetValue ((Type) 101, a.get()) == (Type) 21);
  274. test.expect (a.get() == (Type) 101);
  275. test.expect (! a.compareAndSetBool ((Type) 300, (Type) 200));
  276. test.expect (a.get() == (Type) 101);
  277. test.expect (a.compareAndSetBool ((Type) 200, a.get()));
  278. test.expect (a.get() == (Type) 200);
  279. test.expect (a.exchange ((Type) 300) == (Type) 200);
  280. test.expect (a.get() == (Type) 300);
  281. b = a;
  282. test.expect (b.get() == a.get());
  283. }
  284. };
  285. };
  286. static AtomicTests atomicUnitTests;
  287. #endif