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.

362 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. // NB: deadlock possible if you try to set the thread prio from the thread itself,
  162. // so using setCurrentThreadPriority instead in that case.
  163. if (getCurrentThreadId() == getThreadId())
  164. return setCurrentThreadPriority (newPriority);
  165. const ScopedLock sl (startStopLock);
  166. if (setThreadPriority (threadHandle, newPriority))
  167. {
  168. threadPriority = newPriority;
  169. return true;
  170. }
  171. return false;
  172. }
  173. bool Thread::setCurrentThreadPriority (const int newPriority)
  174. {
  175. return setThreadPriority (0, newPriority);
  176. }
  177. void Thread::setAffinityMask (const uint32 newAffinityMask)
  178. {
  179. affinityMask = newAffinityMask;
  180. }
  181. //==============================================================================
  182. bool Thread::wait (const int timeOutMilliseconds) const
  183. {
  184. return defaultEvent.wait (timeOutMilliseconds);
  185. }
  186. void Thread::notify() const
  187. {
  188. defaultEvent.signal();
  189. }
  190. //==============================================================================
  191. void SpinLock::enter() const noexcept
  192. {
  193. if (! tryEnter())
  194. {
  195. for (int i = 20; --i >= 0;)
  196. if (tryEnter())
  197. return;
  198. while (! tryEnter())
  199. Thread::yield();
  200. }
  201. }
  202. //==============================================================================
  203. #if JUCE_UNIT_TESTS
  204. class AtomicTests : public UnitTest
  205. {
  206. public:
  207. AtomicTests() : UnitTest ("Atomics") {}
  208. void runTest()
  209. {
  210. beginTest ("Misc");
  211. char a1[7];
  212. expect (numElementsInArray(a1) == 7);
  213. int a2[3];
  214. expect (numElementsInArray(a2) == 3);
  215. expect (ByteOrder::swap ((uint16) 0x1122) == 0x2211);
  216. expect (ByteOrder::swap ((uint32) 0x11223344) == 0x44332211);
  217. expect (ByteOrder::swap ((uint64) literal64bit (0x1122334455667788)) == literal64bit (0x8877665544332211));
  218. beginTest ("Atomic int");
  219. AtomicTester <int>::testInteger (*this);
  220. beginTest ("Atomic unsigned int");
  221. AtomicTester <unsigned int>::testInteger (*this);
  222. beginTest ("Atomic int32");
  223. AtomicTester <int32>::testInteger (*this);
  224. beginTest ("Atomic uint32");
  225. AtomicTester <uint32>::testInteger (*this);
  226. beginTest ("Atomic long");
  227. AtomicTester <long>::testInteger (*this);
  228. beginTest ("Atomic void*");
  229. AtomicTester <void*>::testInteger (*this);
  230. beginTest ("Atomic int*");
  231. AtomicTester <int*>::testInteger (*this);
  232. beginTest ("Atomic float");
  233. AtomicTester <float>::testFloat (*this);
  234. #if ! JUCE_64BIT_ATOMICS_UNAVAILABLE // 64-bit intrinsics aren't available on some old platforms
  235. beginTest ("Atomic int64");
  236. AtomicTester <int64>::testInteger (*this);
  237. beginTest ("Atomic uint64");
  238. AtomicTester <uint64>::testInteger (*this);
  239. beginTest ("Atomic double");
  240. AtomicTester <double>::testFloat (*this);
  241. #endif
  242. }
  243. template <typename Type>
  244. class AtomicTester
  245. {
  246. public:
  247. AtomicTester() {}
  248. static void testInteger (UnitTest& test)
  249. {
  250. Atomic<Type> a, b;
  251. a.set ((Type) 10);
  252. test.expect (a.value == (Type) 10);
  253. test.expect (a.get() == (Type) 10);
  254. a += (Type) 15;
  255. test.expect (a.get() == (Type) 25);
  256. a.memoryBarrier();
  257. a -= (Type) 5;
  258. test.expect (a.get() == (Type) 20);
  259. test.expect (++a == (Type) 21);
  260. ++a;
  261. test.expect (--a == (Type) 21);
  262. test.expect (a.get() == (Type) 21);
  263. a.memoryBarrier();
  264. testFloat (test);
  265. }
  266. static void testFloat (UnitTest& test)
  267. {
  268. Atomic<Type> a, b;
  269. a = (Type) 21;
  270. a.memoryBarrier();
  271. /* These are some simple test cases to check the atomics - let me know
  272. if any of these assertions fail on your system!
  273. */
  274. test.expect (a.get() == (Type) 21);
  275. test.expect (a.compareAndSetValue ((Type) 100, (Type) 50) == (Type) 21);
  276. test.expect (a.get() == (Type) 21);
  277. test.expect (a.compareAndSetValue ((Type) 101, a.get()) == (Type) 21);
  278. test.expect (a.get() == (Type) 101);
  279. test.expect (! a.compareAndSetBool ((Type) 300, (Type) 200));
  280. test.expect (a.get() == (Type) 101);
  281. test.expect (a.compareAndSetBool ((Type) 200, a.get()));
  282. test.expect (a.get() == (Type) 200);
  283. test.expect (a.exchange ((Type) 300) == (Type) 200);
  284. test.expect (a.get() == (Type) 300);
  285. b = a;
  286. test.expect (b.get() == a.get());
  287. }
  288. };
  289. };
  290. static AtomicTests atomicUnitTests;
  291. #endif