未验证 提交 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.
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Remote;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.VisualStudio.Composition;
......@@ -25,10 +29,15 @@ internal class CSharpLanguageServerClient : AbstractLanguageServerClient
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public CSharpLanguageServerClient(
IThreadingContext threadingContext,
VisualStudioWorkspace workspace,
IEnumerable<Lazy<IOptionPersister>> lazyOptions,
LanguageServerClientEventListener eventListener,
IAsynchronousOperationListenerProvider listenerProvider)
: base(workspace,
: base(
threadingContext,
workspace,
lazyOptions,
eventListener,
listenerProvider,
languageServerName: WellKnownServiceHubServices.CSharpLanguageServer,
......
......@@ -13,12 +13,18 @@
using Microsoft.CodeAnalysis.Host;
using System.Composition;
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
{
internal abstract class AbstractLanguageServerClient : ILanguageClient
{
private readonly IThreadingContext _threadingContext;
private readonly Workspace _workspace;
private readonly IEnumerable<Lazy<IOptionPersister>> _lazyOptions;
private readonly LanguageServerClientEventListener _eventListener;
private readonly IAsynchronousOperationListener _asyncListener;
......@@ -55,13 +61,17 @@ internal abstract class AbstractLanguageServerClient : ILanguageClient
#pragma warning restore CS0067 // event never used
public AbstractLanguageServerClient(
IThreadingContext threadingContext,
Workspace workspace,
IEnumerable<Lazy<IOptionPersister>> lazyOptions,
LanguageServerClientEventListener eventListener,
IAsynchronousOperationListenerProvider listenerProvider,
string languageServerName,
string serviceHubClientName)
{
_threadingContext = threadingContext;
_workspace = workspace;
_lazyOptions = lazyOptions;
_eventListener = eventListener;
_asyncListener = listenerProvider.GetListener(FeatureAttribute.FindReferences);
......@@ -103,6 +113,9 @@ public Task OnLoadedAsync()
// set up event stream so that we start LSP server once Roslyn is loaded
_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.
// 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
......@@ -122,6 +135,24 @@ public Task OnLoadedAsync()
}, TaskScheduler.Default).CompletesAsyncOperation(token);
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>
......
......@@ -181,8 +181,7 @@ private void SetRemoteHostBitness()
var x64 = _workspace.Options.GetOption(RemoteHostOptions.OOP64Bit);
if (!x64)
{
x64 = _workspace.Services.GetService<IExperimentationService>().IsExperimentEnabled(
WellKnownExperimentNames.RoslynOOP64bit);
x64 = _workspace.Services.GetService<IExperimentationService>().IsExperimentEnabled(WellKnownExperimentNames.RoslynOOP64bit);
}
// log OOP bitness
......
......@@ -2,7 +2,9 @@
Imports System.ComponentModel.Composition
Imports Microsoft.CodeAnalysis.Editor
Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.Options
Imports Microsoft.CodeAnalysis.Remote
Imports Microsoft.CodeAnalysis.Shared.TestHooks
Imports Microsoft.VisualStudio.LanguageServer.Client
......@@ -23,10 +25,14 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.LanguageClient
<ImportingConstructor>
<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,
listenerProvider As IAsynchronousOperationListenerProvider)
MyBase.New(workspace,
MyBase.New(threadingContext,
workspace,
lazyOptions,
eventListener,
listenerProvider,
languageServerName:=WellKnownServiceHubServices.VisualBasicLanguageServer,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册