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
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
48{
49 if (instance == nullptr)
50 {
51 instance = new MessageManager();
52 doPlatformSpecificInitialisation();
53 }
54
55 return instance;
56}
57
59{
60 return instance;
61}
62
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
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
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
175void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* func, void* parameter)
176{
178 return func (parameter);
179
180 // If this thread has the message manager locked, then this will deadlock!
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
195bool 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
215{
216 if (broadcaster == nullptr)
217 broadcaster.reset (new ActionBroadcaster());
218
219 broadcaster->addActionListener (listener);
220}
221
223{
224 if (broadcaster != nullptr)
225 broadcaster->removeActionListener (listener);
226}
227
228//==============================================================================
230{
231 const std::lock_guard<std::mutex> lock { messageThreadIdMutex };
232
233 return Thread::getCurrentThreadId() == messageThreadId;
234}
235
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
253{
254 auto thisThread = Thread::getCurrentThreadId();
255 return thisThread == messageThreadId || thisThread == threadWithLock.get();
256}
257
259{
260 if (auto i = getInstanceWithoutCreating())
261 return i->currentThreadHasLockedMessageManager();
262
263 return false;
264}
265
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//==============================================================================
319void MessageManager::Lock::enter() const noexcept { exclusiveTryAcquire (true); }
320bool 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
401void 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
428void 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//==============================================================================
443 : locked (attemptLock (threadToCheck, nullptr))
444{}
445
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
488
489void MessageManagerLock::exitSignalSent()
490{
491 mmLock.abort();
492}
493
494//==============================================================================
495JUCE_API void JUCE_CALLTYPE initialiseJuce_GUI()
496{
497 JUCE_AUTORELEASEPOOL
498 {
500 }
501}
502
503JUCE_API void JUCE_CALLTYPE shutdownJuce_GUI()
504{
505 JUCE_AUTORELEASEPOOL
506 {
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
static bool isStandaloneApp() noexcept
MessageManagerLock(Thread *threadToCheckForExitSignal=nullptr)
static bool callAsync(std::function< void()> functionToCall)
bool isThisTheMessageThread() const noexcept
static bool existsAndIsCurrentThread() noexcept
bool currentThreadHasLockedMessageManager() const noexcept
void * callFunctionOnMessageThread(MessageCallbackFunction *callback, void *userData)
void deregisterBroadcastListener(ActionListener *listener)
static bool existsAndIsLockedByCurrentThread() noexcept
void registerBroadcastListener(ActionListener *listener)
static MessageManager * getInstanceWithoutCreating() noexcept
static MessageManager * getInstance()
void addListener(Thread::Listener *)
bool shouldExit() const noexcept
void removeListener(Thread::Listener *)
static void JUCE_CALLTYPE sleep(int milliseconds)
static void JUCE_CALLTYPE setCurrentThreadName(const String &newThreadName)
bool threadShouldExit() const
static ThreadID JUCE_CALLTYPE getCurrentThreadId()
void addListener(Listener *)
void removeListener(Listener *)
static int64 currentTimeMillis() noexcept
Type get() const noexcept
Definition juce_Atomic.h:64