Skip to content

Commit

Permalink
Defer joining ProjectBuildRuleSource until solution loaded
Browse files Browse the repository at this point in the history
During solution load we run evaluations but not DTB. CPS has a feature that detects when the main thread needs DTB results and allows the DTB to run before solution load completes, in order to avoid deadlocks.

While it's fine to create a dataflow subscription for build data during solution load, the joining of upstream data sources can cause CPS to accidentally think that DTB is blocking the UI thread. There's only one gate for the whole solution, so even a single project in this state will cause all projects to build.

In order to avoid this, we defer joining upstream sources until after the solution has loaded.
  • Loading branch information
drewnoakes committed Nov 28, 2023
1 parent 8955a19 commit 9268db6
Showing 1 changed file with 14 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ internal class WorkspaceFactory : IWorkspaceFactory
private readonly UnconfiguredProject _unconfiguredProject;
private readonly IProjectService _projectService;
private readonly IProjectThreadingService _threadingService;
private readonly IUnconfiguredProjectTasksService _tasksService;
private readonly IManagedProjectDiagnosticOutputService _logger;
private readonly IDataProgressTrackerService _dataProgressTrackerService;
private readonly IActiveEditorContextTracker _activeWorkspaceProjectContextTracker;
Expand All @@ -46,6 +47,7 @@ public WorkspaceFactory(
_unconfiguredProject = unconfiguredProject;
_projectService = projectService;
_threadingService = threadingService;
_tasksService = tasksService;
_logger = logger;
_dataProgressTrackerService = dataProgressTrackerService;
_activeWorkspaceProjectContextTracker = activeWorkspaceProjectContextTracker;
Expand Down Expand Up @@ -146,10 +148,20 @@ var buildTransformBlock
cancellationToken: cancellationToken),

buildTransformBlock.LinkTo(orderingBlock, DataflowOption.PropagateCompletion),

ProjectDataSources.JoinUpstreamDataSources(joinableTaskFactory, _projectService.Services.FaultHandler, source.ActiveConfiguredProjectSource, source.ProjectBuildRuleSource)
});

// During solution load we run evaluations but not DTB. CPS has a feature that detects when the main thread
// needs DTB results and allows the DTB to run before solution load completes, in order to avoid deadlocks.
// While it's fine to create a dataflow subscription for build data during solution load, the joining of
// upstream data sources can cause CPS to accidentally think that DTB is blocking the UI thread. There's only
// one gate for the whole solution, so even a single project in this state will cause all projects to build.
// In order to avoid this, we defer joining upstream sources until after the solution has loaded.
_ = _tasksService.SolutionLoadedInHost.ContinueWith(
_ => workspace.ChainDisposal(ProjectDataSources.JoinUpstreamDataSources(joinableTaskFactory, _projectService.Services.FaultHandler, source.ActiveConfiguredProjectSource, source.ProjectBuildRuleSource)),
CancellationToken.None,
TaskContinuationOptions.None,
TaskScheduler.Default);

#endregion

return workspace;
Expand Down

0 comments on commit 9268db6

Please sign in to comment.