26 enum { magicMastSlaveConnectionHeader = 0x712baf04 };
28 static const char* startMessage =
"__ipc_st";
29 static const char* killMessage =
"__ipc_k_";
30 static const char* pingMessage =
"__ipc_p_";
31 enum { specialMessageSize = 8, defaultTimeoutMs = 8000 };
33 static inline bool isMessageType (
const MemoryBlock& mb,
const char* messageType) noexcept
35 return mb.matches (messageType, (
size_t) specialMessageSize);
38 static String getCommandLinePrefix (
const String& commandLineUniqueID)
40 return "--" + commandLineUniqueID +
":";
46 struct 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)
85 struct ChildProcessMaster::Connection :
public InterprocessConnection,
86 private ChildProcessPingThread
88 Connection (ChildProcessMaster& m,
const String& pipeName,
int timeout)
89 : InterprocessConnection (false, magicMastSlaveConnectionHeader),
90 ChildProcessPingThread (timeout),
93 if (createPipe (pipeName, timeoutMs))
97 ~Connection()
override 103 void connectionMade()
override {}
104 void connectionLost()
override { owner.handleConnectionLost(); }
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))
114 owner.handleMessageFromSlave (m);
117 ChildProcessMaster& owner;
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())
160 sendMessageToSlave ({ startMessage, specialMessageSize });
172 if (connection !=
nullptr)
174 sendMessageToSlave ({ killMessage, specialMessageSize });
175 connection->disconnect();
179 childProcess.reset();
184 private ChildProcessPingThread
188 ChildProcessPingThread (timeout),
191 connectToPipe (pipeName, timeoutMs);
195 ~Connection()
override 203 void connectionMade()
override {}
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))
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;
String fromFirstOccurrenceOf(StringRef substringToStartFrom, bool includeSubStringInResult, bool ignoreCase) const
Thread(const String &threadName, size_t threadStackSize=0)
void triggerAsyncUpdate()
virtual ~ChildProcessMaster()
virtual void handleConnectionLost()
virtual void handleConnectionLost()
virtual void handleConnectionMade()
bool launchSlaveProcess(const File &executableToLaunch, const String &commandLineUniqueID, int timeoutMs=0, int streamFlags=ChildProcess::wantStdOut|ChildProcess::wantStdErr)
bool sendMessageToSlave(const MemoryBlock &)
bool sendMessageToMaster(const MemoryBlock &)
bool initialiseFromCommandLine(const String &commandLine, const String &commandLineUniqueID, int timeoutMs=0)
bool threadShouldExit() const
static String toHexString(IntegerType number)
String upToFirstOccurrenceOf(StringRef substringToEndWith, bool includeSubStringInResult, bool ignoreCase) const
virtual void handleMessageFromMaster(const MemoryBlock &)=0
virtual ~ChildProcessSlave()
const String & getFullPathName() const noexcept
bool wait(int timeOutMilliseconds) const
bool startsWith(StringRef text) const noexcept
void add(String stringToAdd)