OpenShot Library | libopenshot-audio  0.2.0
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 
23 namespace juce
24 {
25 
26 MessageManager::MessageManager() noexcept
27  : messageThreadId (Thread::getCurrentThreadId())
28 {
30  Thread::setCurrentThreadName ("JUCE Message Thread");
31 }
32 
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 
46 {
47  if (instance == nullptr)
48  {
49  instance = new MessageManager();
50  doPlatformSpecificInitialisation();
51  }
52 
53  return instance;
54 }
55 
57 {
58  return instance;
59 }
60 
62 {
63  deleteAndZero (instance);
64 }
65 
66 //==============================================================================
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)
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:
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 
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 
136 {
137  (new QuitMessage())->post();
138  quitMessagePosted = true;
139 }
140 
141 #endif
142 
143 //==============================================================================
145 {
146 public:
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 
160 private:
161  MessageCallbackFunction* const func;
162  void* const parameter;
163 
164  JUCE_DECLARE_NON_COPYABLE (AsyncFunctionCallback)
165 };
166 
167 void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* const func, void* const parameter)
168 {
170  return func (parameter);
171 
172  // If this thread has the message manager locked, then this will deadlock!
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 //==============================================================================
188 void MessageManager::deliverBroadcastMessage (const String& value)
189 {
190  if (broadcaster != nullptr)
191  broadcaster->sendActionMessage (value);
192 }
193 
195 {
196  if (broadcaster == nullptr)
197  broadcaster.reset (new ActionBroadcaster());
198 
199  broadcaster->addActionListener (listener);
200 }
201 
203 {
204  if (broadcaster != nullptr)
205  broadcaster->removeActionListener (listener);
206 }
207 
208 //==============================================================================
210 {
211  return Thread::getCurrentThreadId() == messageThreadId;
212 }
213 
215 {
216  auto thisThread = Thread::getCurrentThreadId();
217 
218  if (messageThreadId != thisThread)
219  {
220  messageThreadId = thisThread;
221 
222  // This is needed on windows to make sure the message window is created by this thread
223  doPlatformSpecificShutdown();
224  doPlatformSpecificInitialisation();
225  }
226 }
227 
229 {
230  auto thisThread = Thread::getCurrentThreadId();
231  return thisThread == messageThreadId || thisThread == threadWithLock.get();
232 }
233 
235 {
236  if (auto i = getInstanceWithoutCreating())
237  return i->currentThreadHasLockedMessageManager();
238 
239  return false;
240 }
241 
243 {
244  if (auto i = getInstanceWithoutCreating())
245  return i->isThisTheMessageThread();
246 
247  return false;
248 }
249 
250 //==============================================================================
251 //==============================================================================
252 /* The only safe way to lock the message thread while another thread does
253  some work is by posting a special message, whose purpose is to tie up the event
254  loop until the other thread has finished its business.
255 
256  Any other approach can get horribly deadlocked if the OS uses its own hidden locks which
257  get locked before making an event callback, because if the same OS lock gets indirectly
258  accessed from another thread inside a MM lock, you're screwed. (this is exactly what happens
259  in Cocoa).
260 */
262 {
263  BlockingMessage (const MessageManager::Lock* parent) noexcept
264  // need a const_cast here as VS2013 doesn't like a const pointer to be in an atomic
265  : owner (const_cast<MessageManager::Lock*> (parent)) {}
266 
267  void messageCallback() override
268  {
269  {
270  ScopedLock lock (ownerCriticalSection);
271 
272  if (auto* o = owner.get())
273  o->messageCallback();
274  }
275 
276  releaseEvent.wait();
277  }
278 
279  CriticalSection ownerCriticalSection;
281  WaitableEvent releaseEvent;
282 
283  JUCE_DECLARE_NON_COPYABLE (BlockingMessage)
284 };
285 
286 //==============================================================================
289 void MessageManager::Lock::enter() const noexcept { tryAcquire (true); }
290 bool MessageManager::Lock::tryEnter() const noexcept { return tryAcquire (false); }
291 
292 bool MessageManager::Lock::tryAcquire (bool lockIsMandatory) const noexcept
293 {
294  auto* mm = MessageManager::instance;
295 
296  if (mm == nullptr)
297  {
298  jassertfalse;
299  return false;
300  }
301 
302  if (! lockIsMandatory && (abortWait.get() != 0))
303  {
304  abortWait.set (0);
305  return false;
306  }
307 
308  if (mm->currentThreadHasLockedMessageManager())
309  return true;
310 
311  try
312  {
313  blockingMessage = *new BlockingMessage (this);
314  }
315  catch (...)
316  {
317  jassert (! lockIsMandatory);
318  return false;
319  }
320 
321  if (! blockingMessage->post())
322  {
323  // post of message failed while trying to get the lock
324  jassert (! lockIsMandatory);
325  blockingMessage = nullptr;
326  return false;
327  }
328 
329  do
330  {
331  while (abortWait.get() == 0)
332  lockedEvent.wait (-1);
333 
334  abortWait.set (0);
335 
336  if (lockGained.get() != 0)
337  {
338  mm->threadWithLock = Thread::getCurrentThreadId();
339  return true;
340  }
341 
342  } while (lockIsMandatory);
343 
344  // we didn't get the lock
345  blockingMessage->releaseEvent.signal();
346 
347  {
348  ScopedLock lock (blockingMessage->ownerCriticalSection);
349 
350  lockGained.set (0);
351  blockingMessage->owner.set (nullptr);
352  }
353 
354  blockingMessage = nullptr;
355  return false;
356 }
357 
358 void MessageManager::Lock::exit() const noexcept
359 {
360  if (lockGained.compareAndSetBool (false, true))
361  {
362  auto* mm = MessageManager::instance;
363 
364  jassert (mm == nullptr || mm->currentThreadHasLockedMessageManager());
365  lockGained.set (0);
366 
367  if (mm != nullptr)
368  mm->threadWithLock = {};
369 
370  if (blockingMessage != nullptr)
371  {
372  blockingMessage->releaseEvent.signal();
373  blockingMessage = nullptr;
374  }
375  }
376 }
377 
378 void MessageManager::Lock::messageCallback() const
379 {
380  lockGained.set (1);
381  abort();
382 }
383 
384 void MessageManager::Lock::abort() const noexcept
385 {
386  abortWait.set (1);
387  lockedEvent.signal();
388 }
389 
390 //==============================================================================
392  : locked (attemptLock (threadToCheck, nullptr))
393 {}
394 
396  : locked (attemptLock (nullptr, jobToCheck))
397 {}
398 
399 bool MessageManagerLock::attemptLock (Thread* threadToCheck, ThreadPoolJob* jobToCheck)
400 {
401  jassert (threadToCheck == nullptr || jobToCheck == nullptr);
402 
403  if (threadToCheck != nullptr)
404  threadToCheck->addListener (this);
405 
406  if (jobToCheck != nullptr)
407  jobToCheck->addListener (this);
408 
409  // tryEnter may have a spurious abort (return false) so keep checking the condition
410  while ((threadToCheck == nullptr || ! threadToCheck->threadShouldExit())
411  && (jobToCheck == nullptr || ! jobToCheck->shouldExit()))
412  {
413  if (mmLock.tryEnter())
414  break;
415  }
416 
417  if (threadToCheck != nullptr)
418  {
419  threadToCheck->removeListener (this);
420 
421  if (threadToCheck->threadShouldExit())
422  return false;
423  }
424 
425  if (jobToCheck != nullptr)
426  {
427  jobToCheck->removeListener (this);
428 
429  if (jobToCheck->shouldExit())
430  return false;
431  }
432 
433  return true;
434 }
435 
437 
438 void MessageManagerLock::exitSignalSent()
439 {
440  mmLock.abort();
441 }
442 
443 //==============================================================================
444 JUCE_API void JUCE_CALLTYPE initialiseJuce_GUI();
445 JUCE_API void JUCE_CALLTYPE initialiseJuce_GUI()
446 {
447  JUCE_AUTORELEASEPOOL
448  {
450  }
451 }
452 
453 JUCE_API void JUCE_CALLTYPE shutdownJuce_GUI();
454 JUCE_API void JUCE_CALLTYPE shutdownJuce_GUI()
455 {
456  JUCE_AUTORELEASEPOOL
457  {
460  }
461 }
462 
463 static int numScopedInitInstances = 0;
464 
465 ScopedJuceInitialiser_GUI::ScopedJuceInitialiser_GUI() { if (numScopedInitInstances++ == 0) initialiseJuce_GUI(); }
466 ScopedJuceInitialiser_GUI::~ScopedJuceInitialiser_GUI() { if (--numScopedInitInstances == 0) shutdownJuce_GUI(); }
467 
468 } // namespace juce
juce::MessageManager::Lock::BlockingMessage
Definition: juce_MessageManager.cpp:261
juce::Atomic
A simple wrapper around std::atomic.
Definition: juce_Atomic.h:45
juce::ActionBroadcaster
Manages a list of ActionListeners, and can send them messages.
Definition: juce_ActionBroadcaster.h:40
juce::MessageManager::isThisTheMessageThread
bool isThisTheMessageThread() const noexcept
Returns true if the caller-thread is the message thread.
Definition: juce_MessageManager.cpp:209
juce::MessageManager::MessageBase
Internal class used as the base class for all message objects.
Definition: juce_MessageManager.h:190
juce::MessageManager::Lock::tryEnter
bool tryEnter() const noexcept
Attempts to lock the meesage manager and exits if abort is called.
Definition: juce_MessageManager.cpp:290
juce::ThreadPoolJob
A task that is executed by a ThreadPool object.
Definition: juce_ThreadPool.h:48
juce::MessageManager::registerBroadcastListener
void registerBroadcastListener(ActionListener *listener)
Registers a listener to get told about broadcast messages.
Definition: juce_MessageManager.cpp:194
juce::Thread
Encapsulates a thread.
Definition: juce_Thread.h:46
juce::ScopedJuceInitialiser_GUI::ScopedJuceInitialiser_GUI
ScopedJuceInitialiser_GUI()
The constructor simply calls initialiseJuce_GUI().
Definition: juce_MessageManager.cpp:465
juce::Atomic::get
Type get() const noexcept
Atomically reads and returns the current value.
Definition: juce_Atomic.h:68
juce::MessageManagerLock::MessageManagerLock
MessageManagerLock(Thread *threadToCheckForExitSignal=nullptr)
Tries to acquire a lock on the message manager.
Definition: juce_MessageManager.cpp:391
juce::MessageManager::existsAndIsCurrentThread
static bool existsAndIsCurrentThread() noexcept
Returns true if there's an instance of the MessageManager, and if the current thread is running it.
Definition: juce_MessageManager.cpp:242
juce::MessageManager::deleteInstance
static void deleteInstance()
Deletes the global MessageManager instance.
Definition: juce_MessageManager.cpp:61
juce::Time::currentTimeMillis
static int64 currentTimeMillis() noexcept
Returns the current system time.
Definition: juce_Time.cpp:205
juce::Thread::setCurrentThreadName
static void JUCE_CALLTYPE setCurrentThreadName(const String &newThreadName)
Changes the name of the caller thread.
juce::MessageManager::Lock::enter
void enter() const noexcept
Acquires the message manager lock.
Definition: juce_MessageManager.cpp:289
juce::Thread::getCurrentThreadId
static ThreadID JUCE_CALLTYPE getCurrentThreadId()
Returns an id that identifies the caller thread.
juce::Thread::threadShouldExit
bool threadShouldExit() const
Checks whether the thread has been told to stop running.
Definition: juce_Thread.cpp:182
juce::MessageManager::setCurrentThreadAsMessageThread
void setCurrentThreadAsMessageThread()
Called to tell the manager that the current thread is the one that's running the dispatch loop.
Definition: juce_MessageManager.cpp:214
JUCE_API
#define JUCE_API
This macro is added to all JUCE public class declarations.
Definition: juce_StandardHeader.h:143
juce::MessageManager::getInstance
static MessageManager * getInstance()
Returns the global instance of the MessageManager.
Definition: juce_MessageManager.cpp:45
juce::MessageManager::Lock::exit
void exit() const noexcept
Releases the message manager lock.
Definition: juce_MessageManager.cpp:358
juce::Thread::addListener
void addListener(Listener *)
Add a listener to this thread which will receive a callback when signalThreadShouldExit was called on...
Definition: juce_Thread.cpp:247
juce::AsyncFunctionCallback
Definition: juce_MessageManager.cpp:144
juce::JUCEApplicationBase::isStandaloneApp
static bool isStandaloneApp() noexcept
Returns true if this executable is running as an app (as opposed to being a plugin or other kind of s...
Definition: juce_ApplicationBase.h:264
juce::MessageManager::currentThreadHasLockedMessageManager
bool currentThreadHasLockedMessageManager() const noexcept
Returns true if the caller thread has currently got the message manager locked.
Definition: juce_MessageManager.cpp:228
juce::MessageManager
This class is in charge of the application's event-dispatch loop.
Definition: juce_MessageManager.h:53
juce::ThreadPoolJob::removeListener
void removeListener(Thread::Listener *)
Removes a listener added with addListener.
Definition: juce_ThreadPool.cpp:79
juce::MessageManager::Lock::Lock
Lock()
Creates a new critical section to exclusively access methods which can only be called when the messag...
Definition: juce_MessageManager.cpp:287
juce::MessageManager::runDispatchLoop
void runDispatchLoop()
Runs the event dispatch loop until a stop message is posted.
juce::MessageManagerLock::~MessageManagerLock
~MessageManagerLock() override
Releases the current thread's lock on the message manager.
Definition: juce_MessageManager.cpp:436
juce::ScopedJuceInitialiser_GUI::~ScopedJuceInitialiser_GUI
~ScopedJuceInitialiser_GUI()
The destructor simply calls shutdownJuce_GUI().
Definition: juce_MessageManager.cpp:466
juce::MessageManager::Lock::~Lock
~Lock()
Destructor.
Definition: juce_MessageManager.cpp:288
juce::DeletedAtShutdown::deleteAll
static void deleteAll()
Deletes all extant objects.
Definition: juce_DeletedAtShutdown.cpp:53
juce::GenericScopedLock
Automatically locks and unlocks a mutex object.
Definition: juce_ScopedLock.h:58
juce::ThreadPoolJob::addListener
void addListener(Thread::Listener *)
Add a listener to this thread job which will receive a callback when signalJobShouldExit was called o...
Definition: juce_ThreadPool.cpp:74
juce::ReferenceCountedObjectPtr
A smart-pointer class which points to a reference-counted object.
Definition: juce_ReferenceCountedObject.h:245
juce::Thread::removeListener
void removeListener(Listener *)
Removes a listener added with addListener.
Definition: juce_Thread.cpp:252
juce::MessageManager::deregisterBroadcastListener
void deregisterBroadcastListener(ActionListener *listener)
Deregisters a broadcast listener.
Definition: juce_MessageManager.cpp:202
juce::MessageManager::runDispatchLoopUntil
bool runDispatchLoopUntil(int millisecondsToRunFor)
Synchronously dispatches messages until a given time has elapsed.
Definition: juce_MessageManager.cpp:82
juce::ThreadPoolJob::shouldExit
bool shouldExit() const noexcept
Returns true if something is trying to interrupt this job and make it stop.
Definition: juce_ThreadPool.h:111
juce::String
The JUCE String class!
Definition: juce_String.h:42
juce::MessageManager::Lock
A lock you can use to lock the message manager.
Definition: juce_MessageManager.h:208
juce::CriticalSection
A re-entrant mutex.
Definition: juce_CriticalSection.h:46
juce::MessageManager::callFunctionOnMessageThread
void * callFunctionOnMessageThread(MessageCallbackFunction *callback, void *userData)
Calls a function using the message-thread.
Definition: juce_MessageManager.cpp:167
juce::MessageManager::getInstanceWithoutCreating
static MessageManager * getInstanceWithoutCreating() noexcept
Returns the global instance of the MessageManager, or nullptr if it doesn't exist.
Definition: juce_MessageManager.cpp:56
juce::MessageManager::Lock::abort
void abort() const noexcept
Unblocks a thread which is waiting in tryEnter Call this method if you want to unblock a thread which...
Definition: juce_MessageManager.cpp:384
juce::MessageManager::existsAndIsLockedByCurrentThread
static bool existsAndIsLockedByCurrentThread() noexcept
Returns true if there's an instance of the MessageManager, and if the current thread has the lock on ...
Definition: juce_MessageManager.cpp:234
juce::ActionListener
Interface class for delivery of events that are sent by an ActionBroadcaster.
Definition: juce_ActionListener.h:38
juce::MessageManager::stopDispatchLoop
void stopDispatchLoop()
Sends a signal that the dispatch loop should terminate.
juce::Thread::sleep
static void JUCE_CALLTYPE sleep(int milliseconds)
Suspends the execution of the current thread until the specified timeout period has elapsed (note tha...
juce::WaitableEvent
Allows threads to wait for events triggered by other threads.
Definition: juce_WaitableEvent.h:39