Stage 3: Forward BuildProjectFile* callbacks from OOP TaskHost to worker node#13350
Conversation
## What Adds folder-scoped **instructions**, topic-scoped **skills**, and an **expert review agent** for GitHub Copilot working in this repo. ## How it works - **Instructions** (`.github/instructions/`) activate automatically when editing files matching their `applyTo` glob. They provide folder-specific guidance (e.g., concurrency rules for `src/Build/BackEnd/`, evaluation model rules for `src/Build/Evaluation/`). - **Skills** (`.github/skills/`) activate on topic keywords in conversation. They cover overarching concerns like backward compatibility assessment, performance optimization, SDK integration, error authoring, and binary log compatibility. The existing `changewaves` skill gets a cross-reference to the new `assessing-breaking-changes` skill (how vs when). - **Review agent** (`.github/agents/expert-reviewer.md`) is invoked via `@expert-reviewer`. It runs a 4-wave review process: 1. **Find** — one sub-agent per quality dimension (24 total), parallel batches of 6. Each returns LGTM or a finding with exact file:line and a concrete failing scenario. 2. **Validate** — proves each finding by tracing code flow in the PR branch, writing proof-of-concept tests, or simulating thread timelines. Multi-model consensus (Opus + Codex + Gemini) for borderline cases. 3. **Post** — inline review comments at exact diff locations via GitHub CLI. 4. **Summary** — 24-dimension checkbox table as review body. ## Example Applied to [PR #13350](#13350 (review)) — found a shared-state concurrency race, an unlogged exception, and a null-deref edge case. 20 of 24 dimensions passed LGTM. ## Scope No production code changes. Only `.github/` files (instructions, skills, agent). One minor addition to the existing `changewaves` skill (cross-reference line). --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
## What Adds folder-scoped **instructions**, topic-scoped **skills**, and an **expert review agent** for GitHub Copilot working in this repo. ## How it works - **Instructions** (`.github/instructions/`) activate automatically when editing files matching their `applyTo` glob. They provide folder-specific guidance (e.g., concurrency rules for `src/Build/BackEnd/`, evaluation model rules for `src/Build/Evaluation/`). - **Skills** (`.github/skills/`) activate on topic keywords in conversation. They cover overarching concerns like backward compatibility assessment, performance optimization, SDK integration, error authoring, and binary log compatibility. The existing `changewaves` skill gets a cross-reference to the new `assessing-breaking-changes` skill (how vs when). - **Review agent** (`.github/agents/expert-reviewer.md`) is invoked via `@expert-reviewer`. It runs a 4-wave review process: 1. **Find** — one sub-agent per quality dimension (24 total), parallel batches of 6. Each returns LGTM or a finding with exact file:line and a concrete failing scenario. 2. **Validate** — proves each finding by tracing code flow in the PR branch, writing proof-of-concept tests, or simulating thread timelines. Multi-model consensus (Opus + Codex + Gemini) for borderline cases. 3. **Post** — inline review comments at exact diff locations via GitHub CLI. 4. **Summary** — 24-dimension checkbox table as review body. ## Example Applied to [PR dotnet#13350](dotnet#13350 (review)) — found a shared-state concurrency race, an unlogged exception, and a null-deref edge case. 20 of 24 dimensions passed LGTM. ## Scope No production code changes. Only `.github/` files (instructions, skills, agent). One minor addition to the existing `changewaves` skill (cross-reference line). --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
b954baf to
c135644
Compare
Post-review notes (automated multi-agent review of new commits)5 new commits pushed addressing review meeting feedback. Multi-agent review (5 agents: expert-reviewer, 2× Opus 4.6, 2× GPT-5.4) ran against the delta. Findings addressed inline; remaining items for human attention: Items addressed in these commits
Items for human reviewer attention
|
There was a problem hiding this comment.
Pull request overview
Stage 3 of out-of-process TaskHost IBuildEngine callback support: forwards BuildProjectFile* and Yield/Reacquire from the OOP TaskHost back to the owning worker node so ejected tasks (notably WPF XAML compilation) can build projects and cooperate with the scheduler.
Changes:
- Add new callback packet types for BuildProjectFile* and Yield/Reacquire, including serialization round-trip tests.
- Implement callback forwarding in
OutOfProcTaskHostNode, worker-side handling inTaskHostTask, and nested-task process reuse routing via a handler stack inNodeProviderOutOfProcTaskHost. - Add integration/E2E tests and update TaskHost threading documentation plus resource strings.
Reviewed changes
Copilot reviewed 40 out of 40 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Shared/TaskHostBuildRequest.cs | New packet carrying canonical BuildProjectFilesInParallel request data. |
| src/Shared/TaskHostBuildResponse.cs | New response packet with success + optional target outputs (TaskParameter-serialized). |
| src/Shared/TaskHostYieldRequest.cs | New packet for Yield/Reacquire operations. |
| src/Shared/TaskHostYieldResponse.cs | New response packet to unblock TaskHost on Reacquire. |
| src/Shared/Resources/Strings.shared.resx | Adds new resource strings for callback/yield diagnostics. |
| src/Shared/Resources/xlf/Strings.shared.*.xlf | Adds corresponding localization entries for the new resource strings. |
| src/MSBuild/TaskExecutionContext.cs | Introduces per-task execution context for concurrent/nested TaskHost execution. |
| src/MSBuild/OutOfProcTaskHostNode.cs | Implements forwarding for BuildProjectFile* and Yield/Reacquire; adds per-task context + counters + completion queue. |
| src/MSBuild/MSBuild.csproj | Includes new shared packets + TaskExecutionContext in MSBuild build. |
| src/Build/Microsoft.Build.csproj | Includes new shared packets in Microsoft.Build build. |
| src/Build/Instance/TaskFactories/TaskHostTask.cs | Worker-side handlers for build/yield requests and response emission. |
| src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcTaskHost.cs | Adds handler stack to support nested TaskHostTask routing and reuse. |
| src/Build.UnitTests/BackEnd/TaskHostCallbackPacket_Tests.cs | Adds serialization tests for the new request/response packet types. |
| src/Build.UnitTests/BackEnd/TaskHostCallback_Tests.cs | Adds integration tests validating BuildProjectFile forwarding and fallback behavior. |
| src/Build.UnitTests/NetTaskHost_E2E_Tests.cs | Adds E2E tests for cross-runtime BuildProjectFile and same-PID reuse for nested builds. |
| src/Build.UnitTests/BackEnd/BuildProjectFileTask.cs | New test task that triggers BuildProjectFile callback and captures outputs. |
| src/Build.UnitTests/BackEnd/BuildProjectFileAndReportPidTask.cs | New test task for PID reporting + nested BuildProjectFile call (reuse verification). |
| src/Build.UnitTests/TestAssets/ExampleNetTask/TestNetTaskBuildCallback/* | New E2E asset project for callback validation. |
| src/Build.UnitTests/TestAssets/ExampleNetTask/TestNetTaskHostReuse/* | New E2E asset project for nested-build process reuse validation. |
| src/Build.UnitTests/TestAssets/ExampleNetTask/ExampleTask/ExampleTask.csproj | Links new test tasks into ExampleTask assembly. |
| documentation/specs/multithreading/taskhost-threading.md | Documents Stage 3 callback flow, yield-for-callback pattern, and handler stack. |
4e86e10 to
b1c2ab1
Compare
|
I investigated supporting explicit IBuildEngine3.Yield() / Reacquire() in the OOP TaskHost and decided not to implement it in this change. The short version is that this is not a small missing feature in the current design—it conflicts with several core assumptions of the OOP task-host architecture due to having one pipe for communication:
By contrast, the existing internal callback-based blocking path works because it blocks the task thread while the callback is in flight. That preserves the single-active-handler assumption and avoids the routing/logging/state-machine issues above. So the conclusion here is: supporting explicit yield in OOP TaskHost would require broader architectural and wire-protocol work than is appropriate for this PR, and a partial implementation would be brittle and potentially incorrect. Not implementing Yield does not regress correctness, however negative perf impact in |
b1c2ab1 to
573ac4c
Compare
Summary
Stage 3 of IBuildEngine callback support for out-of-process TaskHost. Implements forwarding of
BuildProjectFile*from OOP TaskHost to the owning worker node, enabling tasks ejected to TaskHost (via-mtor explicitTaskHostFactory) to build other projects.Real-world impact: WPF XAML compilation uses
GenerateTemporaryTargetAssemblywhich callsBuildProjectFilefrom TaskHost. Without this change, building any WPF project with-mtfails with MSB5022.Design
Packet pair
TaskHostBuildRequest(0x20) /TaskHostBuildResponse(0x21): All 4BuildProjectFile*overloads normalize to the 6-paramBuildProjectFilesInParallelcanonical form.Callback flow (no Yield/Reacquire)
Unlike the original design, we do not use
Yield/ReacquireforBuildProjectFilecallbacks. Instead:BuildProjectFile→ gates onCallbacksSupportedBlockForCallback()transitions the task from active to blocked (_activeTaskCount--,_blockedTaskCount++)SendCallbackRequestAndWaitForResponse<T>serializes the request and blocks onTaskCompletionSourceTaskHostTask.HandleBuildRequestcallsIBuildEngine3.BuildProjectFilesInParallel— exceptions propagate toTaskBuildernaturally (matching in-proc behavior),finallysends the responseResumeAfterCallback()restores counters and environmentA blocked task does not prevent the node from accepting new work —
HandleTaskHostConfigurationchecks_activeTaskCount == 0(not blocked count), so nested task dispatch works.Yield/Reacquireremain no-ops in the OOP TaskHost.Per-task isolation
TaskExecutionContextstores per-task state viaConcurrentDictionary<int, TaskExecutionContext>+AsyncLocal: configuration, task wrapper, saved environment, debug flags, warning settings, pending callback requests.GetCurrentConfiguration()andEffectiveWarningsAs*read from per-task context on task threads, falling back to_currentConfigurationon the main communication thread.Handler routing (process reuse)
NodeProviderOutOfProcTaskHostroutes packets byTaskHostNodeKey, supporting nested task dispatch when an outer task is blocked on a callback and a new task arrives on the same TaskHost process.Version gating
Gated behind
CallbacksSupported(_parentPacketVersion >= 4ORMSBUILDENABLETASKHOSTCALLBACKS=1). EachBuildProjectFileoverload explicitly checks. Follow-up PR bumpsPacketVersionto 4 and removes the env var.Tests
TaskHostBuildRequest/Responsewith null/empty/populated propertiesBuildProjectFileviaTaskHostFactory, global property forwarding, target output retrieval, callbacks-not-supported error path (MSB5022)BuildProjectFilecallback, TaskHost process reuse (same PID verification)BuildProjectFileduring-mtbuildContext
IsRunningMultipleNodesRequestCores/ReleaseCores