Skip to content

Commit

Permalink
Merge pull request #9623 from drewnoakes/avoid-extra-jtf-collection-a…
Browse files Browse the repository at this point in the history
…nd-factory

Avoid extra JTF collection/factory
  • Loading branch information
drewnoakes authored Dec 18, 2024
2 parents 5742e49 + ca6820a commit a17bdcd
Showing 1 changed file with 19 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ namespace Microsoft.VisualStudio.ProjectSystem.LanguageServices;
[AppliesTo(ProjectCapability.DotNetLanguageService)]
internal sealed class LanguageServiceHost : OnceInitializedOnceDisposedAsync, IProjectDynamicLoadComponent, IWorkspaceWriter
{
/// <summary>
/// Singleton instance across all projects, initialized once.
/// </summary>
private static AsyncLazy<bool>? s_isEnabled;

private readonly TaskCompletionSource _firstPrimaryWorkspaceSet = new();

private readonly UnconfiguredProject _unconfiguredProject;
Expand All @@ -45,9 +50,6 @@ internal sealed class LanguageServiceHost : OnceInitializedOnceDisposedAsync, IP
private readonly IUnconfiguredProjectTasksService _tasksService;
private readonly ISafeProjectGuidService _projectGuidService;
private readonly IProjectFaultHandlerService _projectFaultHandler;
private readonly JoinableTaskCollection _joinableTaskCollection;
private readonly JoinableTaskFactory _joinableTaskFactory;
private readonly AsyncLazy<bool> _isEnabled;

private DisposableBag? _disposables;

Expand Down Expand Up @@ -78,7 +80,9 @@ public LanguageServiceHost(
_projectGuidService = projectGuidService;
_projectFaultHandler = projectFaultHandler;

_isEnabled = new(
// We initialize this once across all instances. Note that we don't need any synchronization here.
// If more than one thread initializes this, it's not a big deal.
s_isEnabled ??= new(
async () =>
{
// If VS is running in command line mode (e.g. "devenv.exe /build my.sln"),
Expand All @@ -87,11 +91,10 @@ public LanguageServiceHost(
return !await vsShell.IsCommandLineModeAsync()
|| await vsShell.IsPopulateSolutionCacheModeAsync();
},
threadingService.JoinableTaskFactory);

_joinableTaskCollection = threadingService.JoinableTaskContext.CreateCollection();
_joinableTaskCollection.DisplayName = "LanguageServiceHostTasks";
_joinableTaskFactory = new JoinableTaskFactory(_joinableTaskCollection);
threadingService.JoinableTaskFactory)
{
SuppressRecursiveFactoryDetection = true
};
}

public Task LoadAsync()
Expand Down Expand Up @@ -175,7 +178,7 @@ protected override async Task InitializeCoreAsync(CancellationToken cancellation
linkOptions: DataflowOption.PropagateCompletion,
cancellationToken: cancellationToken),

ProjectDataSources.JoinUpstreamDataSources(_joinableTaskFactory, _projectFaultHandler, _activeConfiguredProjectProvider, _activeConfigurationGroupSubscriptionService),
ProjectDataSources.JoinUpstreamDataSources(JoinableFactory, _projectFaultHandler, _activeConfiguredProjectProvider, _activeConfigurationGroupSubscriptionService),

new DisposableDelegate(() =>
{
Expand Down Expand Up @@ -211,7 +214,7 @@ async Task OnSlicesChangedAsync(IProjectVersionedValue<(ConfiguredProject Active
Guid projectGuid = await _projectGuidService.GetProjectGuidAsync(cancellationToken);

// New slice. Create a workspace for it.
workspace = _workspaceFactory.Create(source, slice, _joinableTaskCollection, _joinableTaskFactory, projectGuid, cancellationToken);
workspace = _workspaceFactory.Create(source, slice, JoinableCollection, JoinableFactory, projectGuid, cancellationToken);

if (workspace is null)
{
Expand Down Expand Up @@ -274,15 +277,17 @@ async Task OnSlicesChangedAsync(IProjectVersionedValue<(ConfiguredProject Active

public Task<bool> IsEnabledAsync(CancellationToken cancellationToken)
{
Assumes.NotNull(s_isEnabled);

// Defer to the host environment to determine if we're enabled.
return _isEnabled.GetValueAsync(cancellationToken);
return s_isEnabled.GetValueAsync(cancellationToken);
}

public async Task WhenInitialized(CancellationToken token)
{
await ValidateEnabledAsync(token);

using (_joinableTaskCollection.Join())
using (JoinableCollection.Join())
{
await _firstPrimaryWorkspaceSet.Task.WithCancellation(token);
}
Expand Down Expand Up @@ -350,7 +355,7 @@ public async Task AfterLoadInitialConfigurationAsync()
// Ensure the project is not considered loaded until our first publication.
Task result = _tasksService.PrioritizedProjectLoadedInHostAsync(async () =>
{
using (_joinableTaskCollection.Join())
using (JoinableCollection.Join())
{
await WhenInitialized(_tasksService.UnloadCancellationToken);
}
Expand Down

0 comments on commit a17bdcd

Please sign in to comment.