JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
juce_NamedPipe_posix.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
40 ~Pimpl()
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
80 continue;
81 }
82
83 bytesRead += 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
115 else
116 return -1;
117
118 numWritten = 0;
119 }
120
121 bytesWritten += 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
138 return createdFifoIn && createdFifoOut;
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);
170 ::close (descriptor);
171 descriptor = invalidPipe;
172 }
173
174 int get()
175 {
176 const ScopedReadLock l (mutex);
177 return descriptor;
178 }
179
180 private:
181 ReadWriteLock mutex;
182 int descriptor = invalidPipe;
183 };
184
185 const String pipeInName, pipeOutName;
186 PipeDescriptor pipeIn, pipeOut;
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 {
198 }
199
200 static bool hasExpired (uint32 timeoutEnd)
201 {
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)
224 : (createdPipe ? pipeOutName : pipeInName);
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 [[maybe_unused]] const auto done = ::write (pimpl->pipeIn.get(), buffer, numElementsInArray (buffer));
258 }
259 }
260
261 {
262 const ScopedWriteLock sl (lock);
263 pimpl.reset();
264 }
265}
266
267bool NamedPipe::openInternal (const String& pipeName, bool createPipe, bool mustNotExist)
268{
269 #if JUCE_IOS
271 .getChildFile (File::createLegalFileName (pipeName)).getFullPathName(), createPipe));
272 #else
273 auto file = pipeName;
274
275 if (! File::isAbsolutePath (file))
276 file = "/tmp/" + File::createLegalFileName (file);
277
278 pimpl.reset (new Pimpl (file, createPipe));
279 #endif
280
281 if (createPipe && ! pimpl->createFifos (mustNotExist))
282 {
283 pimpl.reset();
284 return false;
285 }
286
287 if (! pimpl->connect (200))
288 {
289 pimpl.reset();
290 return false;
291 }
292
293 return true;
294}
295
297{
298 ScopedReadLock sl (lock);
299 return pimpl != nullptr ? pimpl->read (static_cast<char*> (destBuffer), maxBytesToRead, timeOutMilliseconds) : -1;
300}
301
303{
304 ScopedReadLock sl (lock);
305 return pimpl != nullptr ? pimpl->write (static_cast<const char*> (sourceBuffer), numBytesToWrite, timeOutMilliseconds) : -1;
306}
307
308#endif
309
310} // namespace juce
#define EWOULDBLOCK
static bool isAbsolutePath(StringRef path)
Returns true if the string seems to be a fully-specified absolute path.
@ tempDirectory
The folder that should be used for temporary files.
Definition juce_File.h:919
static File JUCE_CALLTYPE getSpecialLocation(const SpecialLocationType type)
Finds the location of a special type of file or directory, such as a home folder or documents folder.
static String createLegalFileName(const String &fileNameToFix)
Returns a version of a filename with any illegal characters removed.
int write(const void *sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
Writes some data to the pipe.
int read(void *destBuffer, int maxBytesToRead, int timeOutMilliseconds)
Reads data from the pipe.
void close()
Closes the pipe, if it's open.
A critical section that allows multiple simultaneous readers.
Automatically locks and unlocks a ReadWriteLock object.
Automatically locks and unlocks a ReadWriteLock object.
The JUCE String class!
Definition juce_String.h:53
CharPointer_UTF8 toUTF8() const
Returns a pointer to a UTF-8 version of this string.
static void JUCE_CALLTYPE sleep(int milliseconds)
Suspends the execution of the current thread until the specified timeout period has elapsed (note tha...
static uint32 getMillisecondCounter() noexcept
Returns the number of millisecs since a fixed event (usually system startup).
errno
T get(T... args)
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
This is a shorthand way of writing both a JUCE_DECLARE_NON_COPYABLE and JUCE_LEAK_DETECTOR macro for ...
typedef int
T load(T... args)
mkfifo
JUCE Namespace.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
Definition juce_Memory.h:88
unsigned int uint32
A platform-independent 32-bit unsigned integer type.
constexpr int numElementsInArray(Type(&)[N]) noexcept
Handy function for getting the number of elements in a simple const C array.
pipe
poll
T reset(T... args)
signal
unlink