Skip to content

Commit 2e8fcbe

Browse files
authored
Another attempt to move MiscellaneousFilesWorkspace to a bg thread (#77768)
This previously failed with integration test failures. I attribute this to previously trying to move the VisualStudioMetadataReferenceManager when that very much wants to be on the main thread. Instead, just ensure that the code that creates the VisualStudioMetadataReferenceManager is on the main thread when that value is needed (it already was). 1) Move MiscellaneousFilesWorkspace to bg thread MEF construction 2) Move HostServicesProvider to location of VisualStudioMefHostServices and use in a couple places (this prevents MiscellaneousFilesWorkspace from needing to MEF import VisualStudioWorkspace in it's ctor)
1 parent 9654a4d commit 2e8fcbe

File tree

2 files changed

+38
-31
lines changed

2 files changed

+38
-31
lines changed

src/VisualStudio/Core/Def/LanguageService/AbstractPackage`2.cs

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ protected override void RegisterInitializeAsyncWork(PackageLoadTasks packageInit
3939
base.RegisterInitializeAsyncWork(packageInitializationTasks);
4040

4141
packageInitializationTasks.AddTask(isMainThreadTask: true, task: PackageInitializationMainThreadAsync);
42+
packageInitializationTasks.AddTask(isMainThreadTask: false, task: PackageInitializationBackgroundThreadAsync);
4243
}
4344

4445
private async Task PackageInitializationMainThreadAsync(PackageLoadTasks packageInitializationTasks, CancellationToken cancellationToken)
@@ -58,35 +59,33 @@ private async Task PackageInitializationMainThreadAsync(PackageLoadTasks package
5859
RegisterEditorFactory(editorFactory);
5960
}
6061

61-
// Misc workspace has to be up and running by the time our package is usable so that it can track running
62-
// doc events and appropriately map files to/from it and other relevant workspaces (like the
63-
// metadata-as-source workspace).
64-
var miscellaneousFilesWorkspace = this.ComponentModel.GetService<MiscellaneousFilesWorkspace>();
65-
6662
// awaiting an IVsTask guarantees to return on the captured context
6763
await shell.LoadPackageAsync(Guids.RoslynPackageId);
64+
}
6865

69-
packageInitializationTasks.AddTask(
70-
isMainThreadTask: false,
71-
task: (PackageLoadTasks packageInitializationTasks, CancellationToken cancellationToken) =>
72-
{
73-
RegisterLanguageService(typeof(TLanguageService), async cancellationToken =>
74-
{
75-
// Ensure we're on the BG when creating the language service.
76-
await TaskScheduler.Default;
66+
private Task PackageInitializationBackgroundThreadAsync(PackageLoadTasks packageInitializationTasks, CancellationToken cancellationToken)
67+
{
68+
RegisterLanguageService(typeof(TLanguageService), async cancellationToken =>
69+
{
70+
// Ensure we're on the BG when creating the language service.
71+
await TaskScheduler.Default;
72+
73+
// Create the language service, tell it to set itself up, then store it in a field
74+
// so we can notify it that it's time to clean up.
75+
_languageService = CreateLanguageService();
76+
await _languageService.SetupAsync(cancellationToken).ConfigureAwait(false);
7777

78-
// Create the language service, tell it to set itself up, then store it in a field
79-
// so we can notify it that it's time to clean up.
80-
_languageService = CreateLanguageService();
81-
await _languageService.SetupAsync(cancellationToken).ConfigureAwait(false);
78+
return _languageService.ComAggregate!;
79+
});
8280

83-
return _languageService.ComAggregate!;
84-
});
81+
// Misc workspace has to be up and running by the time our package is usable so that it can track running
82+
// doc events and appropriately map files to/from it and other relevant workspaces (like the
83+
// metadata-as-source workspace).
84+
var miscellaneousFilesWorkspace = this.ComponentModel.GetService<MiscellaneousFilesWorkspace>();
8585

86-
RegisterMiscellaneousFilesWorkspaceInformation(miscellaneousFilesWorkspace);
86+
RegisterMiscellaneousFilesWorkspaceInformation(miscellaneousFilesWorkspace);
8787

88-
return Task.CompletedTask;
89-
});
88+
return Task.CompletedTask;
9089
}
9190

9291
protected override void RegisterOnAfterPackageLoadedAsyncWork(PackageLoadTasks afterPackageLoadedTasks)

src/VisualStudio/Core/Def/ProjectSystem/MiscellaneousFilesWorkspace.cs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ internal sealed partial class MiscellaneousFilesWorkspace : Workspace, IOpenText
3131
private readonly IThreadingContext _threadingContext;
3232
private readonly IVsService<IVsTextManager> _textManagerService;
3333
private readonly OpenTextBufferProvider _openTextBufferProvider;
34-
private readonly IMetadataAsSourceFileService _fileTrackingMetadataAsSourceService;
34+
private readonly Lazy<IMetadataAsSourceFileService> _fileTrackingMetadataAsSourceService;
3535

3636
private readonly ConcurrentDictionary<Guid, LanguageInformation> _languageInformationByLanguageGuid = [];
3737

@@ -47,24 +47,24 @@ internal sealed partial class MiscellaneousFilesWorkspace : Workspace, IOpenText
4747
/// </summary>
4848
private readonly Dictionary<string, (ProjectId projectId, SourceTextContainer textContainer)> _monikersToProjectIdAndContainer = [];
4949

50-
private readonly ImmutableArray<MetadataReference> _metadataReferences;
50+
private readonly Lazy<ImmutableArray<MetadataReference>> _metadataReferences;
5151

5252
[ImportingConstructor]
5353
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
5454
public MiscellaneousFilesWorkspace(
5555
IThreadingContext threadingContext,
5656
IVsService<SVsTextManager, IVsTextManager> textManagerService,
5757
OpenTextBufferProvider openTextBufferProvider,
58-
IMetadataAsSourceFileService fileTrackingMetadataAsSourceService,
59-
VisualStudioWorkspace visualStudioWorkspace)
60-
: base(visualStudioWorkspace.Services.HostServices, WorkspaceKind.MiscellaneousFiles)
58+
Lazy<IMetadataAsSourceFileService> fileTrackingMetadataAsSourceService,
59+
Composition.ExportProvider exportProvider)
60+
: base(VisualStudioMefHostServices.Create(exportProvider), WorkspaceKind.MiscellaneousFiles)
6161
{
6262
_threadingContext = threadingContext;
6363
_textManagerService = textManagerService;
6464
_openTextBufferProvider = openTextBufferProvider;
6565
_fileTrackingMetadataAsSourceService = fileTrackingMetadataAsSourceService;
6666

67-
_metadataReferences = [.. CreateMetadataReferences()];
67+
_metadataReferences = new(() => [.. CreateMetadataReferences()]);
6868

6969
_openTextBufferProvider.AddListener(this);
7070
}
@@ -122,6 +122,10 @@ public void RegisterLanguage(Guid languageGuid, string languageName, string scri
122122

123123
private IEnumerable<MetadataReference> CreateMetadataReferences()
124124
{
125+
// VisualStudioMetadataReferenceManager construction requires the main thread
126+
// TODO: Determine if main thread affinity can be removed: https://github.com/dotnet/roslyn/issues/77791
127+
_threadingContext.ThrowIfNotOnUIThread();
128+
125129
var manager = this.Services.GetService<VisualStudioMetadataReferenceManager>();
126130
var searchPaths = VisualStudioMetadataReferenceManager.GetReferencePaths();
127131

@@ -261,7 +265,7 @@ private void AttachToDocument(string moniker, ITextBuffer textBuffer)
261265
{
262266
_threadingContext.ThrowIfNotOnUIThread();
263267

264-
if (_fileTrackingMetadataAsSourceService.TryAddDocumentToWorkspace(moniker, textBuffer.AsTextContainer(), out var _))
268+
if (_fileTrackingMetadataAsSourceService.Value.TryAddDocumentToWorkspace(moniker, textBuffer.AsTextContainer(), out var _))
265269
{
266270
// We already added it, so we will keep it excluded from the misc files workspace
267271
return;
@@ -282,20 +286,24 @@ private void AttachToDocument(string moniker, ITextBuffer textBuffer)
282286
/// </summary>
283287
private ProjectInfo CreateProjectInfoForDocument(string filePath)
284288
{
289+
// Potential calculation of _metadataReferences requires being on the main thread
290+
// TODO: Determine if main thread affinity can be removed: https://github.com/dotnet/roslyn/issues/77791
291+
_threadingContext.ThrowIfNotOnUIThread();
292+
285293
// This should always succeed since we only got here if we already confirmed the moniker is acceptable
286294
var languageInformation = TryGetLanguageInformation(filePath);
287295
Contract.ThrowIfNull(languageInformation);
288296

289297
var checksumAlgorithm = SourceHashAlgorithms.Default;
290298
var fileLoader = new WorkspaceFileTextLoader(Services.SolutionServices, filePath, defaultEncoding: null);
291299
return MiscellaneousFileUtilities.CreateMiscellaneousProjectInfoForDocument(
292-
this, filePath, fileLoader, languageInformation, checksumAlgorithm, Services.SolutionServices, _metadataReferences);
300+
this, filePath, fileLoader, languageInformation, checksumAlgorithm, Services.SolutionServices, _metadataReferences.Value);
293301
}
294302

295303
private void DetachFromDocument(string moniker)
296304
{
297305
_threadingContext.ThrowIfNotOnUIThread();
298-
if (_fileTrackingMetadataAsSourceService.TryRemoveDocumentFromWorkspace(moniker))
306+
if (_fileTrackingMetadataAsSourceService.Value.TryRemoveDocumentFromWorkspace(moniker))
299307
{
300308
return;
301309
}

0 commit comments

Comments
 (0)