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.

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