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 
23 namespace juce
24 {
25 
MessageManager()26 MessageManager::MessageManager() noexcept
27   : messageThreadId (Thread::getCurrentThreadId())
28 {
29     if (JUCEApplicationBase::isStandaloneApp())
30         Thread::setCurrentThreadName ("JUCE Message Thread");
31 }
32 
~MessageManager()33 MessageManager::~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 
43 MessageManager* MessageManager::instance = nullptr;
44 
getInstance()45 MessageManager* MessageManager::getInstance()
46 {
47     if (instance == nullptr)
48     {
49         instance = new MessageManager();
50         doPlatformSpecificInitialisation();
51     }
52 
53     return instance;
54 }
55 
getInstanceWithoutCreating()56 MessageManager* MessageManager::getInstanceWithoutCreating() noexcept
57 {
58     return instance;
59 }
60 
deleteInstance()61 void MessageManager::deleteInstance()
62 {
63     deleteAndZero (instance);
64 }
65 
66 //==============================================================================
post()67 bool 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)
runDispatchLoopUntil(int millisecondsToRunFor)82 bool 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)
106 class MessageManager::QuitMessage   : public MessageManager::MessageBase
107 {
108 public:
QuitMessage()109     QuitMessage() {}
110 
messageCallback()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 
runDispatchLoop()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 
stopDispatchLoop()135 void MessageManager::stopDispatchLoop()
136 {
137     (new QuitMessage())->post();
138     quitMessagePosted = true;
139 }
140 
141 #endif
142 
143 //==============================================================================
144 class AsyncFunctionCallback   : public MessageManager::MessageBase
145 {
146 public:
AsyncFunctionCallback(MessageCallbackFunction * const f,void * const param)147     AsyncFunctionCallback (MessageCallbackFunction* const f, void* const param)
148         : func (f), parameter (param)
149     {}
150 
messageCallback()151     void messageCallback() override
152     {
153         result = (*func) (parameter);
154         finished.signal();
155     }
156 
157     WaitableEvent finished;
158     std::atomic<void*> result { nullptr };
159 
160 private:
161     MessageCallbackFunction* const func;
162     void* const parameter;
163 
164     JUCE_DECLARE_NON_COPYABLE (AsyncFunctionCallback)
165 };
166 
callFunctionOnMessageThread(MessageCallbackFunction * func,void * parameter)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 
callAsync(std::function<void ()> fn)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 //==============================================================================
deliverBroadcastMessage(const String & value)200 void MessageManager::deliverBroadcastMessage (const String& value)
201 {
202     if (broadcaster != nullptr)
203         broadcaster->sendActionMessage (value);
204 }
205 
registerBroadcastListener(ActionListener * const listener)206 void MessageManager::registerBroadcastListener (ActionListener* const listener)
207 {
208     if (broadcaster == nullptr)
209         broadcaster.reset (new ActionBroadcaster());
210 
211     broadcaster->addActionListener (listener);
212 }
213 
deregisterBroadcastListener(ActionListener * const listener)214 void MessageManager::deregisterBroadcastListener (ActionListener* const listener)
215 {
216     if (broadcaster != nullptr)
217         broadcaster->removeActionListener (listener);
218 }
219 
220 //==============================================================================
isThisTheMessageThread() const221 bool MessageManager::isThisTheMessageThread() const noexcept
222 {
223     return Thread::getCurrentThreadId() == messageThreadId;
224 }
225 
setCurrentThreadAsMessageThread()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 
currentThreadHasLockedMessageManager() const240 bool MessageManager::currentThreadHasLockedMessageManager() const noexcept
241 {
242     auto thisThread = Thread::getCurrentThreadId();
243     return thisThread == messageThreadId || thisThread == threadWithLock.get();
244 }
245 
existsAndIsLockedByCurrentThread()246 bool MessageManager::existsAndIsLockedByCurrentThread() noexcept
247 {
248     if (auto i = getInstanceWithoutCreating())
249         return i->currentThreadHasLockedMessageManager();
250 
251     return false;
252 }
253 
existsAndIsCurrentThread()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 */
273 struct MessageManager::Lock::BlockingMessage   : public MessageManager::MessageBase
274 {
BlockingMessagejuce::MessageManager::Lock::BlockingMessage275     BlockingMessage (const MessageManager::Lock* parent) noexcept
276         : owner (parent)
277     {}
278 
messageCallbackjuce::MessageManager::Lock::BlockingMessage279     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 //==============================================================================
Lock()299 MessageManager::Lock::Lock()                            {}
~Lock()300 MessageManager::Lock::~Lock()                           { exit(); }
enter() const301 void MessageManager::Lock::enter()    const noexcept    {        tryAcquire (true); }
tryEnter() const302 bool MessageManager::Lock::tryEnter() const noexcept    { return tryAcquire (false); }
303 
tryAcquire(bool lockIsMandatory) const304 bool 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 
exit() const370 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 
messageCallback() const390 void MessageManager::Lock::messageCallback() const
391 {
392     lockGained.set (1);
393     abort();
394 }
395 
abort() const396 void MessageManager::Lock::abort() const noexcept
397 {
398     abortWait.set (1);
399     lockedEvent.signal();
400 }
401 
402 //==============================================================================
MessageManagerLock(Thread * threadToCheck)403 MessageManagerLock::MessageManagerLock (Thread* threadToCheck)
404     : locked (attemptLock (threadToCheck, nullptr))
405 {}
406 
MessageManagerLock(ThreadPoolJob * jobToCheck)407 MessageManagerLock::MessageManagerLock (ThreadPoolJob* jobToCheck)
408     : locked (attemptLock (nullptr, jobToCheck))
409 {}
410 
attemptLock(Thread * threadToCheck,ThreadPoolJob * jobToCheck)411 bool 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 
~MessageManagerLock()448 MessageManagerLock::~MessageManagerLock()  { mmLock.exit(); }
449 
exitSignalSent()450 void MessageManagerLock::exitSignalSent()
451 {
452     mmLock.abort();
453 }
454 
455 //==============================================================================
456 JUCE_API void JUCE_CALLTYPE initialiseJuce_GUI();
initialiseJuce_GUI()457 JUCE_API void JUCE_CALLTYPE initialiseJuce_GUI()
458 {
459     JUCE_AUTORELEASEPOOL
460     {
461         MessageManager::getInstance();
462     }
463 }
464 
465 JUCE_API void JUCE_CALLTYPE shutdownJuce_GUI();
shutdownJuce_GUI()466 JUCE_API void JUCE_CALLTYPE shutdownJuce_GUI()
467 {
468     JUCE_AUTORELEASEPOOL
469     {
470         DeletedAtShutdown::deleteAll();
471         MessageManager::deleteInstance();
472     }
473 }
474 
475 static int numScopedInitInstances = 0;
476 
ScopedJuceInitialiser_GUI()477 ScopedJuceInitialiser_GUI::ScopedJuceInitialiser_GUI()  { if (numScopedInitInstances++ == 0) initialiseJuce_GUI(); }
~ScopedJuceInitialiser_GUI()478 ScopedJuceInitialiser_GUI::~ScopedJuceInitialiser_GUI() { if (--numScopedInitInstances == 0) shutdownJuce_GUI(); }
479 
480 } // namespace juce
481