OpenShot Library | libopenshot-audio  0.1.9
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  template <typename FunctionType>
103  static void callAsync (FunctionType functionToCall)
104  {
105  new AsyncCallInvoker<FunctionType> (functionToCall);
106  }
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  */
208  class Lock
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 accquired 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 meesage 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 accquired.
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 effetc 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  template <typename FunctionType>
348  struct AsyncCallInvoker : public MessageBase
349  {
350  AsyncCallInvoker (FunctionType f) : callback (f) { post(); }
351  void messageCallback() override { callback(); }
352  FunctionType callback;
353 
354  JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AsyncCallInvoker)
355  };
356 
357  JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MessageManager)
358 };
359 
360 
361 //==============================================================================
362 /** Used to make sure that the calling thread has exclusive access to the message loop.
363 
364  Because it's not thread-safe to call any of the Component or other UI classes
365  from threads other than the message thread, one of these objects can be used to
366  lock the message loop and allow this to be done. The message thread will be
367  suspended for the lifetime of the MessageManagerLock object, so create one on
368  the stack like this: @code
369  void MyThread::run()
370  {
371  someData = 1234;
372 
373  const MessageManagerLock mmLock;
374  // the event loop will now be locked so it's safe to make a few calls..
375 
376  myComponent->setBounds (newBounds);
377  myComponent->repaint();
378 
379  // ..the event loop will now be unlocked as the MessageManagerLock goes out of scope
380  }
381  @endcode
382 
383  Obviously be careful not to create one of these and leave it lying around, or
384  your app will grind to a halt!
385 
386  MessageManagerLocks are re-entrant, so can be safely nested if the current thread
387  already has the lock.
388 
389  Another caveat is that using this in conjunction with other CriticalSections
390  can create lots of interesting ways of producing a deadlock! In particular, if
391  your message thread calls stopThread() for a thread that uses these locks,
392  you'll get an (occasional) deadlock..
393 
394  @see MessageManager, MessageManager::currentThreadHasLockedMessageManager
395 
396  @tags{Events}
397 */
399 {
400 public:
401  //==============================================================================
402  /** Tries to acquire a lock on the message manager.
403 
404  The constructor attempts to gain a lock on the message loop, and the lock will be
405  kept for the lifetime of this object.
406 
407  Optionally, you can pass a thread object here, and while waiting to obtain the lock,
408  this method will keep checking whether the thread has been given the
409  Thread::signalThreadShouldExit() signal. If this happens, then it will return
410  without gaining the lock. If you pass a thread, you must check whether the lock was
411  successful by calling lockWasGained(). If this is false, your thread is being told to
412  die, so you should take evasive action.
413 
414  If you pass nullptr for the thread object, it will wait indefinitely for the lock - be
415  careful when doing this, because it's very easy to deadlock if your message thread
416  attempts to call stopThread() on a thread just as that thread attempts to get the
417  message lock.
418 
419  If the calling thread already has the lock, nothing will be done, so it's safe and
420  quick to use these locks recursively.
421 
422  E.g.
423  @code
424  void run()
425  {
426  ...
427 
428  while (! threadShouldExit())
429  {
430  MessageManagerLock mml (Thread::getCurrentThread());
431 
432  if (! mml.lockWasGained())
433  return; // another thread is trying to kill us!
434 
435  ..do some locked stuff here..
436  }
437 
438  ..and now the MM is now unlocked..
439  }
440  @endcode
441 
442  */
443  MessageManagerLock (Thread* threadToCheckForExitSignal = nullptr);
444 
445  //==============================================================================
446  /** This has the same behaviour as the other constructor, but takes a ThreadPoolJob
447  instead of a thread.
448 
449  See the MessageManagerLock (Thread*) constructor for details on how this works.
450  */
451  MessageManagerLock (ThreadPoolJob* jobToCheckForExitSignal);
452 
453  //==============================================================================
454  /** Releases the current thread's lock on the message manager.
455 
456  Make sure this object is created and deleted by the same thread,
457  otherwise there are no guarantees what will happen!
458  */
459  ~MessageManagerLock() override;
460 
461  //==============================================================================
462  /** Returns true if the lock was successfully acquired.
463  (See the constructor that takes a Thread for more info).
464  */
465  bool lockWasGained() const noexcept { return locked; }
466 
467 private:
468  //==============================================================================
469  MessageManager::Lock mmLock;
470  bool locked;
471 
472  //==============================================================================
473  bool attemptLock (Thread*, ThreadPoolJob*);
474  void exitSignalSent() override;
475 
476  JUCE_DECLARE_NON_COPYABLE (MessageManagerLock)
477 };
478 
479 //==============================================================================
480 /** This macro is used to catch unsafe use of functions which expect to only be called
481  on the message thread, or when a MessageManagerLock is in place.
482  It will also fail if you try to use the function before the message manager has been
483  created, which could happen if you accidentally invoke it during a static constructor.
484 */
485 #define JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED \
486  jassert (juce::MessageManager::existsAndIsLockedByCurrentThread());
487 
488 /** This macro is used to catch unsafe use of functions which expect to only be called
489  on the message thread.
490  It will also fail if you try to use the function before the message manager has been
491  created, which could happen if you accidentally invoke it during a static constructor.
492 */
493 #define JUCE_ASSERT_MESSAGE_THREAD \
494  jassert (juce::MessageManager::existsAndIsCurrentThread());
495 
496 /** This macro is used to catch unsafe use of functions which expect to not be called
497  outside the lifetime of the MessageManager.
498 */
499 #define JUCE_ASSERT_MESSAGE_MANAGER_EXISTS \
500  jassert (juce::MessageManager::getInstanceWithoutCreating() != nullptr);
501 
502 
503 } // namespace juce
504 
505 /** @}*/
#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
static void callAsync(FunctionType functionToCall)
Asynchronously invokes a function or C++11 lambda on the message thread.
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.