OpenShot Library | OpenShotAudio  0.2.2
juce_MessageManager.h
1 
2 /** @weakgroup juce_events-messages
3  * @{
4  */
5 /*
6  ==============================================================================
7 
8  This file is part of the JUCE library.
9  Copyright (c) 2017 - ROLI Ltd.
10 
11  JUCE is an open source library subject to commercial or open-source
12  licensing.
13 
14  The code included in this file is provided under the terms of the ISC license
15  http://www.isc.org/downloads/software-support-policy/isc-license. Permission
16  To use, copy, modify, and/or distribute this software for any purpose with or
17  without fee is hereby granted provided that the above copyright notice and
18  this permission notice appear in all copies.
19 
20  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
21  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
22  DISCLAIMED.
23 
24  ==============================================================================
25 */
26 
27 namespace juce
28 {
29 
30 class MessageManagerLock;
31 class ThreadPoolJob;
32 class ActionListener;
33 class ActionBroadcaster;
34 
35 //==============================================================================
36 #if JUCE_MODULE_AVAILABLE_juce_opengl
37 class OpenGLContext;
38 #endif
39 
40 //==============================================================================
41 /** See MessageManager::callFunctionOnMessageThread() for use of this function type. */
42 using MessageCallbackFunction = void* (void* userData);
43 
44 
45 //==============================================================================
46 /**
47  This class is in charge of the application's event-dispatch loop.
48 
49  @see Message, CallbackMessage, MessageManagerLock, JUCEApplication, JUCEApplicationBase
50 
51  @tags{Events}
52 */
54 {
55 public:
56  //==============================================================================
57  /** Returns the global instance of the MessageManager. */
58  static MessageManager* getInstance();
59 
60  /** Returns the global instance of the MessageManager, or nullptr if it doesn't exist. */
61  static MessageManager* getInstanceWithoutCreating() noexcept;
62 
63  /** Deletes the global MessageManager instance.
64  Does nothing if no instance had been created.
65  */
66  static void deleteInstance();
67 
68  //==============================================================================
69  /** Runs the event dispatch loop until a stop message is posted.
70 
71  This method is only intended to be run by the application's startup routine,
72  as it blocks, and will only return after the stopDispatchLoop() method has been used.
73 
74  @see stopDispatchLoop
75  */
76  void runDispatchLoop();
77 
78  /** Sends a signal that the dispatch loop should terminate.
79 
80  After this is called, the runDispatchLoop() or runDispatchLoopUntil() methods
81  will be interrupted and will return.
82 
83  @see runDispatchLoop
84  */
85  void stopDispatchLoop();
86 
87  /** Returns true if the stopDispatchLoop() method has been called.
88  */
89  bool hasStopMessageBeenSent() const noexcept { return quitMessagePosted.get() != 0; }
90 
91  #if JUCE_MODAL_LOOPS_PERMITTED || DOXYGEN
92  /** Synchronously dispatches messages until a given time has elapsed.
93 
94  Returns false if a quit message has been posted by a call to stopDispatchLoop(),
95  otherwise returns true.
96  */
97  bool runDispatchLoopUntil (int millisecondsToRunFor);
98  #endif
99 
100  //==============================================================================
101  /** Asynchronously invokes a function or C++11 lambda on the message thread.
102 
103  @returns true if the message was successfully posted to the message queue,
104  or false otherwise.
105  */
106  static bool callAsync (std::function<void()> functionToCall);
107 
108  /** Calls a function using the message-thread.
109 
110  This can be used by any thread to cause this function to be called-back
111  by the message thread. If it's the message-thread that's calling this method,
112  then the function will just be called; if another thread is calling, a message
113  will be posted to the queue, and this method will block until that message
114  is delivered, the function is called, and the result is returned.
115 
116  Be careful not to cause any deadlocks with this! It's easy to do - e.g. if the caller
117  thread has a critical section locked, which an unrelated message callback then tries to lock
118  before the message thread gets round to processing this callback.
119 
120  @param callback the function to call - its signature must be @code
121  void* myCallbackFunction (void*) @endcode
122  @param userData a user-defined pointer that will be passed to the function that gets called
123  @returns the value that the callback function returns.
124  @see MessageManagerLock
125  */
126  void* callFunctionOnMessageThread (MessageCallbackFunction* callback, void* userData);
127 
128  /** Returns true if the caller-thread is the message thread. */
129  bool isThisTheMessageThread() const noexcept;
130 
131  /** Called to tell the manager that the current thread is the one that's running the dispatch loop.
132 
133  (Best to ignore this method unless you really know what you're doing..)
134  @see getCurrentMessageThread
135  */
136  void setCurrentThreadAsMessageThread();
137 
138  /** Returns the ID of the current message thread, as set by setCurrentThreadAsMessageThread().
139 
140  (Best to ignore this method unless you really know what you're doing..)
141  @see setCurrentThreadAsMessageThread
142  */
143  Thread::ThreadID getCurrentMessageThread() const noexcept { return messageThreadId; }
144 
145  /** Returns true if the caller thread has currently got the message manager locked.
146 
147  see the MessageManagerLock class for more info about this.
148 
149  This will be true if the caller is the message thread, because that automatically
150  gains a lock while a message is being dispatched.
151  */
152  bool currentThreadHasLockedMessageManager() const noexcept;
153 
154  /** Returns true if there's an instance of the MessageManager, and if the current thread
155  has the lock on it.
156  */
157  static bool existsAndIsLockedByCurrentThread() noexcept;
158 
159  /** Returns true if there's an instance of the MessageManager, and if the current thread
160  is running it.
161  */
162  static bool existsAndIsCurrentThread() noexcept;
163 
164  //==============================================================================
165  /** Sends a message to all other JUCE applications that are running.
166 
167  @param messageText the string that will be passed to the actionListenerCallback()
168  method of the broadcast listeners in the other app.
169  @see registerBroadcastListener, ActionListener
170  */
171  static void broadcastMessage (const String& messageText);
172 
173  /** Registers a listener to get told about broadcast messages.
174 
175  The actionListenerCallback() callback's string parameter
176  is the message passed into broadcastMessage().
177 
178  @see broadcastMessage
179  */
180  void registerBroadcastListener (ActionListener* listener);
181 
182  /** Deregisters a broadcast listener. */
183  void deregisterBroadcastListener (ActionListener* listener);
184 
185  //==============================================================================
186  /** Internal class used as the base class for all message objects.
187  You shouldn't need to use this directly - see the CallbackMessage or Message
188  classes instead.
189  */
191  {
192  public:
193  MessageBase() = default;
194  ~MessageBase() override = default;
195 
196  virtual void messageCallback() = 0;
197  bool post();
198 
200 
201  JUCE_DECLARE_NON_COPYABLE (MessageBase)
202  };
203 
204  //==============================================================================
205  /** A lock you can use to lock the message manager. You can use this class with
206  the RAII-based ScopedLock classes.
207  */
209  {
210  public:
211  /**
212  Creates a new critical section to exclusively access methods which can
213  only be called when the message manager is locked.
214 
215  Unlike CrititcalSection, multiple instances of this lock class provide
216  exclusive access to a single resource - the MessageManager.
217  */
218  Lock();
219 
220  /** Destructor. */
221  ~Lock();
222 
223  /** Acquires the message manager lock.
224 
225  If the caller thread already has exclusive access to the MessageManager, this method
226  will return immediately.
227  If another thread is currently using the MessageManager, this will wait until that
228  thread releases the lock to the MessageManager.
229 
230  This call will only exit if the lock was acquired by this thread. Calling abort while
231  a thread is waiting for enter to finish, will have no effect.
232 
233  @see exit, abort
234  */
235  void enter() const noexcept;
236 
237  /** Attempts to lock the message manager and exits if abort is called.
238 
239  This method behaves identically to enter, except that it will abort waiting for
240  the lock if the abort method is called.
241 
242  Unlike other JUCE critical sections, this method **will** block waiting for the lock.
243 
244  To ensure predictable behaviour, you should re-check your abort condition if tryEnter
245  returns false.
246 
247  This method can be used if you want to do some work while waiting for the
248  MessageManagerLock:
249 
250  void doWorkWhileWaitingForMessageManagerLock()
251  {
252  MessageManager::Lock::ScopedTryLockType mmLock (messageManagerLock);
253 
254  while (! mmLock.isLocked())
255  {
256  while (workQueue.size() > 0)
257  {
258  auto work = workQueue.pop();
259  doSomeWork (work);
260  }
261 
262  // this will block until we either have the lock or there is work
263  mmLock.retryLock();
264  }
265 
266  // we have the mmlock
267  // do some message manager stuff like resizing and painting components
268  }
269 
270  // called from another thread
271  void addWorkToDo (Work work)
272  {
273  queue.push (work);
274  messageManagerLock.abort();
275  }
276 
277  @returns false if waiting for a lock was aborted, true if the lock was acquired.
278  @see enter, abort, ScopedTryLock
279  */
280  bool tryEnter() const noexcept;
281 
282  /** Releases the message manager lock.
283  @see enter, ScopedLock
284  */
285  void exit() const noexcept;
286 
287  /** Unblocks a thread which is waiting in tryEnter
288  Call this method if you want to unblock a thread which is waiting for the
289  MessageManager lock in tryEnter.
290  This method does not have any effect on a thread waiting for a lock in enter.
291  @see tryEnter
292  */
293  void abort() const noexcept;
294 
295  //==============================================================================
296  /** Provides the type of scoped lock to use with a CriticalSection. */
298 
299  /** Provides the type of scoped unlocker to use with a CriticalSection. */
301 
302  /** Provides the type of scoped try-locker to use with a CriticalSection. */
304 
305  private:
306  struct BlockingMessage;
308 
309  bool tryAcquire (bool) const noexcept;
310  void messageCallback() const;
311 
312  //==============================================================================
313  mutable ReferenceCountedObjectPtr<BlockingMessage> blockingMessage;
314  WaitableEvent lockedEvent;
315  mutable Atomic<int> abortWait, lockGained;
316  };
317 
318  //==============================================================================
319  #ifndef DOXYGEN
320  // Internal methods - do not use!
321  void deliverBroadcastMessage (const String&);
322  ~MessageManager() noexcept;
323  #endif
324 
325 private:
326  //==============================================================================
327  MessageManager() noexcept;
328 
329  static MessageManager* instance;
330 
331  friend class MessageBase;
332  class QuitMessage;
333  friend class QuitMessage;
334  friend class MessageManagerLock;
335 
336  std::unique_ptr<ActionBroadcaster> broadcaster;
337  Atomic<int> quitMessagePosted { 0 }, quitMessageReceived { 0 };
338  Thread::ThreadID messageThreadId;
339  Atomic<Thread::ThreadID> threadWithLock;
340 
341  static bool postMessageToSystemQueue (MessageBase*);
342  static void* exitModalLoopCallback (void*);
343  static void doPlatformSpecificInitialisation();
344  static void doPlatformSpecificShutdown();
345  static bool dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages);
346 
347  JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MessageManager)
348 };
349 
350 
351 //==============================================================================
352 /** Used to make sure that the calling thread has exclusive access to the message loop.
353 
354  Because it's not thread-safe to call any of the Component or other UI classes
355  from threads other than the message thread, one of these objects can be used to
356  lock the message loop and allow this to be done. The message thread will be
357  suspended for the lifetime of the MessageManagerLock object, so create one on
358  the stack like this: @code
359  void MyThread::run()
360  {
361  someData = 1234;
362 
363  const MessageManagerLock mmLock;
364  // the event loop will now be locked so it's safe to make a few calls..
365 
366  myComponent->setBounds (newBounds);
367  myComponent->repaint();
368 
369  // ..the event loop will now be unlocked as the MessageManagerLock goes out of scope
370  }
371  @endcode
372 
373  Obviously be careful not to create one of these and leave it lying around, or
374  your app will grind to a halt!
375 
376  MessageManagerLocks are re-entrant, so can be safely nested if the current thread
377  already has the lock.
378 
379  Another caveat is that using this in conjunction with other CriticalSections
380  can create lots of interesting ways of producing a deadlock! In particular, if
381  your message thread calls stopThread() for a thread that uses these locks,
382  you'll get an (occasional) deadlock..
383 
384  @see MessageManager, MessageManager::currentThreadHasLockedMessageManager
385 
386  @tags{Events}
387 */
389 {
390 public:
391  //==============================================================================
392  /** Tries to acquire a lock on the message manager.
393 
394  The constructor attempts to gain a lock on the message loop, and the lock will be
395  kept for the lifetime of this object.
396 
397  Optionally, you can pass a thread object here, and while waiting to obtain the lock,
398  this method will keep checking whether the thread has been given the
399  Thread::signalThreadShouldExit() signal. If this happens, then it will return
400  without gaining the lock. If you pass a thread, you must check whether the lock was
401  successful by calling lockWasGained(). If this is false, your thread is being told to
402  die, so you should take evasive action.
403 
404  If you pass nullptr for the thread object, it will wait indefinitely for the lock - be
405  careful when doing this, because it's very easy to deadlock if your message thread
406  attempts to call stopThread() on a thread just as that thread attempts to get the
407  message lock.
408 
409  If the calling thread already has the lock, nothing will be done, so it's safe and
410  quick to use these locks recursively.
411 
412  E.g.
413  @code
414  void run()
415  {
416  ...
417 
418  while (! threadShouldExit())
419  {
420  MessageManagerLock mml (Thread::getCurrentThread());
421 
422  if (! mml.lockWasGained())
423  return; // another thread is trying to kill us!
424 
425  ..do some locked stuff here..
426  }
427 
428  ..and now the MM is now unlocked..
429  }
430  @endcode
431 
432  */
433  MessageManagerLock (Thread* threadToCheckForExitSignal = nullptr);
434 
435  //==============================================================================
436  /** This has the same behaviour as the other constructor, but takes a ThreadPoolJob
437  instead of a thread.
438 
439  See the MessageManagerLock (Thread*) constructor for details on how this works.
440  */
441  MessageManagerLock (ThreadPoolJob* jobToCheckForExitSignal);
442 
443  //==============================================================================
444  /** Releases the current thread's lock on the message manager.
445 
446  Make sure this object is created and deleted by the same thread,
447  otherwise there are no guarantees what will happen!
448  */
449  ~MessageManagerLock() override;
450 
451  //==============================================================================
452  /** Returns true if the lock was successfully acquired.
453  (See the constructor that takes a Thread for more info).
454  */
455  bool lockWasGained() const noexcept { return locked; }
456 
457 private:
458  //==============================================================================
459  MessageManager::Lock mmLock;
460  bool locked;
461 
462  //==============================================================================
463  bool attemptLock (Thread*, ThreadPoolJob*);
464  void exitSignalSent() override;
465 
466  JUCE_DECLARE_NON_COPYABLE (MessageManagerLock)
467 };
468 
469 //==============================================================================
470 /** This macro is used to catch unsafe use of functions which expect to only be called
471  on the message thread, or when a MessageManagerLock is in place.
472  It will also fail if you try to use the function before the message manager has been
473  created, which could happen if you accidentally invoke it during a static constructor.
474 */
475 #define JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED \
476  jassert (juce::MessageManager::existsAndIsLockedByCurrentThread());
477 
478 /** This macro is used to catch unsafe use of functions which expect to only be called
479  on the message thread.
480  It will also fail if you try to use the function before the message manager has been
481  created, which could happen if you accidentally invoke it during a static constructor.
482 */
483 #define JUCE_ASSERT_MESSAGE_THREAD \
484  jassert (juce::MessageManager::existsAndIsCurrentThread());
485 
486 /** This macro is used to catch unsafe use of functions which expect to not be called
487  outside the lifetime of the MessageManager.
488 */
489 #define JUCE_ASSERT_MESSAGE_MANAGER_EXISTS \
490  jassert (juce::MessageManager::getInstanceWithoutCreating() != nullptr);
491 
492 
493 } // namespace juce
494 
495 /** @}*/
#define JUCE_API
This macro is added to all JUCE public class declarations.
Thread::ThreadID getCurrentMessageThread() const noexcept
Returns the ID of the current message thread, as set by setCurrentThreadAsMessageThread().
Interface class for delivery of events that are sent by an ActionBroadcaster.
void * ThreadID
A value type used for thread IDs.
Definition: juce_Thread.h:308
bool lockWasGained() const noexcept
Returns true if the lock was successfully acquired.
Allows threads to wait for events triggered by other threads.
STL namespace.
This class is in charge of the application&#39;s event-dispatch loop.
The JUCE String class!
Definition: juce_String.h:42
Used to receive callbacks for thread exit calls.
Definition: juce_Thread.h:184
Encapsulates a thread.
Definition: juce_Thread.h:46
bool hasStopMessageBeenSent() const noexcept
Returns true if the stopDispatchLoop() method has been called.
A smart-pointer class which points to a reference-counted object.
Automatically locks and unlocks a mutex object.
A base class which provides methods for reference-counting.
A task that is executed by a ThreadPool object.
Automatically locks and unlocks a mutex object.
Used to make sure that the calling thread has exclusive access to the message loop.
Automatically unlocks and re-locks a mutex object.
Manages a list of ActionListeners, and can send them messages.
Internal class used as the base class for all message objects.
A lock you can use to lock the message manager.