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 <guthadam@amazon.com>
This commit is contained in:
Guthrie Adams
2021-08-18 17:41:15 -05:00
parent 7814d7679c
commit 4b3ce6738f
4 changed files with 43 additions and 60 deletions
@@ -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);
@@ -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<AzToolsFramework::EditorPythonEventsInterface>::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<AzToolsFramework::EditorPythonEventsInterface>::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();
@@ -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)
@@ -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;