LMMS
Loading...
Searching...
No Matches
juce_posix_NamedPipe.cpp
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
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
23namespace juce
24{
25
26#if ! JUCE_WASM
27
29{
30public:
31 Pimpl (const String& pipePath, bool createPipe)
32 : pipeInName (pipePath + "_in"),
33 pipeOutName (pipePath + "_out"),
34 createdPipe (createPipe)
35 {
36 signal (SIGPIPE, signalHandler);
37 juce_siginterrupt (SIGPIPE, 1);
38 }
39
41 {
42 pipeIn .close();
43 pipeOut.close();
44
45 if (createdPipe)
46 {
47 if (createdFifoIn) unlink (pipeInName.toUTF8());
48 if (createdFifoOut) unlink (pipeOutName.toUTF8());
49 }
50 }
51
52 bool connect (int timeOutMilliseconds)
53 {
54 return openPipe (true, getTimeoutEnd (timeOutMilliseconds)) != invalidPipe;
55 }
56
57 int read (char* destBuffer, int maxBytesToRead, int timeOutMilliseconds)
58 {
59 auto timeoutEnd = getTimeoutEnd (timeOutMilliseconds);
60 int bytesRead = 0;
61
62 while (bytesRead < maxBytesToRead)
63 {
64 const auto pipe = pipeIn.get();
65
66 auto bytesThisTime = maxBytesToRead - bytesRead;
67 auto numRead = (int) ::read (pipe, destBuffer, (size_t) bytesThisTime);
68
69 if (numRead <= 0)
70 {
71 const auto error = errno;
72
73 if (! (error == EWOULDBLOCK || error == EAGAIN) || stopReadOperation.load() || hasExpired (timeoutEnd))
74 return -1;
75
76 const int maxWaitingTime = 30;
77 waitForInput (pipe, timeoutEnd == 0 ? maxWaitingTime
78 : jmin (maxWaitingTime,
79 (int) (timeoutEnd - Time::getMillisecondCounter())));
80 continue;
81 }
82
83 bytesRead += numRead;
84 destBuffer += numRead;
85 }
86
87 return bytesRead;
88 }
89
90 int write (const char* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
91 {
92 auto timeoutEnd = getTimeoutEnd (timeOutMilliseconds);
93
94 const auto pipe = openPipe (false, timeoutEnd);
95
96 if (pipe == invalidPipe)
97 return -1;
98
99 int bytesWritten = 0;
100
101 while (bytesWritten < numBytesToWrite && ! hasExpired (timeoutEnd))
102 {
103 auto bytesThisTime = numBytesToWrite - bytesWritten;
104 auto numWritten = (int) ::write (pipe, sourceBuffer, (size_t) bytesThisTime);
105
106 if (numWritten < 0)
107 {
108 const auto error = errno;
109 const int maxWaitingTime = 30;
110
111 if (error == EWOULDBLOCK || error == EAGAIN)
112 waitToWrite (pipe, timeoutEnd == 0 ? maxWaitingTime
113 : jmin (maxWaitingTime,
114 (int) (timeoutEnd - Time::getMillisecondCounter())));
115 else
116 return -1;
117
118 numWritten = 0;
119 }
120
121 bytesWritten += numWritten;
122 sourceBuffer += numWritten;
123 }
124
125 return bytesWritten;
126 }
127
128 static bool createFifo (const String& name, bool mustNotExist)
129 {
130 return mkfifo (name.toUTF8(), 0666) == 0 || ((! mustNotExist) && errno == EEXIST);
131 }
132
133 bool createFifos (bool mustNotExist)
134 {
135 createdFifoIn = createFifo (pipeInName, mustNotExist);
136 createdFifoOut = createFifo (pipeOutName, mustNotExist);
137
139 }
140
141 static constexpr auto invalidPipe = -1;
142
144 {
145 public:
146 template <typename Fn>
147 int get (Fn&& fn)
148 {
149 {
150 const ScopedReadLock l (mutex);
151
152 if (descriptor != invalidPipe)
153 return descriptor;
154 }
155
156 const ScopedWriteLock l (mutex);
157 return descriptor = fn();
158 }
159
160 void close()
161 {
162 {
163 const ScopedReadLock l (mutex);
164
165 if (descriptor == invalidPipe)
166 return;
167 }
168
169 const ScopedWriteLock l (mutex);
172 }
173
174 int get()
175 {
176 const ScopedReadLock l (mutex);
177 return descriptor;
178 }
179
180 private:
183 };
184
187 bool createdFifoIn = false, createdFifoOut = false;
188
189 const bool createdPipe;
190 std::atomic<bool> stopReadOperation { false };
191
192private:
193 static void signalHandler (int) {}
194
195 static uint32 getTimeoutEnd (int timeOutMilliseconds)
196 {
197 return timeOutMilliseconds >= 0 ? Time::getMillisecondCounter() + (uint32) timeOutMilliseconds : 0;
198 }
199
200 static bool hasExpired (uint32 timeoutEnd)
201 {
202 return timeoutEnd != 0 && Time::getMillisecondCounter() >= timeoutEnd;
203 }
204
205 int openPipe (const String& name, int flags, uint32 timeoutEnd)
206 {
207 for (;;)
208 {
209 auto p = ::open (name.toUTF8(), flags);
210
211 if (p != invalidPipe || hasExpired (timeoutEnd) || stopReadOperation.load())
212 return p;
213
214 Thread::sleep (2);
215 }
216 }
217
218 int openPipe (bool isInput, uint32 timeoutEnd)
219 {
220 auto& pipe = isInput ? pipeIn : pipeOut;
221 const auto flags = (isInput ? O_RDWR : O_WRONLY) | O_NONBLOCK;
222
223 const String& pipeName = isInput ? (createdPipe ? pipeInName : pipeOutName)
225
226 return pipe.get ([this, &pipeName, &flags, &timeoutEnd]
227 {
228 return openPipe (pipeName, flags, timeoutEnd);
229 });
230 }
231
232 static void waitForInput (int handle, int timeoutMsecs) noexcept
233 {
234 pollfd pfd { handle, POLLIN, 0 };
235 poll (&pfd, 1, timeoutMsecs);
236 }
237
238 static void waitToWrite (int handle, int timeoutMsecs) noexcept
239 {
240 pollfd pfd { handle, POLLOUT, 0 };
241 poll (&pfd, 1, timeoutMsecs);
242 }
243
245};
246
248{
249 {
250 const ScopedReadLock sl (lock);
251
252 if (pimpl != nullptr)
253 {
254 pimpl->stopReadOperation = true;
255
256 const char buffer[] { 0 };
257 const auto done = ::write (pimpl->pipeIn.get(), buffer, numElementsInArray (buffer));
258 ignoreUnused (done);
259 }
260 }
261
262 {
263 const ScopedWriteLock sl (lock);
264 pimpl.reset();
265 }
266}
267
268bool NamedPipe::openInternal (const String& pipeName, bool createPipe, bool mustNotExist)
269{
270 #if JUCE_IOS
272 .getChildFile (File::createLegalFileName (pipeName)).getFullPathName(), createPipe));
273 #else
274 auto file = pipeName;
275
277 file = "/tmp/" + File::createLegalFileName (file);
278
279 pimpl.reset (new Pimpl (file, createPipe));
280 #endif
281
282 if (createPipe && ! pimpl->createFifos (mustNotExist))
283 {
284 pimpl.reset();
285 return false;
286 }
287
288 if (! pimpl->connect (200))
289 {
290 pimpl.reset();
291 return false;
292 }
293
294 return true;
295}
296
297int NamedPipe::read (void* destBuffer, int maxBytesToRead, int timeOutMilliseconds)
298{
299 ScopedReadLock sl (lock);
300 return pimpl != nullptr ? pimpl->read (static_cast<char*> (destBuffer), maxBytesToRead, timeOutMilliseconds) : -1;
301}
302
303int NamedPipe::write (const void* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
304{
305 ScopedReadLock sl (lock);
306 return pimpl != nullptr ? pimpl->write (static_cast<const char*> (sourceBuffer), numBytesToWrite, timeOutMilliseconds) : -1;
307}
308
309#endif
310
311} // namespace juce
static String createLegalFileName(const String &fileNameToFix)
Definition File.cpp:848
static bool isAbsolutePath(StringRef path)
Definition juce_File.cpp:400
@ tempDirectory
Definition juce_File.h:913
static File JUCE_CALLTYPE getSpecialLocation(const SpecialLocationType type)
Definition juce_linux_Files.cpp:107
static String createLegalFileName(const String &fileNameToFix)
Definition juce_File.cpp:835
Definition juce_posix_NamedPipe.cpp:144
void close()
Definition juce_posix_NamedPipe.cpp:160
int descriptor
Definition juce_posix_NamedPipe.cpp:182
int get(Fn &&fn)
Definition juce_posix_NamedPipe.cpp:147
ReadWriteLock mutex
Definition juce_posix_NamedPipe.cpp:181
int get()
Definition juce_posix_NamedPipe.cpp:174
Definition juce_posix_NamedPipe.cpp:29
const bool createdPipe
Definition juce_posix_NamedPipe.cpp:189
const String pipeInName
Definition juce_posix_NamedPipe.cpp:185
int read(char *destBuffer, int maxBytesToRead, int timeOutMilliseconds)
Definition juce_posix_NamedPipe.cpp:57
PipeDescriptor pipeIn
Definition juce_posix_NamedPipe.cpp:186
~Pimpl()
Definition juce_posix_NamedPipe.cpp:40
static constexpr auto invalidPipe
Definition juce_posix_NamedPipe.cpp:141
const String pipeOutName
Definition juce_posix_NamedPipe.cpp:185
static void waitToWrite(int handle, int timeoutMsecs) noexcept
Definition juce_posix_NamedPipe.cpp:238
bool createdFifoIn
Definition juce_posix_NamedPipe.cpp:187
int write(const char *sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
Definition juce_posix_NamedPipe.cpp:90
bool connect(int timeOutMilliseconds)
Definition juce_posix_NamedPipe.cpp:52
int openPipe(bool isInput, uint32 timeoutEnd)
Definition juce_posix_NamedPipe.cpp:218
Pimpl(const String &pipePath, bool createPipe)
Definition juce_posix_NamedPipe.cpp:31
bool createFifos(bool mustNotExist)
Definition juce_posix_NamedPipe.cpp:133
std::atomic< bool > stopReadOperation
Definition juce_posix_NamedPipe.cpp:190
static bool createFifo(const String &name, bool mustNotExist)
Definition juce_posix_NamedPipe.cpp:128
static void signalHandler(int)
Definition juce_posix_NamedPipe.cpp:193
static void waitForInput(int handle, int timeoutMsecs) noexcept
Definition juce_posix_NamedPipe.cpp:232
bool createdFifoOut
Definition juce_posix_NamedPipe.cpp:187
int openPipe(const String &name, int flags, uint32 timeoutEnd)
Definition juce_posix_NamedPipe.cpp:205
static bool hasExpired(uint32 timeoutEnd)
Definition juce_posix_NamedPipe.cpp:200
static uint32 getTimeoutEnd(int timeOutMilliseconds)
Definition juce_posix_NamedPipe.cpp:195
PipeDescriptor pipeOut
Definition juce_posix_NamedPipe.cpp:186
int write(const void *sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
Definition juce_posix_NamedPipe.cpp:303
ReadWriteLock lock
Definition juce_NamedPipe.h:93
int read(void *destBuffer, int maxBytesToRead, int timeOutMilliseconds)
Definition juce_posix_NamedPipe.cpp:297
std::unique_ptr< Pimpl > pimpl
Definition juce_NamedPipe.h:91
bool openInternal(const String &pipeName, bool createPipe, bool mustNotExist)
Definition juce_posix_NamedPipe.cpp:268
void close()
Definition juce_posix_NamedPipe.cpp:247
Definition juce_ReadWriteLock.h:48
Definition juce_ScopedReadLock.h:52
Definition juce_ScopedWriteLock.h:52
Definition juce_String.h:53
static void JUCE_CALLTYPE sleep(int milliseconds)
Definition juce_posix_SharedCode.h:44
static uint32 getMillisecondCounter() noexcept
Definition juce_Time.cpp:241
int * l
Definition inflate.c:1579
static const char * name
Definition pugl.h:1582
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
Definition carla_juce.cpp:31
int juce_siginterrupt(int sig, int flag)
Definition juce_posix_SharedCode.h:143
constexpr Type jmin(Type a, Type b)
Definition juce_MathsFunctions.h:106
unsigned int uint32
Definition juce_MathsFunctions.h:45
void ignoreUnused(Types &&...) noexcept
Definition juce_MathsFunctions.h:333
constexpr int numElementsInArray(Type(&)[N]) noexcept
Definition juce_MathsFunctions.h:344
jack_client_t client jack_client_t client jack_client_t client jack_client_t JackInfoShutdownCallback void arg jack_client_t jack_port_t port void func jack_client_t const char const char unsigned long flags
Definition juce_linux_JackAudio.cpp:69
const char const char const char const char char * fn
Definition swell-functions.h:168
uch * p
Definition crypt.c:594
int error
Definition extract.c:1038
typedef int(UZ_EXP MsgFn)()
struct zdirent * file
Definition win32.c:1500