From 4b3ce6738fab46fd3134b7a9b3a1b5f967dc7a84 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Wed, 18 Aug 2021 17:41:15 -0500 Subject: [PATCH] AtomTools: fix multiple material editor processes launching Atom tools launch or check for the existence of a local server in order to prevent multiple application processes from running. These checks were being done far too late, after initialization and asset processing, leaving time for multiple processes to start before the server or checks. Zombie processes could start and run indefinitely without user interaction because the event loop was being entered despite the request to exit the application early. These changes launch the server and checks immediately after the application object is constructed and exit before any other work is done if the application will not be run. Signed-off-by: Guthrie Adams --- .../Application/AtomToolsApplication.h | 4 +- .../Application/AtomToolsApplication.cpp | 81 +++++++------------ .../Tools/MaterialEditor/Code/Source/main.cpp | 7 +- .../Code/Source/main.cpp | 11 ++- 4 files changed, 43 insertions(+), 60 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h index 3639606f03..6421c877b0 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h @@ -46,6 +46,8 @@ namespace AtomToolsFramework AtomToolsApplication(int* argc, char*** argv); ~AtomToolsApplication(); + virtual bool LaunchLocalServer(); + ////////////////////////////////////////////////////////////////////////// // AzFramework::Application void CreateReflectionManager() override; @@ -106,8 +108,6 @@ namespace AtomToolsFramework virtual void UnloadSettings(); virtual void CompileCriticalAssets(); virtual void ProcessCommandLine(const AZ::CommandLine& commandLine); - virtual bool LaunchDiscoveryService(); - virtual void StartInternal(); static void PyIdleWaitFrames(uint32_t frames); diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp index efd3fec0e8..4cc98a15aa 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp @@ -152,7 +152,33 @@ namespace AtomToolsFramework Base::StartCommon(systemEntity); - StartInternal(); + m_traceLogger.PrepareLogFile(GetBuildTargetName() + ".log"); + + AzToolsFramework::AssetDatabase::AssetDatabaseRequestsBus::Handler::BusConnect(); + AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotificationBus::Broadcast( + &AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotifications::OnDatabaseInitialized); + + AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, "@assets@/assetcatalog.xml"); + + AZ::RPI::RPISystemInterface::Get()->InitializeSystemAssets(); + + LoadSettings(); + + AtomToolsMainWindowNotificationBus::Handler::BusConnect(); + + AtomToolsMainWindowFactoryRequestBus::Broadcast(&AtomToolsMainWindowFactoryRequestBus::Handler::CreateMainWindow); + + auto editorPythonEventsInterface = AZ::Interface::Get(); + if (editorPythonEventsInterface) + { + // The PythonSystemComponent does not call StartPython to allow for lazy python initialization, so start it here + // The PythonSystemComponent will call StopPython when it deactivates, so we do not need our own corresponding call to + // StopPython + editorPythonEventsInterface->StartPython(); + } + + // Delay execution of commands and scripts post initialization + QTimer::singleShot(0, [this]() { ProcessCommandLine(m_commandLine); }); m_timer.start(); } @@ -334,7 +360,7 @@ namespace AtomToolsFramework } } - bool AtomToolsApplication::LaunchDiscoveryService() + bool AtomToolsApplication::LaunchLocalServer() { // Determine if this is the first launch of the tool by attempting to connect to a running server if (m_socket.Connect(QApplication::applicationName())) @@ -376,7 +402,7 @@ namespace AtomToolsFramework { AZ::CommandLine commandLine; commandLine.Parse(tokens); - ProcessCommandLine(commandLine); + QTimer::singleShot(0, [this, commandLine]() { ProcessCommandLine(commandLine); }); } } }); @@ -390,55 +416,6 @@ namespace AtomToolsFramework return true; } - void AtomToolsApplication::StartInternal() - { - if (WasExitMainLoopRequested()) - { - return; - } - - AZStd::string fileName = GetBuildTargetName() + ".log"; - - m_traceLogger.PrepareLogFile(fileName.c_str()); - - if (!LaunchDiscoveryService()) - { - ExitMainLoop(); - return; - } - - AzToolsFramework::AssetDatabase::AssetDatabaseRequestsBus::Handler::BusConnect(); - AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotificationBus::Broadcast( - &AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotifications::OnDatabaseInitialized); - - AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, "@assets@/assetcatalog.xml"); - - AZ::RPI::RPISystemInterface::Get()->InitializeSystemAssets(); - - LoadSettings(); - - AtomToolsMainWindowNotificationBus::Handler::BusConnect(); - - AtomToolsMainWindowFactoryRequestBus::Broadcast(&AtomToolsMainWindowFactoryRequestBus::Handler::CreateMainWindow); - - auto editorPythonEventsInterface = AZ::Interface::Get(); - if (editorPythonEventsInterface) - { - // The PythonSystemComponent does not call StartPython to allow for lazy python initialization, so start it here - // The PythonSystemComponent will call StopPython when it deactivates, so we do not need our own corresponding call to - // StopPython - editorPythonEventsInterface->StartPython(); - } - - // Delay execution of commands and scripts post initialization - QTimer::singleShot( - 0, - [this]() - { - ProcessCommandLine(m_commandLine); - }); - } - bool AtomToolsApplication::GetAssetDatabaseLocation(AZStd::string& result) { AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get(); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/main.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/main.cpp index 47432ed83c..de29c27b71 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/main.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/main.cpp @@ -28,9 +28,12 @@ int main(int argc, char** argv) AzQtComponents::AzQtApplication::InitializeDpiScaling(); MaterialEditor::MaterialEditorApplication app(&argc, &argv); + if (!app.LaunchLocalServer()) + { + return 0; + } - auto globalEventFilter = new AzQtComponents::GlobalEventFilter(&app); - app.installEventFilter(globalEventFilter); + app.installEventFilter(new AzQtComponents::GlobalEventFilter(&app)); AZ::IO::FixedMaxPath engineRootPath; if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/main.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/main.cpp index d6f017eee8..cf3f25cf6c 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/main.cpp +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/main.cpp @@ -28,6 +28,12 @@ int main(int argc, char** argv) AzQtComponents::AzQtApplication::InitializeDpiScaling(); ShaderManagementConsole::ShaderManagementConsoleApplication app(&argc, &argv); + if (!app.LaunchLocalServer()) + { + return 0; + } + + app.installEventFilter(new AzQtComponents::GlobalEventFilter(&app)); AZ::IO::FixedMaxPath engineRootPath; if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) @@ -35,13 +41,10 @@ int main(int argc, char** argv) settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); } - auto globalEventFilter = new AzQtComponents::GlobalEventFilter(&app); - app.installEventFilter(globalEventFilter); - AzQtComponents::StyleManager styleManager(&app); styleManager.initialize(&app, engineRootPath); - app.Start({}); + app.Start(AZ::ComponentApplication::Descriptor{}); app.exec(); app.Stop(); return 0;