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.

439 lines
12KB

  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. BEGIN_JUCE_NAMESPACE
  19. //==============================================================================
  20. class RunningThreadsList
  21. {
  22. public:
  23. RunningThreadsList()
  24. {
  25. }
  26. ~RunningThreadsList()
  27. {
  28. // Some threads are still running! Make sure you stop all your
  29. // threads cleanly before your app quits!
  30. jassert (threads.size() == 0);
  31. }
  32. void add (Thread* const thread)
  33. {
  34. const SpinLock::ScopedLockType sl (lock);
  35. jassert (! threads.contains (thread));
  36. threads.add (thread);
  37. }
  38. void remove (Thread* const thread)
  39. {
  40. const SpinLock::ScopedLockType sl (lock);
  41. jassert (threads.contains (thread));
  42. threads.removeValue (thread);
  43. }
  44. int size() const noexcept
  45. {
  46. return threads.size();
  47. }
  48. Thread* getThreadWithID (const Thread::ThreadID targetID) const noexcept
  49. {
  50. const SpinLock::ScopedLockType sl (lock);
  51. for (int i = threads.size(); --i >= 0;)
  52. {
  53. Thread* const t = threads.getUnchecked(i);
  54. if (t->getThreadId() == targetID)
  55. return t;
  56. }
  57. return nullptr;
  58. }
  59. void stopAll (const int timeOutMilliseconds)
  60. {
  61. signalAllThreadsToStop();
  62. for (;;)
  63. {
  64. Thread* firstThread = getFirstThread();
  65. if (firstThread != nullptr)
  66. firstThread->stopThread (timeOutMilliseconds);
  67. else
  68. break;
  69. }
  70. }
  71. static RunningThreadsList& getInstance()
  72. {
  73. static RunningThreadsList runningThreads;
  74. return runningThreads;
  75. }
  76. private:
  77. Array<Thread*> threads;
  78. SpinLock lock;
  79. void signalAllThreadsToStop()
  80. {
  81. const SpinLock::ScopedLockType sl (lock);
  82. for (int i = threads.size(); --i >= 0;)
  83. threads.getUnchecked(i)->signalThreadShouldExit();
  84. }
  85. Thread* getFirstThread() const
  86. {
  87. const SpinLock::ScopedLockType sl (lock);
  88. return threads.getFirst();
  89. }
  90. };
  91. //==============================================================================
  92. void Thread::threadEntryPoint()
  93. {
  94. RunningThreadsList::getInstance().add (this);
  95. JUCE_TRY
  96. {
  97. if (threadName_.isNotEmpty())
  98. setCurrentThreadName (threadName_);
  99. if (startSuspensionEvent_.wait (10000))
  100. {
  101. jassert (getCurrentThreadId() == threadId_);
  102. if (affinityMask_ != 0)
  103. setCurrentThreadAffinityMask (affinityMask_);
  104. run();
  105. }
  106. }
  107. JUCE_CATCH_ALL_ASSERT
  108. RunningThreadsList::getInstance().remove (this);
  109. closeThreadHandle();
  110. }
  111. // used to wrap the incoming call from the platform-specific code
  112. void JUCE_API juce_threadEntryPoint (void* userData)
  113. {
  114. static_cast <Thread*> (userData)->threadEntryPoint();
  115. }
  116. //==============================================================================
  117. Thread::Thread (const String& threadName)
  118. : threadName_ (threadName),
  119. threadHandle_ (nullptr),
  120. threadId_ (0),
  121. threadPriority_ (5),
  122. affinityMask_ (0),
  123. threadShouldExit_ (false)
  124. {
  125. }
  126. Thread::~Thread()
  127. {
  128. /* If your thread class's destructor has been called without first stopping the thread, that
  129. means that this partially destructed object is still performing some work - and that's
  130. probably a Bad Thing!
  131. To avoid this type of nastiness, always make sure you call stopThread() before or during
  132. your subclass's destructor.
  133. */
  134. jassert (! isThreadRunning());
  135. stopThread (100);
  136. }
  137. //==============================================================================
  138. void Thread::startThread()
  139. {
  140. const ScopedLock sl (startStopLock);
  141. threadShouldExit_ = false;
  142. if (threadHandle_ == nullptr)
  143. {
  144. launchThread();
  145. setThreadPriority (threadHandle_, threadPriority_);
  146. startSuspensionEvent_.signal();
  147. }
  148. }
  149. void Thread::startThread (const int priority)
  150. {
  151. const ScopedLock sl (startStopLock);
  152. if (threadHandle_ == nullptr)
  153. {
  154. threadPriority_ = priority;
  155. startThread();
  156. }
  157. else
  158. {
  159. setPriority (priority);
  160. }
  161. }
  162. bool Thread::isThreadRunning() const
  163. {
  164. return threadHandle_ != nullptr;
  165. }
  166. //==============================================================================
  167. void Thread::signalThreadShouldExit()
  168. {
  169. threadShouldExit_ = true;
  170. }
  171. bool Thread::waitForThreadToExit (const int timeOutMilliseconds) const
  172. {
  173. // Doh! So how exactly do you expect this thread to wait for itself to stop??
  174. jassert (getThreadId() != getCurrentThreadId() || getCurrentThreadId() == 0);
  175. const int sleepMsPerIteration = 5;
  176. int count = timeOutMilliseconds / sleepMsPerIteration;
  177. while (isThreadRunning())
  178. {
  179. if (timeOutMilliseconds > 0 && --count < 0)
  180. return false;
  181. sleep (sleepMsPerIteration);
  182. }
  183. return true;
  184. }
  185. void Thread::stopThread (const int timeOutMilliseconds)
  186. {
  187. // agh! You can't stop the thread that's calling this method! How on earth
  188. // would that work??
  189. jassert (getCurrentThreadId() != getThreadId());
  190. const ScopedLock sl (startStopLock);
  191. if (isThreadRunning())
  192. {
  193. signalThreadShouldExit();
  194. notify();
  195. if (timeOutMilliseconds != 0)
  196. waitForThreadToExit (timeOutMilliseconds);
  197. if (isThreadRunning())
  198. {
  199. // very bad karma if this point is reached, as there are bound to be
  200. // locks and events left in silly states when a thread is killed by force..
  201. jassertfalse;
  202. Logger::writeToLog ("!! killing thread by force !!");
  203. killThread();
  204. RunningThreadsList::getInstance().remove (this);
  205. threadHandle_ = nullptr;
  206. threadId_ = 0;
  207. }
  208. }
  209. }
  210. //==============================================================================
  211. bool Thread::setPriority (const int priority)
  212. {
  213. const ScopedLock sl (startStopLock);
  214. if (setThreadPriority (threadHandle_, priority))
  215. {
  216. threadPriority_ = priority;
  217. return true;
  218. }
  219. return false;
  220. }
  221. bool Thread::setCurrentThreadPriority (const int priority)
  222. {
  223. return setThreadPriority (0, priority);
  224. }
  225. void Thread::setAffinityMask (const uint32 affinityMask)
  226. {
  227. affinityMask_ = affinityMask;
  228. }
  229. //==============================================================================
  230. bool Thread::wait (const int timeOutMilliseconds) const
  231. {
  232. return defaultEvent_.wait (timeOutMilliseconds);
  233. }
  234. void Thread::notify() const
  235. {
  236. defaultEvent_.signal();
  237. }
  238. //==============================================================================
  239. int Thread::getNumRunningThreads()
  240. {
  241. return RunningThreadsList::getInstance().size();
  242. }
  243. Thread* Thread::getCurrentThread()
  244. {
  245. return RunningThreadsList::getInstance().getThreadWithID (getCurrentThreadId());
  246. }
  247. void Thread::stopAllThreads (const int timeOutMilliseconds)
  248. {
  249. RunningThreadsList::getInstance().stopAll (timeOutMilliseconds);
  250. }
  251. //==============================================================================
  252. void SpinLock::enter() const noexcept
  253. {
  254. if (! tryEnter())
  255. {
  256. for (int i = 20; --i >= 0;)
  257. if (tryEnter())
  258. return;
  259. while (! tryEnter())
  260. Thread::yield();
  261. }
  262. }
  263. //==============================================================================
  264. #if JUCE_UNIT_TESTS
  265. class AtomicTests : public UnitTest
  266. {
  267. public:
  268. AtomicTests() : UnitTest ("Atomics") {}
  269. void runTest()
  270. {
  271. beginTest ("Misc");
  272. char a1[7];
  273. expect (numElementsInArray(a1) == 7);
  274. int a2[3];
  275. expect (numElementsInArray(a2) == 3);
  276. expect (ByteOrder::swap ((uint16) 0x1122) == 0x2211);
  277. expect (ByteOrder::swap ((uint32) 0x11223344) == 0x44332211);
  278. expect (ByteOrder::swap ((uint64) literal64bit (0x1122334455667788)) == literal64bit (0x8877665544332211));
  279. beginTest ("Atomic int");
  280. AtomicTester <int>::testInteger (*this);
  281. beginTest ("Atomic unsigned int");
  282. AtomicTester <unsigned int>::testInteger (*this);
  283. beginTest ("Atomic int32");
  284. AtomicTester <int32>::testInteger (*this);
  285. beginTest ("Atomic uint32");
  286. AtomicTester <uint32>::testInteger (*this);
  287. beginTest ("Atomic long");
  288. AtomicTester <long>::testInteger (*this);
  289. beginTest ("Atomic void*");
  290. AtomicTester <void*>::testInteger (*this);
  291. beginTest ("Atomic int*");
  292. AtomicTester <int*>::testInteger (*this);
  293. beginTest ("Atomic float");
  294. AtomicTester <float>::testFloat (*this);
  295. #if ! JUCE_64BIT_ATOMICS_UNAVAILABLE // 64-bit intrinsics aren't available on some old platforms
  296. beginTest ("Atomic int64");
  297. AtomicTester <int64>::testInteger (*this);
  298. beginTest ("Atomic uint64");
  299. AtomicTester <uint64>::testInteger (*this);
  300. beginTest ("Atomic double");
  301. AtomicTester <double>::testFloat (*this);
  302. #endif
  303. }
  304. template <typename Type>
  305. class AtomicTester
  306. {
  307. public:
  308. AtomicTester() {}
  309. static void testInteger (UnitTest& test)
  310. {
  311. Atomic<Type> a, b;
  312. a.set ((Type) 10);
  313. test.expect (a.value == (Type) 10);
  314. test.expect (a.get() == (Type) 10);
  315. a += (Type) 15;
  316. test.expect (a.get() == (Type) 25);
  317. a.memoryBarrier();
  318. a -= (Type) 5;
  319. test.expect (a.get() == (Type) 20);
  320. test.expect (++a == (Type) 21);
  321. ++a;
  322. test.expect (--a == (Type) 21);
  323. test.expect (a.get() == (Type) 21);
  324. a.memoryBarrier();
  325. testFloat (test);
  326. }
  327. static void testFloat (UnitTest& test)
  328. {
  329. Atomic<Type> a, b;
  330. a = (Type) 21;
  331. a.memoryBarrier();
  332. /* These are some simple test cases to check the atomics - let me know
  333. if any of these assertions fail on your system!
  334. */
  335. test.expect (a.get() == (Type) 21);
  336. test.expect (a.compareAndSetValue ((Type) 100, (Type) 50) == (Type) 21);
  337. test.expect (a.get() == (Type) 21);
  338. test.expect (a.compareAndSetValue ((Type) 101, a.get()) == (Type) 21);
  339. test.expect (a.get() == (Type) 101);
  340. test.expect (! a.compareAndSetBool ((Type) 300, (Type) 200));
  341. test.expect (a.get() == (Type) 101);
  342. test.expect (a.compareAndSetBool ((Type) 200, a.get()));
  343. test.expect (a.get() == (Type) 200);
  344. test.expect (a.exchange ((Type) 300) == (Type) 200);
  345. test.expect (a.get() == (Type) 300);
  346. b = a;
  347. test.expect (b.get() == a.get());
  348. }
  349. };
  350. };
  351. static AtomicTests atomicUnitTests;
  352. #endif
  353. END_JUCE_NAMESPACE