diff --git a/modules/juce_events/interprocess/juce_ConnectedChildProcess.cpp b/modules/juce_events/interprocess/juce_ConnectedChildProcess.cpp index 093b5b0862..6370e1ebef 100644 --- a/modules/juce_events/interprocess/juce_ConnectedChildProcess.cpp +++ b/modules/juce_events/interprocess/juce_ConnectedChildProcess.cpp @@ -30,6 +30,11 @@ static const char* killMessage = "__ipc_k_"; static const char* pingMessage = "__ipc_p_"; enum { specialMessageSize = 8, defaultTimeoutMs = 8000 }; +static inline bool isMessageType (const MemoryBlock& mb, const char* messageType) noexcept +{ + return mb.matches (messageType, (size_t) specialMessageSize); +} + static String getCommandLinePrefix (const String& commandLineUniqueID) { return "--" + commandLineUniqueID + ":"; @@ -46,11 +51,6 @@ struct ChildProcessPingThread : public Thread, pingReceived(); } - static bool isPingMessage (const MemoryBlock& m) noexcept - { - return memcmp (m.getData(), pingMessage, specialMessageSize) == 0; - } - void pingReceived() noexcept { countdown = timeoutMs / 1000 + 1; } void triggerConnectionLostMessage() { triggerAsyncUpdate(); } @@ -68,7 +68,7 @@ private: { while (! threadShouldExit()) { - if (--countdown <= 0 || ! sendPingMessage (MemoryBlock (pingMessage, specialMessageSize))) + if (--countdown <= 0 || ! sendPingMessage ({ pingMessage, specialMessageSize })) { triggerConnectionLostMessage(); break; @@ -110,7 +110,7 @@ private: { pingReceived(); - if (m.getSize() != specialMessageSize || ! isPingMessage (m)) + if (m.getSize() != specialMessageSize || ! isMessageType (m, pingMessage)) owner.handleMessageFromSlave (m); } @@ -124,12 +124,7 @@ ChildProcessMaster::ChildProcessMaster() {} ChildProcessMaster::~ChildProcessMaster() { - if (connection != nullptr) - { - sendMessageToSlave (MemoryBlock (killMessage, specialMessageSize)); - connection->disconnect(); - connection.reset(); - } + killSlaveProcess(); } void ChildProcessMaster::handleConnectionLost() {} @@ -143,10 +138,10 @@ bool ChildProcessMaster::sendMessageToSlave (const MemoryBlock& mb) return false; } -bool ChildProcessMaster::launchSlaveProcess (const File& executable, const String& commandLineUniqueID, int timeoutMs, int streamFlags) +bool ChildProcessMaster::launchSlaveProcess (const File& executable, const String& commandLineUniqueID, + int timeoutMs, int streamFlags) { - connection.reset(); - jassert (childProcess.kill()); + killSlaveProcess(); auto pipeName = "p" + String::toHexString (Random().nextInt64()); @@ -154,13 +149,15 @@ bool ChildProcessMaster::launchSlaveProcess (const File& executable, const Strin args.add (executable.getFullPathName()); args.add (getCommandLinePrefix (commandLineUniqueID) + pipeName); - if (childProcess.start (args, streamFlags)) + childProcess.reset (new ChildProcess()); + + if (childProcess->start (args, streamFlags)) { connection = new Connection (*this, pipeName, timeoutMs <= 0 ? defaultTimeoutMs : timeoutMs); if (connection->isConnected()) { - sendMessageToSlave (MemoryBlock (startMessage, specialMessageSize)); + sendMessageToSlave ({ startMessage, specialMessageSize }); return true; } @@ -170,6 +167,18 @@ bool ChildProcessMaster::launchSlaveProcess (const File& executable, const Strin return false; } +void ChildProcessMaster::killSlaveProcess() +{ + if (connection != nullptr) + { + sendMessageToSlave ({ killMessage, specialMessageSize }); + connection->disconnect(); + connection.reset(); + } + + childProcess.reset(); +} + //============================================================================== struct ChildProcessSlave::Connection : public InterprocessConnection, private ChildProcessPingThread @@ -201,23 +210,14 @@ private: { pingReceived(); - if (m.getSize() == specialMessageSize) - { - if (isPingMessage (m)) - return; + if (isMessageType (m, pingMessage)) + return; - if (memcmp (m.getData(), killMessage, specialMessageSize) == 0) - { - triggerConnectionLostMessage(); - return; - } + if (isMessageType (m, killMessage)) + return triggerConnectionLostMessage(); - if (memcmp (m.getData(), startMessage, specialMessageSize) == 0) - { - owner.handleConnectionMade(); - return; - } - } + if (isMessageType (m, startMessage)) + return owner.handleConnectionMade(); owner.handleMessageFromMaster (m); } @@ -245,12 +245,12 @@ bool ChildProcessSlave::initialiseFromCommandLine (const String& commandLine, const String& commandLineUniqueID, int timeoutMs) { - String prefix (getCommandLinePrefix (commandLineUniqueID)); + auto prefix = getCommandLinePrefix (commandLineUniqueID); if (commandLine.trim().startsWith (prefix)) { - String pipeName (commandLine.fromFirstOccurrenceOf (prefix, false, false) - .upToFirstOccurrenceOf (" ", false, false).trim()); + auto pipeName = commandLine.fromFirstOccurrenceOf (prefix, false, false) + .upToFirstOccurrenceOf (" ", false, false).trim(); if (pipeName.isNotEmpty()) { diff --git a/modules/juce_events/interprocess/juce_ConnectedChildProcess.h b/modules/juce_events/interprocess/juce_ConnectedChildProcess.h index 8f6cc8cc1e..b7a81cb3fa 100644 --- a/modules/juce_events/interprocess/juce_ConnectedChildProcess.h +++ b/modules/juce_events/interprocess/juce_ConnectedChildProcess.h @@ -135,7 +135,10 @@ public: */ ChildProcessMaster(); - /** Destructor. */ + /** Destructor. + Note that the destructor calls killSlaveProcess(), but doesn't wait for + the child process to finish terminating. + */ virtual ~ChildProcessMaster(); /** Attempts to launch and connect to a slave process. @@ -152,12 +155,20 @@ public: If this all works, the method returns true, and you can begin sending and receiving messages with the slave process. + + If a child process is already running, this will call killSlaveProcess() and + start a new one. */ bool launchSlaveProcess (const File& executableToLaunch, const String& commandLineUniqueID, int timeoutMs = 0, int streamFlags = ChildProcess::wantStdOut | ChildProcess::wantStdErr); + /** Sends a kill message to the slave, and disconnects from it. + Note that this won't wait for it to terminate. + */ + void killSlaveProcess(); + /** This will be called to deliver a message from the slave process. The call will probably be made on a background thread, so be careful with your thread-safety! */ @@ -176,7 +187,7 @@ public: bool sendMessageToSlave (const MemoryBlock&); private: - ChildProcess childProcess; + ScopedPointer childProcess; struct Connection; friend struct Connection;