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.

361 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 uint32 timeoutEnd = Time::getMillisecondCounter() + (uint32) timeOutMilliseconds;
  125. while (isThreadRunning())
  126. {
  127. if (timeOutMilliseconds >= 0 && Time::getMillisecondCounter() > timeoutEnd)
  128. return false;
  129. sleep (2);
  130. }
  131. return true;
  132. }
  133. void Thread::stopThread (const int timeOutMilliseconds)
  134. {
  135. // agh! You can't stop the thread that's calling this method! How on earth
  136. // would that work??
  137. jassert (getCurrentThreadId() != getThreadId());
  138. const ScopedLock sl (startStopLock);
  139. if (isThreadRunning())
  140. {
  141. signalThreadShouldExit();
  142. notify();
  143. if (timeOutMilliseconds != 0)
  144. waitForThreadToExit (timeOutMilliseconds);
  145. if (isThreadRunning())
  146. {
  147. // very bad karma if this point is reached, as there are bound to be
  148. // locks and events left in silly states when a thread is killed by force..
  149. jassertfalse;
  150. Logger::writeToLog ("!! killing thread by force !!");
  151. killThread();
  152. threadHandle = nullptr;
  153. threadId = 0;
  154. }
  155. }
  156. }
  157. //==============================================================================
  158. bool Thread::setPriority (const int newPriority)
  159. {
  160. // NB: deadlock possible if you try to set the thread prio from the thread itself,
  161. // so using setCurrentThreadPriority instead in that case.
  162. if (getCurrentThreadId() == getThreadId())
  163. return setCurrentThreadPriority (newPriority);
  164. const ScopedLock sl (startStopLock);
  165. if (setThreadPriority (threadHandle, newPriority))
  166. {
  167. threadPriority = newPriority;
  168. return true;
  169. }
  170. return false;
  171. }
  172. bool Thread::setCurrentThreadPriority (const int newPriority)
  173. {
  174. return setThreadPriority (0, newPriority);
  175. }
  176. void Thread::setAffinityMask (const uint32 newAffinityMask)
  177. {
  178. affinityMask = newAffinityMask;
  179. }
  180. //==============================================================================
  181. bool Thread::wait (const int timeOutMilliseconds) const
  182. {
  183. return defaultEvent.wait (timeOutMilliseconds);
  184. }
  185. void Thread::notify() const
  186. {
  187. defaultEvent.signal();
  188. }
  189. //==============================================================================
  190. void SpinLock::enter() const noexcept
  191. {
  192. if (! tryEnter())
  193. {
  194. for (int i = 20; --i >= 0;)
  195. if (tryEnter())
  196. return;
  197. while (! tryEnter())
  198. Thread::yield();
  199. }
  200. }
  201. //==============================================================================
  202. #if JUCE_UNIT_TESTS
  203. class AtomicTests : public UnitTest
  204. {
  205. public:
  206. AtomicTests() : UnitTest ("Atomics") {}
  207. void runTest()
  208. {
  209. beginTest ("Misc");
  210. char a1[7];
  211. expect (numElementsInArray(a1) == 7);
  212. int a2[3];
  213. expect (numElementsInArray(a2) == 3);
  214. expect (ByteOrder::swap ((uint16) 0x1122) == 0x2211);
  215. expect (ByteOrder::swap ((uint32) 0x11223344) == 0x44332211);
  216. expect (ByteOrder::swap ((uint64) literal64bit (0x1122334455667788)) == literal64bit (0x8877665544332211));
  217. beginTest ("Atomic int");
  218. AtomicTester <int>::testInteger (*this);
  219. beginTest ("Atomic unsigned int");
  220. AtomicTester <unsigned int>::testInteger (*this);
  221. beginTest ("Atomic int32");
  222. AtomicTester <int32>::testInteger (*this);
  223. beginTest ("Atomic uint32");
  224. AtomicTester <uint32>::testInteger (*this);
  225. beginTest ("Atomic long");
  226. AtomicTester <long>::testInteger (*this);
  227. beginTest ("Atomic void*");
  228. AtomicTester <void*>::testInteger (*this);
  229. beginTest ("Atomic int*");
  230. AtomicTester <int*>::testInteger (*this);
  231. beginTest ("Atomic float");
  232. AtomicTester <float>::testFloat (*this);
  233. #if ! JUCE_64BIT_ATOMICS_UNAVAILABLE // 64-bit intrinsics aren't available on some old platforms
  234. beginTest ("Atomic int64");
  235. AtomicTester <int64>::testInteger (*this);
  236. beginTest ("Atomic uint64");
  237. AtomicTester <uint64>::testInteger (*this);
  238. beginTest ("Atomic double");
  239. AtomicTester <double>::testFloat (*this);
  240. #endif
  241. }
  242. template <typename Type>
  243. class AtomicTester
  244. {
  245. public:
  246. AtomicTester() {}
  247. static void testInteger (UnitTest& test)
  248. {
  249. Atomic<Type> a, b;
  250. a.set ((Type) 10);
  251. test.expect (a.value == (Type) 10);
  252. test.expect (a.get() == (Type) 10);
  253. a += (Type) 15;
  254. test.expect (a.get() == (Type) 25);
  255. a.memoryBarrier();
  256. a -= (Type) 5;
  257. test.expect (a.get() == (Type) 20);
  258. test.expect (++a == (Type) 21);
  259. ++a;
  260. test.expect (--a == (Type) 21);
  261. test.expect (a.get() == (Type) 21);
  262. a.memoryBarrier();
  263. testFloat (test);
  264. }
  265. static void testFloat (UnitTest& test)
  266. {
  267. Atomic<Type> a, b;
  268. a = (Type) 21;
  269. a.memoryBarrier();
  270. /* These are some simple test cases to check the atomics - let me know
  271. if any of these assertions fail on your system!
  272. */
  273. test.expect (a.get() == (Type) 21);
  274. test.expect (a.compareAndSetValue ((Type) 100, (Type) 50) == (Type) 21);
  275. test.expect (a.get() == (Type) 21);
  276. test.expect (a.compareAndSetValue ((Type) 101, a.get()) == (Type) 21);
  277. test.expect (a.get() == (Type) 101);
  278. test.expect (! a.compareAndSetBool ((Type) 300, (Type) 200));
  279. test.expect (a.get() == (Type) 101);
  280. test.expect (a.compareAndSetBool ((Type) 200, a.get()));
  281. test.expect (a.get() == (Type) 200);
  282. test.expect (a.exchange ((Type) 300) == (Type) 200);
  283. test.expect (a.get() == (Type) 300);
  284. b = a;
  285. test.expect (b.get() == a.get());
  286. }
  287. };
  288. };
  289. static AtomicTests atomicUnitTests;
  290. #endif