Enlighten AssignProjectConfiguration for multithreaded mode#13615
Enlighten AssignProjectConfiguration for multithreaded mode#13615jankratochvilcz wants to merge 2 commits intomainfrom
Conversation
Add [MSBuildMultiThreadableTask] attribute to AssignProjectConfiguration. This is an attribute-only migration - no IMultiThreadableTask needed since the task has no cwd-dependent operations. Fixes #13613 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR “enlightens” the AssignProjectConfiguration built-in task for MSBuild’s multithreaded execution mode by marking it as safe to run in-process on thread nodes.
Changes:
- Add
[MSBuildMultiThreadableTask]toAssignProjectConfigurationto opt into multithreaded scheduling.
|
|
||
| namespace Microsoft.Build.Tasks | ||
| { | ||
| [MSBuildMultiThreadableTask] |
There was a problem hiding this comment.
Pushing back on this — a concurrency test is not justified for an attribute-only migration:
-
Per-instance state: MSBuild creates a fresh task instance per Execute() call (verified in the expert review on this PR). All mutable state (
_mappingsPopulated,_vcxToDefaultMap,_defaultToVcxMap, base class_cachedProjectReferencesByAbsolutePath,_solutionConfiguration) is instance-scoped, so concurrent task instances cannot interfere by construction. -
No process-global state touched: The expert review on this PR systematically verified no
Environment.CurrentDirectory, noPath.GetFullPath, noFile.*/Directory.*, noProcessStartInfo, no static mutable state.GetMetadata(\"FullPath\")resolves throughFileUtilities.CurrentThreadWorkingDirectory(anAsyncLocal<string?>) under the multithreaded driver, notEnvironment.CurrentDirectory. -
Pattern consistency: ~27 other attribute-only migrations in the codebase (e.g.,
CreateProperty,Message,AssignCulture,CombinePath) ship without concurrency tests for the same reason — the attribute is a metadata declaration, not behavior. A concurrency test for an attribute-only migration would be exercising MSBuild's task instantiation model, not this task.
The concurrency-safety claim is a property of the absence of shared mutable state, which is an audit outcome, not a runtime invariant a test can falsify.
There was a problem hiding this comment.
Review: Attribute-only multithreaded migration for AssignProjectConfiguration
Verdict: Looks correct ✅
I verified the PR author's claims systematically:
Thread Safety Analysis
| Check | Result |
|---|---|
| Static mutable state | ✅ None — only static member is SetBuildInProjectAndReferenceOutputAssemblyMetadata, which is pure/stateless |
Environment.CurrentDirectory usage |
✅ None |
Path.GetFullPath (without base) |
✅ None |
File.* / Directory.* static methods |
✅ None |
ProcessStartInfo usage |
✅ None |
| Instance state thread safety | ✅ All mutable state (_mappingsPopulated, _vcxToDefaultMap, _defaultToVcxMap, _cachedProjectReferencesByAbsolutePath, _solutionConfiguration) is instance-scoped. MSBuild creates a new task instance per execution, so these are not shared across threads. |
Path Resolution Safety
The task uses GetMetadata("FullPath") for path resolution (via ResolveProjectBase). This is safe in multithreaded mode because ItemSpecModifiers.ComputeFullPath resolves through FileUtilities.CurrentThreadWorkingDirectory — an AsyncLocal<string?> set by MultiThreadedTaskEnvironmentDriver per task thread, not Environment.CurrentDirectory.
Attribute-Only Pattern
No IMultiThreadableTask implementation is needed because the task doesn't use any TaskEnvironment APIs (no file I/O, no env var access, no process management). This is consistent with ~27 other attribute-only migrations in the codebase (e.g., CreateProperty, Message, AssignCulture, CombinePath).
Inheritance Chain
AssignProjectConfiguration → ResolveProjectBase → TaskExtension → Task — no thread safety issues in the chain. TaskLoggingHelper (from Task.Log) is documented as thread-safe.
Test Coverage
Existing functional tests in AssignProjectConfiguration_Tests.cs cover the task's core behavior. Dedicated multithreading tests are not required for attribute-only migrations (no behavioral change).
No issues found.
Generated by Expert Code Review (on open) for issue #13615 · ● 7.2M
|
@AR-May The projectAbsolutePath is read from the AbsolutePath attribute of elements in Is it possible that this AbsolutePath attribute could ever contain a relative path? If a relative path If we expect this to always be an absolute path, should we add an assert (Path.IsPathRooted) in |
Rainer said that there is no need in assert. One source of this XML is us the second is VS, so we will trust them. |
Summary
Attribute-only migration for
AssignProjectConfiguration— adds[MSBuildMultiThreadableTask]to declare the task safe for multithreaded scheduling.Why attribute-only?
Environment.CurrentDirectory,Path.GetFullPath,File.*, orProcessStartInfousageGetMetadata(""FullPath"")which returns engine-resolved absolute pathsSetBuildInProjectAndReferenceOutputAssemblyMetadata) is pure/statelessNo
IMultiThreadableTaskimplementation needed. No behavioral change. No ChangeWave required.Fixes #13613
Parent epic: #11834