Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

juce_linux_Messaging.cpp 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. The code included in this file is provided under the terms of the ISC license
  8. http://www.isc.org/downloads/software-support-policy/isc-license. Permission
  9. To use, copy, modify, and/or distribute this software for any purpose with or
  10. without fee is hereby granted provided that the above copyright notice and
  11. this permission notice appear in all copies.
  12. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  13. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  14. DISCLAIMED.
  15. ==============================================================================
  16. */
  17. namespace juce
  18. {
  19. //==============================================================================
  20. class InternalMessageQueue
  21. {
  22. public:
  23. InternalMessageQueue()
  24. {
  25. auto err = ::socketpair (AF_LOCAL, SOCK_STREAM, 0, msgpipe);
  26. jassert (err == 0);
  27. ignoreUnused (err);
  28. LinuxEventLoop::registerFdCallback (getReadHandle(),
  29. [this] (int fd)
  30. {
  31. while (auto msg = popNextMessage (fd))
  32. {
  33. JUCE_TRY
  34. {
  35. msg->messageCallback();
  36. }
  37. JUCE_CATCH_EXCEPTION
  38. }
  39. });
  40. }
  41. ~InternalMessageQueue()
  42. {
  43. LinuxEventLoop::unregisterFdCallback (getReadHandle());
  44. close (getReadHandle());
  45. close (getWriteHandle());
  46. clearSingletonInstance();
  47. }
  48. //==============================================================================
  49. void postMessage (MessageManager::MessageBase* const msg) noexcept
  50. {
  51. ScopedLock sl (lock);
  52. queue.add (msg);
  53. if (bytesInSocket < maxBytesInSocketQueue)
  54. {
  55. bytesInSocket++;
  56. ScopedUnlock ul (lock);
  57. unsigned char x = 0xff;
  58. auto numBytes = write (getWriteHandle(), &x, 1);
  59. ignoreUnused (numBytes);
  60. }
  61. }
  62. //==============================================================================
  63. JUCE_DECLARE_SINGLETON (InternalMessageQueue, false)
  64. private:
  65. CriticalSection lock;
  66. ReferenceCountedArray <MessageManager::MessageBase> queue;
  67. int msgpipe[2];
  68. int bytesInSocket = 0;
  69. static constexpr int maxBytesInSocketQueue = 128;
  70. int getWriteHandle() const noexcept { return msgpipe[0]; }
  71. int getReadHandle() const noexcept { return msgpipe[1]; }
  72. MessageManager::MessageBase::Ptr popNextMessage (int fd) noexcept
  73. {
  74. const ScopedLock sl (lock);
  75. if (bytesInSocket > 0)
  76. {
  77. --bytesInSocket;
  78. ScopedUnlock ul (lock);
  79. unsigned char x;
  80. auto numBytes = read (fd, &x, 1);
  81. ignoreUnused (numBytes);
  82. }
  83. return queue.removeAndReturn (0);
  84. }
  85. };
  86. JUCE_IMPLEMENT_SINGLETON (InternalMessageQueue)
  87. //==============================================================================
  88. struct InternalRunLoop
  89. {
  90. public:
  91. InternalRunLoop()
  92. {
  93. fdReadCallbacks.reserve (16);
  94. }
  95. void registerFdCallback (int fd, std::function<void (int)>&& cb, short eventMask)
  96. {
  97. const ScopedLock sl (lock);
  98. if (shouldDeferModifyingReadCallbacks)
  99. {
  100. deferredReadCallbackModifications.emplace_back ([this, fd, cb, eventMask]() mutable
  101. {
  102. registerFdCallback (fd, std::move (cb), eventMask);
  103. });
  104. return;
  105. }
  106. fdReadCallbacks.push_back ({ fd, std::move (cb) });
  107. pfds.push_back ({ fd, eventMask, 0 });
  108. }
  109. void unregisterFdCallback (int fd)
  110. {
  111. const ScopedLock sl (lock);
  112. if (shouldDeferModifyingReadCallbacks)
  113. {
  114. deferredReadCallbackModifications.emplace_back ([this, fd] { unregisterFdCallback (fd); });
  115. return;
  116. }
  117. {
  118. auto removePredicate = [=] (const std::pair<int, std::function<void (int)>>& cb) { return cb.first == fd; };
  119. fdReadCallbacks.erase (std::remove_if (std::begin (fdReadCallbacks), std::end (fdReadCallbacks), removePredicate),
  120. std::end (fdReadCallbacks));
  121. }
  122. {
  123. auto removePredicate = [=] (const pollfd& pfd) { return pfd.fd == fd; };
  124. pfds.erase (std::remove_if (std::begin (pfds), std::end (pfds), removePredicate),
  125. std::end (pfds));
  126. }
  127. }
  128. bool dispatchPendingEvents()
  129. {
  130. const ScopedLock sl (lock);
  131. if (poll (&pfds.front(), static_cast<nfds_t> (pfds.size()), 0) == 0)
  132. return false;
  133. bool eventWasSent = false;
  134. for (auto& pfd : pfds)
  135. {
  136. if (pfd.revents == 0)
  137. continue;
  138. pfd.revents = 0;
  139. auto fd = pfd.fd;
  140. for (auto& fdAndCallback : fdReadCallbacks)
  141. {
  142. if (fdAndCallback.first == fd)
  143. {
  144. {
  145. ScopedValueSetter<bool> insideFdReadCallback (shouldDeferModifyingReadCallbacks, true);
  146. fdAndCallback.second (fd);
  147. }
  148. if (! deferredReadCallbackModifications.empty())
  149. {
  150. for (auto& deferredRegisterEvent : deferredReadCallbackModifications)
  151. deferredRegisterEvent();
  152. deferredReadCallbackModifications.clear();
  153. // elements may have been removed from the fdReadCallbacks/pfds array so we really need
  154. // to call poll again
  155. return true;
  156. }
  157. eventWasSent = true;
  158. }
  159. }
  160. }
  161. return eventWasSent;
  162. }
  163. void sleepUntilNextEvent (int timeoutMs)
  164. {
  165. poll (&pfds.front(), static_cast<nfds_t> (pfds.size()), timeoutMs);
  166. }
  167. std::vector<std::pair<int, std::function<void (int)>>> getFdReadCallbacks()
  168. {
  169. const ScopedLock sl (lock);
  170. return fdReadCallbacks;
  171. }
  172. //==============================================================================
  173. JUCE_DECLARE_SINGLETON (InternalRunLoop, false)
  174. private:
  175. CriticalSection lock;
  176. std::vector<std::pair<int, std::function<void (int)>>> fdReadCallbacks;
  177. std::vector<pollfd> pfds;
  178. bool shouldDeferModifyingReadCallbacks = false;
  179. std::vector<std::function<void()>> deferredReadCallbackModifications;
  180. };
  181. JUCE_IMPLEMENT_SINGLETON (InternalRunLoop)
  182. //==============================================================================
  183. namespace LinuxErrorHandling
  184. {
  185. static bool keyboardBreakOccurred = false;
  186. void keyboardBreakSignalHandler (int sig)
  187. {
  188. if (sig == SIGINT)
  189. keyboardBreakOccurred = true;
  190. }
  191. void installKeyboardBreakHandler()
  192. {
  193. struct sigaction saction;
  194. sigset_t maskSet;
  195. sigemptyset (&maskSet);
  196. saction.sa_handler = keyboardBreakSignalHandler;
  197. saction.sa_mask = maskSet;
  198. saction.sa_flags = 0;
  199. sigaction (SIGINT, &saction, nullptr);
  200. }
  201. }
  202. //==============================================================================
  203. void MessageManager::doPlatformSpecificInitialisation()
  204. {
  205. if (JUCEApplicationBase::isStandaloneApp())
  206. LinuxErrorHandling::installKeyboardBreakHandler();
  207. InternalRunLoop::getInstance();
  208. InternalMessageQueue::getInstance();
  209. }
  210. void MessageManager::doPlatformSpecificShutdown()
  211. {
  212. InternalMessageQueue::deleteInstance();
  213. InternalRunLoop::deleteInstance();
  214. }
  215. bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message)
  216. {
  217. if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating())
  218. {
  219. queue->postMessage (message);
  220. return true;
  221. }
  222. return false;
  223. }
  224. void MessageManager::broadcastMessage (const String&)
  225. {
  226. // TODO
  227. }
  228. // this function expects that it will NEVER be called simultaneously for two concurrent threads
  229. bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)
  230. {
  231. for (;;)
  232. {
  233. if (LinuxErrorHandling::keyboardBreakOccurred)
  234. JUCEApplicationBase::quit();
  235. if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
  236. {
  237. if (runLoop->dispatchPendingEvents())
  238. break;
  239. if (returnIfNoPendingMessages)
  240. return false;
  241. runLoop->sleepUntilNextEvent (2000);
  242. }
  243. }
  244. return true;
  245. }
  246. //==============================================================================
  247. void LinuxEventLoop::registerFdCallback (int fd, std::function<void (int)> readCallback, short eventMask)
  248. {
  249. if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
  250. runLoop->registerFdCallback (fd, std::move (readCallback), eventMask);
  251. }
  252. void LinuxEventLoop::unregisterFdCallback (int fd)
  253. {
  254. if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
  255. runLoop->unregisterFdCallback (fd);
  256. }
  257. } // namespace juce
  258. JUCE_API std::vector<std::pair<int, std::function<void (int)>>> getFdReadCallbacks()
  259. {
  260. using namespace juce;
  261. if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
  262. return runLoop->getFdReadCallbacks();
  263. jassertfalse;
  264. return {};
  265. }