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 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - 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. jassertquiet (err == 0);
  27. LinuxEventLoop::registerFdCallback (getReadHandle(),
  28. [this] (int fd)
  29. {
  30. while (auto msg = popNextMessage (fd))
  31. {
  32. JUCE_TRY
  33. {
  34. msg->messageCallback();
  35. }
  36. JUCE_CATCH_EXCEPTION
  37. }
  38. });
  39. }
  40. ~InternalMessageQueue()
  41. {
  42. LinuxEventLoop::unregisterFdCallback (getReadHandle());
  43. close (getReadHandle());
  44. close (getWriteHandle());
  45. clearSingletonInstance();
  46. }
  47. //==============================================================================
  48. void postMessage (MessageManager::MessageBase* const msg) noexcept
  49. {
  50. ScopedLock sl (lock);
  51. queue.add (msg);
  52. if (bytesInSocket < maxBytesInSocketQueue)
  53. {
  54. bytesInSocket++;
  55. ScopedUnlock ul (lock);
  56. unsigned char x = 0xff;
  57. auto numBytes = write (getWriteHandle(), &x, 1);
  58. ignoreUnused (numBytes);
  59. }
  60. }
  61. //==============================================================================
  62. JUCE_DECLARE_SINGLETON (InternalMessageQueue, false)
  63. private:
  64. CriticalSection lock;
  65. ReferenceCountedArray <MessageManager::MessageBase> queue;
  66. int msgpipe[2];
  67. int bytesInSocket = 0;
  68. static constexpr int maxBytesInSocketQueue = 128;
  69. int getWriteHandle() const noexcept { return msgpipe[0]; }
  70. int getReadHandle() const noexcept { return msgpipe[1]; }
  71. MessageManager::MessageBase::Ptr popNextMessage (int fd) noexcept
  72. {
  73. const ScopedLock sl (lock);
  74. if (bytesInSocket > 0)
  75. {
  76. --bytesInSocket;
  77. ScopedUnlock ul (lock);
  78. unsigned char x;
  79. auto numBytes = read (fd, &x, 1);
  80. ignoreUnused (numBytes);
  81. }
  82. return queue.removeAndReturn (0);
  83. }
  84. };
  85. JUCE_IMPLEMENT_SINGLETON (InternalMessageQueue)
  86. //==============================================================================
  87. /*
  88. Stores callbacks associated with file descriptors (FD).
  89. The callback for a particular FD should be called whenever that file has data to read.
  90. For standalone apps, the main thread will call poll to wait for new data on any FD, and then
  91. call the associated callbacks for any FDs that changed.
  92. For plugins, the host (generally) provides some kind of run loop mechanism instead.
  93. - In VST2 plugins, the host should call effEditIdle at regular intervals, and plugins can
  94. dispatch all pending events inside this callback. The host doesn't know about any of the
  95. plugin's FDs, so it's possible there will be a bit of latency between an FD becoming ready,
  96. and its associated callback being called.
  97. - In VST3 plugins, it's possible to register each FD individually with the host. In this case,
  98. the facilities in LinuxEventLoopInternal can be used to observe added/removed FD callbacks,
  99. and the host can be notified whenever the set of FDs changes. The host will call onFDIsSet
  100. whenever a particular FD has data ready. This call should be forwarded through to
  101. InternalRunLoop::dispatchEvent.
  102. */
  103. struct InternalRunLoop
  104. {
  105. public:
  106. InternalRunLoop() = default;
  107. void registerFdCallback (int fd, std::function<void()>&& cb, short eventMask)
  108. {
  109. {
  110. const ScopedLock sl (lock);
  111. callbacks.emplace (fd, std::make_shared<std::function<void()>> (std::move (cb)));
  112. const auto iter = getPollfd (fd);
  113. if (iter == pfds.end() || iter->fd != fd)
  114. pfds.insert (iter, { fd, eventMask, 0 });
  115. else
  116. jassertfalse;
  117. jassert (pfdsAreSorted());
  118. }
  119. listeners.call ([] (auto& l) { l.fdCallbacksChanged(); });
  120. }
  121. void unregisterFdCallback (int fd)
  122. {
  123. {
  124. const ScopedLock sl (lock);
  125. callbacks.erase (fd);
  126. const auto iter = getPollfd (fd);
  127. if (iter != pfds.end() && iter->fd == fd)
  128. pfds.erase (iter);
  129. else
  130. jassertfalse;
  131. jassert (pfdsAreSorted());
  132. }
  133. listeners.call ([] (auto& l) { l.fdCallbacksChanged(); });
  134. }
  135. bool dispatchPendingEvents()
  136. {
  137. callbackStorage.clear();
  138. getFunctionsToCallThisTime (callbackStorage);
  139. // CriticalSection should be available during the callback
  140. for (auto& fn : callbackStorage)
  141. (*fn)();
  142. return ! callbackStorage.empty();
  143. }
  144. void dispatchEvent (int fd) const
  145. {
  146. const auto fn = [&]
  147. {
  148. const ScopedLock sl (lock);
  149. const auto iter = callbacks.find (fd);
  150. return iter != callbacks.end() ? iter->second : nullptr;
  151. }();
  152. // CriticalSection should be available during the callback
  153. if (auto* callback = fn.get())
  154. (*callback)();
  155. }
  156. bool sleepUntilNextEvent (int timeoutMs)
  157. {
  158. const ScopedLock sl (lock);
  159. return poll (pfds.data(), static_cast<nfds_t> (pfds.size()), timeoutMs) != 0;
  160. }
  161. std::vector<int> getRegisteredFds()
  162. {
  163. const ScopedLock sl (lock);
  164. std::vector<int> result;
  165. result.reserve (callbacks.size());
  166. std::transform (callbacks.begin(),
  167. callbacks.end(),
  168. std::back_inserter (result),
  169. [] (const auto& pair) { return pair.first; });
  170. return result;
  171. }
  172. void addListener (LinuxEventLoopInternal::Listener& listener) { listeners.add (&listener); }
  173. void removeListener (LinuxEventLoopInternal::Listener& listener) { listeners.remove (&listener); }
  174. //==============================================================================
  175. JUCE_DECLARE_SINGLETON (InternalRunLoop, false)
  176. private:
  177. using SharedCallback = std::shared_ptr<std::function<void()>>;
  178. /* Appends any functions that need to be called to the passed-in vector.
  179. We take a copy of each shared function so that the functions can be called without
  180. locking or racing in the event that the function attempts to register/deregister a
  181. new FD callback.
  182. */
  183. void getFunctionsToCallThisTime (std::vector<SharedCallback>& functions)
  184. {
  185. const ScopedLock sl (lock);
  186. if (! sleepUntilNextEvent (0))
  187. return;
  188. for (auto& pfd : pfds)
  189. {
  190. if (std::exchange (pfd.revents, 0) != 0)
  191. {
  192. const auto iter = callbacks.find (pfd.fd);
  193. if (iter != callbacks.end())
  194. functions.emplace_back (iter->second);
  195. }
  196. }
  197. }
  198. std::vector<pollfd>::iterator getPollfd (int fd)
  199. {
  200. return std::lower_bound (pfds.begin(), pfds.end(), fd, [] (auto descriptor, auto toFind)
  201. {
  202. return descriptor.fd < toFind;
  203. });
  204. }
  205. bool pfdsAreSorted() const
  206. {
  207. return std::is_sorted (pfds.begin(), pfds.end(), [] (auto a, auto b) { return a.fd < b.fd; });
  208. }
  209. CriticalSection lock;
  210. std::map<int, SharedCallback> callbacks;
  211. std::vector<SharedCallback> callbackStorage;
  212. std::vector<pollfd> pfds;
  213. ListenerList<LinuxEventLoopInternal::Listener> listeners;
  214. };
  215. JUCE_IMPLEMENT_SINGLETON (InternalRunLoop)
  216. //==============================================================================
  217. namespace LinuxErrorHandling
  218. {
  219. static bool keyboardBreakOccurred = false;
  220. static void keyboardBreakSignalHandler (int sig)
  221. {
  222. if (sig == SIGINT)
  223. keyboardBreakOccurred = true;
  224. }
  225. static void installKeyboardBreakHandler()
  226. {
  227. struct sigaction saction;
  228. sigset_t maskSet;
  229. sigemptyset (&maskSet);
  230. saction.sa_handler = keyboardBreakSignalHandler;
  231. saction.sa_mask = maskSet;
  232. saction.sa_flags = 0;
  233. sigaction (SIGINT, &saction, nullptr);
  234. }
  235. }
  236. //==============================================================================
  237. void MessageManager::doPlatformSpecificInitialisation()
  238. {
  239. if (JUCEApplicationBase::isStandaloneApp())
  240. LinuxErrorHandling::installKeyboardBreakHandler();
  241. InternalRunLoop::getInstance();
  242. InternalMessageQueue::getInstance();
  243. }
  244. void MessageManager::doPlatformSpecificShutdown()
  245. {
  246. InternalMessageQueue::deleteInstance();
  247. InternalRunLoop::deleteInstance();
  248. }
  249. bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message)
  250. {
  251. if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating())
  252. {
  253. queue->postMessage (message);
  254. return true;
  255. }
  256. return false;
  257. }
  258. void MessageManager::broadcastMessage (const String&)
  259. {
  260. // TODO
  261. }
  262. // this function expects that it will NEVER be called simultaneously for two concurrent threads
  263. bool dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)
  264. {
  265. for (;;)
  266. {
  267. if (LinuxErrorHandling::keyboardBreakOccurred)
  268. JUCEApplicationBase::quit();
  269. if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
  270. {
  271. if (runLoop->dispatchPendingEvents())
  272. break;
  273. if (returnIfNoPendingMessages)
  274. return false;
  275. runLoop->sleepUntilNextEvent (2000);
  276. }
  277. }
  278. return true;
  279. }
  280. //==============================================================================
  281. void LinuxEventLoop::registerFdCallback (int fd, std::function<void (int)> readCallback, short eventMask)
  282. {
  283. if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
  284. runLoop->registerFdCallback (fd, [cb = std::move (readCallback), fd] { cb (fd); }, eventMask);
  285. }
  286. void LinuxEventLoop::unregisterFdCallback (int fd)
  287. {
  288. if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
  289. runLoop->unregisterFdCallback (fd);
  290. }
  291. //==============================================================================
  292. void LinuxEventLoopInternal::registerLinuxEventLoopListener (LinuxEventLoopInternal::Listener& listener)
  293. {
  294. if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
  295. runLoop->addListener (listener);
  296. }
  297. void LinuxEventLoopInternal::deregisterLinuxEventLoopListener (LinuxEventLoopInternal::Listener& listener)
  298. {
  299. if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
  300. runLoop->removeListener (listener);
  301. }
  302. void LinuxEventLoopInternal::invokeEventLoopCallbackForFd (int fd)
  303. {
  304. if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
  305. runLoop->dispatchEvent (fd);
  306. }
  307. std::vector<int> LinuxEventLoopInternal::getRegisteredFds()
  308. {
  309. if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
  310. return runLoop->getRegisteredFds();
  311. return {};
  312. }
  313. } // namespace juce