OpenShot Audio Library | OpenShotAudio: juce_Thread.cpp Source File

OpenShot Audio Library | OpenShotAudio 0.3.2

Loading...
Searching...
No Matches
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
23namespace juce
24{
25
26Thread::Thread (const String& name, size_t stackSize)
27 : threadName (name), threadStackSize (stackSize)
28{
29}
30
31Thread::~Thread()
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.
51struct 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
61static char currentThreadHolderLock [sizeof (SpinLock)]; // (statically initialised to zeros).
62
63static SpinLock* castToSpinLockWithoutAliasingWarning (void* s)
64{
65 return static_cast<SpinLock*> (s);
66}
67
68static 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
79void 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
116void JUCE_API juce_threadEntryPoint (void* userData)
117{
118 static_cast<Thread*> (userData)->threadEntryPoint();
119}
120
121//==============================================================================
122 void Thread::startThread()
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
160 bool Thread::isThreadRunning() const
161{
162 return threadHandle.get() != nullptr;
163}
164
165 Thread* JUCE_CALLTYPE Thread::getCurrentThread()
166{
167 return getCurrentThreadHolder()->value.get();
168}
169
170 Thread::ThreadID Thread::getThreadId() const noexcept
171{
172 return threadId.get();
173}
174
175//==============================================================================
176 void Thread::signalThreadShouldExit()
177{
178 shouldExit = 1;
179 listeners.call ([] (Listener& l) { l.exitSignalSent(); });
180}
181
182 bool Thread::threadShouldExit() const
183{
184 return shouldExit.get() != 0;
185}
186
187 bool Thread::currentThreadShouldExit()
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 {
223 signalThreadShouldExit();
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
247 void Thread::addListener (Listener* listener)
248{
249 listeners.add (listener);
250}
251
252 void Thread::removeListener (Listener* listener)
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//==============================================================================
311struct 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
358class AtomicTests : public UnitTest
359{
360public:
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
479static AtomicTests atomicUnitTests;
480
481//==============================================================================
482class ThreadLocalValueUnitTest : public UnitTest,
483 private Thread
484{
485public:
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
525private:
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
536ThreadLocalValueUnitTest threadLocalValueUnitTest;
537
538#endif
539
540} // namespace juce
juce::GenericScopedLock
Definition: juce_ScopedLock.h:55
juce::Logger::writeToLog
static void JUCE_CALLTYPE writeToLog(const String &message)
Definition: juce_Logger.cpp:40
juce::Process::isRunningUnderDebugger
static bool JUCE_CALLTYPE isRunningUnderDebugger() noexcept
Definition: juce_Thread.cpp:348
juce::ReferenceCountedObjectPtr::get
ReferencedType * get() const noexcept
Definition: juce_ReferenceCountedObject.h:381
juce::ReferenceCountedObject
Definition: juce_ReferenceCountedObject.h:66
juce::SpinLock::enter
void enter() const noexcept
Definition: juce_Thread.cpp:334
juce::SpinLock::tryEnter
bool tryEnter() const noexcept
Definition: juce_SpinLock.h:59
juce::SpinLock::ScopedLockType
GenericScopedLock< SpinLock > ScopedLockType
Definition: juce_SpinLock.h:73
juce::String
Definition: juce_String.h:39
juce::String::isNotEmpty
bool isNotEmpty() const noexcept
Definition: juce_String.h:302
juce::Thread::Listener
Definition: juce_Thread.h:181
juce::Thread::Listener::exitSignalSent
virtual void exitSignalSent()=0
juce::Thread
Definition: juce_Thread.h:43
juce::Thread::setPriority
bool setPriority(int priority)
Definition: juce_Thread.cpp:258
juce::Thread::setAffinityMask
void setAffinityMask(uint32 affinityMask)
Definition: juce_Thread.cpp:294
juce::Thread::setCurrentThreadAffinityMask
static void JUCE_CALLTYPE setCurrentThreadAffinityMask(uint32 affinityMask)
juce::Thread::ThreadID
void * ThreadID
Definition: juce_Thread.h:304
juce::Thread::sleep
static void JUCE_CALLTYPE sleep(int milliseconds)
juce::Thread::~Thread
virtual ~Thread()
Definition: juce_Thread.cpp:31
juce::Thread::getCurrentThread
static Thread *JUCE_CALLTYPE getCurrentThread()
Definition: juce_Thread.cpp:165
juce::Thread::startThread
void startThread()
Definition: juce_Thread.cpp:122
juce::Thread::wait
bool wait(int timeOutMilliseconds) const
Definition: juce_Thread.cpp:300
juce::Thread::getThreadId
ThreadID getThreadId() const noexcept
Definition: juce_Thread.cpp:170
juce::Thread::waitForThreadToExit
bool waitForThreadToExit(int timeOutMilliseconds) const
Definition: juce_Thread.cpp:195
juce::Thread::setCurrentThreadName
static void JUCE_CALLTYPE setCurrentThreadName(const String &newThreadName)
juce::Thread::run
virtual void run()=0
juce::Thread::Thread
Thread(const String &threadName, size_t threadStackSize=0)
Definition: juce_Thread.cpp:26
juce::Thread::currentThreadShouldExit
static bool currentThreadShouldExit()
Definition: juce_Thread.cpp:187
juce::Thread::threadShouldExit
bool threadShouldExit() const
Definition: juce_Thread.cpp:182
juce::Thread::yield
static void JUCE_CALLTYPE yield()
juce::Thread::getCurrentThreadId
static ThreadID JUCE_CALLTYPE getCurrentThreadId()
juce::Thread::stopThread
bool stopThread(int timeOutMilliseconds)
Definition: juce_Thread.cpp:213
juce::Thread::notify
void notify() const
Definition: juce_Thread.cpp:305
juce::Thread::addListener
void addListener(Listener *)
Definition: juce_Thread.cpp:247
juce::Thread::signalThreadShouldExit
void signalThreadShouldExit()
Definition: juce_Thread.cpp:176
juce::Thread::setCurrentThreadPriority
static bool setCurrentThreadPriority(int priority)
Definition: juce_Thread.cpp:289
juce::Thread::isThreadRunning
bool isThreadRunning() const
Definition: juce_Thread.cpp:160
juce::Thread::removeListener
void removeListener(Listener *)
Definition: juce_Thread.cpp:252
juce::Thread::launch
static void launch(std::function< void()> functionToRun)
Definition: juce_Thread.cpp:326
juce::Time::getMillisecondCounter
static uint32 getMillisecondCounter() noexcept
Definition: juce_Time.cpp:226
juce::UnitTest
Definition: juce_UnitTest.h:70
juce::WaitableEvent::wait
bool wait(int timeOutMilliseconds=-1) const
Definition: juce_WaitableEvent.cpp:31
juce::WaitableEvent::signal
void signal() const
Definition: juce_WaitableEvent.cpp:57
juce::Atomic::get
Type get() const noexcept
Definition: juce_Atomic.h:64