From 171afa2b08b9ecf1c4148aef554b0c586ca6cc48 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Mon, 15 Feb 2016 17:58:14 -0800 Subject: [PATCH] Fix #159: LanguageServer.Shutdown hangs on flush The change fixes an issue in the LanguageServer's Shutdown method where buffered output in the OutputDebouncer gets flushed before shutting down. The problem here is the Wait call which blocks the message dispatcher thread from completing the OutputDebouncer.OnFlush method's SendEvent call. The fix is to change the Shutdown method to async so that the Flush call can be awaited, unblocking the message dispatcher thread's SynchronizationContext for the SendEvent call to complete. --- .../Server/LanguageServer.cs | 4 ++-- .../Server/LanguageServerBase.cs | 24 +++++++++---------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs index 571c3fa67..ebbb33b79 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs @@ -80,10 +80,10 @@ protected override void Initialize() this.SetRequestHandler(DebugAdapterMessages.EvaluateRequest.Type, this.HandleEvaluateRequest); } - protected override void Shutdown() + protected override async Task Shutdown() { // Make sure remaining output is flushed before exiting - this.outputDebouncer.Flush().Wait(); + await this.outputDebouncer.Flush(); Logger.Write(LogLevel.Normal, "Language service is shutting down..."); diff --git a/src/PowerShellEditorServices.Protocol/Server/LanguageServerBase.cs b/src/PowerShellEditorServices.Protocol/Server/LanguageServerBase.cs index 57d477bc8..f9a9219c5 100644 --- a/src/PowerShellEditorServices.Protocol/Server/LanguageServerBase.cs +++ b/src/PowerShellEditorServices.Protocol/Server/LanguageServerBase.cs @@ -34,11 +34,9 @@ protected override Task OnStart() return Task.FromResult(true); } - protected override Task OnStop() + protected override async Task OnStop() { - this.Shutdown(); - - return Task.FromResult(true); + await this.Shutdown(); } /// @@ -49,37 +47,37 @@ protected override Task OnStop() /// /// Can be overridden by the subclass to provide shutdown - /// logic before the server exits. + /// logic before the server exits. Subclasses do not need + /// to invoke or return the value of the base implementation. /// - protected virtual void Shutdown() + protected virtual Task Shutdown() { // No default implementation yet. + return Task.FromResult(true); } - private Task HandleShutdownRequest( + private async Task HandleShutdownRequest( object shutdownParams, RequestContext requestContext) { // Allow the implementor to shut down gracefully - this.Shutdown(); + await this.Shutdown(); - return requestContext.SendResult(new object()); + await requestContext.SendResult(new object()); } - private Task HandleExitNotification( + private async Task HandleExitNotification( object exitParams, EventContext eventContext) { // Stop the server channel - this.Stop(); + await this.Stop(); // Notify any waiter that the server has exited if (this.serverExitedTask != null) { this.serverExitedTask.SetResult(true); } - - return Task.FromResult(true); } } }