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
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//==============================================================================
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
136void 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
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
196{
197 // Doh! So how exactly do you expect this thread to wait for itself to stop??
199
201
202 while (isThreadRunning())
203 {
205 return false;
206
207 sleep (2);
208 }
209
210 return true;
211}
212
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)
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//==============================================================================
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.
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!
276
278 #endif
279
280 if ((! isThreadRunning()) || setThreadPriority (threadHandle.get(), newPriority))
281 {
282 threadPriority = newPriority;
283 return true;
284 }
285
286 return false;
287}
288
290{
291 return setThreadPriority ({}, newPriority);
292}
293
295{
296 affinityMask = newAffinityMask;
297}
298
299//==============================================================================
300bool Thread::wait (const int timeOutMilliseconds) const
301{
302 return defaultEvent.wait (timeOutMilliseconds);
303}
304
305void 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
326void Thread::launch (std::function<void()> functionToRun)
327{
328 auto anon = new LambdaThread (functionToRun);
329 anon->deleteOnThreadEnd = true;
330 anon->startThread();
331}
332
333//==============================================================================
335{
336 if (! tryEnter())
337 {
338 for (int i = 20; --i >= 0;)
339 if (tryEnter())
340 return;
341
342 while (! tryEnter())
344 }
345}
346
347//==============================================================================
349{
350 return juce_isRunningUnderDebugger();
351}
352
353
354//==============================================================================
355//==============================================================================
356#if JUCE_UNIT_TESTS
357
358class AtomicTests : public UnitTest
359{
360public:
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:
487 : UnitTest ("ThreadLocalValue", UnitTestCategories::threads),
488 Thread ("ThreadLocalValue Thread")
489 {}
490
491 void runTest() override
492 {
493 beginTest ("values are thread local");
494
495 {
497
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 {
516
517 a.get() = 1;
518 b.get() = 2;
519
520 expectEquals (a.get(), 1);
521 expectEquals (b.get(), 2);
522 }
523 }
524
525private:
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
void remove(int indexToRemove)
Definition juce_Array.h:767
Array()=default
void add(const ElementType &newElement)
Definition juce_Array.h:418
static JUCE_CONSTEXPR uint16 swap(uint16 value) noexcept
static void JUCE_CALLTYPE writeToLog(const String &message)
static bool JUCE_CALLTYPE isRunningUnderDebugger() noexcept
void enter() const noexcept
bool tryEnter() const noexcept
GenericScopedLock< SpinLock > ScopedLockType
bool setPriority(int priority)
void setAffinityMask(uint32 affinityMask)
static void JUCE_CALLTYPE setCurrentThreadAffinityMask(uint32 affinityMask)
void * ThreadID
static void JUCE_CALLTYPE sleep(int milliseconds)
virtual ~Thread()
static Thread *JUCE_CALLTYPE getCurrentThread()
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)
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
bool wait(int timeOutMilliseconds=-1) const
Type get() const noexcept
Definition juce_Atomic.h:64