VST3: fetch midi mappings all at once, use it for note/sound-off
[carla.git] / source / modules / juce_events / native / juce_linux_Messaging.cpp
blobdcf583346693e5cbea53e21bdadbf0fb87b230f1
1 /*
2 ==============================================================================
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
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.
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.
20 ==============================================================================
23 namespace juce
26 //==============================================================================
27 class InternalMessageQueue
29 public:
30 InternalMessageQueue()
32 auto err = ::socketpair (AF_LOCAL, SOCK_STREAM, 0, msgpipe);
33 jassertquiet (err == 0);
35 LinuxEventLoop::registerFdCallback (getReadHandle(),
36 [this] (int fd)
38 while (auto msg = popNextMessage (fd))
40 JUCE_TRY
42 msg->messageCallback();
44 JUCE_CATCH_EXCEPTION
46 });
49 ~InternalMessageQueue()
51 LinuxEventLoop::unregisterFdCallback (getReadHandle());
53 close (getReadHandle());
54 close (getWriteHandle());
56 clearSingletonInstance();
59 //==============================================================================
60 void postMessage (MessageManager::MessageBase* const msg) noexcept
62 ScopedLock sl (lock);
63 queue.add (msg);
65 if (bytesInSocket < maxBytesInSocketQueue)
67 bytesInSocket++;
69 ScopedUnlock ul (lock);
70 unsigned char x = 0xff;
71 auto numBytes = write (getWriteHandle(), &x, 1);
72 ignoreUnused (numBytes);
76 //==============================================================================
77 JUCE_DECLARE_SINGLETON (InternalMessageQueue, false)
79 private:
80 CriticalSection lock;
81 ReferenceCountedArray <MessageManager::MessageBase> queue;
83 int msgpipe[2];
84 int bytesInSocket = 0;
85 static constexpr int maxBytesInSocketQueue = 128;
87 int getWriteHandle() const noexcept { return msgpipe[0]; }
88 int getReadHandle() const noexcept { return msgpipe[1]; }
90 MessageManager::MessageBase::Ptr popNextMessage (int fd) noexcept
92 const ScopedLock sl (lock);
94 if (bytesInSocket > 0)
96 --bytesInSocket;
98 ScopedUnlock ul (lock);
99 unsigned char x;
100 auto numBytes = read (fd, &x, 1);
101 ignoreUnused (numBytes);
104 return queue.removeAndReturn (0);
108 JUCE_IMPLEMENT_SINGLETON (InternalMessageQueue)
110 //==============================================================================
112 Stores callbacks associated with file descriptors (FD).
114 The callback for a particular FD should be called whenever that file has data to read.
116 For standalone apps, the main thread will call poll to wait for new data on any FD, and then
117 call the associated callbacks for any FDs that changed.
119 For plugins, the host (generally) provides some kind of run loop mechanism instead.
120 - In VST2 plugins, the host should call effEditIdle at regular intervals, and plugins can
121 dispatch all pending events inside this callback. The host doesn't know about any of the
122 plugin's FDs, so it's possible there will be a bit of latency between an FD becoming ready,
123 and its associated callback being called.
124 - In VST3 plugins, it's possible to register each FD individually with the host. In this case,
125 the facilities in LinuxEventLoopInternal can be used to observe added/removed FD callbacks,
126 and the host can be notified whenever the set of FDs changes. The host will call onFDIsSet
127 whenever a particular FD has data ready. This call should be forwarded through to
128 InternalRunLoop::dispatchEvent.
130 struct InternalRunLoop
132 public:
133 InternalRunLoop() = default;
135 void registerFdCallback (int fd, std::function<void()>&& cb, short eventMask)
138 const ScopedLock sl (lock);
140 callbacks.emplace (fd, std::make_shared<std::function<void()>> (std::move (cb)));
142 const auto iter = getPollfd (fd);
144 if (iter == pfds.end() || iter->fd != fd)
145 pfds.insert (iter, { fd, eventMask, 0 });
146 else
147 jassertfalse;
149 jassert (pfdsAreSorted());
152 listeners.call ([] (auto& l) { l.fdCallbacksChanged(); });
155 void unregisterFdCallback (int fd)
158 const ScopedLock sl (lock);
160 callbacks.erase (fd);
162 const auto iter = getPollfd (fd);
164 if (iter != pfds.end() && iter->fd == fd)
165 pfds.erase (iter);
166 else
167 jassertfalse;
169 jassert (pfdsAreSorted());
172 listeners.call ([] (auto& l) { l.fdCallbacksChanged(); });
175 bool dispatchPendingEvents()
177 callbackStorage.clear();
178 getFunctionsToCallThisTime (callbackStorage);
180 // CriticalSection should be available during the callback
181 for (auto& fn : callbackStorage)
182 (*fn)();
184 return ! callbackStorage.empty();
187 void dispatchEvent (int fd) const
189 const auto fn = [&]
191 const ScopedLock sl (lock);
192 const auto iter = callbacks.find (fd);
193 return iter != callbacks.end() ? iter->second : nullptr;
194 }();
196 // CriticalSection should be available during the callback
197 if (auto* callback = fn.get())
198 (*callback)();
201 bool sleepUntilNextEvent (int timeoutMs)
203 const ScopedLock sl (lock);
204 return poll (pfds.data(), static_cast<nfds_t> (pfds.size()), timeoutMs) != 0;
207 std::vector<int> getRegisteredFds()
209 const ScopedLock sl (lock);
210 std::vector<int> result;
211 result.reserve (callbacks.size());
212 std::transform (callbacks.begin(),
213 callbacks.end(),
214 std::back_inserter (result),
215 [] (const auto& pair) { return pair.first; });
216 return result;
219 void addListener (LinuxEventLoopInternal::Listener& listener) { listeners.add (&listener); }
220 void removeListener (LinuxEventLoopInternal::Listener& listener) { listeners.remove (&listener); }
222 //==============================================================================
223 JUCE_DECLARE_SINGLETON (InternalRunLoop, false)
225 private:
226 using SharedCallback = std::shared_ptr<std::function<void()>>;
228 /* Appends any functions that need to be called to the passed-in vector.
230 We take a copy of each shared function so that the functions can be called without
231 locking or racing in the event that the function attempts to register/deregister a
232 new FD callback.
234 void getFunctionsToCallThisTime (std::vector<SharedCallback>& functions)
236 const ScopedLock sl (lock);
238 if (! sleepUntilNextEvent (0))
239 return;
241 for (auto& pfd : pfds)
243 if (std::exchange (pfd.revents, 0) != 0)
245 const auto iter = callbacks.find (pfd.fd);
247 if (iter != callbacks.end())
248 functions.emplace_back (iter->second);
253 std::vector<pollfd>::iterator getPollfd (int fd)
255 return std::lower_bound (pfds.begin(), pfds.end(), fd, [] (auto descriptor, auto toFind)
257 return descriptor.fd < toFind;
261 bool pfdsAreSorted() const
263 return std::is_sorted (pfds.begin(), pfds.end(), [] (auto a, auto b) { return a.fd < b.fd; });
266 CriticalSection lock;
268 std::map<int, SharedCallback> callbacks;
269 std::vector<SharedCallback> callbackStorage;
270 std::vector<pollfd> pfds;
272 ListenerList<LinuxEventLoopInternal::Listener> listeners;
275 JUCE_IMPLEMENT_SINGLETON (InternalRunLoop)
277 //==============================================================================
278 namespace LinuxErrorHandling
280 static bool keyboardBreakOccurred = false;
282 static void keyboardBreakSignalHandler (int sig)
284 if (sig == SIGINT)
285 keyboardBreakOccurred = true;
288 static void installKeyboardBreakHandler()
290 struct sigaction saction;
291 sigset_t maskSet;
292 sigemptyset (&maskSet);
293 saction.sa_handler = keyboardBreakSignalHandler;
294 saction.sa_mask = maskSet;
295 saction.sa_flags = 0;
296 sigaction (SIGINT, &saction, nullptr);
300 //==============================================================================
301 void MessageManager::doPlatformSpecificInitialisation()
303 if (JUCEApplicationBase::isStandaloneApp())
304 LinuxErrorHandling::installKeyboardBreakHandler();
306 InternalRunLoop::getInstance();
307 InternalMessageQueue::getInstance();
310 void MessageManager::doPlatformSpecificShutdown()
312 InternalMessageQueue::deleteInstance();
313 InternalRunLoop::deleteInstance();
316 bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message)
318 if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating())
320 queue->postMessage (message);
321 return true;
324 return false;
327 void MessageManager::broadcastMessage (const String&)
329 // TODO
332 // this function expects that it will NEVER be called simultaneously for two concurrent threads
333 bool dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)
335 for (;;)
337 if (LinuxErrorHandling::keyboardBreakOccurred)
338 JUCEApplicationBase::quit();
340 if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
342 if (runLoop->dispatchPendingEvents())
343 break;
345 if (returnIfNoPendingMessages)
346 return false;
348 runLoop->sleepUntilNextEvent (2000);
352 return true;
355 //==============================================================================
356 void LinuxEventLoop::registerFdCallback (int fd, std::function<void (int)> readCallback, short eventMask)
358 if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
359 runLoop->registerFdCallback (fd, [cb = std::move (readCallback), fd] { cb (fd); }, eventMask);
362 void LinuxEventLoop::unregisterFdCallback (int fd)
364 if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
365 runLoop->unregisterFdCallback (fd);
368 //==============================================================================
369 void LinuxEventLoopInternal::registerLinuxEventLoopListener (LinuxEventLoopInternal::Listener& listener)
371 if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
372 runLoop->addListener (listener);
375 void LinuxEventLoopInternal::deregisterLinuxEventLoopListener (LinuxEventLoopInternal::Listener& listener)
377 if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
378 runLoop->removeListener (listener);
381 void LinuxEventLoopInternal::invokeEventLoopCallbackForFd (int fd)
383 if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
384 runLoop->dispatchEvent (fd);
387 std::vector<int> LinuxEventLoopInternal::getRegisteredFds()
389 if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
390 return runLoop->getRegisteredFds();
392 return {};
395 } // namespace juce