|
|
|
@@ -39,8 +39,8 @@ public: |
|
|
|
|
|
|
|
~Pimpl()
|
|
|
|
{
|
|
|
|
if (pipeIn != -1) ::close (pipeIn);
|
|
|
|
if (pipeOut != -1) ::close (pipeOut);
|
|
|
|
pipeIn .close();
|
|
|
|
pipeOut.close();
|
|
|
|
|
|
|
|
if (createdPipe)
|
|
|
|
{
|
|
|
|
@@ -51,7 +51,7 @@ public: |
|
|
|
|
|
|
|
bool connect (int timeOutMilliseconds)
|
|
|
|
{
|
|
|
|
return openPipe (true, getTimeoutEnd (timeOutMilliseconds));
|
|
|
|
return openPipe (true, getTimeoutEnd (timeOutMilliseconds)) != invalidPipe;
|
|
|
|
}
|
|
|
|
|
|
|
|
int read (char* destBuffer, int maxBytesToRead, int timeOutMilliseconds)
|
|
|
|
@@ -61,8 +61,10 @@ public: |
|
|
|
|
|
|
|
while (bytesRead < maxBytesToRead)
|
|
|
|
{
|
|
|
|
const auto pipe = pipeIn.get();
|
|
|
|
|
|
|
|
auto bytesThisTime = maxBytesToRead - bytesRead;
|
|
|
|
auto numRead = (int) ::read (pipeIn, destBuffer, (size_t) bytesThisTime);
|
|
|
|
auto numRead = (int) ::read (pipe, destBuffer, (size_t) bytesThisTime);
|
|
|
|
|
|
|
|
if (numRead <= 0)
|
|
|
|
{
|
|
|
|
@@ -72,9 +74,9 @@ public: |
|
|
|
return -1;
|
|
|
|
|
|
|
|
const int maxWaitingTime = 30;
|
|
|
|
waitForInput (pipeIn, timeoutEnd == 0 ? maxWaitingTime
|
|
|
|
: jmin (maxWaitingTime,
|
|
|
|
(int) (timeoutEnd - Time::getMillisecondCounter())));
|
|
|
|
waitForInput (pipe, timeoutEnd == 0 ? maxWaitingTime
|
|
|
|
: jmin (maxWaitingTime,
|
|
|
|
(int) (timeoutEnd - Time::getMillisecondCounter())));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
@@ -89,7 +91,9 @@ public: |
|
|
|
{
|
|
|
|
auto timeoutEnd = getTimeoutEnd (timeOutMilliseconds);
|
|
|
|
|
|
|
|
if (! openPipe (false, timeoutEnd))
|
|
|
|
const auto pipe = openPipe (false, timeoutEnd);
|
|
|
|
|
|
|
|
if (pipe == invalidPipe)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
int bytesWritten = 0;
|
|
|
|
@@ -97,7 +101,7 @@ public: |
|
|
|
while (bytesWritten < numBytesToWrite && ! hasExpired (timeoutEnd))
|
|
|
|
{
|
|
|
|
auto bytesThisTime = numBytesToWrite - bytesWritten;
|
|
|
|
auto numWritten = (int) ::write (pipeOut, sourceBuffer, (size_t) bytesThisTime);
|
|
|
|
auto numWritten = (int) ::write (pipe, sourceBuffer, (size_t) bytesThisTime);
|
|
|
|
|
|
|
|
if (numWritten < 0)
|
|
|
|
{
|
|
|
|
@@ -105,9 +109,9 @@ public: |
|
|
|
const int maxWaitingTime = 30;
|
|
|
|
|
|
|
|
if (error == EWOULDBLOCK || error == EAGAIN)
|
|
|
|
waitToWrite (pipeOut, timeoutEnd == 0 ? maxWaitingTime
|
|
|
|
: jmin (maxWaitingTime,
|
|
|
|
(int) (timeoutEnd - Time::getMillisecondCounter())));
|
|
|
|
waitToWrite (pipe, timeoutEnd == 0 ? maxWaitingTime
|
|
|
|
: jmin (maxWaitingTime,
|
|
|
|
(int) (timeoutEnd - Time::getMillisecondCounter())));
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
@@ -134,8 +138,52 @@ public: |
|
|
|
return createdFifoIn && createdFifoOut;
|
|
|
|
}
|
|
|
|
|
|
|
|
static constexpr auto invalidPipe = -1;
|
|
|
|
|
|
|
|
class PipeDescriptor
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
template <typename Fn>
|
|
|
|
int get (Fn&& fn)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
const ScopedReadLock l (mutex);
|
|
|
|
|
|
|
|
if (descriptor != invalidPipe)
|
|
|
|
return descriptor;
|
|
|
|
}
|
|
|
|
|
|
|
|
const ScopedWriteLock l (mutex);
|
|
|
|
return descriptor = fn();
|
|
|
|
}
|
|
|
|
|
|
|
|
void close()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
const ScopedReadLock l (mutex);
|
|
|
|
|
|
|
|
if (descriptor == invalidPipe)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const ScopedWriteLock l (mutex);
|
|
|
|
::close (descriptor);
|
|
|
|
descriptor = invalidPipe;
|
|
|
|
}
|
|
|
|
|
|
|
|
int get()
|
|
|
|
{
|
|
|
|
const ScopedReadLock l (mutex);
|
|
|
|
return descriptor;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
ReadWriteLock mutex;
|
|
|
|
int descriptor = invalidPipe;
|
|
|
|
};
|
|
|
|
|
|
|
|
const String pipeInName, pipeOutName;
|
|
|
|
int pipeIn = -1, pipeOut = -1;
|
|
|
|
PipeDescriptor pipeIn, pipeOut;
|
|
|
|
bool createdFifoIn = false, createdFifoOut = false;
|
|
|
|
|
|
|
|
const bool createdPipe;
|
|
|
|
@@ -160,30 +208,25 @@ private: |
|
|
|
{
|
|
|
|
auto p = ::open (name.toUTF8(), flags);
|
|
|
|
|
|
|
|
if (p != -1 || hasExpired (timeoutEnd) || stopReadOperation.load())
|
|
|
|
if (p != invalidPipe || hasExpired (timeoutEnd) || stopReadOperation.load())
|
|
|
|
return p;
|
|
|
|
|
|
|
|
Thread::sleep (2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool openPipe (bool isInput, uint32 timeoutEnd)
|
|
|
|
int openPipe (bool isInput, uint32 timeoutEnd)
|
|
|
|
{
|
|
|
|
auto& pipe = isInput ? pipeIn : pipeOut;
|
|
|
|
int flags = (isInput ? O_RDWR : O_WRONLY) | O_NONBLOCK;
|
|
|
|
const auto flags = (isInput ? O_RDWR : O_WRONLY) | O_NONBLOCK;
|
|
|
|
|
|
|
|
const String& pipeName = isInput ? (createdPipe ? pipeInName : pipeOutName)
|
|
|
|
: (createdPipe ? pipeOutName : pipeInName);
|
|
|
|
|
|
|
|
if (pipe == -1)
|
|
|
|
return pipe.get ([this, &pipeName, &flags, &timeoutEnd]
|
|
|
|
{
|
|
|
|
pipe = openPipe (pipeName, flags, timeoutEnd);
|
|
|
|
|
|
|
|
if (pipe == -1)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
return openPipe (pipeName, flags, timeoutEnd);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
static void waitForInput (int handle, int timeoutMsecs) noexcept
|
|
|
|
@@ -203,23 +246,18 @@ private: |
|
|
|
|
|
|
|
void NamedPipe::close()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
ScopedReadLock sl (lock);
|
|
|
|
ScopedWriteLock sl (lock);
|
|
|
|
|
|
|
|
if (pimpl != nullptr)
|
|
|
|
{
|
|
|
|
pimpl->stopReadOperation = true;
|
|
|
|
if (pimpl != nullptr)
|
|
|
|
{
|
|
|
|
pimpl->stopReadOperation = true;
|
|
|
|
|
|
|
|
char buffer[1] = { 0 };
|
|
|
|
ssize_t done = ::write (pimpl->pipeIn, buffer, 1);
|
|
|
|
ignoreUnused (done);
|
|
|
|
}
|
|
|
|
const char buffer[] { 0 };
|
|
|
|
const auto done = ::write (pimpl->pipeIn.get(), buffer, numElementsInArray (buffer));
|
|
|
|
ignoreUnused (done);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
ScopedWriteLock sl (lock);
|
|
|
|
pimpl.reset();
|
|
|
|
}
|
|
|
|
pimpl.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool NamedPipe::openInternal (const String& pipeName, bool createPipe, bool mustNotExist)
|
|
|
|
|