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