OpenShot Audio Library | OpenShotAudio  0.3.2
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.
51 struct CurrentThreadHolder : public ReferenceCountedObject
52 {
53  CurrentThreadHolder() noexcept {}
54 
55  using Ptr = ReferenceCountedObjectPtr<CurrentThreadHolder>;
56  ThreadLocalValue<Thread*> value;
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 = nullptr; // 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 
354 //==============================================================================
355 //==============================================================================
356 #if JUCE_UNIT_TESTS
357 
358 class AtomicTests : public UnitTest
359 {
360 public:
361  AtomicTests()
362  : UnitTest ("Atomics", UnitTestCategories::threads)
363  {}
364 
365  void runTest() override
366  {
367  beginTest ("Misc");
368 
369  char a1[7];
370  expect (numElementsInArray(a1) == 7);
371  int a2[3];
372  expect (numElementsInArray(a2) == 3);
373 
374  expect (ByteOrder::swap ((uint16) 0x1122) == 0x2211);
375  expect (ByteOrder::swap ((uint32) 0x11223344) == 0x44332211);
376  expect (ByteOrder::swap ((uint64) 0x1122334455667788ULL) == 0x8877665544332211LL);
377 
378  beginTest ("Atomic int");
379  AtomicTester <int>::testInteger (*this);
380  beginTest ("Atomic unsigned int");
381  AtomicTester <unsigned int>::testInteger (*this);
382  beginTest ("Atomic int32");
383  AtomicTester <int32>::testInteger (*this);
384  beginTest ("Atomic uint32");
385  AtomicTester <uint32>::testInteger (*this);
386  beginTest ("Atomic long");
387  AtomicTester <long>::testInteger (*this);
388  beginTest ("Atomic int*");
389  AtomicTester <int*>::testInteger (*this);
390  beginTest ("Atomic float");
391  AtomicTester <float>::testFloat (*this);
392  #if ! JUCE_64BIT_ATOMICS_UNAVAILABLE // 64-bit intrinsics aren't available on some old platforms
393  beginTest ("Atomic int64");
394  AtomicTester <int64>::testInteger (*this);
395  beginTest ("Atomic uint64");
396  AtomicTester <uint64>::testInteger (*this);
397  beginTest ("Atomic double");
398  AtomicTester <double>::testFloat (*this);
399  #endif
400  beginTest ("Atomic pointer increment/decrement");
401  Atomic<int*> a (a2); int* b (a2);
402  expect (++a == ++b);
403 
404  {
405  beginTest ("Atomic void*");
406  Atomic<void*> atomic;
407  void* c;
408 
409  atomic.set ((void*) 10);
410  c = (void*) 10;
411 
412  expect (atomic.value == c);
413  expect (atomic.get() == c);
414  }
415  }
416 
417  template <typename Type>
418  class AtomicTester
419  {
420  public:
421  AtomicTester() {}
422 
423  static void testInteger (UnitTest& test)
424  {
425  Atomic<Type> a, b;
426  Type c;
427 
428  a.set ((Type) 10);
429  c = (Type) 10;
430 
431  test.expect (a.value == c);
432  test.expect (a.get() == c);
433 
434  a += 15;
435  c += 15;
436  test.expect (a.get() == c);
437  a.memoryBarrier();
438 
439  a -= 5;
440  c -= 5;
441  test.expect (a.get() == c);
442 
443  test.expect (++a == ++c);
444  ++a;
445  ++c;
446  test.expect (--a == --c);
447  test.expect (a.get() == c);
448  a.memoryBarrier();
449 
450  testFloat (test);
451  }
452 
453 
454 
455  static void testFloat (UnitTest& test)
456  {
457  Atomic<Type> a, b;
458  a = (Type) 101;
459  a.memoryBarrier();
460 
461  /* These are some simple test cases to check the atomics - let me know
462  if any of these assertions fail on your system!
463  */
464  test.expect (a.get() == (Type) 101);
465  test.expect (! a.compareAndSetBool ((Type) 300, (Type) 200));
466  test.expect (a.get() == (Type) 101);
467  test.expect (a.compareAndSetBool ((Type) 200, a.get()));
468  test.expect (a.get() == (Type) 200);
469 
470  test.expect (a.exchange ((Type) 300) == (Type) 200);
471  test.expect (a.get() == (Type) 300);
472 
473  b = a;
474  test.expect (b.get() == a.get());
475  }
476  };
477 };
478 
479 static AtomicTests atomicUnitTests;
480 
481 //==============================================================================
482 class ThreadLocalValueUnitTest : public UnitTest,
483  private Thread
484 {
485 public:
486  ThreadLocalValueUnitTest()
487  : UnitTest ("ThreadLocalValue", UnitTestCategories::threads),
488  Thread ("ThreadLocalValue Thread")
489  {}
490 
491  void runTest() override
492  {
493  beginTest ("values are thread local");
494 
495  {
496  ThreadLocalValue<int> threadLocal;
497 
498  sharedThreadLocal = &threadLocal;
499 
500  sharedThreadLocal.get()->get() = 1;
501 
502  startThread();
503  signalThreadShouldExit();
504  waitForThreadToExit (-1);
505 
506  mainThreadResult = sharedThreadLocal.get()->get();
507 
508  expectEquals (mainThreadResult.get(), 1);
509  expectEquals (auxThreadResult.get(), 2);
510  }
511 
512  beginTest ("values are per-instance");
513 
514  {
515  ThreadLocalValue<int> a, b;
516 
517  a.get() = 1;
518  b.get() = 2;
519 
520  expectEquals (a.get(), 1);
521  expectEquals (b.get(), 2);
522  }
523  }
524 
525 private:
526  Atomic<int> mainThreadResult, auxThreadResult;
527  Atomic<ThreadLocalValue<int>*> sharedThreadLocal;
528 
529  void run() override
530  {
531  sharedThreadLocal.get()->get() = 2;
532  auxThreadResult = sharedThreadLocal.get()->get();
533  }
534 };
535 
536 ThreadLocalValueUnitTest threadLocalValueUnitTest;
537 
538 #endif
539 
540 } // namespace juce
static JUCE_CONSTEXPR uint16 swap(uint16 value) noexcept
static void JUCE_CALLTYPE writeToLog(const String &message)
Definition: juce_Logger.cpp:40
static bool JUCE_CALLTYPE isRunningUnderDebugger() noexcept
ReferencedType * get() const noexcept
void enter() const noexcept
bool tryEnter() const noexcept
Definition: juce_SpinLock.h:59
GenericScopedLock< SpinLock > ScopedLockType
Definition: juce_SpinLock.h:73
bool isNotEmpty() const noexcept
Definition: juce_String.h:302
virtual void exitSignalSent()=0
bool setPriority(int priority)
void setAffinityMask(uint32 affinityMask)
static void JUCE_CALLTYPE setCurrentThreadAffinityMask(uint32 affinityMask)
void * ThreadID
Definition: juce_Thread.h:304
static void JUCE_CALLTYPE sleep(int milliseconds)
virtual ~Thread()
Definition: juce_Thread.cpp:31
static Thread *JUCE_CALLTYPE getCurrentThread()
void startThread()
bool wait(int timeOutMilliseconds) const
ThreadID getThreadId() const noexcept
bool waitForThreadToExit(int timeOutMilliseconds) const
static void JUCE_CALLTYPE setCurrentThreadName(const String &newThreadName)
virtual void run()=0
Thread(const String &threadName, size_t threadStackSize=0)
Definition: juce_Thread.cpp:26
static bool currentThreadShouldExit()
bool threadShouldExit() const
static void JUCE_CALLTYPE yield()
static ThreadID JUCE_CALLTYPE getCurrentThreadId()
bool stopThread(int timeOutMilliseconds)
void notify() const
void addListener(Listener *)
void signalThreadShouldExit()
static bool setCurrentThreadPriority(int priority)
bool isThreadRunning() const
void removeListener(Listener *)
static void launch(std::function< void()> functionToRun)
static uint32 getMillisecondCounter() noexcept
Definition: juce_Time.cpp:226
bool wait(int timeOutMilliseconds=-1) const
Type get() const noexcept
Definition: juce_Atomic.h:64