diff --git a/examples/Utilities/ChildProcessDemo.h b/examples/Utilities/ChildProcessDemo.h index e6eb544611..2b3c4a580a 100644 --- a/examples/Utilities/ChildProcessDemo.h +++ b/examples/Utilities/ChildProcessDemo.h @@ -98,7 +98,12 @@ public: testResultsBox.setFont ({ Font::getDefaultMonospacedFontName(), 12.0f, Font::plain }); logMessage (String ("This demo uses the ChildProcessCoordinator and ChildProcessWorker classes to launch and communicate " - "with a child process, sending messages in the form of serialised ValueTree objects.") + newLine); + "with a child process, sending messages in the form of serialised ValueTree objects.") + newLine + + String ("In this demo, the child process will automatically quit if it fails to receive a ping message at least every ") + + String (timeoutSeconds) + + String (" seconds. To keep the process alive, press the \"") + + pingButton.getButtonText() + + String ("\" button periodically.") + newLine); setSize (500, 500); } @@ -136,10 +141,14 @@ public: { if (coordinatorProcess.get() == nullptr) { - coordinatorProcess.reset (new DemoCoordinatorProcess (*this)); + coordinatorProcess = std::make_unique (*this); - if (coordinatorProcess->launchWorkerProcess (File::getSpecialLocation (File::currentExecutableFile), demoCommandLineUID)) + if (coordinatorProcess->launchWorkerProcess (File::getSpecialLocation (File::currentExecutableFile), + demoCommandLineUID, + timeoutMillis)) + { logMessage ("Child process started"); + } } } @@ -166,11 +175,14 @@ public: // This class is used by the main process, acting as the coordinator and receiving messages // from the worker process. class DemoCoordinatorProcess : public ChildProcessCoordinator, - private DeletedAtShutdown + private DeletedAtShutdown, + private AsyncUpdater { public: DemoCoordinatorProcess (ChildProcessDemo& d) : demo (d) {} + ~DemoCoordinatorProcess() override { cancelPendingUpdate(); } + // This gets called when a message arrives from the worker process.. void handleMessageFromWorker (const MemoryBlock& mb) override { @@ -183,6 +195,11 @@ public: void handleConnectionLost() override { demo.logMessage ("Connection lost to child process!"); + triggerAsyncUpdate(); + } + + void handleAsyncUpdate() override + { demo.killChildProcess(); } @@ -203,7 +220,11 @@ public: //============================================================================== std::unique_ptr coordinatorProcess; + static constexpr auto timeoutSeconds = 10; + static constexpr auto timeoutMillis = timeoutSeconds * 1000; + private: + TextButton launchButton { "Launch Child Process" }; TextButton pingButton { "Send Ping" }; TextButton killButton { "Kill Child Process" }; @@ -268,8 +289,8 @@ public: } /* If no pings are received from the coordinator process for a number of seconds, then this will get invoked. - Typically you'll want to use this as a signal to kill the process as quickly as possible, as you - don't want to leave it hanging around as a zombie.. + Typically, you'll want to use this as a signal to kill the process as quickly as possible, as you + don't want to leave it hanging around as a zombie. */ void handleConnectionLost() override { @@ -280,13 +301,13 @@ public: //============================================================================== /* The JUCEApplication::initialise method calls this function to allow the child process to launch when the command line parameters indicate that we're - being asked to run as a child process.. + being asked to run as a child process. */ bool invokeChildProcessDemo (const String& commandLine) { - std::unique_ptr worker (new DemoWorkerProcess()); + auto worker = std::make_unique(); - if (worker->initialiseFromCommandLine (commandLine, demoCommandLineUID)) + if (worker->initialiseFromCommandLine (commandLine, demoCommandLineUID, ChildProcessDemo::timeoutMillis)) { worker.release(); // allow the worker object to stay alive - it'll handle its own deletion. return true; @@ -316,7 +337,7 @@ bool invokeChildProcessDemo (const String& commandLine) if (invokeChildProcessDemo (commandLine)) return; - mainWindow.reset (new MainWindow ("ChildProcessDemo", new ChildProcessDemo())); + mainWindow = std::make_unique ("ChildProcessDemo", std::make_unique()); } void shutdown() override { mainWindow = nullptr; } @@ -325,13 +346,14 @@ bool invokeChildProcessDemo (const String& commandLine) class MainWindow : public DocumentWindow { public: - MainWindow (const String& name, Component* c) : DocumentWindow (name, - Desktop::getInstance().getDefaultLookAndFeel() - .findColour (ResizableWindow::backgroundColourId), - DocumentWindow::allButtons) + MainWindow (const String& name, std::unique_ptr c) + : DocumentWindow (name, + Desktop::getInstance().getDefaultLookAndFeel() + .findColour (ResizableWindow::backgroundColourId), + DocumentWindow::allButtons) { setUsingNativeTitleBar (true); - setContentOwned (c, true); + setContentOwned (c.release(), true); centreWithSize (getWidth(), getHeight());