OpenShot Audio Library | OpenShotAudio  0.6.0
juce_MessageManager.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2022 - Raw Material Software Limited
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 {
29  JUCE_VERSION_ID
30 
32  Thread::setCurrentThreadName ("JUCE Message Thread");
33 }
34 
35 MessageManager::~MessageManager() noexcept
36 {
37  broadcaster.reset();
38 
39  doPlatformSpecificShutdown();
40 
41  jassert (instance == this);
42  instance = nullptr; // do this last in case this instance is still needed by doPlatformSpecificShutdown()
43 }
44 
45 MessageManager* MessageManager::instance = nullptr;
46 
48 {
49  if (instance == nullptr)
50  {
51  instance = new MessageManager();
52  doPlatformSpecificInitialisation();
53  }
54 
55  return instance;
56 }
57 
59 {
60  return instance;
61 }
62 
64 {
65  deleteAndZero (instance);
66 }
67 
68 //==============================================================================
69 bool MessageManager::MessageBase::post()
70 {
71  auto* mm = MessageManager::instance;
72 
73  if (mm == nullptr || mm->quitMessagePosted.get() != 0 || ! postMessageToSystemQueue (this))
74  {
75  Ptr deleter (this); // (this will delete messages that were just created with a 0 ref count)
76  return false;
77  }
78 
79  return true;
80 }
81 
82 //==============================================================================
83 #if ! (JUCE_MAC || JUCE_IOS || JUCE_ANDROID)
84 // implemented in platform-specific code (juce_Messaging_linux.cpp and juce_Messaging_windows.cpp)
85 namespace detail
86 {
87 bool dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages);
88 } // namespace detail
89 
90 class MessageManager::QuitMessage final : public MessageManager::MessageBase
91 {
92 public:
93  QuitMessage() {}
94 
95  void messageCallback() override
96  {
97  if (auto* mm = MessageManager::instance)
98  mm->quitMessageReceived = true;
99  }
100 
101  JUCE_DECLARE_NON_COPYABLE (QuitMessage)
102 };
103 
105 {
106  jassert (isThisTheMessageThread()); // must only be called by the message thread
107 
108  while (quitMessageReceived.get() == 0)
109  {
110  JUCE_TRY
111  {
112  if (! detail::dispatchNextMessageOnSystemQueue (false))
113  Thread::sleep (1);
114  }
115  JUCE_CATCH_EXCEPTION
116  }
117 }
118 
120 {
121  (new QuitMessage())->post();
122  quitMessagePosted = true;
123 }
124 
125 #if JUCE_MODAL_LOOPS_PERMITTED
126 bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor)
127 {
128  jassert (isThisTheMessageThread()); // must only be called by the message thread
129 
130  auto endTime = Time::currentTimeMillis() + millisecondsToRunFor;
131 
132  while (quitMessageReceived.get() == 0)
133  {
134  JUCE_TRY
135  {
136  if (! detail::dispatchNextMessageOnSystemQueue (millisecondsToRunFor >= 0))
137  Thread::sleep (1);
138  }
139  JUCE_CATCH_EXCEPTION
140 
141  if (millisecondsToRunFor >= 0 && Time::currentTimeMillis() >= endTime)
142  break;
143  }
144 
145  return quitMessageReceived.get() == 0;
146 }
147 #endif
148 
149 #endif
150 
151 //==============================================================================
152 class AsyncFunctionCallback final : public MessageManager::MessageBase
153 {
154 public:
155  AsyncFunctionCallback (MessageCallbackFunction* const f, void* const param)
156  : func (f), parameter (param)
157  {}
158 
159  void messageCallback() override
160  {
161  result = (*func) (parameter);
162  finished.signal();
163  }
164 
165  WaitableEvent finished;
166  std::atomic<void*> result { nullptr };
167 
168 private:
169  MessageCallbackFunction* const func;
170  void* const parameter;
171 
172  JUCE_DECLARE_NON_COPYABLE (AsyncFunctionCallback)
173 };
174 
175 void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* func, void* parameter)
176 {
178  return func (parameter);
179 
180  // If this thread has the message manager locked, then this will deadlock!
182 
183  const ReferenceCountedObjectPtr<AsyncFunctionCallback> message (new AsyncFunctionCallback (func, parameter));
184 
185  if (message->post())
186  {
187  message->finished.wait();
188  return message->result.load();
189  }
190 
191  jassertfalse; // the OS message queue failed to send the message!
192  return nullptr;
193 }
194 
195 bool MessageManager::callAsync (std::function<void()> fn)
196 {
197  struct AsyncCallInvoker final : public MessageBase
198  {
199  AsyncCallInvoker (std::function<void()> f) : callback (std::move (f)) {}
200  void messageCallback() override { callback(); }
201  std::function<void()> callback;
202  };
203 
204  return (new AsyncCallInvoker (std::move (fn)))->post();
205 }
206 
207 //==============================================================================
208 void MessageManager::deliverBroadcastMessage (const String& value)
209 {
210  if (broadcaster != nullptr)
211  broadcaster->sendActionMessage (value);
212 }
213 
215 {
216  if (broadcaster == nullptr)
217  broadcaster.reset (new ActionBroadcaster());
218 
219  broadcaster->addActionListener (listener);
220 }
221 
223 {
224  if (broadcaster != nullptr)
225  broadcaster->removeActionListener (listener);
226 }
227 
228 //==============================================================================
230 {
231  const std::lock_guard<std::mutex> lock { messageThreadIdMutex };
232 
233  return Thread::getCurrentThreadId() == messageThreadId;
234 }
235 
237 {
238  auto thisThread = Thread::getCurrentThreadId();
239 
240  const std::lock_guard<std::mutex> lock { messageThreadIdMutex };
241 
242  if (std::exchange (messageThreadId, thisThread) != thisThread)
243  {
244  #if JUCE_WINDOWS
245  // This is needed on windows to make sure the message window is created by this thread
246  doPlatformSpecificShutdown();
247  doPlatformSpecificInitialisation();
248  #endif
249  }
250 }
251 
253 {
254  auto thisThread = Thread::getCurrentThreadId();
255  return thisThread == messageThreadId || thisThread == threadWithLock.get();
256 }
257 
259 {
260  if (auto i = getInstanceWithoutCreating())
261  return i->currentThreadHasLockedMessageManager();
262 
263  return false;
264 }
265 
267 {
268  if (auto i = getInstanceWithoutCreating())
269  return i->isThisTheMessageThread();
270 
271  return false;
272 }
273 
274 //==============================================================================
275 //==============================================================================
276 /* The only safe way to lock the message thread while another thread does
277  some work is by posting a special message, whose purpose is to tie up the event
278  loop until the other thread has finished its business.
279 
280  Any other approach can get horribly deadlocked if the OS uses its own hidden locks which
281  get locked before making an event callback, because if the same OS lock gets indirectly
282  accessed from another thread inside a MM lock, you're screwed. (this is exactly what happens
283  in Cocoa).
284 */
285 struct MessageManager::Lock::BlockingMessage final : public MessageManager::MessageBase
286 {
287  explicit BlockingMessage (const MessageManager::Lock* parent) noexcept
288  : owner (parent) {}
289 
290  void messageCallback() override
291  {
292  std::unique_lock lock { mutex };
293 
294  if (owner != nullptr)
295  owner->setAcquired (true);
296 
297  condvar.wait (lock, [&] { return owner == nullptr; });
298  }
299 
300  void stopWaiting()
301  {
302  const ScopeGuard scope { [&] { condvar.notify_one(); } };
303  const std::scoped_lock lock { mutex };
304  owner = nullptr;
305  }
306 
307 private:
308  std::mutex mutex;
309  std::condition_variable condvar;
310 
311  const MessageManager::Lock* owner = nullptr;
312 
313  JUCE_DECLARE_NON_COPYABLE (BlockingMessage)
314 };
315 
316 //==============================================================================
319 void MessageManager::Lock::enter() const noexcept { exclusiveTryAcquire (true); }
320 bool MessageManager::Lock::tryEnter() const noexcept { return exclusiveTryAcquire (false); }
321 
322 bool MessageManager::Lock::exclusiveTryAcquire (bool lockIsMandatory) const noexcept
323 {
324  if (lockIsMandatory)
325  entryMutex.enter();
326  else if (! entryMutex.tryEnter())
327  return false;
328 
329  const auto result = tryAcquire (lockIsMandatory);
330 
331  if (! result)
332  entryMutex.exit();
333 
334  return result;
335 }
336 
337 bool MessageManager::Lock::tryAcquire (bool lockIsMandatory) const noexcept
338 {
339  auto* mm = MessageManager::instance;
340 
341  if (mm == nullptr)
342  {
343  jassertfalse;
344  return false;
345  }
346 
347  if (! lockIsMandatory && [&]
348  {
349  const std::scoped_lock lock { mutex };
350  return std::exchange (abortWait, false);
351  }())
352  {
353  return false;
354  }
355 
356  if (mm->currentThreadHasLockedMessageManager())
357  return true;
358 
359  try
360  {
361  blockingMessage = *new BlockingMessage (this);
362  }
363  catch (...)
364  {
365  jassert (! lockIsMandatory);
366  return false;
367  }
368 
369  if (! blockingMessage->post())
370  {
371  // post of message failed while trying to get the lock
372  jassert (! lockIsMandatory);
373  blockingMessage = nullptr;
374  return false;
375  }
376 
377  for (;;)
378  {
379  {
380  std::unique_lock lock { mutex };
381  condvar.wait (lock, [&] { return std::exchange (abortWait, false); });
382  }
383 
384  if (acquired)
385  {
386  mm->threadWithLock = Thread::getCurrentThreadId();
387  return true;
388  }
389 
390  if (! lockIsMandatory)
391  break;
392  }
393 
394  // we didn't get the lock
395 
396  blockingMessage->stopWaiting();
397  blockingMessage = nullptr;
398  return false;
399 }
400 
401 void MessageManager::Lock::exit() const noexcept
402 {
403  const auto wasAcquired = [&]
404  {
405  const std::scoped_lock lock { mutex };
406  return acquired;
407  }();
408 
409  if (! wasAcquired)
410  return;
411 
412  const ScopeGuard unlocker { [&] { entryMutex.exit(); } };
413 
414  if (blockingMessage == nullptr)
415  return;
416 
417  if (auto* mm = MessageManager::instance)
418  {
419  jassert (mm->currentThreadHasLockedMessageManager());
420  mm->threadWithLock = {};
421  }
422 
423  blockingMessage->stopWaiting();
424  blockingMessage = nullptr;
425  acquired = false;
426 }
427 
428 void MessageManager::Lock::abort() const noexcept
429 {
430  setAcquired (false);
431 }
432 
433 void MessageManager::Lock::setAcquired (bool x) const noexcept
434 {
435  const ScopeGuard scope { [&] { condvar.notify_one(); } };
436  const std::scoped_lock lock { mutex };
437  abortWait = true;
438  acquired = x;
439 }
440 
441 //==============================================================================
443  : locked (attemptLock (threadToCheck, nullptr))
444 {}
445 
447  : locked (attemptLock (nullptr, jobToCheck))
448 {}
449 
450 bool MessageManagerLock::attemptLock (Thread* threadToCheck, ThreadPoolJob* jobToCheck)
451 {
452  jassert (threadToCheck == nullptr || jobToCheck == nullptr);
453 
454  if (threadToCheck != nullptr)
455  threadToCheck->addListener (this);
456 
457  if (jobToCheck != nullptr)
458  jobToCheck->addListener (this);
459 
460  // tryEnter may have a spurious abort (return false) so keep checking the condition
461  while ((threadToCheck == nullptr || ! threadToCheck->threadShouldExit())
462  && (jobToCheck == nullptr || ! jobToCheck->shouldExit()))
463  {
464  if (mmLock.tryEnter())
465  break;
466  }
467 
468  if (threadToCheck != nullptr)
469  {
470  threadToCheck->removeListener (this);
471 
472  if (threadToCheck->threadShouldExit())
473  return false;
474  }
475 
476  if (jobToCheck != nullptr)
477  {
478  jobToCheck->removeListener (this);
479 
480  if (jobToCheck->shouldExit())
481  return false;
482  }
483 
484  return true;
485 }
486 
488 
489 void MessageManagerLock::exitSignalSent()
490 {
491  mmLock.abort();
492 }
493 
494 //==============================================================================
495 JUCE_API void JUCE_CALLTYPE initialiseJuce_GUI()
496 {
497  JUCE_AUTORELEASEPOOL
498  {
500  }
501 }
502 
503 JUCE_API void JUCE_CALLTYPE shutdownJuce_GUI()
504 {
505  JUCE_AUTORELEASEPOOL
506  {
509  }
510 }
511 
512 static int numScopedInitInstances = 0;
513 
514 ScopedJuceInitialiser_GUI::ScopedJuceInitialiser_GUI() { if (numScopedInitInstances++ == 0) initialiseJuce_GUI(); }
515 ScopedJuceInitialiser_GUI::~ScopedJuceInitialiser_GUI() { if (--numScopedInitInstances == 0) shutdownJuce_GUI(); }
516 
517 } // namespace juce
static bool isStandaloneApp() noexcept
MessageManagerLock(Thread *threadToCheckForExitSignal=nullptr)
bool tryEnter() const noexcept
static bool callAsync(std::function< void()> functionToCall)
bool isThisTheMessageThread() const noexcept
static bool existsAndIsCurrentThread() noexcept
bool currentThreadHasLockedMessageManager() const noexcept
void * callFunctionOnMessageThread(MessageCallbackFunction *callback, void *userData)
void deregisterBroadcastListener(ActionListener *listener)
static bool existsAndIsLockedByCurrentThread() noexcept
void registerBroadcastListener(ActionListener *listener)
static MessageManager * getInstanceWithoutCreating() noexcept
static MessageManager * getInstance()
void addListener(Thread::Listener *)
bool shouldExit() const noexcept
void removeListener(Thread::Listener *)
static void JUCE_CALLTYPE sleep(int milliseconds)
static void JUCE_CALLTYPE setCurrentThreadName(const String &newThreadName)
bool threadShouldExit() const
static ThreadID JUCE_CALLTYPE getCurrentThreadId()
void addListener(Listener *)
void removeListener(Listener *)
static int64 currentTimeMillis() noexcept
Definition: juce_Time.cpp:220
Type get() const noexcept
Definition: juce_Atomic.h:64