- /*
- ==============================================================================
-
- This file is part of the JUCE library.
- Copyright (c) 2020 - Raw Material Software Limited
-
- JUCE is an open source library subject to commercial or open-source
- licensing.
-
- The code included in this file is provided under the terms of the ISC license
- http://www.isc.org/downloads/software-support-policy/isc-license. Permission
- To use, copy, modify, and/or distribute this software for any purpose with or
- without fee is hereby granted provided that the above copyright notice and
- this permission notice appear in all copies.
-
- JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
- EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
- DISCLAIMED.
-
- ==============================================================================
- */
-
- namespace juce
- {
-
- //==============================================================================
- class InternalMessageQueue
- {
- public:
- InternalMessageQueue()
- {
- auto err = ::socketpair (AF_LOCAL, SOCK_STREAM, 0, msgpipe);
- jassert (err == 0);
- ignoreUnused (err);
-
- LinuxEventLoop::registerFdCallback (getReadHandle(),
- [this] (int fd)
- {
- while (auto msg = popNextMessage (fd))
- {
- JUCE_TRY
- {
- msg->messageCallback();
- }
- JUCE_CATCH_EXCEPTION
- }
- });
- }
-
- ~InternalMessageQueue()
- {
- LinuxEventLoop::unregisterFdCallback (getReadHandle());
-
- close (getReadHandle());
- close (getWriteHandle());
-
- clearSingletonInstance();
- }
-
- //==============================================================================
- void postMessage (MessageManager::MessageBase* const msg) noexcept
- {
- ScopedLock sl (lock);
- queue.add (msg);
-
- if (bytesInSocket < maxBytesInSocketQueue)
- {
- bytesInSocket++;
-
- ScopedUnlock ul (lock);
- unsigned char x = 0xff;
- auto numBytes = write (getWriteHandle(), &x, 1);
- ignoreUnused (numBytes);
- }
- }
-
- //==============================================================================
- JUCE_DECLARE_SINGLETON (InternalMessageQueue, false)
-
- private:
- CriticalSection lock;
- ReferenceCountedArray <MessageManager::MessageBase> queue;
-
- int msgpipe[2];
- int bytesInSocket = 0;
- static constexpr int maxBytesInSocketQueue = 128;
-
- int getWriteHandle() const noexcept { return msgpipe[0]; }
- int getReadHandle() const noexcept { return msgpipe[1]; }
-
- MessageManager::MessageBase::Ptr popNextMessage (int fd) noexcept
- {
- const ScopedLock sl (lock);
-
- if (bytesInSocket > 0)
- {
- --bytesInSocket;
-
- ScopedUnlock ul (lock);
- unsigned char x;
- auto numBytes = read (fd, &x, 1);
- ignoreUnused (numBytes);
- }
-
- return queue.removeAndReturn (0);
- }
- };
-
- JUCE_IMPLEMENT_SINGLETON (InternalMessageQueue)
-
- //==============================================================================
- struct InternalRunLoop
- {
- public:
- InternalRunLoop()
- {
- fdReadCallbacks.reserve (16);
- }
-
- void registerFdCallback (int fd, std::function<void (int)>&& cb, short eventMask)
- {
- const ScopedLock sl (lock);
-
- if (shouldDeferModifyingReadCallbacks)
- {
- deferredReadCallbackModifications.emplace_back ([this, fd, cb, eventMask]() mutable
- {
- registerFdCallback (fd, std::move (cb), eventMask);
- });
- return;
- }
-
- fdReadCallbacks.push_back ({ fd, std::move (cb) });
- pfds.push_back ({ fd, eventMask, 0 });
- }
-
- void unregisterFdCallback (int fd)
- {
- const ScopedLock sl (lock);
-
- if (shouldDeferModifyingReadCallbacks)
- {
- deferredReadCallbackModifications.emplace_back ([this, fd] { unregisterFdCallback (fd); });
- return;
- }
-
- {
- auto removePredicate = [=] (const std::pair<int, std::function<void (int)>>& cb) { return cb.first == fd; };
-
- fdReadCallbacks.erase (std::remove_if (std::begin (fdReadCallbacks), std::end (fdReadCallbacks), removePredicate),
- std::end (fdReadCallbacks));
- }
-
- {
- auto removePredicate = [=] (const pollfd& pfd) { return pfd.fd == fd; };
-
- pfds.erase (std::remove_if (std::begin (pfds), std::end (pfds), removePredicate),
- std::end (pfds));
- }
- }
-
- bool dispatchPendingEvents()
- {
- const ScopedLock sl (lock);
-
- if (poll (&pfds.front(), static_cast<nfds_t> (pfds.size()), 0) == 0)
- return false;
-
- bool eventWasSent = false;
-
- for (auto& pfd : pfds)
- {
- if (pfd.revents == 0)
- continue;
-
- pfd.revents = 0;
-
- auto fd = pfd.fd;
-
- for (auto& fdAndCallback : fdReadCallbacks)
- {
- if (fdAndCallback.first == fd)
- {
- {
- ScopedValueSetter<bool> insideFdReadCallback (shouldDeferModifyingReadCallbacks, true);
- fdAndCallback.second (fd);
- }
-
- if (! deferredReadCallbackModifications.empty())
- {
- for (auto& deferredRegisterEvent : deferredReadCallbackModifications)
- deferredRegisterEvent();
-
- deferredReadCallbackModifications.clear();
-
- // elements may have been removed from the fdReadCallbacks/pfds array so we really need
- // to call poll again
- return true;
- }
-
- eventWasSent = true;
- }
- }
- }
-
- return eventWasSent;
- }
-
- void sleepUntilNextEvent (int timeoutMs)
- {
- poll (&pfds.front(), static_cast<nfds_t> (pfds.size()), timeoutMs);
- }
-
- std::vector<std::pair<int, std::function<void (int)>>> getFdReadCallbacks()
- {
- const ScopedLock sl (lock);
- return fdReadCallbacks;
- }
-
- //==============================================================================
- JUCE_DECLARE_SINGLETON (InternalRunLoop, false)
-
- private:
- CriticalSection lock;
-
- std::vector<std::pair<int, std::function<void (int)>>> fdReadCallbacks;
- std::vector<pollfd> pfds;
-
- bool shouldDeferModifyingReadCallbacks = false;
- std::vector<std::function<void()>> deferredReadCallbackModifications;
- };
-
- JUCE_IMPLEMENT_SINGLETON (InternalRunLoop)
-
- //==============================================================================
- namespace LinuxErrorHandling
- {
- static bool keyboardBreakOccurred = false;
-
- void keyboardBreakSignalHandler (int sig)
- {
- if (sig == SIGINT)
- keyboardBreakOccurred = true;
- }
-
- void installKeyboardBreakHandler()
- {
- struct sigaction saction;
- sigset_t maskSet;
- sigemptyset (&maskSet);
- saction.sa_handler = keyboardBreakSignalHandler;
- saction.sa_mask = maskSet;
- saction.sa_flags = 0;
- sigaction (SIGINT, &saction, nullptr);
- }
- }
-
- //==============================================================================
- void MessageManager::doPlatformSpecificInitialisation()
- {
- if (JUCEApplicationBase::isStandaloneApp())
- LinuxErrorHandling::installKeyboardBreakHandler();
-
- InternalRunLoop::getInstance();
- InternalMessageQueue::getInstance();
- }
-
- void MessageManager::doPlatformSpecificShutdown()
- {
- InternalMessageQueue::deleteInstance();
- InternalRunLoop::deleteInstance();
- }
-
- bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message)
- {
- if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating())
- {
- queue->postMessage (message);
- return true;
- }
-
- return false;
- }
-
- void MessageManager::broadcastMessage (const String&)
- {
- // TODO
- }
-
- // this function expects that it will NEVER be called simultaneously for two concurrent threads
- bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)
- {
- for (;;)
- {
- if (LinuxErrorHandling::keyboardBreakOccurred)
- JUCEApplicationBase::quit();
-
- if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
- {
- if (runLoop->dispatchPendingEvents())
- break;
-
- if (returnIfNoPendingMessages)
- return false;
-
- runLoop->sleepUntilNextEvent (2000);
- }
- }
-
- return true;
- }
-
- //==============================================================================
- void LinuxEventLoop::registerFdCallback (int fd, std::function<void (int)> readCallback, short eventMask)
- {
- if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
- runLoop->registerFdCallback (fd, std::move (readCallback), eventMask);
- }
-
- void LinuxEventLoop::unregisterFdCallback (int fd)
- {
- if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
- runLoop->unregisterFdCallback (fd);
- }
-
- } // namespace juce
-
- JUCE_API std::vector<std::pair<int, std::function<void (int)>>> getFdReadCallbacks()
- {
- using namespace juce;
-
- if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
- return runLoop->getFdReadCallbacks();
-
- jassertfalse;
- return {};
- }
|