OpenShot Audio Library | OpenShotAudio  0.3.1
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 //==============================================================================
144 class AsyncFunctionCallback : public MessageManager::MessageBase
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* func, void* 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 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 //==============================================================================
200 void MessageManager::deliverBroadcastMessage (const String& value)
201 {
202  if (broadcaster != nullptr)
203  broadcaster->sendActionMessage (value);
204 }
205 
207 {
208  if (broadcaster == nullptr)
209  broadcaster.reset (new ActionBroadcaster());
210 
211  broadcaster->addActionListener (listener);
212 }
213 
215 {
216  if (broadcaster != nullptr)
217  broadcaster->removeActionListener (listener);
218 }
219 
220 //==============================================================================
222 {
223  return Thread::getCurrentThreadId() == messageThreadId;
224 }
225 
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 
241 {
242  auto thisThread = Thread::getCurrentThreadId();
243  return thisThread == messageThreadId || thisThread == threadWithLock.get();
244 }
245 
247 {
248  if (auto i = getInstanceWithoutCreating())
249  return i->currentThreadHasLockedMessageManager();
250 
251  return false;
252 }
253 
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 {
275  BlockingMessage (const MessageManager::Lock* parent) noexcept
276  : owner (parent)
277  {}
278 
279  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;
293  WaitableEvent releaseEvent;
294 
295  JUCE_DECLARE_NON_COPYABLE (BlockingMessage)
296 };
297 
298 //==============================================================================
301 void MessageManager::Lock::enter() const noexcept { tryAcquire (true); }
302 bool MessageManager::Lock::tryEnter() const noexcept { return tryAcquire (false); }
303 
304 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 
370 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 
390 void MessageManager::Lock::messageCallback() const
391 {
392  lockGained.set (1);
393  abort();
394 }
395 
396 void MessageManager::Lock::abort() const noexcept
397 {
398  abortWait.set (1);
399  lockedEvent.signal();
400 }
401 
402 //==============================================================================
404  : locked (attemptLock (threadToCheck, nullptr))
405 {}
406 
408  : locked (attemptLock (nullptr, jobToCheck))
409 {}
410 
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 
449 
450 void MessageManagerLock::exitSignalSent()
451 {
452  mmLock.abort();
453 }
454 
455 //==============================================================================
456 JUCE_API void JUCE_CALLTYPE initialiseJuce_GUI();
457 JUCE_API void JUCE_CALLTYPE initialiseJuce_GUI()
458 {
459  JUCE_AUTORELEASEPOOL
460  {
462  }
463 }
464 
465 JUCE_API void JUCE_CALLTYPE shutdownJuce_GUI();
466 JUCE_API void JUCE_CALLTYPE shutdownJuce_GUI()
467 {
468  JUCE_AUTORELEASEPOOL
469  {
472  }
473 }
474 
475 static int numScopedInitInstances = 0;
476 
477 ScopedJuceInitialiser_GUI::ScopedJuceInitialiser_GUI() { if (numScopedInitInstances++ == 0) initialiseJuce_GUI(); }
478 ScopedJuceInitialiser_GUI::~ScopedJuceInitialiser_GUI() { if (--numScopedInitInstances == 0) shutdownJuce_GUI(); }
479 
480 } // namespace juce
void * callFunctionOnMessageThread(MessageCallbackFunction *callback, void *userData)
bool currentThreadHasLockedMessageManager() const noexcept
static bool existsAndIsCurrentThread() noexcept
void addListener(Listener *)
void removeListener(Thread::Listener *)
static MessageManager * getInstance()
static int64 currentTimeMillis() noexcept
Definition: juce_Time.cpp:205
static ThreadID JUCE_CALLTYPE getCurrentThreadId()
bool isThisTheMessageThread() const noexcept
bool threadShouldExit() const
MessageManagerLock(Thread *threadToCheckForExitSignal=nullptr)
void addListener(Thread::Listener *)
void registerBroadcastListener(ActionListener *listener)
Type get() const noexcept
Definition: juce_Atomic.h:64
static bool existsAndIsLockedByCurrentThread() noexcept
bool tryEnter() const noexcept
static void JUCE_CALLTYPE sleep(int milliseconds)
static bool callAsync(std::function< void()> functionToCall)
static MessageManager * getInstanceWithoutCreating() noexcept
void deregisterBroadcastListener(ActionListener *listener)
void removeListener(Listener *)
static bool isStandaloneApp() noexcept
static void JUCE_CALLTYPE setCurrentThreadName(const String &newThreadName)
bool shouldExit() const noexcept