OpenShot Audio Library | OpenShotAudio  0.6.0
juce_Thread.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2022 - Raw Material Software Limited
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) : threadName (name),
27  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 final : 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  // This 'startSuspensionEvent' protects 'threadId' which is initialised after the platform's native 'CreateThread' method.
88  // This ensures it has been initialised correctly before it reaches this point.
89  if (startSuspensionEvent.wait (10000))
90  {
91  jassert (getCurrentThreadId() == threadId);
92 
93  if (affinityMask != 0)
94  setCurrentThreadAffinityMask (affinityMask);
95 
96  try
97  {
98  run();
99  }
100  catch (...)
101  {
102  jassertfalse; // Your run() method mustn't throw any exceptions!
103  }
104  }
105 
106  currentThreadHolder->value.releaseCurrentThreadStorage();
107 
108  // Once closeThreadHandle is called this class may be deleted by a different
109  // thread, so we need to store deleteOnThreadEnd in a local variable.
110  auto shouldDeleteThis = deleteOnThreadEnd;
111  closeThreadHandle();
112 
113  if (shouldDeleteThis)
114  delete this;
115 }
116 
117 // used to wrap the incoming call from the platform-specific code
118 void JUCE_API juce_threadEntryPoint (void* userData)
119 {
120  static_cast<Thread*> (userData)->threadEntryPoint();
121 }
122 
123 //==============================================================================
124 bool Thread::startThreadInternal (Priority threadPriority)
125 {
126  shouldExit = false;
127 
128  // 'priority' is essentially useless on Linux as only realtime
129  // has any options but we need to set this here to satisfy
130  // later queries, otherwise we get inconsistent results across
131  // platforms.
132  #if JUCE_ANDROID || JUCE_LINUX || JUCE_BSD
133  priority = threadPriority;
134  #endif
135 
136  if (createNativeThread (threadPriority))
137  {
138  startSuspensionEvent.signal();
139  return true;
140  }
141 
142  return false;
143 }
144 
146 {
147  return startThread (Priority::normal);
148 }
149 
150 bool Thread::startThread (Priority threadPriority)
151 {
152  const ScopedLock sl (startStopLock);
153 
154  if (threadHandle == nullptr)
155  {
156  realtimeOptions.reset();
157  return startThreadInternal (threadPriority);
158  }
159 
160  return false;
161 }
162 
164 {
165  const ScopedLock sl (startStopLock);
166 
167  if (threadHandle == nullptr)
168  {
169  realtimeOptions = std::make_optional (options);
170 
171  if (startThreadInternal (Priority::normal))
172  return true;
173 
174  realtimeOptions.reset();
175  }
176 
177  return false;
178 }
179 
181 {
182  return threadHandle != nullptr;
183 }
184 
186 {
187  return getCurrentThreadHolder()->value.get();
188 }
189 
191 {
192  return threadId;
193 }
194 
195 //==============================================================================
197 {
198  shouldExit = true;
199  listeners.call ([] (Listener& l) { l.exitSignalSent(); });
200 }
201 
203 {
204  return shouldExit;
205 }
206 
208 {
209  if (auto* currentThread = getCurrentThread())
210  return currentThread->threadShouldExit();
211 
212  return false;
213 }
214 
215 bool Thread::waitForThreadToExit (const int timeOutMilliseconds) const
216 {
217  // Doh! So how exactly do you expect this thread to wait for itself to stop??
218  jassert (getThreadId() != getCurrentThreadId() || getCurrentThreadId() == ThreadID());
219 
220  auto timeoutEnd = Time::getMillisecondCounter() + (uint32) timeOutMilliseconds;
221 
222  while (isThreadRunning())
223  {
224  if (timeOutMilliseconds >= 0 && Time::getMillisecondCounter() > timeoutEnd)
225  return false;
226 
227  sleep (2);
228  }
229 
230  return true;
231 }
232 
233 bool Thread::stopThread (const int timeOutMilliseconds)
234 {
235  // agh! You can't stop the thread that's calling this method! How on earth
236  // would that work??
237  jassert (getCurrentThreadId() != getThreadId());
238 
239  const ScopedLock sl (startStopLock);
240 
241  if (isThreadRunning())
242  {
244  notify();
245 
246  if (timeOutMilliseconds != 0)
247  waitForThreadToExit (timeOutMilliseconds);
248 
249  if (isThreadRunning())
250  {
251  // very bad karma if this point is reached, as there are bound to be
252  // locks and events left in silly states when a thread is killed by force..
253  jassertfalse;
254  Logger::writeToLog ("!! killing thread by force !!");
255 
256  killThread();
257 
258  threadHandle = nullptr;
259  threadId = {};
260  return false;
261  }
262  }
263 
264  return true;
265 }
266 
268 {
269  listeners.add (listener);
270 }
271 
273 {
274  listeners.remove (listener);
275 }
276 
277 bool Thread::isRealtime() const
278 {
279  return realtimeOptions.has_value();
280 }
281 
282 void Thread::setAffinityMask (const uint32 newAffinityMask)
283 {
284  affinityMask = newAffinityMask;
285 }
286 
287 //==============================================================================
288 bool Thread::wait (double timeOutMilliseconds) const
289 {
290  return defaultEvent.wait (timeOutMilliseconds);
291 }
292 
293 void Thread::notify() const
294 {
295  defaultEvent.signal();
296 }
297 
298 //==============================================================================
299 struct LambdaThread final : public Thread
300 {
301  LambdaThread (std::function<void()>&& f) : Thread ("anonymous"), fn (std::move (f)) {}
302 
303  void run() override
304  {
305  fn();
306  fn = nullptr; // free any objects that the lambda might contain while the thread is still active
307  }
308 
309  std::function<void()> fn;
310 
311  JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LambdaThread)
312 };
313 
314 bool Thread::launch (std::function<void()> functionToRun)
315 {
316  return launch (Priority::normal, std::move (functionToRun));
317 }
318 
319 bool Thread::launch (Priority priority, std::function<void()> functionToRun)
320 {
321  auto anon = std::make_unique<LambdaThread> (std::move (functionToRun));
322  anon->deleteOnThreadEnd = true;
323 
324  if (anon->startThread (priority))
325  {
326  anon.release();
327  return true;
328  }
329 
330  return false;
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 #if JUCE_UNIT_TESTS
356 
357 class AtomicTests final : public UnitTest
358 {
359 public:
360  AtomicTests()
361  : UnitTest ("Atomics", UnitTestCategories::threads)
362  {}
363 
364  void runTest() override
365  {
366  beginTest ("Misc");
367 
368  char a1[7];
369  expect (numElementsInArray (a1) == 7);
370  int a2[3];
371  expect (numElementsInArray (a2) == 3);
372 
373  expect (ByteOrder::swap ((uint16) 0x1122) == 0x2211);
374  expect (ByteOrder::swap ((uint32) 0x11223344) == 0x44332211);
375  expect (ByteOrder::swap ((uint64) 0x1122334455667788ULL) == (uint64) 0x8877665544332211LL);
376 
377  beginTest ("Atomic int");
378  AtomicTester <int>::testInteger (*this);
379  beginTest ("Atomic unsigned int");
380  AtomicTester <unsigned int>::testInteger (*this);
381  beginTest ("Atomic int32");
382  AtomicTester <int32>::testInteger (*this);
383  beginTest ("Atomic uint32");
384  AtomicTester <uint32>::testInteger (*this);
385  beginTest ("Atomic long");
386  AtomicTester <long>::testInteger (*this);
387  beginTest ("Atomic int*");
388  AtomicTester <int*>::testInteger (*this);
389  beginTest ("Atomic float");
390  AtomicTester <float>::testFloat (*this);
391  #if ! JUCE_64BIT_ATOMICS_UNAVAILABLE // 64-bit intrinsics aren't available on some old platforms
392  beginTest ("Atomic int64");
393  AtomicTester <int64>::testInteger (*this);
394  beginTest ("Atomic uint64");
395  AtomicTester <uint64>::testInteger (*this);
396  beginTest ("Atomic double");
397  AtomicTester <double>::testFloat (*this);
398  #endif
399  beginTest ("Atomic pointer increment/decrement");
400  Atomic<int*> a (a2); int* b (a2);
401  expect (++a == ++b);
402 
403  {
404  beginTest ("Atomic void*");
405  Atomic<void*> atomic;
406  void* c;
407 
408  atomic.set ((void*) 10);
409  c = (void*) 10;
410 
411  expect (atomic.value == c);
412  expect (atomic.get() == c);
413  }
414  }
415 
416  template <typename Type>
417  class AtomicTester
418  {
419  public:
420  AtomicTester() = default;
421 
422  static void testInteger (UnitTest& test)
423  {
424  Atomic<Type> a, b;
425  Type c;
426 
427  a.set ((Type) 10);
428  c = (Type) 10;
429 
430  test.expect (a.value == c);
431  test.expect (a.get() == c);
432 
433  a += 15;
434  c += 15;
435  test.expect (a.get() == c);
436  a.memoryBarrier();
437 
438  a -= 5;
439  c -= 5;
440  test.expect (a.get() == c);
441 
442  test.expect (++a == ++c);
443  ++a;
444  ++c;
445  test.expect (--a == --c);
446  test.expect (a.get() == c);
447  a.memoryBarrier();
448 
449  testFloat (test);
450  }
451 
452 
453 
454  static void testFloat (UnitTest& test)
455  {
456  Atomic<Type> a, b;
457  a = (Type) 101;
458  a.memoryBarrier();
459 
460  /* These are some simple test cases to check the atomics - let me know
461  if any of these assertions fail on your system!
462  */
463  test.expect (exactlyEqual (a.get(), (Type) 101));
464  test.expect (! a.compareAndSetBool ((Type) 300, (Type) 200));
465  test.expect (exactlyEqual (a.get(), (Type) 101));
466  test.expect (a.compareAndSetBool ((Type) 200, a.get()));
467  test.expect (exactlyEqual (a.get(), (Type) 200));
468 
469  test.expect (exactlyEqual (a.exchange ((Type) 300), (Type) 200));
470  test.expect (exactlyEqual (a.get(), (Type) 300));
471 
472  b = a;
473  test.expect (exactlyEqual (b.get(), a.get()));
474  }
475  };
476 };
477 
478 static AtomicTests atomicUnitTests;
479 
480 //==============================================================================
481 class ThreadLocalValueUnitTest final : public UnitTest,
482  private Thread
483 {
484 public:
485  ThreadLocalValueUnitTest()
486  : UnitTest ("ThreadLocalValue", UnitTestCategories::threads),
487  Thread ("ThreadLocalValue Thread")
488  {}
489 
490  void runTest() override
491  {
492  beginTest ("values are thread local");
493 
494  {
495  ThreadLocalValue<int> threadLocal;
496 
497  sharedThreadLocal = &threadLocal;
498 
499  sharedThreadLocal.get()->get() = 1;
500 
501  startThread();
502  signalThreadShouldExit();
503  waitForThreadToExit (-1);
504 
505  mainThreadResult = sharedThreadLocal.get()->get();
506 
507  expectEquals (mainThreadResult.get(), 1);
508  expectEquals (auxThreadResult.get(), 2);
509  }
510 
511  beginTest ("values are per-instance");
512 
513  {
514  ThreadLocalValue<int> a, b;
515 
516  a.get() = 1;
517  b.get() = 2;
518 
519  expectEquals (a.get(), 1);
520  expectEquals (b.get(), 2);
521  }
522  }
523 
524 private:
525  Atomic<int> mainThreadResult, auxThreadResult;
526  Atomic<ThreadLocalValue<int>*> sharedThreadLocal;
527 
528  void run() override
529  {
530  sharedThreadLocal.get()->get() = 2;
531  auxThreadResult = sharedThreadLocal.get()->get();
532  }
533 };
534 
535 ThreadLocalValueUnitTest threadLocalValueUnitTest;
536 
537 #endif
538 
539 } // namespace juce
constexpr static 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:316
virtual void exitSignalSent()=0
void setAffinityMask(uint32 affinityMask)
static void JUCE_CALLTYPE setCurrentThreadAffinityMask(uint32 affinityMask)
void * ThreadID
Definition: juce_Thread.h:477
static void JUCE_CALLTYPE sleep(int milliseconds)
bool isRealtime() const
virtual ~Thread()
Definition: juce_Thread.cpp:31
static Thread *JUCE_CALLTYPE getCurrentThread()
bool wait(double timeOutMilliseconds) const
static bool launch(std::function< void()> functionToRun)
ThreadID getThreadId() const noexcept
bool waitForThreadToExit(int timeOutMilliseconds) const
static void JUCE_CALLTYPE setCurrentThreadName(const String &newThreadName)
Thread(const String &threadName, size_t threadStackSize=osDefaultStackSize)
Definition: juce_Thread.cpp:26
virtual void run()=0
bool startThread()
static bool currentThreadShouldExit()
bool threadShouldExit() const
bool startRealtimeThread(const RealtimeOptions &options)
static void JUCE_CALLTYPE yield()
static ThreadID JUCE_CALLTYPE getCurrentThreadId()
bool stopThread(int timeOutMilliseconds)
void notify() const
void addListener(Listener *)
void signalThreadShouldExit()
bool isThreadRunning() const
void removeListener(Listener *)
static uint32 getMillisecondCounter() noexcept
Definition: juce_Time.cpp:241
bool wait(double timeOutMilliseconds=-1.0) const