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.

298 lines
7.9KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-10 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. #include "../core/juce_StandardHeader.h"
  19. BEGIN_JUCE_NAMESPACE
  20. #include "juce_Thread.h"
  21. #include "juce_ScopedLock.h"
  22. #include "../core/juce_Time.h"
  23. // these functions are implemented in the platform-specific code.
  24. void* juce_createThread (void* userData);
  25. void juce_killThread (void* handle);
  26. bool juce_setThreadPriority (void* handle, int priority);
  27. void juce_setCurrentThreadName (const String& name);
  28. #if JUCE_WINDOWS
  29. void juce_CloseThreadHandle (void* handle);
  30. #endif
  31. //==============================================================================
  32. void Thread::threadEntryPoint (Thread* const thread)
  33. {
  34. {
  35. const ScopedLock sl (runningThreadsLock);
  36. runningThreads.add (thread);
  37. }
  38. JUCE_TRY
  39. {
  40. thread->threadId_ = Thread::getCurrentThreadId();
  41. if (thread->threadName_.isNotEmpty())
  42. juce_setCurrentThreadName (thread->threadName_);
  43. if (thread->startSuspensionEvent_.wait (10000))
  44. {
  45. if (thread->affinityMask_ != 0)
  46. setCurrentThreadAffinityMask (thread->affinityMask_);
  47. thread->run();
  48. }
  49. }
  50. JUCE_CATCH_ALL_ASSERT
  51. {
  52. const ScopedLock sl (runningThreadsLock);
  53. jassert (runningThreads.contains (thread));
  54. runningThreads.removeValue (thread);
  55. }
  56. #if JUCE_WINDOWS
  57. juce_CloseThreadHandle (thread->threadHandle_);
  58. #endif
  59. thread->threadHandle_ = 0;
  60. thread->threadId_ = 0;
  61. }
  62. // used to wrap the incoming call from the platform-specific code
  63. void JUCE_API juce_threadEntryPoint (void* userData)
  64. {
  65. Thread::threadEntryPoint (static_cast <Thread*> (userData));
  66. }
  67. //==============================================================================
  68. Thread::Thread (const String& threadName)
  69. : threadName_ (threadName),
  70. threadHandle_ (0),
  71. threadPriority_ (5),
  72. threadId_ (0),
  73. affinityMask_ (0),
  74. threadShouldExit_ (false)
  75. {
  76. }
  77. Thread::~Thread()
  78. {
  79. /* If your thread class's destructor has been called without first stopping the thread, that
  80. means that this partially destructed object is still performing some work - and that's not
  81. unlikely to be a safe approach to take!
  82. To avoid this type of nastiness, always make sure you call stopThread() before or during
  83. your subclass's destructor.
  84. */
  85. jassert (! isThreadRunning());
  86. stopThread (100);
  87. }
  88. //==============================================================================
  89. void Thread::startThread()
  90. {
  91. const ScopedLock sl (startStopLock);
  92. threadShouldExit_ = false;
  93. if (threadHandle_ == 0)
  94. {
  95. threadHandle_ = juce_createThread (this);
  96. juce_setThreadPriority (threadHandle_, threadPriority_);
  97. startSuspensionEvent_.signal();
  98. }
  99. }
  100. void Thread::startThread (const int priority)
  101. {
  102. const ScopedLock sl (startStopLock);
  103. if (threadHandle_ == 0)
  104. {
  105. threadPriority_ = priority;
  106. startThread();
  107. }
  108. else
  109. {
  110. setPriority (priority);
  111. }
  112. }
  113. bool Thread::isThreadRunning() const
  114. {
  115. return threadHandle_ != 0;
  116. }
  117. //==============================================================================
  118. void Thread::signalThreadShouldExit()
  119. {
  120. threadShouldExit_ = true;
  121. }
  122. bool Thread::waitForThreadToExit (const int timeOutMilliseconds) const
  123. {
  124. // Doh! So how exactly do you expect this thread to wait for itself to stop??
  125. jassert (getThreadId() != getCurrentThreadId());
  126. const int sleepMsPerIteration = 5;
  127. int count = timeOutMilliseconds / sleepMsPerIteration;
  128. while (isThreadRunning())
  129. {
  130. if (timeOutMilliseconds > 0 && --count < 0)
  131. return false;
  132. sleep (sleepMsPerIteration);
  133. }
  134. return true;
  135. }
  136. void Thread::stopThread (const int timeOutMilliseconds)
  137. {
  138. // agh! You can't stop the thread that's calling this method! How on earth
  139. // would that work??
  140. jassert (getCurrentThreadId() != getThreadId());
  141. const ScopedLock sl (startStopLock);
  142. if (isThreadRunning())
  143. {
  144. signalThreadShouldExit();
  145. notify();
  146. if (timeOutMilliseconds != 0)
  147. waitForThreadToExit (timeOutMilliseconds);
  148. if (isThreadRunning())
  149. {
  150. // very bad karma if this point is reached, as
  151. // there are bound to be locks and events left in
  152. // silly states when a thread is killed by force..
  153. jassertfalse;
  154. Logger::writeToLog ("!! killing thread by force !!");
  155. juce_killThread (threadHandle_);
  156. threadHandle_ = 0;
  157. threadId_ = 0;
  158. const ScopedLock sl2 (runningThreadsLock);
  159. runningThreads.removeValue (this);
  160. }
  161. }
  162. }
  163. //==============================================================================
  164. bool Thread::setPriority (const int priority)
  165. {
  166. const ScopedLock sl (startStopLock);
  167. const bool worked = juce_setThreadPriority (threadHandle_, priority);
  168. if (worked)
  169. threadPriority_ = priority;
  170. return worked;
  171. }
  172. bool Thread::setCurrentThreadPriority (const int priority)
  173. {
  174. return juce_setThreadPriority (0, priority);
  175. }
  176. void Thread::setAffinityMask (const uint32 affinityMask)
  177. {
  178. affinityMask_ = affinityMask;
  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. int Thread::getNumRunningThreads()
  191. {
  192. return runningThreads.size();
  193. }
  194. Thread* Thread::getCurrentThread()
  195. {
  196. const ThreadID thisId = getCurrentThreadId();
  197. const ScopedLock sl (runningThreadsLock);
  198. for (int i = runningThreads.size(); --i >= 0;)
  199. {
  200. Thread* const t = runningThreads.getUnchecked(i);
  201. if (t->threadId_ == thisId)
  202. return t;
  203. }
  204. return 0;
  205. }
  206. void Thread::stopAllThreads (const int timeOutMilliseconds)
  207. {
  208. {
  209. const ScopedLock sl (runningThreadsLock);
  210. for (int i = runningThreads.size(); --i >= 0;)
  211. runningThreads.getUnchecked(i)->signalThreadShouldExit();
  212. }
  213. for (;;)
  214. {
  215. Thread* firstThread;
  216. {
  217. const ScopedLock sl (runningThreadsLock);
  218. firstThread = runningThreads.getFirst();
  219. }
  220. if (firstThread == 0)
  221. break;
  222. firstThread->stopThread (timeOutMilliseconds);
  223. }
  224. }
  225. Array<Thread*> Thread::runningThreads;
  226. CriticalSection Thread::runningThreadsLock;
  227. END_JUCE_NAMESPACE