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; }
55 void triggerConnectionLostMessage() { triggerAsyncUpdate(); }
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
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);
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),
191 connectToPipe (pipeName, timeoutMs);
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;
bool sendMessageToSlave(const MemoryBlock &)
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)
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