OpenShot Audio Library | OpenShotAudio: juce_MessageManager.cpp Source File

OpenShot Audio Library | OpenShotAudio 0.3.0

Loading...
Searching...
No Matches
juce_MessageManager.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
26MessageManager::MessageManager() noexcept
27 : messageThreadId (Thread::getCurrentThreadId())
28{
29 if (JUCEApplicationBase::isStandaloneApp())
30 Thread::setCurrentThreadName ("JUCE Message Thread");
31}
32
33MessageManager::~MessageManager() noexcept
34{
35 broadcaster.reset();
36
37 doPlatformSpecificShutdown();
38
39 jassert (instance == this);
40 instance = nullptr; // do this last in case this instance is still needed by doPlatformSpecificShutdown()
41}
42
43MessageManager* MessageManager::instance = nullptr;
44
45 MessageManager* MessageManager::getInstance()
46{
47 if (instance == nullptr)
48 {
49 instance = new MessageManager();
50 doPlatformSpecificInitialisation();
51 }
52
53 return instance;
54}
55
56 MessageManager* MessageManager::getInstanceWithoutCreating() noexcept
57{
58 return instance;
59}
60
61 void MessageManager::deleteInstance()
62{
63 deleteAndZero (instance);
64}
65
66//==============================================================================
67bool MessageManager::MessageBase::post()
68{
69 auto* mm = MessageManager::instance;
70
71 if (mm == nullptr || mm->quitMessagePosted.get() != 0 || ! postMessageToSystemQueue (this))
72 {
73 Ptr deleter (this); // (this will delete messages that were just created with a 0 ref count)
74 return false;
75 }
76
77 return true;
78}
79
80//==============================================================================
81#if JUCE_MODAL_LOOPS_PERMITTED && ! (JUCE_MAC || JUCE_IOS)
82bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor)
83{
84 jassert (isThisTheMessageThread()); // must only be called by the message thread
85
86 auto endTime = Time::currentTimeMillis() + millisecondsToRunFor;
87
88 while (quitMessageReceived.get() == 0)
89 {
90 JUCE_TRY
91 {
92 if (! dispatchNextMessageOnSystemQueue (millisecondsToRunFor >= 0))
93 Thread::sleep (1);
94 }
95 JUCE_CATCH_EXCEPTION
96
97 if (millisecondsToRunFor >= 0 && Time::currentTimeMillis() >= endTime)
98 break;
99 }
100
101 return quitMessageReceived.get() == 0;
102}
103#endif
104
105#if ! (JUCE_MAC || JUCE_IOS || JUCE_ANDROID)
106class MessageManager::QuitMessage : public MessageManager::MessageBase
107{
108public:
109 QuitMessage() {}
110
111 void messageCallback() override
112 {
113 if (auto* mm = MessageManager::instance)
114 mm->quitMessageReceived = true;
115 }
116
117 JUCE_DECLARE_NON_COPYABLE (QuitMessage)
118};
119
120 void MessageManager::runDispatchLoop()
121{
122 jassert (isThisTheMessageThread()); // must only be called by the message thread
123
124 while (quitMessageReceived.get() == 0)
125 {
126 JUCE_TRY
127 {
128 if (! dispatchNextMessageOnSystemQueue (false))
129 Thread::sleep (1);
130 }
131 JUCE_CATCH_EXCEPTION
132 }
133}
134
135 void MessageManager::stopDispatchLoop()
136{
137 (new QuitMessage())->post();
138 quitMessagePosted = true;
139}
140
141#endif
142
143//==============================================================================
144class AsyncFunctionCallback : public MessageManager::MessageBase
145{
146public:
147 AsyncFunctionCallback (MessageCallbackFunction* const f, void* const param)
148 : func (f), parameter (param)
149 {}
150
151 void messageCallback() override
152 {
153 result = (*func) (parameter);
154 finished.signal();
155 }
156
157 WaitableEvent finished;
158 std::atomic<void*> result { nullptr };
159
160private:
161 MessageCallbackFunction* const func;
162 void* const parameter;
163
164 JUCE_DECLARE_NON_COPYABLE (AsyncFunctionCallback)
165};
166
167 void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* func, void* parameter)
168{
169 if (isThisTheMessageThread())
170 return func (parameter);
171
172 // If this thread has the message manager locked, then this will deadlock!
173 jassert (! currentThreadHasLockedMessageManager());
174
175 const ReferenceCountedObjectPtr<AsyncFunctionCallback> message (new AsyncFunctionCallback (func, parameter));
176
177 if (message->post())
178 {
179 message->finished.wait();
180 return message->result.load();
181 }
182
183 jassertfalse; // the OS message queue failed to send the message!
184 return nullptr;
185}
186
187 bool MessageManager::callAsync (std::function<void()> fn)
188{
189 struct AsyncCallInvoker : public MessageBase
190 {
191 AsyncCallInvoker (std::function<void()> f) : callback (std::move (f)) {}
192 void messageCallback() override { callback(); }
193 std::function<void()> callback;
194 };
195
196 return (new AsyncCallInvoker (std::move (fn)))->post();
197}
198
199//==============================================================================
200void MessageManager::deliverBroadcastMessage (const String& value)
201{
202 if (broadcaster != nullptr)
203 broadcaster->sendActionMessage (value);
204}
205
206 void MessageManager::registerBroadcastListener (ActionListener* const listener)
207{
208 if (broadcaster == nullptr)
209 broadcaster.reset (new ActionBroadcaster());
210
211 broadcaster->addActionListener (listener);
212}
213
214 void MessageManager::deregisterBroadcastListener (ActionListener* const listener)
215{
216 if (broadcaster != nullptr)
217 broadcaster->removeActionListener (listener);
218}
219
220//==============================================================================
221 bool MessageManager::isThisTheMessageThread() const noexcept
222{
223 return Thread::getCurrentThreadId() == messageThreadId;
224}
225
226 void MessageManager::setCurrentThreadAsMessageThread()
227{
228 auto thisThread = Thread::getCurrentThreadId();
229
230 if (messageThreadId != thisThread)
231 {
232 messageThreadId = thisThread;
233
234 // This is needed on windows to make sure the message window is created by this thread
235 doPlatformSpecificShutdown();
236 doPlatformSpecificInitialisation();
237 }
238}
239
240 bool MessageManager::currentThreadHasLockedMessageManager() const noexcept
241{
242 auto thisThread = Thread::getCurrentThreadId();
243 return thisThread == messageThreadId || thisThread == threadWithLock.get();
244}
245
246 bool MessageManager::existsAndIsLockedByCurrentThread() noexcept
247{
248 if (auto i = getInstanceWithoutCreating())
249 return i->currentThreadHasLockedMessageManager();
250
251 return false;
252}
253
254 bool MessageManager::existsAndIsCurrentThread() noexcept
255{
256 if (auto i = getInstanceWithoutCreating())
257 return i->isThisTheMessageThread();
258
259 return false;
260}
261
262//==============================================================================
263//==============================================================================
264/* The only safe way to lock the message thread while another thread does
265 some work is by posting a special message, whose purpose is to tie up the event
266 loop until the other thread has finished its business.
267
268 Any other approach can get horribly deadlocked if the OS uses its own hidden locks which
269 get locked before making an event callback, because if the same OS lock gets indirectly
270 accessed from another thread inside a MM lock, you're screwed. (this is exactly what happens
271 in Cocoa).
272*/
273struct MessageManager::Lock::BlockingMessage : public MessageManager::MessageBase
274{
275 BlockingMessage (const MessageManager::Lock* parent) noexcept
276 : owner (parent)
277 {}
278
279 void messageCallback() override
280 {
281 {
282 ScopedLock lock (ownerCriticalSection);
283
284 if (auto* o = owner.get())
285 o->messageCallback();
286 }
287
288 releaseEvent.wait();
289 }
290
291 CriticalSection ownerCriticalSection;
292 Atomic<const MessageManager::Lock*> owner;
293 WaitableEvent releaseEvent;
294
295 JUCE_DECLARE_NON_COPYABLE (BlockingMessage)
296};
297
298//==============================================================================
299MessageManager::Lock::Lock() {}
300MessageManager::Lock::~Lock() { exit(); }
301 void MessageManager::Lock::enter() const noexcept { tryAcquire (true); }
302 bool MessageManager::Lock::tryEnter() const noexcept { return tryAcquire (false); }
303
304bool MessageManager::Lock::tryAcquire (bool lockIsMandatory) const noexcept
305{
306 auto* mm = MessageManager::instance;
307
308 if (mm == nullptr)
309 {
310 jassertfalse;
311 return false;
312 }
313
314 if (! lockIsMandatory && (abortWait.get() != 0))
315 {
316 abortWait.set (0);
317 return false;
318 }
319
320 if (mm->currentThreadHasLockedMessageManager())
321 return true;
322
323 try
324 {
325 blockingMessage = *new BlockingMessage (this);
326 }
327 catch (...)
328 {
329 jassert (! lockIsMandatory);
330 return false;
331 }
332
333 if (! blockingMessage->post())
334 {
335 // post of message failed while trying to get the lock
336 jassert (! lockIsMandatory);
337 blockingMessage = nullptr;
338 return false;
339 }
340
341 do
342 {
343 while (abortWait.get() == 0)
344 lockedEvent.wait (-1);
345
346 abortWait.set (0);
347
348 if (lockGained.get() != 0)
349 {
350 mm->threadWithLock = Thread::getCurrentThreadId();
351 return true;
352 }
353
354 } while (lockIsMandatory);
355
356 // we didn't get the lock
357 blockingMessage->releaseEvent.signal();
358
359 {
360 ScopedLock lock (blockingMessage->ownerCriticalSection);
361
362 lockGained.set (0);
363 blockingMessage->owner.set (nullptr);
364 }
365
366 blockingMessage = nullptr;
367 return false;
368}
369
370 void MessageManager::Lock::exit() const noexcept
371{
372 if (lockGained.compareAndSetBool (false, true))
373 {
374 auto* mm = MessageManager::instance;
375
376 jassert (mm == nullptr || mm->currentThreadHasLockedMessageManager());
377 lockGained.set (0);
378
379 if (mm != nullptr)
380 mm->threadWithLock = {};
381
382 if (blockingMessage != nullptr)
383 {
384 blockingMessage->releaseEvent.signal();
385 blockingMessage = nullptr;
386 }
387 }
388}
389
390void MessageManager::Lock::messageCallback() const
391{
392 lockGained.set (1);
393 abort();
394}
395
396 void MessageManager::Lock::abort() const noexcept
397{
398 abortWait.set (1);
399 lockedEvent.signal();
400}
401
402//==============================================================================
403MessageManagerLock::MessageManagerLock (Thread* threadToCheck)
404 : locked (attemptLock (threadToCheck, nullptr))
405{}
406
407 MessageManagerLock::MessageManagerLock (ThreadPoolJob* jobToCheck)
408 : locked (attemptLock (nullptr, jobToCheck))
409{}
410
411bool MessageManagerLock::attemptLock (Thread* threadToCheck, ThreadPoolJob* jobToCheck)
412{
413 jassert (threadToCheck == nullptr || jobToCheck == nullptr);
414
415 if (threadToCheck != nullptr)
416 threadToCheck->addListener (this);
417
418 if (jobToCheck != nullptr)
419 jobToCheck->addListener (this);
420
421 // tryEnter may have a spurious abort (return false) so keep checking the condition
422 while ((threadToCheck == nullptr || ! threadToCheck->threadShouldExit())
423 && (jobToCheck == nullptr || ! jobToCheck->shouldExit()))
424 {
425 if (mmLock.tryEnter())
426 break;
427 }
428
429 if (threadToCheck != nullptr)
430 {
431 threadToCheck->removeListener (this);
432
433 if (threadToCheck->threadShouldExit())
434 return false;
435 }
436
437 if (jobToCheck != nullptr)
438 {
439 jobToCheck->removeListener (this);
440
441 if (jobToCheck->shouldExit())
442 return false;
443 }
444
445 return true;
446}
447
448MessageManagerLock::~MessageManagerLock() { mmLock.exit(); }
449
450void MessageManagerLock::exitSignalSent()
451{
452 mmLock.abort();
453}
454
455//==============================================================================
456JUCE_API void JUCE_CALLTYPE initialiseJuce_GUI();
457JUCE_API void JUCE_CALLTYPE initialiseJuce_GUI()
458{
459 JUCE_AUTORELEASEPOOL
460 {
461 MessageManager::getInstance();
462 }
463}
464
465JUCE_API void JUCE_CALLTYPE shutdownJuce_GUI();
466JUCE_API void JUCE_CALLTYPE shutdownJuce_GUI()
467{
468 JUCE_AUTORELEASEPOOL
469 {
470 DeletedAtShutdown::deleteAll();
471 MessageManager::deleteInstance();
472 }
473}
474
475static int numScopedInitInstances = 0;
476
477ScopedJuceInitialiser_GUI::ScopedJuceInitialiser_GUI() { if (numScopedInitInstances++ == 0) initialiseJuce_GUI(); }
478ScopedJuceInitialiser_GUI::~ScopedJuceInitialiser_GUI() { if (--numScopedInitInstances == 0) shutdownJuce_GUI(); }
479
480} // namespace juce
juce::ActionBroadcaster
Definition: juce_ActionBroadcaster.h:37
juce::ActionListener
Definition: juce_ActionListener.h:35
juce::DeletedAtShutdown::deleteAll
static void deleteAll()
Definition: juce_DeletedAtShutdown.cpp:53
juce::JUCEApplicationBase::isStandaloneApp
static bool isStandaloneApp() noexcept
Definition: juce_ApplicationBase.h:267
juce::MessageManagerLock::~MessageManagerLock
~MessageManagerLock() override
Definition: juce_MessageManager.cpp:448
juce::MessageManagerLock::MessageManagerLock
MessageManagerLock(Thread *threadToCheckForExitSignal=nullptr)
Definition: juce_MessageManager.cpp:403
juce::MessageManager::Lock
Definition: juce_MessageManager.h:205
juce::MessageManager::Lock::Lock
Lock()
Definition: juce_MessageManager.cpp:299
juce::MessageManager::Lock::~Lock
~Lock()
Definition: juce_MessageManager.cpp:300
juce::MessageManager::Lock::enter
void enter() const noexcept
Definition: juce_MessageManager.cpp:301
juce::MessageManager::Lock::abort
void abort() const noexcept
Definition: juce_MessageManager.cpp:396
juce::MessageManager::Lock::tryEnter
bool tryEnter() const noexcept
Definition: juce_MessageManager.cpp:302
juce::MessageManager::Lock::exit
void exit() const noexcept
Definition: juce_MessageManager.cpp:370
juce::MessageManager::MessageBase
Definition: juce_MessageManager.h:187
juce::MessageManager
Definition: juce_MessageManager.h:50
juce::MessageManager::callAsync
static bool callAsync(std::function< void()> functionToCall)
Definition: juce_MessageManager.cpp:187
juce::MessageManager::isThisTheMessageThread
bool isThisTheMessageThread() const noexcept
Definition: juce_MessageManager.cpp:221
juce::MessageManager::existsAndIsCurrentThread
static bool existsAndIsCurrentThread() noexcept
Definition: juce_MessageManager.cpp:254
juce::MessageManager::runDispatchLoop
void runDispatchLoop()
Definition: juce_MessageManager.cpp:120
juce::MessageManager::stopDispatchLoop
void stopDispatchLoop()
Definition: juce_MessageManager.cpp:135
juce::MessageManager::currentThreadHasLockedMessageManager
bool currentThreadHasLockedMessageManager() const noexcept
Definition: juce_MessageManager.cpp:240
juce::MessageManager::callFunctionOnMessageThread
void * callFunctionOnMessageThread(MessageCallbackFunction *callback, void *userData)
Definition: juce_MessageManager.cpp:167
juce::MessageManager::deregisterBroadcastListener
void deregisterBroadcastListener(ActionListener *listener)
Definition: juce_MessageManager.cpp:214
juce::MessageManager::setCurrentThreadAsMessageThread
void setCurrentThreadAsMessageThread()
Definition: juce_MessageManager.cpp:226
juce::MessageManager::existsAndIsLockedByCurrentThread
static bool existsAndIsLockedByCurrentThread() noexcept
Definition: juce_MessageManager.cpp:246
juce::MessageManager::registerBroadcastListener
void registerBroadcastListener(ActionListener *listener)
Definition: juce_MessageManager.cpp:206
juce::MessageManager::deleteInstance
static void deleteInstance()
Definition: juce_MessageManager.cpp:61
juce::MessageManager::getInstanceWithoutCreating
static MessageManager * getInstanceWithoutCreating() noexcept
Definition: juce_MessageManager.cpp:56
juce::MessageManager::getInstance
static MessageManager * getInstance()
Definition: juce_MessageManager.cpp:45
juce::ReferenceCountedObjectPtr
Definition: juce_ReferenceCountedObject.h:247
juce::ScopedJuceInitialiser_GUI::~ScopedJuceInitialiser_GUI
~ScopedJuceInitialiser_GUI()
Definition: juce_MessageManager.cpp:478
juce::ScopedJuceInitialiser_GUI::ScopedJuceInitialiser_GUI
ScopedJuceInitialiser_GUI()
Definition: juce_MessageManager.cpp:477
juce::String
Definition: juce_String.h:39
juce::ThreadPoolJob
Definition: juce_ThreadPool.h:45
juce::ThreadPoolJob::addListener
void addListener(Thread::Listener *)
Definition: juce_ThreadPool.cpp:74
juce::ThreadPoolJob::shouldExit
bool shouldExit() const noexcept
Definition: juce_ThreadPool.h:107
juce::ThreadPoolJob::removeListener
void removeListener(Thread::Listener *)
Definition: juce_ThreadPool.cpp:79
juce::Thread
Definition: juce_Thread.h:43
juce::Thread::sleep
static void JUCE_CALLTYPE sleep(int milliseconds)
juce::Thread::setCurrentThreadName
static void JUCE_CALLTYPE setCurrentThreadName(const String &newThreadName)
juce::Thread::threadShouldExit
bool threadShouldExit() const
Definition: juce_Thread.cpp:182
juce::Thread::getCurrentThreadId
static ThreadID JUCE_CALLTYPE getCurrentThreadId()
juce::Thread::addListener
void addListener(Listener *)
Definition: juce_Thread.cpp:247
juce::Thread::removeListener
void removeListener(Listener *)
Definition: juce_Thread.cpp:252
juce::Time::currentTimeMillis
static int64 currentTimeMillis() noexcept
Definition: juce_Time.cpp:205
juce::Atomic::get
Type get() const noexcept
Definition: juce_Atomic.h:64