LSP: use asynchronous shutdown for running servers

Change-Id: I3b1853177d07c98e051de0bc9f494389fbf4c104
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
David Schulz
2018-09-13 15:31:00 +02:00
parent 41dee83bec
commit 5ef4530b8f
4 changed files with 48 additions and 6 deletions

View File

@@ -82,8 +82,7 @@ LanguageClientManager::LanguageClientManager()
LanguageClientManager::~LanguageClientManager() LanguageClientManager::~LanguageClientManager()
{ {
for (auto interface : Utils::filtered(m_clients, &BaseClient::reachable)) QTC_ASSERT(m_clients.isEmpty(), qDeleteAll(m_clients));
interface->shutdown();
} }
void LanguageClientManager::init() void LanguageClientManager::init()
@@ -168,6 +167,8 @@ void LanguageClientManager::removeMarks(const Core::Id &id)
void LanguageClientManager::startClient(LanguageClientSettings setting) void LanguageClientManager::startClient(LanguageClientSettings setting)
{ {
if (managerInstance->m_shuttingDown)
return;
auto client = new StdIOClient(setting.m_executable, setting.m_arguments); auto client = new StdIOClient(setting.m_executable, setting.m_arguments);
client->setName(setting.m_name); client->setName(setting.m_name);
if (setting.m_mimeType != noLanguageFilter) if (setting.m_mimeType != noLanguageFilter)
@@ -177,6 +178,10 @@ void LanguageClientManager::startClient(LanguageClientSettings setting)
void LanguageClientManager::startClient(BaseClient *client) void LanguageClientManager::startClient(BaseClient *client)
{ {
if (managerInstance->m_shuttingDown) {
managerInstance->clientFinished(client);
return;
}
if (!managerInstance->m_clients.contains(client)) if (!managerInstance->m_clients.contains(client))
managerInstance->m_clients.append(client); managerInstance->m_clients.append(client);
connect(client, &BaseClient::finished, managerInstance, [client](){ connect(client, &BaseClient::finished, managerInstance, [client](){
@@ -215,6 +220,20 @@ void LanguageClientManager::deleteClient(BaseClient *client)
delete client; delete client;
} }
void LanguageClientManager::shutdown()
{
if (managerInstance->m_shuttingDown)
return;
managerInstance->m_shuttingDown = true;
for (auto interface : managerInstance->m_clients)
interface->shutdown();
}
LanguageClientManager *LanguageClientManager::instance()
{
return managerInstance;
}
QVector<BaseClient *> LanguageClientManager::reachableClients() QVector<BaseClient *> LanguageClientManager::reachableClients()
{ {
return Utils::filtered(m_clients, &BaseClient::reachable); return Utils::filtered(m_clients, &BaseClient::reachable);
@@ -236,15 +255,17 @@ void LanguageClientManager::clientFinished(BaseClient *client)
constexpr int restartTimeoutS = 5; constexpr int restartTimeoutS = 5;
const bool unexpectedFinish = client->state() != BaseClient::Shutdown const bool unexpectedFinish = client->state() != BaseClient::Shutdown
&& client->state() != BaseClient::ShutdownRequested; && client->state() != BaseClient::ShutdownRequested;
if (unexpectedFinish) { if (unexpectedFinish && !m_shuttingDown) {
managerInstance->removeMarks(client->id()); removeMarks(client->id());
client->disconnect(managerInstance); client->disconnect(this);
client->log(tr("Unexpectedly finished. Restarting in %1 seconds.").arg(restartTimeoutS), client->log(tr("Unexpectedly finished. Restarting in %1 seconds.").arg(restartTimeoutS),
Core::MessageManager::Flash); Core::MessageManager::Flash);
client->reset(); client->reset();
QTimer::singleShot(restartTimeoutS * 1000, this, [client](){ startClient(client); }); QTimer::singleShot(restartTimeoutS * 1000, client, [client](){ startClient(client); });
} else { } else {
deleteClient(client); deleteClient(client);
if (m_shuttingDown && m_clients.isEmpty())
emit shutdownFinished();
} }
} }

View File

@@ -70,6 +70,13 @@ public:
static void deleteClient(BaseClient *client); static void deleteClient(BaseClient *client);
static void shutdown();
static LanguageClientManager *instance();
signals:
void shutdownFinished();
private: private:
LanguageClientManager(); LanguageClientManager();
LanguageClientManager(const LanguageClientManager &other) = delete; LanguageClientManager(const LanguageClientManager &other) = delete;
@@ -90,6 +97,7 @@ private:
void clientFinished(BaseClient *client); void clientFinished(BaseClient *client);
bool m_shuttingDown = false;
QVector<BaseClient *> m_clients; QVector<BaseClient *> m_clients;
QHash<Utils::FileName, QHash<Core::Id, QVector<LanguageClientMark *>>> m_marks; QHash<Utils::FileName, QHash<Core::Id, QVector<LanguageClientMark *>>> m_marks;
QHash<LanguageServerProtocol::MessageId, QList<BaseClient *>> m_exclusiveRequests; QHash<LanguageServerProtocol::MessageId, QList<BaseClient *>> m_exclusiveRequests;

View File

@@ -25,6 +25,8 @@
#include "languageclientplugin.h" #include "languageclientplugin.h"
#include "baseclient.h"
namespace LanguageClient { namespace LanguageClient {
bool LanguageClientPlugin::initialize(const QStringList & /*arguments*/, QString * /*errorString*/) bool LanguageClientPlugin::initialize(const QStringList & /*arguments*/, QString * /*errorString*/)
@@ -38,4 +40,14 @@ void LanguageClientPlugin::extensionsInitialized()
LanguageClientSettings::init(); LanguageClientSettings::init();
} }
ExtensionSystem::IPlugin::ShutdownFlag LanguageClientPlugin::aboutToShutdown()
{
LanguageClientManager::shutdown();
if (LanguageClientManager::clients().isEmpty())
return ExtensionSystem::IPlugin::SynchronousShutdown;
connect(LanguageClientManager::instance(), &LanguageClientManager::shutdownFinished,
this, &ExtensionSystem::IPlugin::asynchronousShutdownFinished);
return ExtensionSystem::IPlugin::AsynchronousShutdown;
}
} // namespace LanguageClient } // namespace LanguageClient

View File

@@ -43,6 +43,7 @@ public:
private: private:
bool initialize(const QStringList &arguments, QString *errorString) override; bool initialize(const QStringList &arguments, QString *errorString) override;
void extensionsInitialized() override; void extensionsInitialized() override;
ShutdownFlag aboutToShutdown() override;
private: private:
LanguageClientManager m_clientManager; LanguageClientManager m_clientManager;