From 3541b692f56a8510761c036e409d66f46f8a1540 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 23 May 2023 11:02:15 +0200 Subject: [PATCH] LanguageClient: track clients scheduled for deletion So report an async shutdown if we have clients scheduled for deletion and wait until all clients have been fully deleted. Change-Id: I40d35d3429003ab2a5c68cb81486c3e16b5f6f63 Reviewed-by: Christian Stenger Reviewed-by: Qt CI Bot --- .../languageclient/languageclientmanager.cpp | 23 ++++++++++++++++++- .../languageclient/languageclientmanager.h | 4 ++++ .../languageclient/languageclientplugin.cpp | 4 ++-- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 482f4e8e39e..50a38071892 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -189,7 +189,7 @@ void LanguageClientManager::clientFinished(Client *client) } } deleteClient(client); - if (PluginManager::isShuttingDown() && managerInstance->m_clients.isEmpty()) + if (isShutdownFinished()) emit managerInstance->shutdownFinished(); } @@ -243,6 +243,7 @@ void LanguageClientManager::deleteClient(Client *client) // that will not handle the delete later event. Use invokeMethod with Qt::QueuedConnection // instead. QMetaObject::invokeMethod(client, [client] {delete client;}, Qt::QueuedConnection); + managerInstance->trackClientDeletion(client); if (!PluginManager::isShuttingDown()) emit instance()->clientRemoved(client); @@ -608,4 +609,24 @@ void LanguageClientManager::projectAdded(ProjectExplorer::Project *project) client->projectOpened(project); } +void LanguageClientManager::trackClientDeletion(Client *client) +{ + QTC_ASSERT(!m_scheduledForDeletion.contains(client->id()), return); + m_scheduledForDeletion.insert(client->id()); + connect(client, &QObject::destroyed, [this, id = client->id()](){ + m_scheduledForDeletion.remove(id); + if (isShutdownFinished()) + emit shutdownFinished(); + }); +} + +bool LanguageClientManager::isShutdownFinished() +{ + if (!PluginManager::isShuttingDown()) + return false; + QTC_ASSERT(managerInstance, return true); + return managerInstance->m_clients.isEmpty() + && managerInstance->m_scheduledForDeletion.isEmpty(); +} + } // namespace LanguageClient diff --git a/src/plugins/languageclient/languageclientmanager.h b/src/plugins/languageclient/languageclientmanager.h index e29d87a0f23..0a38b3d3872 100644 --- a/src/plugins/languageclient/languageclientmanager.h +++ b/src/plugins/languageclient/languageclientmanager.h @@ -48,6 +48,7 @@ public: static void deleteClient(Client *client); static void shutdown(); + static bool isShutdownFinished(); static LanguageClientManager *instance(); @@ -96,6 +97,8 @@ private: void updateProject(ProjectExplorer::Project *project); void projectAdded(ProjectExplorer::Project *project); + void trackClientDeletion(Client *client); + QList reachableClients(); QList m_clients; @@ -105,6 +108,7 @@ private: QHash> m_clientForDocument; std::unique_ptr d; LspInspector m_inspector; + QSet m_scheduledForDeletion; }; template bool LanguageClientManager::hasClients() diff --git a/src/plugins/languageclient/languageclientplugin.cpp b/src/plugins/languageclient/languageclientplugin.cpp index 7332f03e2b1..b6b411f8cb4 100644 --- a/src/plugins/languageclient/languageclientplugin.cpp +++ b/src/plugins/languageclient/languageclientplugin.cpp @@ -60,12 +60,12 @@ void LanguageClientPlugin::extensionsInitialized() ExtensionSystem::IPlugin::ShutdownFlag LanguageClientPlugin::aboutToShutdown() { LanguageClientManager::shutdown(); - if (LanguageClientManager::clients().isEmpty()) + if (LanguageClientManager::isShutdownFinished()) return ExtensionSystem::IPlugin::SynchronousShutdown; QTC_ASSERT(LanguageClientManager::instance(), return ExtensionSystem::IPlugin::SynchronousShutdown); connect(LanguageClientManager::instance(), &LanguageClientManager::shutdownFinished, - this, &ExtensionSystem::IPlugin::asynchronousShutdownFinished, Qt::QueuedConnection); + this, &ExtensionSystem::IPlugin::asynchronousShutdownFinished); return ExtensionSystem::IPlugin::AsynchronousShutdown; }