OpenShot Audio Library | OpenShotAudio: juce_MessageManager.cpp Source File

OpenShot Audio Library | OpenShotAudio 0.4.0

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