1 /*
2   ==============================================================================
3 
4    This file is part of the JUCE library.
5    Copyright (c) 2017 - ROLI Ltd.
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 //==============================================================================
27 class InternalMessageQueue
28 {
29 public:
InternalMessageQueue()30     InternalMessageQueue()
31     {
32         auto err = ::socketpair (AF_LOCAL, SOCK_STREAM, 0, msgpipe);
33         jassert (err == 0);
34         ignoreUnused (err);
35 
36         LinuxEventLoop::registerFdCallback (getReadHandle(),
37                                             [this] (int fd)
38                                             {
39                                                 while (auto msg = popNextMessage (fd))
40                                                 {
41                                                     JUCE_TRY
42                                                     {
43                                                         msg->messageCallback();
44                                                     }
45                                                     JUCE_CATCH_EXCEPTION
46                                                 }
47                                             });
48     }
49 
~InternalMessageQueue()50     ~InternalMessageQueue()
51     {
52         LinuxEventLoop::unregisterFdCallback (getReadHandle());
53 
54         close (getReadHandle());
55         close (getWriteHandle());
56 
57         clearSingletonInstance();
58     }
59 
60     //==============================================================================
postMessage(MessageManager::MessageBase * const msg)61     void postMessage (MessageManager::MessageBase* const msg) noexcept
62     {
63         ScopedLock sl (lock);
64         queue.add (msg);
65 
66         if (bytesInSocket < maxBytesInSocketQueue)
67         {
68             bytesInSocket++;
69 
70             ScopedUnlock ul (lock);
71             unsigned char x = 0xff;
72             auto numBytes = write (getWriteHandle(), &x, 1);
73             ignoreUnused (numBytes);
74         }
75     }
76 
77     //==============================================================================
78     JUCE_DECLARE_SINGLETON (InternalMessageQueue, false)
79 
80 private:
81     CriticalSection lock;
82     ReferenceCountedArray <MessageManager::MessageBase> queue;
83 
84     int msgpipe[2];
85     int bytesInSocket = 0;
86     static constexpr int maxBytesInSocketQueue = 128;
87 
getWriteHandle() const88     int getWriteHandle() const noexcept  { return msgpipe[0]; }
getReadHandle() const89     int getReadHandle() const noexcept   { return msgpipe[1]; }
90 
popNextMessage(int fd)91     MessageManager::MessageBase::Ptr popNextMessage (int fd) noexcept
92     {
93         const ScopedLock sl (lock);
94 
95         if (bytesInSocket > 0)
96         {
97             --bytesInSocket;
98 
99             ScopedUnlock ul (lock);
100             unsigned char x;
101             auto numBytes = read (fd, &x, 1);
102             ignoreUnused (numBytes);
103         }
104 
105         return queue.removeAndReturn (0);
106     }
107 };
108 
109 JUCE_IMPLEMENT_SINGLETON (InternalMessageQueue)
110 
111 //==============================================================================
112 struct InternalRunLoop
113 {
114 public:
InternalRunLoopjuce::InternalRunLoop115     InternalRunLoop()
116     {
117         fdReadCallbacks.reserve (8);
118     }
119 
registerFdCallbackjuce::InternalRunLoop120     void registerFdCallback (int fd, std::function<void(int)>&& cb, short eventMask)
121     {
122         const ScopedLock sl (lock);
123 
124         fdReadCallbacks.push_back ({ fd, std::move (cb) });
125         pfds.push_back ({ fd, eventMask, 0 });
126     }
127 
unregisterFdCallbackjuce::InternalRunLoop128     void unregisterFdCallback (int fd)
129     {
130         const ScopedLock sl (lock);
131 
132         {
133             auto removePredicate = [=] (const std::pair<int, std::function<void(int)>>& cb)  { return cb.first == fd; };
134 
135             fdReadCallbacks.erase (std::remove_if (std::begin (fdReadCallbacks), std::end (fdReadCallbacks), removePredicate),
136                                    std::end (fdReadCallbacks));
137         }
138 
139         {
140             auto removePredicate = [=] (const pollfd& pfd)  { return pfd.fd == fd; };
141 
142             pfds.erase (std::remove_if (std::begin (pfds), std::end (pfds), removePredicate),
143                         std::end (pfds));
144         }
145     }
146 
dispatchPendingEventsjuce::InternalRunLoop147     bool dispatchPendingEvents()
148     {
149         const ScopedLock sl (lock);
150 
151         if (poll (&pfds.front(), static_cast<nfds_t> (pfds.size()), 0) == 0)
152             return false;
153 
154         bool eventWasSent = false;
155 
156         for (auto& pfd : pfds)
157         {
158             if (pfd.revents == 0)
159                 continue;
160 
161             pfd.revents = 0;
162 
163             auto fd = pfd.fd;
164 
165             for (auto& fdAndCallback : fdReadCallbacks)
166             {
167                 if (fdAndCallback.first == fd)
168                 {
169                     fdAndCallback.second (fd);
170                     eventWasSent = true;
171                 }
172             }
173         }
174 
175         return eventWasSent;
176     }
177 
sleepUntilNextEventjuce::InternalRunLoop178     void sleepUntilNextEvent (int timeoutMs)
179     {
180         poll (&pfds.front(), static_cast<nfds_t> (pfds.size()), timeoutMs);
181     }
182 
183     //==============================================================================
184     JUCE_DECLARE_SINGLETON (InternalRunLoop, false)
185 
186 private:
187     CriticalSection lock;
188 
189     std::vector<std::pair<int, std::function<void(int)>>> fdReadCallbacks;
190     std::vector<pollfd> pfds;
191 };
192 
193 JUCE_IMPLEMENT_SINGLETON (InternalRunLoop)
194 
195 //==============================================================================
196 namespace LinuxErrorHandling
197 {
198     static bool keyboardBreakOccurred = false;
199 
keyboardBreakSignalHandler(int sig)200     void keyboardBreakSignalHandler (int sig)
201     {
202         if (sig == SIGINT)
203             keyboardBreakOccurred = true;
204     }
205 
installKeyboardBreakHandler()206     void installKeyboardBreakHandler()
207     {
208         struct sigaction saction;
209         sigset_t maskSet;
210         sigemptyset (&maskSet);
211         saction.sa_handler = keyboardBreakSignalHandler;
212         saction.sa_mask = maskSet;
213         saction.sa_flags = 0;
214         sigaction (SIGINT, &saction, nullptr);
215     }
216 }
217 
218 //==============================================================================
doPlatformSpecificInitialisation()219 void MessageManager::doPlatformSpecificInitialisation()
220 {
221     if (JUCEApplicationBase::isStandaloneApp())
222         LinuxErrorHandling::installKeyboardBreakHandler();
223 
224     InternalRunLoop::getInstance();
225     InternalMessageQueue::getInstance();
226 }
227 
doPlatformSpecificShutdown()228 void MessageManager::doPlatformSpecificShutdown()
229 {
230     InternalMessageQueue::deleteInstance();
231     InternalRunLoop::deleteInstance();
232 }
233 
postMessageToSystemQueue(MessageManager::MessageBase * const message)234 bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message)
235 {
236     if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating())
237     {
238         queue->postMessage (message);
239         return true;
240     }
241 
242     return false;
243 }
244 
broadcastMessage(const String &)245 void MessageManager::broadcastMessage (const String&)
246 {
247     // TODO
248 }
249 
250 // this function expects that it will NEVER be called simultaneously for two concurrent threads
dispatchNextMessageOnSystemQueue(bool returnIfNoPendingMessages)251 bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)
252 {
253     for (;;)
254     {
255         if (LinuxErrorHandling::keyboardBreakOccurred)
256             JUCEApplicationBase::quit();
257 
258         if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
259         {
260             if (runLoop->dispatchPendingEvents())
261                 break;
262 
263             if (returnIfNoPendingMessages)
264                 return false;
265 
266             runLoop->sleepUntilNextEvent (2000);
267         }
268     }
269 
270     return true;
271 }
272 
273 //==============================================================================
registerFdCallback(int fd,std::function<void (int)> readCallback,short eventMask)274 void LinuxEventLoop::registerFdCallback (int fd, std::function<void(int)> readCallback, short eventMask)
275 {
276     if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
277         runLoop->registerFdCallback (fd, std::move (readCallback), eventMask);
278 }
279 
unregisterFdCallback(int fd)280 void LinuxEventLoop::unregisterFdCallback (int fd)
281 {
282     if (auto* runLoop = InternalRunLoop::getInstanceWithoutCreating())
283         runLoop->unregisterFdCallback (fd);
284 }
285 
286 } // namespace juce
287