未验证 提交 d23ca432 编写于 作者: J Joey Robichaud 提交者: GitHub

Merge pull request #38356 from heejaechang/experimentService

Fix deadlock due to VS Experiement service jumping to UI thread in certain cases.
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Composition; using System.ComponentModel.Composition;
using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Remote; using Microsoft.CodeAnalysis.Remote;
using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.VisualStudio.Composition; using Microsoft.VisualStudio.Composition;
...@@ -25,10 +29,15 @@ internal class CSharpLanguageServerClient : AbstractLanguageServerClient ...@@ -25,10 +29,15 @@ internal class CSharpLanguageServerClient : AbstractLanguageServerClient
[ImportingConstructor] [ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public CSharpLanguageServerClient( public CSharpLanguageServerClient(
IThreadingContext threadingContext,
VisualStudioWorkspace workspace, VisualStudioWorkspace workspace,
IEnumerable<Lazy<IOptionPersister>> lazyOptions,
LanguageServerClientEventListener eventListener, LanguageServerClientEventListener eventListener,
IAsynchronousOperationListenerProvider listenerProvider) IAsynchronousOperationListenerProvider listenerProvider)
: base(workspace, : base(
threadingContext,
workspace,
lazyOptions,
eventListener, eventListener,
listenerProvider, listenerProvider,
languageServerName: WellKnownServiceHubServices.CSharpLanguageServer, languageServerName: WellKnownServiceHubServices.CSharpLanguageServer,
......
...@@ -13,12 +13,18 @@ ...@@ -13,12 +13,18 @@
using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host;
using System.Composition; using System.Composition;
using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Options;
using System.Linq;
using Microsoft.CodeAnalysis.Experiments;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService namespace Microsoft.VisualStudio.LanguageServices.Implementation.LanguageService
{ {
internal abstract class AbstractLanguageServerClient : ILanguageClient internal abstract class AbstractLanguageServerClient : ILanguageClient
{ {
private readonly IThreadingContext _threadingContext;
private readonly Workspace _workspace; private readonly Workspace _workspace;
private readonly IEnumerable<Lazy<IOptionPersister>> _lazyOptions;
private readonly LanguageServerClientEventListener _eventListener; private readonly LanguageServerClientEventListener _eventListener;
private readonly IAsynchronousOperationListener _asyncListener; private readonly IAsynchronousOperationListener _asyncListener;
...@@ -55,13 +61,17 @@ internal abstract class AbstractLanguageServerClient : ILanguageClient ...@@ -55,13 +61,17 @@ internal abstract class AbstractLanguageServerClient : ILanguageClient
#pragma warning restore CS0067 // event never used #pragma warning restore CS0067 // event never used
public AbstractLanguageServerClient( public AbstractLanguageServerClient(
IThreadingContext threadingContext,
Workspace workspace, Workspace workspace,
IEnumerable<Lazy<IOptionPersister>> lazyOptions,
LanguageServerClientEventListener eventListener, LanguageServerClientEventListener eventListener,
IAsynchronousOperationListenerProvider listenerProvider, IAsynchronousOperationListenerProvider listenerProvider,
string languageServerName, string languageServerName,
string serviceHubClientName) string serviceHubClientName)
{ {
_threadingContext = threadingContext;
_workspace = workspace; _workspace = workspace;
_lazyOptions = lazyOptions;
_eventListener = eventListener; _eventListener = eventListener;
_asyncListener = listenerProvider.GetListener(FeatureAttribute.FindReferences); _asyncListener = listenerProvider.GetListener(FeatureAttribute.FindReferences);
...@@ -103,6 +113,9 @@ public Task OnLoadedAsync() ...@@ -103,6 +113,9 @@ public Task OnLoadedAsync()
// set up event stream so that we start LSP server once Roslyn is loaded // set up event stream so that we start LSP server once Roslyn is loaded
_eventListener.WorkspaceStarted.ContinueWith(async _ => _eventListener.WorkspaceStarted.ContinueWith(async _ =>
{ {
// initialize things on UI thread
await InitializeOnUIAsync().ConfigureAwait(false);
// this might get called before solution is fully loaded and before file is opened. // this might get called before solution is fully loaded and before file is opened.
// we delay our OOP start until then, but user might do vsstart before that. so we make sure we start OOP if // we delay our OOP start until then, but user might do vsstart before that. so we make sure we start OOP if
// it is not running yet. multiple start is no-op // it is not running yet. multiple start is no-op
...@@ -122,6 +135,24 @@ public Task OnLoadedAsync() ...@@ -122,6 +135,24 @@ public Task OnLoadedAsync()
}, TaskScheduler.Default).CompletesAsyncOperation(token); }, TaskScheduler.Default).CompletesAsyncOperation(token);
return Task.CompletedTask; return Task.CompletedTask;
async Task InitializeOnUIAsync()
{
await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync();
// this doesn't attempt to solve our JTF and some services being not free-thread issue here, but
// try to fix this particular deadlock issue only. we already have long discussion on
// how we need to deal with JTF, Roslyn service requirements and VS services reality conflicting
// each others. architectural fix should come from the result of that discussion.
// Ensure the options persisters are loaded since we have to fetch options from the shell
_lazyOptions.Select(o => o.Value);
// experimentation service unfortunately uses JTF to jump to UI thread in certain cases
// which can cause deadlock if 2 parties try to enable OOP from BG and then FG before
// experimentation service tries to jump to UI thread.
var experimentationService = _workspace.Services.GetService<IExperimentationService>();
}
} }
/// <summary> /// <summary>
......
...@@ -181,8 +181,7 @@ private void SetRemoteHostBitness() ...@@ -181,8 +181,7 @@ private void SetRemoteHostBitness()
var x64 = _workspace.Options.GetOption(RemoteHostOptions.OOP64Bit); var x64 = _workspace.Options.GetOption(RemoteHostOptions.OOP64Bit);
if (!x64) if (!x64)
{ {
x64 = _workspace.Services.GetService<IExperimentationService>().IsExperimentEnabled( x64 = _workspace.Services.GetService<IExperimentationService>().IsExperimentEnabled(WellKnownExperimentNames.RoslynOOP64bit);
WellKnownExperimentNames.RoslynOOP64bit);
} }
// log OOP bitness // log OOP bitness
......
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
Imports System.ComponentModel.Composition Imports System.ComponentModel.Composition
Imports Microsoft.CodeAnalysis.Editor Imports Microsoft.CodeAnalysis.Editor
Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities
Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.Options
Imports Microsoft.CodeAnalysis.Remote Imports Microsoft.CodeAnalysis.Remote
Imports Microsoft.CodeAnalysis.Shared.TestHooks Imports Microsoft.CodeAnalysis.Shared.TestHooks
Imports Microsoft.VisualStudio.LanguageServer.Client Imports Microsoft.VisualStudio.LanguageServer.Client
...@@ -23,10 +25,14 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.LanguageClient ...@@ -23,10 +25,14 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.LanguageClient
<ImportingConstructor> <ImportingConstructor>
<Obsolete(MefConstruction.ImportingConstructorMessage, True)> <Obsolete(MefConstruction.ImportingConstructorMessage, True)>
Public Sub New(workspace As VisualStudioWorkspace, Public Sub New(threadingContext As IThreadingContext,
workspace As VisualStudioWorkspace,
lazyOptions As IEnumerable(Of Lazy(Of IOptionPersister)),
eventListener As LanguageServerClientEventListener, eventListener As LanguageServerClientEventListener,
listenerProvider As IAsynchronousOperationListenerProvider) listenerProvider As IAsynchronousOperationListenerProvider)
MyBase.New(workspace, MyBase.New(threadingContext,
workspace,
lazyOptions,
eventListener, eventListener,
listenerProvider, listenerProvider,
languageServerName:=WellKnownServiceHubServices.VisualBasicLanguageServer, languageServerName:=WellKnownServiceHubServices.VisualBasicLanguageServer,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册