26enum { magicCoordWorkerConnectionHeader = 0x712baf04 };
28static const char* startMessage =
"__ipc_st";
29static const char* killMessage =
"__ipc_k_";
30static const char* pingMessage =
"__ipc_p_";
31enum { specialMessageSize = 8, defaultTimeoutMs = 8000 };
33static bool isMessageType (
const MemoryBlock& mb,
const char* messageType)
noexcept
35 return mb.matches (messageType, (
size_t) specialMessageSize);
38static String getCommandLinePrefix (
const String& commandLineUniqueID)
40 return "--" + commandLineUniqueID +
":";
46struct ChildProcessPingThread :
public Thread,
49 ChildProcessPingThread (
int timeout) :
Thread (
"IPC ping"), timeoutMs (timeout)
56 void pingReceived() noexcept { countdown = timeoutMs / 1000 + 1; }
59 virtual bool sendPingMessage (
const MemoryBlock&) = 0;
60 virtual void pingFailed() = 0;
67 Atomic<int> countdown;
69 void handleAsyncUpdate()
override { pingFailed(); }
75 if (--countdown <= 0 || ! sendPingMessage ({ pingMessage, specialMessageSize }))
77 triggerConnectionLostMessage();
85 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChildProcessPingThread)
89struct ChildProcessCoordinator::Connection final :
public InterprocessConnection,
90 private ChildProcessPingThread
92 Connection (ChildProcessCoordinator& m,
const String& pipeName,
int timeout)
94 ChildProcessPingThread (timeout),
100 ~Connection()
override
102 cancelPendingUpdate();
106 using ChildProcessPingThread::startPinging;
109 void connectionMade()
override {}
110 void connectionLost()
override { owner.handleConnectionLost(); }
112 bool sendPingMessage (
const MemoryBlock& m)
override {
return owner.sendMessageToWorker (m); }
113 void pingFailed()
override { connectionLost(); }
115 void messageReceived (
const MemoryBlock& m)
override
119 if (m.getSize() != specialMessageSize || ! isMessageType (m, pingMessage))
120 owner.handleMessageFromWorker (m);
123 ChildProcessCoordinator& owner;
125 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Connection)
140 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE (
"-Wdeprecated-declarations")
141 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996)
142 handleMessageFromSlave (mb);
143 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
144 JUCE_END_IGNORE_WARNINGS_MSVC
149 if (connection !=
nullptr)
150 return connection->sendMessage (mb);
157 int timeoutMs,
int streamFlags)
165 args.
add (getCommandLinePrefix (commandLineUniqueID) + pipeName);
167 childProcess = [&]() -> std::shared_ptr<ChildProcess>
170 return ChildProcessManager::getInstance()->createAndStartManagedChildProcess (args, streamFlags);
172 auto p = std::make_shared<ChildProcess>();
174 if (p->start (args, streamFlags))
180 if (childProcess !=
nullptr)
182 connection.reset (
new Connection (*
this, pipeName, timeoutMs <= 0 ? defaultTimeoutMs : timeoutMs));
184 if (connection->isConnected())
186 connection->startPinging();
199 if (connection !=
nullptr)
202 connection->disconnect();
206 childProcess.reset();
211 private ChildProcessPingThread
215 ChildProcessPingThread (timeout),
218 connectToPipe (pipeName, timeoutMs);
221 ~Connection()
override
223 cancelPendingUpdate();
228 using ChildProcessPingThread::startPinging;
231 ChildProcessWorker& owner;
233 void connectionMade()
override {}
234 void connectionLost()
override { owner.handleConnectionLost(); }
236 bool sendPingMessage (
const MemoryBlock& m)
override {
return owner.sendMessageToCoordinator (m); }
237 void pingFailed()
override { connectionLost(); }
239 void messageReceived (
const MemoryBlock& m)
override
243 if (isMessageType (m, pingMessage))
246 if (isMessageType (m, killMessage))
247 return triggerConnectionLostMessage();
249 if (isMessageType (m, startMessage))
250 return owner.handleConnectionMade();
252 owner.handleMessageFromCoordinator (m);
255 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Connection)
267 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE (
"-Wdeprecated-declarations")
268 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996)
269 handleMessageFromMaster (mb);
270 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
271 JUCE_END_IGNORE_WARNINGS_MSVC
276 if (connection !=
nullptr)
277 return connection->sendMessage (mb);
284 const String& commandLineUniqueID,
287 auto prefix = getCommandLinePrefix (commandLineUniqueID);
294 if (pipeName.isNotEmpty())
296 connection.reset (
new Connection (*
this, pipeName, timeoutMs <= 0 ? defaultTimeoutMs : timeoutMs));
298 if (connection->isConnected())
299 connection->startPinging();
305 return connection !=
nullptr;
void triggerAsyncUpdate()
void cancelPendingUpdate() noexcept
ChildProcessCoordinator()
virtual ~ChildProcessCoordinator()
bool sendMessageToWorker(const MemoryBlock &)
virtual void handleMessageFromWorker(const MemoryBlock &)
virtual void handleConnectionLost()
bool launchWorkerProcess(const File &executableToLaunch, const String &commandLineUniqueID, int timeoutMs=0, int streamFlags=ChildProcess::wantStdOut|ChildProcess::wantStdErr)
bool sendMessageToCoordinator(const MemoryBlock &)
virtual ~ChildProcessWorker()
virtual void handleMessageFromCoordinator(const MemoryBlock &mb)
bool initialiseFromCommandLine(const String &commandLine, const String &commandLineUniqueID, int timeoutMs=0)
virtual void handleConnectionLost()
virtual void handleConnectionMade()
const String & getFullPathName() const noexcept
InterprocessConnection(bool callbacksOnMessageThread=true, uint32 magicMessageHeaderNumber=0xf2b49e2c)
bool createPipe(const String &pipeName, int pipeReceiveMessageTimeoutMs, bool mustNotExist=false)
void add(String stringToAdd)
String upToFirstOccurrenceOf(StringRef substringToEndWith, bool includeSubStringInResult, bool ignoreCase) const
bool startsWith(StringRef text) const noexcept
static String toHexString(IntegerType number)
String fromFirstOccurrenceOf(StringRef substringToStartFrom, bool includeSubStringInResult, bool ignoreCase) const
static OperatingSystemType getOperatingSystemType()
bool wait(double timeOutMilliseconds) const
Thread(const String &threadName, size_t threadStackSize=osDefaultStackSize)
bool threadShouldExit() const