提交 8cc2a5ea 编写于 作者: J Jason Malinowski

Workaround IExperimentationService having a UI thread dependency

Right now we are seeing deadlocks where MEF is trying to create
the RoslynVisualStudioWorkspace on a background thread, and that
deadlocks because the IExperimentationService it tries to use has a
UI thread dependency. This breaks that specific cycle by avoiding using
the IExperimentationService until on the UI thread -- we know we can't
be asked for document options until we have documents, and that can't
happen until we get projects. Thankfully, the creation of projects
are still UI affinitized so we can initialize it there.
上级 0d06776a
......@@ -41,6 +41,9 @@ public VisualStudioProject CreateAndAddToWorkspace(string projectSystemName, str
// HACK: Fetch this service to ensure it's still created on the UI thread; once this is moved off we'll need to fix up it's constructor to be free-threaded.
_visualStudioWorkspaceImpl.Services.GetRequiredService<VisualStudioMetadataReferenceManager>();
// HACK: since we're on the UI thread, ensure we initialize our options provider which depends on a UI-affinitized experimentation service
_visualStudioWorkspaceImpl.EnsureDocumentOptionProvidersInitialized();
var id = ProjectId.CreateNewId(projectSystemName);
var directoryNameOpt = creationInfo.FilePath != null ? Path.GetDirectoryName(creationInfo.FilePath) : null;
......
......@@ -15,6 +15,7 @@
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;
......@@ -91,11 +92,12 @@ internal abstract partial class VisualStudioWorkspaceImpl : VisualStudioWorkspac
internal FileWatchedPortableExecutableReferenceFactory FileWatchedReferenceFactory { get; }
private readonly Lazy<IProjectCodeModelFactory> _projectCodeModelFactory;
private readonly IEnumerable<IDocumentOptionsProviderFactory> _documentOptionsProviderFactories;
private bool _documentOptionsProvidersInitialized = false;
private readonly Dictionary<ProjectId, CompilationOutputs> _projectCompilationOutputs = new Dictionary<ProjectId, CompilationOutputs>();
private readonly object _projectCompilationOutputsGuard = new object();
public VisualStudioWorkspaceImpl(ExportProvider exportProvider, IAsyncServiceProvider asyncServiceProvider)
public VisualStudioWorkspaceImpl(ExportProvider exportProvider, IAsyncServiceProvider asyncServiceProvider, IEnumerable<CodeAnalysis.Options.IDocumentOptionsProviderFactory> documentOptionsProviderFactories)
: base(VisualStudioMefHostServices.Create(exportProvider))
{
_threadingContext = exportProvider.GetExportedValue<IThreadingContext>();
......@@ -103,6 +105,7 @@ public VisualStudioWorkspaceImpl(ExportProvider exportProvider, IAsyncServicePro
_textBufferFactoryService = exportProvider.GetExportedValue<ITextBufferFactoryService>();
_projectionBufferFactoryService = exportProvider.GetExportedValue<IProjectionBufferFactoryService>();
_projectCodeModelFactory = exportProvider.GetExport<IProjectCodeModelFactory>();
_documentOptionsProviderFactories = documentOptionsProviderFactories;
// We fetch this lazily because VisualStudioProjectFactory depends on VisualStudioWorkspaceImpl -- we have a circularity. Since this
// exists right now as a compat shim, we'll just do this.
......@@ -1885,5 +1888,27 @@ internal CompilationOutputs GetCompilationOutputs(ProjectId projectId)
return _projectCompilationOutputs.TryGetValue(projectId, out var outputs) ? outputs : CompilationOutputFiles.None;
}
}
internal void EnsureDocumentOptionProvidersInitialized()
{
_foregroundObject.AssertIsForeground();
if (_documentOptionsProvidersInitialized)
{
return;
}
_documentOptionsProvidersInitialized = true;
foreach (var providerFactory in _documentOptionsProviderFactories)
{
var optionsProvider = providerFactory.TryCreate(this);
if (optionsProvider != null)
{
Services.GetRequiredService<IOptionService>().RegisterDocumentOptionsProvider(optionsProvider);
}
}
}
}
}
......@@ -36,19 +36,9 @@ internal class RoslynVisualStudioWorkspace : VisualStudioWorkspaceImpl
[ImportMany] IEnumerable<Lazy<IStreamingFindUsagesPresenter>> streamingPresenters,
[ImportMany] IEnumerable<IDocumentOptionsProviderFactory> documentOptionsProviderFactories,
[Import(typeof(SVsServiceProvider))] IAsyncServiceProvider asyncServiceProvider)
: base(exportProvider, asyncServiceProvider)
: base(exportProvider, asyncServiceProvider, documentOptionsProviderFactories)
{
_streamingPresenters = streamingPresenters;
foreach (var providerFactory in documentOptionsProviderFactories)
{
var optionsProvider = providerFactory.TryCreate(this);
if (optionsProvider != null)
{
Services.GetRequiredService<IOptionService>().RegisterDocumentOptionsProvider(optionsProvider);
}
}
}
internal override IInvisibleEditor OpenInvisibleEditor(DocumentId documentId)
......
......@@ -23,6 +23,7 @@ Imports Microsoft.VisualStudio.Shell.Interop
Imports Moq
Imports Microsoft.VisualStudio.LanguageServices.Implementation.TaskList
Imports Microsoft.VisualStudio.LanguageServices.UnitTests.CodeModel
Imports Microsoft.CodeAnalysis.Options
Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim.Framework
......@@ -78,7 +79,9 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim.Fr
<ImportingConstructor>
Public Sub New(exportProvider As Composition.ExportProvider)
MyBase.New(exportProvider, exportProvider.GetExportedValue(Of MockServiceProvider))
MyBase.New(exportProvider,
exportProvider.GetExportedValue(Of MockServiceProvider),
exportProvider.GetExportedValues(Of IDocumentOptionsProviderFactory))
End Sub
Public Overrides Sub DisplayReferencedSymbols(solution As Microsoft.CodeAnalysis.Solution, referencedSymbols As IEnumerable(Of ReferencedSymbol))
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册