OpenShot Library | libopenshot-audio  0.2.0
juce_Thread.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2017 - ROLI Ltd.
6 
7  JUCE is an open source library subject to commercial or open-source
8  licensing.
9 
10  The code included in this file is provided under the terms of the ISC license
11  http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12  To use, copy, modify, and/or distribute this software for any purpose with or
13  without fee is hereby granted provided that the above copyright notice and
14  this permission notice appear in all copies.
15 
16  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18  DISCLAIMED.
19 
20  ==============================================================================
21 */
22 
23 namespace juce
24 {
25 
26 Thread::Thread (const String& name, size_t stackSize)
27  : threadName (name), threadStackSize (stackSize)
28 {
29 }
30 
32 {
33  if (deleteOnThreadEnd)
34  return;
35 
36  /* If your thread class's destructor has been called without first stopping the thread, that
37  means that this partially destructed object is still performing some work - and that's
38  probably a Bad Thing!
39 
40  To avoid this type of nastiness, always make sure you call stopThread() before or during
41  your subclass's destructor.
42  */
43  jassert (! isThreadRunning());
44 
45  stopThread (-1);
46 }
47 
48 //==============================================================================
49 // Use a ref-counted object to hold this shared data, so that it can outlive its static
50 // shared pointer when threads are still running during static shutdown.
52 {
53  CurrentThreadHolder() noexcept {}
54 
57 
58  JUCE_DECLARE_NON_COPYABLE (CurrentThreadHolder)
59 };
60 
61 static char currentThreadHolderLock [sizeof (SpinLock)]; // (statically initialised to zeros).
62 
63 static SpinLock* castToSpinLockWithoutAliasingWarning (void* s)
64 {
65  return static_cast<SpinLock*> (s);
66 }
67 
68 static CurrentThreadHolder::Ptr getCurrentThreadHolder()
69 {
70  static CurrentThreadHolder::Ptr currentThreadHolder;
71  SpinLock::ScopedLockType lock (*castToSpinLockWithoutAliasingWarning (currentThreadHolderLock));
72 
73  if (currentThreadHolder == nullptr)
74  currentThreadHolder = new CurrentThreadHolder();
75 
76  return currentThreadHolder;
77 }
78 
79 void Thread::threadEntryPoint()
80 {
81  const CurrentThreadHolder::Ptr currentThreadHolder (getCurrentThreadHolder());
82  currentThreadHolder->value = this;
83 
84  if (threadName.isNotEmpty())
85  setCurrentThreadName (threadName);
86 
87  if (startSuspensionEvent.wait (10000))
88  {
89  jassert (getCurrentThreadId() == threadId.get());
90 
91  if (affinityMask != 0)
92  setCurrentThreadAffinityMask (affinityMask);
93 
94  try
95  {
96  run();
97  }
98  catch (...)
99  {
100  jassertfalse; // Your run() method mustn't throw any exceptions!
101  }
102  }
103 
104  currentThreadHolder->value.releaseCurrentThreadStorage();
105 
106  // Once closeThreadHandle is called this class may be deleted by a different
107  // thread, so we need to store deleteOnThreadEnd in a local variable.
108  auto shouldDeleteThis = deleteOnThreadEnd;
109  closeThreadHandle();
110 
111  if (shouldDeleteThis)
112  delete this;
113 }
114 
115 // used to wrap the incoming call from the platform-specific code
116 void JUCE_API juce_threadEntryPoint (void* userData)
117 {
118  static_cast<Thread*> (userData)->threadEntryPoint();
119 }
120 
121 //==============================================================================
123 {
124  const ScopedLock sl (startStopLock);
125 
126  shouldExit = 0;
127 
128  if (threadHandle.get() == nullptr)
129  {
130  launchThread();
131  setThreadPriority (threadHandle.get(), threadPriority);
132  startSuspensionEvent.signal();
133  }
134 }
135 
136 void Thread::startThread (int priority)
137 {
138  const ScopedLock sl (startStopLock);
139 
140  if (threadHandle.get() == nullptr)
141  {
142  auto isRealtime = (priority == realtimeAudioPriority);
143 
144  #if JUCE_ANDROID
145  isAndroidRealtimeThread = isRealtime;
146  #endif
147 
148  if (isRealtime)
149  priority = 9;
150 
151  threadPriority = priority;
152  startThread();
153  }
154  else
155  {
156  setPriority (priority);
157  }
158 }
159 
161 {
162  return threadHandle.get() != nullptr;
163 }
164 
166 {
167  return getCurrentThreadHolder()->value.get();
168 }
169 
171 {
172  return threadId.get();
173 }
174 
175 //==============================================================================
177 {
178  shouldExit = 1;
179  listeners.call ([] (Listener& l) { l.exitSignalSent(); });
180 }
181 
183 {
184  return shouldExit.get() != 0;
185 }
186 
188 {
189  if (auto* currentThread = getCurrentThread())
190  return currentThread->threadShouldExit();
191 
192  return false;
193 }
194 
195 bool Thread::waitForThreadToExit (const int timeOutMilliseconds) const
196 {
197  // Doh! So how exactly do you expect this thread to wait for itself to stop??
198  jassert (getThreadId() != getCurrentThreadId() || getCurrentThreadId() == ThreadID());
199 
200  auto timeoutEnd = Time::getMillisecondCounter() + (uint32) timeOutMilliseconds;
201 
202  while (isThreadRunning())
203  {
204  if (timeOutMilliseconds >= 0 && Time::getMillisecondCounter() > timeoutEnd)
205  return false;
206 
207  sleep (2);
208  }
209 
210  return true;
211 }
212 
213 bool Thread::stopThread (const int timeOutMilliseconds)
214 {
215  // agh! You can't stop the thread that's calling this method! How on earth
216  // would that work??
217  jassert (getCurrentThreadId() != getThreadId());
218 
219  const ScopedLock sl (startStopLock);
220 
221  if (isThreadRunning())
222  {
224  notify();
225 
226  if (timeOutMilliseconds != 0)
227  waitForThreadToExit (timeOutMilliseconds);
228 
229  if (isThreadRunning())
230  {
231  // very bad karma if this point is reached, as there are bound to be
232  // locks and events left in silly states when a thread is killed by force..
233  jassertfalse;
234  Logger::writeToLog ("!! killing thread by force !!");
235 
236  killThread();
237 
238  threadHandle = nullptr;
239  threadId = {};
240  return false;
241  }
242  }
243 
244  return true;
245 }
246 
248 {
249  listeners.add (listener);
250 }
251 
253 {
254  listeners.remove (listener);
255 }
256 
257 //==============================================================================
258 bool Thread::setPriority (int newPriority)
259 {
260  bool isRealtime = (newPriority == realtimeAudioPriority);
261 
262  if (isRealtime)
263  newPriority = 9;
264 
265  // NB: deadlock possible if you try to set the thread prio from the thread itself,
266  // so using setCurrentThreadPriority instead in that case.
267  if (getCurrentThreadId() == getThreadId())
268  return setCurrentThreadPriority (newPriority);
269 
270  const ScopedLock sl (startStopLock);
271 
272  #if JUCE_ANDROID
273  // you cannot switch from or to an Android realtime thread once the
274  // thread is already running!
275  jassert (isThreadRunning() && (isRealtime == isAndroidRealtimeThread));
276 
277  isAndroidRealtimeThread = isRealtime;
278  #endif
279 
280  if ((! isThreadRunning()) || setThreadPriority (threadHandle.get(), newPriority))
281  {
282  threadPriority = newPriority;
283  return true;
284  }
285 
286  return false;
287 }
288 
289 bool Thread::setCurrentThreadPriority (const int newPriority)
290 {
291  return setThreadPriority ({}, newPriority);
292 }
293 
294 void Thread::setAffinityMask (const uint32 newAffinityMask)
295 {
296  affinityMask = newAffinityMask;
297 }
298 
299 //==============================================================================
300 bool Thread::wait (const int timeOutMilliseconds) const
301 {
302  return defaultEvent.wait (timeOutMilliseconds);
303 }
304 
305 void Thread::notify() const
306 {
307  defaultEvent.signal();
308 }
309 
310 //==============================================================================
311 struct LambdaThread : public Thread
312 {
313  LambdaThread (std::function<void()> f) : Thread ("anonymous"), fn (f) {}
314 
315  void run() override
316  {
317  fn();
318  fn = {}; // free any objects that the lambda might contain while the thread is still active
319  }
320 
321  std::function<void()> fn;
322 
323  JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LambdaThread)
324 };
325 
326 void Thread::launch (std::function<void()> functionToRun)
327 {
328  auto anon = new LambdaThread (functionToRun);
329  anon->deleteOnThreadEnd = true;
330  anon->startThread();
331 }
332 
333 //==============================================================================
334 void SpinLock::enter() const noexcept
335 {
336  if (! tryEnter())
337  {
338  for (int i = 20; --i >= 0;)
339  if (tryEnter())
340  return;
341 
342  while (! tryEnter())
343  Thread::yield();
344  }
345 }
346 
347 //==============================================================================
348 bool JUCE_CALLTYPE Process::isRunningUnderDebugger() noexcept
349 {
350  return juce_isRunningUnderDebugger();
351 }
352 
353 #if JUCE_UNIT_TESTS
354 
355 //==============================================================================
356 class AtomicTests : public UnitTest
357 {
358 public:
359  AtomicTests() : UnitTest ("Atomics", "Threads") {}
360 
361  void runTest() override
362  {
363  beginTest ("Misc");
364 
365  char a1[7];
366  expect (numElementsInArray(a1) == 7);
367  int a2[3];
368  expect (numElementsInArray(a2) == 3);
369 
370  expect (ByteOrder::swap ((uint16) 0x1122) == 0x2211);
371  expect (ByteOrder::swap ((uint32) 0x11223344) == 0x44332211);
372  expect (ByteOrder::swap ((uint64) 0x1122334455667788ULL) == 0x8877665544332211LL);
373 
374  beginTest ("Atomic int");
375  AtomicTester <int>::testInteger (*this);
376  beginTest ("Atomic unsigned int");
377  AtomicTester <unsigned int>::testInteger (*this);
378  beginTest ("Atomic int32");
379  AtomicTester <int32>::testInteger (*this);
380  beginTest ("Atomic uint32");
381  AtomicTester <uint32>::testInteger (*this);
382  beginTest ("Atomic long");
383  AtomicTester <long>::testInteger (*this);
384  beginTest ("Atomic int*");
385  AtomicTester <int*>::testInteger (*this);
386  beginTest ("Atomic float");
387  AtomicTester <float>::testFloat (*this);
388  #if ! JUCE_64BIT_ATOMICS_UNAVAILABLE // 64-bit intrinsics aren't available on some old platforms
389  beginTest ("Atomic int64");
390  AtomicTester <int64>::testInteger (*this);
391  beginTest ("Atomic uint64");
392  AtomicTester <uint64>::testInteger (*this);
393  beginTest ("Atomic double");
394  AtomicTester <double>::testFloat (*this);
395  #endif
396  beginTest ("Atomic pointer increment/decrement");
397  Atomic<int*> a (a2); int* b (a2);
398  expect (++a == ++b);
399 
400  {
401  beginTest ("Atomic void*");
402  Atomic<void*> atomic;
403  void* c;
404 
405  atomic.set ((void*) 10);
406  c = (void*) 10;
407 
408  expect (atomic.value == c);
409  expect (atomic.get() == c);
410  }
411  }
412 
413  template <typename Type>
414  class AtomicTester
415  {
416  public:
417  AtomicTester() {}
418 
419  static void testInteger (UnitTest& test)
420  {
421  Atomic<Type> a, b;
422  Type c;
423 
424  a.set ((Type) 10);
425  c = (Type) 10;
426 
427  test.expect (a.value == c);
428  test.expect (a.get() == c);
429 
430  a += 15;
431  c += 15;
432  test.expect (a.get() == c);
433  a.memoryBarrier();
434 
435  a -= 5;
436  c -= 5;
437  test.expect (a.get() == c);
438 
439  test.expect (++a == ++c);
440  ++a;
441  ++c;
442  test.expect (--a == --c);
443  test.expect (a.get() == c);
444  a.memoryBarrier();
445 
446  testFloat (test);
447  }
448 
449 
450 
451  static void testFloat (UnitTest& test)
452  {
453  Atomic<Type> a, b;
454  a = (Type) 101;
455  a.memoryBarrier();
456 
457  /* These are some simple test cases to check the atomics - let me know
458  if any of these assertions fail on your system!
459  */
460  test.expect (a.get() == (Type) 101);
461  test.expect (! a.compareAndSetBool ((Type) 300, (Type) 200));
462  test.expect (a.get() == (Type) 101);
463  test.expect (a.compareAndSetBool ((Type) 200, a.get()));
464  test.expect (a.get() == (Type) 200);
465 
466  test.expect (a.exchange ((Type) 300) == (Type) 200);
467  test.expect (a.get() == (Type) 300);
468 
469  b = a;
470  test.expect (b.get() == a.get());
471  }
472  };
473 };
474 
475 static AtomicTests atomicUnitTests;
476 
477 //==============================================================================
478 class ThreadLocalValueUnitTest : public UnitTest,
479  private Thread
480 {
481 public:
482  ThreadLocalValueUnitTest()
483  : UnitTest ("ThreadLocalValue", "Threads"),
484  Thread ("ThreadLocalValue Thread")
485  {}
486 
487  void runTest() override
488  {
489  beginTest ("values are thread local");
490 
491  {
492  ThreadLocalValue<int> threadLocal;
493 
494  sharedThreadLocal = &threadLocal;
495 
496  sharedThreadLocal.get()->get() = 1;
497 
498  startThread();
500  waitForThreadToExit (-1);
501 
502  mainThreadResult = sharedThreadLocal.get()->get();
503 
504  expectEquals (mainThreadResult.get(), 1);
505  expectEquals (auxThreadResult.get(), 2);
506  }
507 
508  beginTest ("values are per-instance");
509 
510  {
512 
513  a.get() = 1;
514  b.get() = 2;
515 
516  expectEquals (a.get(), 1);
517  expectEquals (b.get(), 2);
518  }
519  }
520 
521 private:
522  Atomic<int> mainThreadResult, auxThreadResult;
523  Atomic<ThreadLocalValue<int>*> sharedThreadLocal;
524 
525  void run() override
526  {
527  sharedThreadLocal.get()->get() = 2;
528  auxThreadResult = sharedThreadLocal.get()->get();
529  }
530 };
531 
532 ThreadLocalValueUnitTest threadLocalValueUnitTest;
533 
534 #endif
535 
536 } // namespace juce
A simple wrapper around std::atomic.
Definition: juce_Atomic.h:45
#define JUCE_API
This macro is added to all JUCE public class declarations.
bool stopThread(int timeOutMilliseconds)
Attempts to stop the thread running.
void addListener(Listener *)
Add a listener to this thread which will receive a callback when signalThreadShouldExit was called on...
void * ThreadID
A value type used for thread IDs.
Definition: juce_Thread.h:308
static void launch(std::function< void()> functionToRun)
Invokes a lambda or function on its own thread.
void set(Type newValue) noexcept
Atomically sets the current value.
Definition: juce_Atomic.h:71
Thread(const String &threadName, size_t threadStackSize=0)
Creates a thread.
Definition: juce_Thread.cpp:26
void signalThreadShouldExit()
Sets a flag to tell the thread it should stop.
static bool currentThreadShouldExit()
Checks whether the current thread has been told to stop running.
void run() override
Must be implemented to perform the thread&#39;s actual code.
virtual void run()=0
Must be implemented to perform the thread&#39;s actual code.
void notify() const
Wakes up the thread.
The JUCE String class!
Definition: juce_String.h:42
virtual ~Thread()
Destructor.
Definition: juce_Thread.cpp:31
void setAffinityMask(uint32 affinityMask)
Sets the affinity mask for the thread.
This is a base class for classes that perform a unit test.
Definition: juce_UnitTest.h:73
static void JUCE_CALLTYPE yield()
Yields the current thread&#39;s CPU time-slot and allows a new thread to run.
ThreadID getThreadId() const noexcept
Returns the ID of this thread.
static ThreadID JUCE_CALLTYPE getCurrentThreadId()
Returns an id that identifies the caller thread.
std::atomic< Type > value
The std::atomic object that this class operates on.
Definition: juce_Atomic.h:139
A simple spin-lock class that can be used as a simple, low-overhead mutex for uncontended situations...
Definition: juce_SpinLock.h:45
void enter() const noexcept
Acquires the lock.
Used to receive callbacks for thread exit calls.
Definition: juce_Thread.h:184
static JUCE_CONSTEXPR uint16 swap(uint16 value) noexcept
Swaps the upper and lower bytes of a 16-bit integer.
bool threadShouldExit() const
Checks whether the thread has been told to stop running.
Encapsulates a thread.
Definition: juce_Thread.h:46
Provides cross-platform support for thread-local objects.
ReferencedType * get() const noexcept
Returns the object that this pointer references.
Type exchange(Type newValue) noexcept
Atomically sets the current value, returning the value that was replaced.
Definition: juce_Atomic.h:74
bool setPriority(int priority)
Changes the thread&#39;s priority.
void expect(bool testResult, const String &failureMessage=String())
Checks that the result of a test is true, and logs this result.
static void JUCE_CALLTYPE writeToLog(const String &message)
Writes a string to the current logger.
Definition: juce_Logger.cpp:40
void memoryBarrier() noexcept
Implements a memory read/write barrier.
Definition: juce_Atomic.h:136
virtual void exitSignalSent()=0
Called if Thread::signalThreadShouldExit was called.
bool waitForThreadToExit(int timeOutMilliseconds) const
Waits for the thread to stop.
Type get() const noexcept
Atomically reads and returns the current value.
Definition: juce_Atomic.h:68
bool isThreadRunning() const
Returns true if the thread is currently active.
Type & get() const noexcept
Returns a reference to this thread&#39;s instance of the value.
A smart-pointer class which points to a reference-counted object.
bool compareAndSetBool(Type newValue, Type valueToCompare) noexcept
Atomically compares this value with a target value, and if it is equal, sets this to be equal to a ne...
Definition: juce_Atomic.h:100
static void JUCE_CALLTYPE setCurrentThreadAffinityMask(uint32 affinityMask)
Changes the affinity mask for the caller thread.
static void JUCE_CALLTYPE sleep(int milliseconds)
Suspends the execution of the current thread until the specified timeout period has elapsed (note tha...
A base class which provides methods for reference-counting.
static Thread *JUCE_CALLTYPE getCurrentThread()
Finds the thread object that is currently running.
Automatically locks and unlocks a mutex object.
static bool setCurrentThreadPriority(int priority)
Changes the priority of the caller thread.
static bool JUCE_CALLTYPE isRunningUnderDebugger() noexcept
Returns true if this process is being hosted by a debugger.
bool wait(int timeOutMilliseconds) const
Suspends the execution of this thread until either the specified timeout period has elapsed...
void removeListener(Listener *)
Removes a listener added with addListener.
void startThread()
Starts the thread running.
static uint32 getMillisecondCounter() noexcept
Returns the number of millisecs since a fixed event (usually system startup).
Definition: juce_Time.cpp:226
static void JUCE_CALLTYPE setCurrentThreadName(const String &newThreadName)
Changes the name of the caller thread.