From d58e6e4235fd354dba52c4caa62b23de4581cf96 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Fri, 6 Mar 2026 12:49:00 -0600 Subject: [PATCH] Handle RequestCores returning 0 in TaskHostFactory tasks MSBuild PR dotnet/msbuild#13306 changed OutOfProcTaskHostNode.RequestCores from throwing NotImplementedException to returning 0 (and logging MSB5022) when callbacks aren't supported. This broke four tasks that only caught NotImplementedException: - EmccCompile: caused blazorwasm publish failure (dotnet/sdk#53300) - MonoAOTCompiler, ILStrip, EmitBundleBase: same latent bug The failure chain was: 1. RequestCores returns 0 (no exception thrown) 2. allowedParallelism becomes 0 3. Parallel.ForEach with MaxDegreeOfParallelism=0 throws 4. ReleaseCores(0) in finally block throws ArgumentOutOfRangeException Fix: track cores actually acquired separately. If RequestCores returns 0 or throws any exception, fall back to the original parallelism and skip ReleaseCores. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/tasks/AotCompilerTask/MonoAOTCompiler.cs | 24 ++++++++++++------- .../EmitBundleTask/EmitBundleBase.cs | 24 ++++++++++++------- src/tasks/MonoTargetsTasks/ILStrip/ILStrip.cs | 24 ++++++++++++------- src/tasks/WasmAppBuilder/EmccCompile.cs | 24 ++++++++++++------- 4 files changed, 60 insertions(+), 36 deletions(-) diff --git a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs index 9f3101b38b6234..d7493cefa2eaa7 100644 --- a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs +++ b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs @@ -541,16 +541,21 @@ private bool ExecuteInternal() else { int allowedParallelism = DisableParallelAot ? 1 : Math.Min(_assembliesToCompile.Count, Environment.ProcessorCount); + int coresAcquired = 0; IBuildEngine9? be9 = BuildEngine as IBuildEngine9; - try - { - if (be9 is not null) - allowedParallelism = be9.RequestCores(allowedParallelism); - } - catch (NotImplementedException) + if (be9 is not null) { - // RequestCores is not implemented in TaskHostFactory - be9 = null; + try + { + coresAcquired = be9.RequestCores(allowedParallelism); + if (coresAcquired > 0) + allowedParallelism = coresAcquired; + } + catch + { + // RequestCores may not be supported in all host environments + coresAcquired = 0; + } } /* @@ -598,7 +603,8 @@ all assigned to that one partition. } finally { - be9?.ReleaseCores(allowedParallelism); + if (coresAcquired > 0) + be9?.ReleaseCores(coresAcquired); } } diff --git a/src/tasks/MonoTargetsTasks/EmitBundleTask/EmitBundleBase.cs b/src/tasks/MonoTargetsTasks/EmitBundleTask/EmitBundleBase.cs index c2c813c495d362..29d0a8f94dfb57 100644 --- a/src/tasks/MonoTargetsTasks/EmitBundleTask/EmitBundleBase.cs +++ b/src/tasks/MonoTargetsTasks/EmitBundleTask/EmitBundleBase.cs @@ -154,16 +154,21 @@ public override bool Execute() // Generate source file(s) containing each resource's byte data and size int allowedParallelism = Math.Max(Math.Min(bundledResources.Count, Environment.ProcessorCount), 1); + int coresAcquired = 0; IBuildEngine9? be9 = BuildEngine as IBuildEngine9; - try - { - if (be9 is not null) - allowedParallelism = be9.RequestCores(allowedParallelism); - } - catch (NotImplementedException) + if (be9 is not null) { - // RequestCores is not implemented in TaskHostFactory - be9 = null; + try + { + coresAcquired = be9.RequestCores(allowedParallelism); + if (coresAcquired > 0) + allowedParallelism = coresAcquired; + } + catch + { + // RequestCores may not be supported in all host environments + coresAcquired = 0; + } } try @@ -196,7 +201,8 @@ public override bool Execute() } finally { - be9?.ReleaseCores(allowedParallelism); + if (coresAcquired > 0) + be9?.ReleaseCores(coresAcquired); } foreach (ITaskItem bundledResource in bundledResources) diff --git a/src/tasks/MonoTargetsTasks/ILStrip/ILStrip.cs b/src/tasks/MonoTargetsTasks/ILStrip/ILStrip.cs index 9976b737b56463..a4198d4262ba35 100644 --- a/src/tasks/MonoTargetsTasks/ILStrip/ILStrip.cs +++ b/src/tasks/MonoTargetsTasks/ILStrip/ILStrip.cs @@ -74,16 +74,21 @@ public override bool Execute() Log.LogMessage(MessageImportance.High, "IL stripping assemblies"); int allowedParallelism = DisableParallelStripping ? 1 : Math.Min(Assemblies.Length, Environment.ProcessorCount); + int coresAcquired = 0; IBuildEngine9? be9 = BuildEngine as IBuildEngine9; - try - { - if (be9 is not null) - allowedParallelism = be9.RequestCores(allowedParallelism); - } - catch (NotImplementedException) + if (be9 is not null) { - // RequestCores is not implemented in TaskHostFactory - be9 = null; + try + { + coresAcquired = be9.RequestCores(allowedParallelism); + if (coresAcquired > 0) + allowedParallelism = coresAcquired; + } + catch + { + // RequestCores may not be supported in all host environments + coresAcquired = 0; + } } try @@ -113,7 +118,8 @@ public override bool Execute() } finally { - be9?.ReleaseCores(allowedParallelism); + if (coresAcquired > 0) + be9?.ReleaseCores(coresAcquired); } return !Log.HasLoggedErrors; diff --git a/src/tasks/WasmAppBuilder/EmccCompile.cs b/src/tasks/WasmAppBuilder/EmccCompile.cs index e93e77203ae30b..9bba434460546a 100644 --- a/src/tasks/WasmAppBuilder/EmccCompile.cs +++ b/src/tasks/WasmAppBuilder/EmccCompile.cs @@ -131,16 +131,21 @@ private bool ExecuteActual() Directory.CreateDirectory(_tempPath); int allowedParallelism = DisableParallelCompile ? 1 : Math.Min(SourceFiles.Length, Environment.ProcessorCount); + int coresAcquired = 0; IBuildEngine9? be9 = BuildEngine as IBuildEngine9; - try - { - if (be9 is not null) - allowedParallelism = be9.RequestCores(allowedParallelism); - } - catch (NotImplementedException) + if (be9 is not null) { - // RequestCores is not implemented in TaskHostFactory - be9 = null; + try + { + coresAcquired = be9.RequestCores(allowedParallelism); + if (coresAcquired > 0) + allowedParallelism = coresAcquired; + } + catch + { + // RequestCores may not be supported in all host environments + coresAcquired = 0; + } } /* @@ -184,7 +189,8 @@ all assigned to that one partition. } finally { - be9?.ReleaseCores(allowedParallelism); + if (coresAcquired > 0) + be9?.ReleaseCores(coresAcquired); }