26enum { magicMastSlaveConnectionHeader = 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 inline 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)
54 void pingReceived() noexcept { countdown = timeoutMs / 1000 + 1; }
57 virtual bool sendPingMessage (
const MemoryBlock&) = 0;
58 virtual void pingFailed() = 0;
63 Atomic<int> countdown;
65 void handleAsyncUpdate()
override { pingFailed(); }
71 if (--countdown <= 0 || ! sendPingMessage ({ pingMessage, specialMessageSize }))
73 triggerConnectionLostMessage();
81 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChildProcessPingThread)
85struct ChildProcessMaster::Connection :
public InterprocessConnection,
86 private ChildProcessPingThread
90 ChildProcessPingThread (timeout),
97 ~Connection()
override
103 void connectionMade()
override {}
106 bool sendPingMessage (
const MemoryBlock& m)
override {
return owner.
sendMessageToSlave (m); }
107 void pingFailed()
override { connectionLost(); }
109 void messageReceived (
const MemoryBlock& m)
override
113 if (m.getSize() != specialMessageSize || ! isMessageType (m, pingMessage))
119 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Connection)
134 if (connection !=
nullptr)
135 return connection->sendMessage (mb);
142 int timeoutMs,
int streamFlags)
150 args.
add (getCommandLinePrefix (commandLineUniqueID) + pipeName);
154 if (childProcess->start (args, streamFlags))
156 connection.reset (
new Connection (*
this, pipeName, timeoutMs <= 0 ? defaultTimeoutMs : timeoutMs));
158 if (connection->isConnected())
172 if (connection !=
nullptr)
175 connection->disconnect();
179 childProcess.reset();
184 private ChildProcessPingThread
188 ChildProcessPingThread (timeout),
195 ~Connection()
override
203 void connectionMade()
override {}
204 void connectionLost()
override { owner.handleConnectionLost(); }
206 bool sendPingMessage (
const MemoryBlock& m)
override {
return owner.sendMessageToMaster (m); }
207 void pingFailed()
override { connectionLost(); }
209 void messageReceived (
const MemoryBlock& m)
override
213 if (isMessageType (m, pingMessage))
216 if (isMessageType (m, killMessage))
217 return triggerConnectionLostMessage();
219 if (isMessageType (m, startMessage))
220 return owner.handleConnectionMade();
222 owner.handleMessageFromMaster (m);
225 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Connection)
237 if (connection !=
nullptr)
238 return connection->sendMessage (mb);
245 const String& commandLineUniqueID,
248 auto prefix = getCommandLinePrefix (commandLineUniqueID);
255 if (pipeName.isNotEmpty())
257 connection.reset (
new Connection (*
this, pipeName, timeoutMs <= 0 ? defaultTimeoutMs : timeoutMs));
259 if (! connection->isConnected())
264 return connection !=
nullptr;
void triggerAsyncUpdate()
bool sendMessageToSlave(const MemoryBlock &)
virtual void handleMessageFromSlave(const MemoryBlock &)=0
virtual ~ChildProcessMaster()
bool launchSlaveProcess(const File &executableToLaunch, const String &commandLineUniqueID, int timeoutMs=0, int streamFlags=ChildProcess::wantStdOut|ChildProcess::wantStdErr)
virtual void handleConnectionLost()
bool initialiseFromCommandLine(const String &commandLine, const String &commandLineUniqueID, int timeoutMs=0)
virtual void handleConnectionMade()
virtual ~ChildProcessSlave()
virtual void handleConnectionLost()
bool sendMessageToMaster(const MemoryBlock &)
const String & getFullPathName() const noexcept
InterprocessConnection(bool callbacksOnMessageThread=true, uint32 magicMessageHeaderNumber=0xf2b49e2c)
bool createPipe(const String &pipeName, int pipeReceiveMessageTimeoutMs, bool mustNotExist=false)
bool connectToPipe(const String &pipeName, int pipeReceiveMessageTimeoutMs)
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
bool wait(int timeOutMilliseconds) const
Thread(const String &threadName, size_t threadStackSize=0)
bool threadShouldExit() const
bool stopThread(int timeOutMilliseconds)