From b4873669d21c2d2d7250354b99ac979d5e47cc38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Thu, 30 Jul 2020 22:07:53 +0200 Subject: [PATCH 01/61] Adding MSBuild.Tasks to MSBuild --- .../Components/Communications/NodeProviderOutOfProcBase.cs | 3 ++- .../Components/SdkResolution/MainNodeSdkResolverService.cs | 1 + src/Build/BackEnd/TaskExecutionHost/TaskExecutionHost.cs | 2 +- src/Build/Microsoft.Build.csproj | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs index 3b69a13427a..b8ce731c906 100644 --- a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs +++ b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Runtime.InteropServices; using System.Security.Principal; +using Task = System.Threading.Tasks.Task; using Microsoft.Build.Shared; using Microsoft.Build.Exceptions; @@ -225,7 +226,7 @@ protected NodeContext GetNode(string msbuildLocation, string commandLineArgs, in string taskHostNameForClr2TaskHost = Path.GetFileNameWithoutExtension(NodeProviderOutOfProcTaskHost.TaskHostNameForClr2TaskHost); if (Path.GetFileNameWithoutExtension(msbuildLocation).Equals(taskHostNameForClr2TaskHost, StringComparison.OrdinalIgnoreCase)) { - if (FrameworkLocationHelper.GetPathToDotNetFrameworkV35(DotNetFrameworkArchitecture.Current) == null) + if (FrameworkLocationHelper.GetPathToDotNetFrameworkV35(Shared.DotNetFrameworkArchitecture.Current) == null) { CommunicationsUtilities.Trace ( diff --git a/src/Build/BackEnd/Components/SdkResolution/MainNodeSdkResolverService.cs b/src/Build/BackEnd/Components/SdkResolution/MainNodeSdkResolverService.cs index 96a9aba7954..f94ff37aea3 100644 --- a/src/Build/BackEnd/Components/SdkResolution/MainNodeSdkResolverService.cs +++ b/src/Build/BackEnd/Components/SdkResolution/MainNodeSdkResolverService.cs @@ -13,6 +13,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using Task = System.Threading.Tasks.Task; namespace Microsoft.Build.BackEnd.SdkResolution { diff --git a/src/Build/BackEnd/TaskExecutionHost/TaskExecutionHost.cs b/src/Build/BackEnd/TaskExecutionHost/TaskExecutionHost.cs index 81183622bb9..089ec042aa5 100644 --- a/src/Build/BackEnd/TaskExecutionHost/TaskExecutionHost.cs +++ b/src/Build/BackEnd/TaskExecutionHost/TaskExecutionHost.cs @@ -13,6 +13,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Task = System.Threading.Tasks.Task; using Microsoft.Build.BackEnd.Logging; using Microsoft.Build.Construction; @@ -22,7 +23,6 @@ using Microsoft.Build.Framework; using Microsoft.Build.Shared; using Microsoft.Build.Utilities; - using TaskItem = Microsoft.Build.Execution.ProjectItemInstance.TaskItem; namespace Microsoft.Build.BackEnd diff --git a/src/Build/Microsoft.Build.csproj b/src/Build/Microsoft.Build.csproj index 43a84039b2e..5a6014e01db 100644 --- a/src/Build/Microsoft.Build.csproj +++ b/src/Build/Microsoft.Build.csproj @@ -30,6 +30,7 @@ + From b7a7943892e5a0f9a2dc8fae1a0c48e2058f0b3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Wed, 5 Aug 2020 15:36:28 +0200 Subject: [PATCH 02/61] RAR node provider --- .../BuildComponentFactoryCollection.cs | 1 + .../Communications/INodeProvider.cs | 7 +- .../Communications/NodeEndpointOutOfProc.cs | 11 +- .../Components/Communications/NodeManager.cs | 28 ++++ .../Communications/NodeProviderOutOfProc.cs | 14 +- .../NodeProviderOutOfProcBase.cs | 16 ++- .../NodeProviderOutOfProcRar.cs | 136 ++++++++++++++++++ .../NodeProviderOutOfProcTaskHost.cs | 5 +- .../BackEnd/Components/IBuildComponentHost.cs | 5 + .../Components/RequestBuilder/TaskHost.cs | 44 +++++- src/Build/BackEnd/Node/NodeConfiguration.cs | 14 +- src/Build/BackEnd/Node/OutOfProcNode.cs | 15 +- src/Build/Instance/HostServices.cs | 7 +- src/Build/Microsoft.Build.csproj | 1 + src/Shared/CommunicationsUtilities.cs | 29 +++- 15 files changed, 312 insertions(+), 21 deletions(-) create mode 100644 src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcRar.cs diff --git a/src/Build/BackEnd/Components/BuildComponentFactoryCollection.cs b/src/Build/BackEnd/Components/BuildComponentFactoryCollection.cs index 05ea23f5425..702c0a0a87e 100644 --- a/src/Build/BackEnd/Components/BuildComponentFactoryCollection.cs +++ b/src/Build/BackEnd/Components/BuildComponentFactoryCollection.cs @@ -61,6 +61,7 @@ public void RegisterDefaultFactories() _componentEntriesByType[BuildComponentType.InProcNodeProvider] = new BuildComponentEntry(BuildComponentType.InProcNodeProvider, NodeProviderInProc.CreateComponent, CreationPattern.Singleton); _componentEntriesByType[BuildComponentType.OutOfProcNodeProvider] = new BuildComponentEntry(BuildComponentType.OutOfProcNodeProvider, NodeProviderOutOfProc.CreateComponent, CreationPattern.Singleton); + _componentEntriesByType[BuildComponentType.OutOfProcNodeRarProvider] = new BuildComponentEntry(BuildComponentType.OutOfProcNodeRarProvider, NodeProviderOutOfProcRar.CreateComponent, CreationPattern.Singleton); _componentEntriesByType[BuildComponentType.OutOfProcTaskHostNodeProvider] = new BuildComponentEntry(BuildComponentType.OutOfProcTaskHostNodeProvider, NodeProviderOutOfProcTaskHost.CreateComponent, CreationPattern.Singleton); // PropertyCache, diff --git a/src/Build/BackEnd/Components/Communications/INodeProvider.cs b/src/Build/BackEnd/Components/Communications/INodeProvider.cs index bd2cacc7266..d6f8116f414 100644 --- a/src/Build/BackEnd/Components/Communications/INodeProvider.cs +++ b/src/Build/BackEnd/Components/Communications/INodeProvider.cs @@ -24,7 +24,12 @@ internal enum NodeProviderType /// /// The provider provides remote nodes. /// - Remote + Remote, + + /// + /// The provider provides RAR nodes. + /// + ResolveAssemblyReference } /// diff --git a/src/Build/BackEnd/Components/Communications/NodeEndpointOutOfProc.cs b/src/Build/BackEnd/Components/Communications/NodeEndpointOutOfProc.cs index a30017ca426..b381f275f47 100644 --- a/src/Build/BackEnd/Components/Communications/NodeEndpointOutOfProc.cs +++ b/src/Build/BackEnd/Components/Communications/NodeEndpointOutOfProc.cs @@ -21,6 +21,8 @@ internal class NodeEndpointOutOfProc : NodeEndpointOutOfProcBase private readonly bool _lowPriority; + private readonly bool _workerNode; + #endregion #region Constructors and Factories @@ -35,12 +37,15 @@ internal NodeEndpointOutOfProc( string pipeName, IBuildComponentHost host, bool enableReuse, - bool lowPriority) + bool lowPriority, + bool workerNode) { ErrorUtilities.VerifyThrowArgumentNull(host, "host"); _componentHost = host; _enableReuse = enableReuse; _lowPriority = lowPriority; + _workerNode = workerNode; + InternalConstruct(pipeName); } @@ -52,7 +57,7 @@ internal NodeEndpointOutOfProc( /// protected override long GetHostHandshake() { - return NodeProviderOutOfProc.GetHostHandshake(_enableReuse, _lowPriority); + return NodeProviderOutOfProc.GetHostHandshake(_enableReuse, _lowPriority, _workerNode); } /// @@ -60,7 +65,7 @@ protected override long GetHostHandshake() /// protected override long GetClientHandshake() { - return NodeProviderOutOfProc.GetClientHandshake(_enableReuse, _lowPriority); + return NodeProviderOutOfProc.GetClientHandshake(_enableReuse, _lowPriority, _workerNode); } #region Structs diff --git a/src/Build/BackEnd/Components/Communications/NodeManager.cs b/src/Build/BackEnd/Components/Communications/NodeManager.cs index e0c45681ff0..6b8e496b406 100644 --- a/src/Build/BackEnd/Components/Communications/NodeManager.cs +++ b/src/Build/BackEnd/Components/Communications/NodeManager.cs @@ -35,6 +35,12 @@ internal class NodeManager : INodeManager /// private INodeProvider _outOfProcNodeProvider; + + /// + /// The node provider for out-of-proc RAR nodes. + /// + private INodeProvider _outOfProcRarNodeProvider; + /// /// The build component host. /// @@ -113,6 +119,11 @@ public NodeInfo CreateNode(NodeConfiguration configuration, NodeAffinity nodeAff nodeId = AttemptCreateNode(_outOfProcNodeProvider, configuration); } + if (nodeId == InvalidNodeId && (nodeAffinity == NodeAffinity.RarNode)) + { + nodeId = AttemptCreateNode(_outOfProcRarNodeProvider, configuration); + } + if (nodeId == InvalidNodeId) { return null; @@ -166,6 +177,11 @@ public void ShutdownConnectedNodes(bool enableReuse) { _outOfProcNodeProvider.ShutdownConnectedNodes(enableReuse); } + + if(null != _outOfProcRarNodeProvider) + { + _outOfProcRarNodeProvider.ShutdownConnectedNodes(enableReuse); + } } /// @@ -178,6 +194,11 @@ public void ShutdownAllNodes() { _outOfProcNodeProvider.ShutdownAllNodes(); } + + if (null != _outOfProcRarNodeProvider) + { + _outOfProcRarNodeProvider.ShutdownAllNodes(); + } } #endregion @@ -196,6 +217,7 @@ public void InitializeComponent(IBuildComponentHost host) _inProcNodeProvider = _componentHost.GetComponent(BuildComponentType.InProcNodeProvider) as INodeProvider; _outOfProcNodeProvider = _componentHost.GetComponent(BuildComponentType.OutOfProcNodeProvider) as INodeProvider; + _outOfProcRarNodeProvider = _componentHost.GetComponent(BuildComponentType.OutOfProcNodeRarProvider) as INodeProvider; _componentShutdown = false; @@ -217,8 +239,14 @@ public void ShutdownComponent() ((IDisposable)_outOfProcNodeProvider).Dispose(); } + if (_outOfProcRarNodeProvider != null && _outOfProcRarNodeProvider is IDisposable) + { + ((IDisposable)_outOfProcRarNodeProvider).Dispose(); + } + _inProcNodeProvider = null; _outOfProcNodeProvider = null; + _outOfProcRarNodeProvider = null; _componentHost = null; _componentShutdown = true; diff --git a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProc.cs b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProc.cs index 63ca1cadc74..f5c3c0734e0 100644 --- a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProc.cs +++ b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProc.cs @@ -63,19 +63,20 @@ public int AvailableNodes /// /// Is reuse of build nodes allowed? /// Is the build running at low priority? - internal static long GetHostHandshake(bool enableNodeReuse, bool enableLowPriority) + /// /Indicates if node can accept standard MSBuild work + internal static long GetHostHandshake(bool enableNodeReuse, bool enableLowPriority, bool workerNode) { CommunicationsUtilities.Trace("MSBUILDNODEHANDSHAKESALT=\"{0}\", msbuildDirectory=\"{1}\", enableNodeReuse={2}, enableLowPriority={3}", Traits.MSBuildNodeHandshakeSalt, BuildEnvironmentHelper.Instance.MSBuildToolsDirectory32, enableNodeReuse, enableLowPriority); - return CommunicationsUtilities.GetHostHandshake(CommunicationsUtilities.GetHandshakeOptions(taskHost: false, nodeReuse: enableNodeReuse, lowPriority: enableLowPriority, is64Bit: EnvironmentUtilities.Is64BitProcess)); + return CommunicationsUtilities.GetHostHandshake(CommunicationsUtilities.GetHandshakeOptions(taskHost: false, nodeReuse: enableNodeReuse, lowPriority: enableLowPriority, workerNode: workerNode, is64Bit: EnvironmentUtilities.Is64BitProcess)); } /// /// Magic number sent by the client to the host during the handshake. /// Munged version of the host handshake. /// - internal static long GetClientHandshake(bool enableNodeReuse, bool enableLowPriority) + internal static long GetClientHandshake(bool enableNodeReuse, bool enableLowPriority, bool workerNode) { - return CommunicationsUtilities.GetClientHandshake(CommunicationsUtilities.GetHandshakeOptions(false, nodeReuse: enableNodeReuse, lowPriority: enableLowPriority, is64Bit: EnvironmentUtilities.Is64BitProcess)); + return CommunicationsUtilities.GetClientHandshake(CommunicationsUtilities.GetHandshakeOptions(false, nodeReuse: enableNodeReuse, lowPriority: enableLowPriority, workerNode: workerNode, is64Bit: EnvironmentUtilities.Is64BitProcess)); } /// @@ -100,8 +101,9 @@ public bool CreateNode(int nodeId, INodePacketFactory factory, NodeConfiguration // Make it here. CommunicationsUtilities.Trace("Starting to acquire a new or existing node to establish node ID {0}...", nodeId); - long hostHandShake = NodeProviderOutOfProc.GetHostHandshake(ComponentHost.BuildParameters.EnableNodeReuse, ComponentHost.BuildParameters.LowPriority); - NodeContext context = GetNode(null, commandLineArgs, nodeId, factory, hostHandShake, NodeProviderOutOfProc.GetClientHandshake(ComponentHost.BuildParameters.EnableNodeReuse, ComponentHost.BuildParameters.LowPriority), NodeContextTerminated); + // All OutOfProc nodes are worker nodes. + long hostHandShake = NodeProviderOutOfProc.GetHostHandshake(ComponentHost.BuildParameters.EnableNodeReuse, ComponentHost.BuildParameters.LowPriority, true); + NodeContext context = GetNode(null, commandLineArgs, nodeId, factory, hostHandShake, NodeProviderOutOfProc.GetClientHandshake(ComponentHost.BuildParameters.EnableNodeReuse, ComponentHost.BuildParameters.LowPriority, true), NodeContextTerminated); if (null != context) { diff --git a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs index b8ce731c906..785ca2b9ee2 100644 --- a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs +++ b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs @@ -126,12 +126,24 @@ protected void ShutdownAllNodes(bool nodeReuse, NodeContextTerminateDelegate ter int timeout = 30; // Attempt to connect to the process with the handshake without low priority. - Stream nodeStream = TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHostHandshake(nodeReuse, false), NodeProviderOutOfProc.GetClientHandshake(nodeReuse, false)); + Stream nodeStream = TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHostHandshake(nodeReuse, false, true), NodeProviderOutOfProc.GetClientHandshake(nodeReuse, false, true)); if (null == nodeStream) { // If we couldn't connect attempt to connect to the process with the handshake including low priority. - nodeStream = TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHostHandshake(nodeReuse, true), NodeProviderOutOfProc.GetClientHandshake(nodeReuse, true)); + nodeStream = TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHostHandshake(nodeReuse, true, true), NodeProviderOutOfProc.GetClientHandshake(nodeReuse, true, true)); + } + + // Couldn't connect to normal node, try to connect to non-worker node. + if (null == nodeStream) + { + nodeStream = TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHostHandshake(nodeReuse, false, false), NodeProviderOutOfProc.GetClientHandshake(nodeReuse, false, false)); + + if (null == nodeStream) + { + // If we couldn't connect attempt to connect to the process with the handshake including low priority. + nodeStream = TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHostHandshake(nodeReuse, true, false), NodeProviderOutOfProc.GetClientHandshake(nodeReuse, true, false)); + } } if (null != nodeStream) diff --git a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcRar.cs b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcRar.cs new file mode 100644 index 00000000000..66555d38ecf --- /dev/null +++ b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcRar.cs @@ -0,0 +1,136 @@ +using Microsoft.Build.Exceptions; +using Microsoft.Build.Internal; +using Microsoft.Build.Shared; +using System.Collections.Generic; + +namespace Microsoft.Build.BackEnd +{ + class NodeProviderOutOfProcRar : NodeProviderOutOfProcBase, INodeProvider + { + private int? _rarNodeId = null; + private NodeContext _rarNodeContext = null; + + public NodeProviderType ProviderType => NodeProviderType.ResolveAssemblyReference; + + public int AvailableNodes => 1; + + public bool CreateNode(int nodeId, INodePacketFactory factory, NodeConfiguration configuration) + { + ErrorUtilities.VerifyThrowArgumentNull(factory, "factory"); + + if (_rarNodeId.HasValue) + { + ErrorUtilities.ThrowInternalError("RAR node already creared."); + return false; + } + + // Start the new process. We pass in a node mode with a node number of 1, to indicate that we + // want to start up just a standard MSBuild out-of-proc node. + // Note: We need to always pass /nodeReuse to ensure the value for /nodeReuse from msbuild.rsp + // (next to msbuild.exe) is ignored. + string commandLineArgs = $"/nologo /nodemode:3 /nodeReuse:{ComponentHost.BuildParameters.EnableNodeReuse.ToString().ToLower()} /low:{ComponentHost.BuildParameters.LowPriority.ToString().ToLower()}"; + + // Make it here. + CommunicationsUtilities.Trace("Starting to acquire a new or existing node to establish node ID {0}...", nodeId); + + // TODO: Fix this. Be able to decide which option to choose. + var hostHandShake = NodeProviderOutOfProc.GetHostHandshake(ComponentHost.BuildParameters.EnableNodeReuse, ComponentHost.BuildParameters.LowPriority, false); + var clientHandShake = NodeProviderOutOfProc.GetClientHandshake(ComponentHost.BuildParameters.EnableNodeReuse, ComponentHost.BuildParameters.LowPriority, false); + NodeContext context = GetNode(null, commandLineArgs, nodeId, factory, hostHandShake, clientHandShake, NodeContextTerminated); + + if (null != context) + { + _rarNodeId = nodeId; + _rarNodeContext = context; + + // Is this necesarry? + // Start the asynchronous read. + context.BeginAsyncPacketRead(); + + // Configure the node. + context.SendData(configuration); + + return true; + } + + throw new BuildAbortedException(ResourceUtilities.FormatResourceStringStripCodeAndKeyword("CouldNotConnectToMSBuildExe", ComponentHost.BuildParameters.NodeExeLocation)); + } + + private void NodeContextTerminated(int nodeId) + { + if (_rarNodeId == nodeId) + { + _rarNodeId = null; + _rarNodeContext = null; + } + } + + #region IBuildComponent Members + + /// + /// Initializes the component. + /// + /// The component host. + public void InitializeComponent(IBuildComponentHost host) + { + this.ComponentHost = host; + } + + /// + /// Shuts down the component + /// + public void ShutdownComponent() + { + } + + #endregion + + /// + /// Static factory for component creation. + /// + static internal IBuildComponent CreateComponent(BuildComponentType componentType) + { + ErrorUtilities.VerifyThrow(componentType == BuildComponentType.OutOfProcNodeRarProvider, "Factory cannot create components of type {0}", componentType); + return new NodeProviderOutOfProcRar(); + } + + public void SendData(int node, INodePacket packet) + { + if (_rarNodeId == node) + { + _rarNodeContext.SendData(packet); + } + } + + public void ShutdownAllNodes() + { + // If no BuildParameters were specified for this build, + // we must be trying to shut down idle nodes from some + // other, completed build. If they're still around, + // they must have been started with node reuse. + bool nodeReuse = ComponentHost.BuildParameters?.EnableNodeReuse ?? true; + + // To avoid issues with mismatched priorities not shutting + // down all the nodes on exit, we will attempt to shutdown + // all matching nodes with and without the priority bit set. + // This means we need both versions of the handshake. + + // RAR node is special... + if(!nodeReuse) + ShutdownAllNodes(nodeReuse, NodeContextTerminated); + } + + public void ShutdownConnectedNodes(bool enableReuse) + { + // RAR node is special + if (_rarNodeId != null && !enableReuse) + { + var contextList = new List() + { + _rarNodeContext + }; + ShutdownConnectedNodes(contextList, enableReuse); + } + } + } +} diff --git a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcTaskHost.cs b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcTaskHost.cs index 44a2de9a749..db6357413d2 100644 --- a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcTaskHost.cs +++ b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcTaskHost.cs @@ -206,8 +206,9 @@ public void ShutdownAllNodes() // down all the nodes on exit, we will attempt to shutdown // all matching notes with and without the priroity bit set. // So precompute both versions of the handshake now. - long hostHandshake = NodeProviderOutOfProc.GetHostHandshake(nodeReuse, enableLowPriority: false); - long hostHandshakeWithLow = NodeProviderOutOfProc.GetHostHandshake(nodeReuse, enableLowPriority: true); + // TODO: Chceck if this is necessary, shouldn't be... + long hostHandshake = NodeProviderOutOfProc.GetHostHandshake(nodeReuse, enableLowPriority: false, workerNode: true); + long hostHandshakeWithLow = NodeProviderOutOfProc.GetHostHandshake(nodeReuse, enableLowPriority: true, workerNode: true); ShutdownAllNodes(nodeReuse, NodeContextTerminated); } diff --git a/src/Build/BackEnd/Components/IBuildComponentHost.cs b/src/Build/BackEnd/Components/IBuildComponentHost.cs index 6e18d9ec4ef..6ba70a8ed38 100644 --- a/src/Build/BackEnd/Components/IBuildComponentHost.cs +++ b/src/Build/BackEnd/Components/IBuildComponentHost.cs @@ -128,6 +128,11 @@ internal enum BuildComponentType /// The SDK resolution service. /// SdkResolverService, + + /// + /// The OutOfProc RAR node provider. + /// + OutOfProcNodeRarProvider, } /// diff --git a/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs b/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs index 81e53c7ba6b..dcfc221b25f 100644 --- a/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs +++ b/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs @@ -5,6 +5,7 @@ using System.Collections; using System.Collections.Generic; using System.Globalization; +using System.IO.Pipes; #if FEATURE_APPDOMAIN using System.Runtime.Remoting.Lifetime; using System.Runtime.Remoting; @@ -23,6 +24,7 @@ using Microsoft.Build.BackEnd.Components.Caching; using System.Reflection; using Microsoft.Build.Eventing; +using Microsoft.Build.Internal; namespace Microsoft.Build.BackEnd { @@ -34,7 +36,7 @@ internal class TaskHost : #if FEATURE_APPDOMAIN MarshalByRefObject, #endif - IBuildEngine7 + IBuildEngine7, IRarBuildEngine { /// /// True if the "secret" environment variable MSBUILDNOINPROCNODE is set. @@ -989,5 +991,45 @@ private void VerifyActiveProxy() { ErrorUtilities.VerifyThrow(_activeProxy == true, "Attempted to use an inactive task host."); } + + /// + /// Inialize new RAR node + /// + bool IRarBuildEngine.CreateRarNode() + { + var nodeManager = _host.GetComponent(BuildComponentType.NodeManager) as INodeManager; + + var configuration = new NodeConfiguration + ( + -1, /* must be assigned by the NodeManager */ + _host.BuildParameters, + null + #if FEATURE_APPDOMAIN + , AppDomain.CurrentDomain.SetupInformation + #endif + , new LoggingNodeConfiguration(_host.LoggingService.IncludeEvaluationMetaprojects, _host.LoggingService.IncludeEvaluationProfile, _host.LoggingService.IncludeTaskInputs) + ); + + var nodeInfo = nodeManager.CreateNode(configuration, NodeAffinity.RarNode); + + return nodeInfo != null; + } + + /// + /// Provides RAR node name for current configuration + /// + string IRarBuildEngine.GetRarPipeName() + { + var parameters = _host.BuildParameters; + return CommunicationsUtilities.GetRARPipeName(parameters.EnableNodeReuse, parameters.LowPriority); + } + + /// + /// Constructs + /// + NamedPipeClientStream IRarBuildEngine.GetRarClientStream(string pipeName, int timeout) + { + return NamedPipeUtil.GetClientStream(pipeName, timeout); + } } } diff --git a/src/Build/BackEnd/Node/NodeConfiguration.cs b/src/Build/BackEnd/Node/NodeConfiguration.cs index 5cb25db468c..3708b9be7f2 100644 --- a/src/Build/BackEnd/Node/NodeConfiguration.cs +++ b/src/Build/BackEnd/Node/NodeConfiguration.cs @@ -49,13 +49,15 @@ internal class NodeConfiguration : INodePacket /// The forwarding loggers. /// The AppDomain setup information. /// The logging configuration for the node. + /// Indicates if node works as RAR node. public NodeConfiguration ( int nodeId, BuildParameters buildParameters, LoggerDescription[] forwardingLoggers, AppDomainSetup appDomainSetup, - LoggingNodeConfiguration loggingNodeConfiguration + LoggingNodeConfiguration loggingNodeConfiguration, + bool rarNode = false ) { _nodeId = nodeId; @@ -63,6 +65,7 @@ LoggingNodeConfiguration loggingNodeConfiguration _forwardingLoggers = forwardingLoggers; _appDomainSetup = appDomainSetup; _loggingNodeConfiguration = loggingNodeConfiguration; + RarNode = rarNode; } #else /// @@ -162,9 +165,14 @@ public NodePacketType Type { return NodePacketType.NodeConfiguration; } } -#endregion + /// + /// Indicates if the node is RAR node or not (executes only one task) + /// + public bool RarNode { get; } + + #endregion -#region INodePacketTranslatable Members + #region INodePacketTranslatable Members /// /// Translates the packet to/from binary form. diff --git a/src/Build/BackEnd/Node/OutOfProcNode.cs b/src/Build/BackEnd/Node/OutOfProcNode.cs index d7bddbdc133..af4c859ac09 100644 --- a/src/Build/BackEnd/Node/OutOfProcNode.cs +++ b/src/Build/BackEnd/Node/OutOfProcNode.cs @@ -246,11 +246,24 @@ public NodeEngineShutdownReason Run(bool enableReuse, out Exception shutdownExce /// The exception which caused shutdown, if any. /// The reason for shutting down. public NodeEngineShutdownReason Run(bool enableReuse, bool lowPriority, out Exception shutdownException) + { + return Run(enableReuse, lowPriority, true, out shutdownException); + } + + /// + /// Starts up the node and processes messages until the node is requested to shut down. + /// + /// Whether this node is eligible for reuse later. + /// Whether this node should be running with low priority. + /// Whether this node should act as worker node and accpet build requests. + /// The exception which caused shutdown, if any. + /// The reason for shutting down. + public NodeEngineShutdownReason Run(bool enableReuse, bool lowPriority, bool workerNode, out Exception shutdownException) { // Console.WriteLine("Run called at {0}", DateTime.Now); string pipeName = NamedPipeUtil.GetPipeNameOrPath("MSBuild" + Process.GetCurrentProcess().Id); - _nodeEndpoint = new NodeEndpointOutOfProc(pipeName, this, enableReuse, lowPriority); + _nodeEndpoint = new NodeEndpointOutOfProc(pipeName, this, enableReuse, lowPriority, workerNode); _nodeEndpoint.OnLinkStatusChanged += OnLinkStatusChanged; _nodeEndpoint.Listen(this); diff --git a/src/Build/Instance/HostServices.cs b/src/Build/Instance/HostServices.cs index 8c820643d32..578c6f8a122 100644 --- a/src/Build/Instance/HostServices.cs +++ b/src/Build/Instance/HostServices.cs @@ -35,7 +35,12 @@ public enum NodeAffinity /// /// The project may be scheduled anywhere. /// - Any + Any, + + /// + /// The node accepts only RAR tasks. + /// + RarNode } /// diff --git a/src/Build/Microsoft.Build.csproj b/src/Build/Microsoft.Build.csproj index 5a6014e01db..fb4f5adce77 100644 --- a/src/Build/Microsoft.Build.csproj +++ b/src/Build/Microsoft.Build.csproj @@ -157,6 +157,7 @@ + diff --git a/src/Shared/CommunicationsUtilities.cs b/src/Shared/CommunicationsUtilities.cs index 2bb61d35127..2e9715cdc18 100644 --- a/src/Shared/CommunicationsUtilities.cs +++ b/src/Shared/CommunicationsUtilities.cs @@ -495,7 +495,7 @@ internal static async Task ReadAsync(Stream stream, byte[] buffer, int byte /// /// Given the appropriate information, return the equivalent HandshakeOptions. /// - internal static HandshakeOptions GetHandshakeOptions(bool taskHost, bool is64Bit = false, int clrVersion = 0, bool nodeReuse = false, bool lowPriority = false, IDictionary taskHostParameters = null) + internal static HandshakeOptions GetHandshakeOptions(bool taskHost, bool is64Bit = false, int clrVersion = 0, bool nodeReuse = false, bool lowPriority = false, bool workerNode = true, IDictionary taskHostParameters = null) { HandshakeOptions context = taskHost ? HandshakeOptions.TaskHost : HandshakeOptions.None; @@ -646,5 +646,32 @@ internal static int GetHandshakeHashCode(string fileVersion) } } } + + internal static string GetRARPipeName(bool nodeReuse, bool lowPriority) + { + var context = HandshakeOptions.None; + var userName = Environment.UserName; + var clrVersion = typeof(bool).GetTypeInfo().Assembly.GetName().Version.Major; + var is64Bit = XMakeAttributes.GetCurrentMSBuildArchitecture().Equals(XMakeAttributes.MSBuildArchitectureValues.x64); + + if (is64Bit) + { + context |= HandshakeOptions.X64; + } + if (clrVersion == 2) + { + context |= HandshakeOptions.CLR2; + } + if (nodeReuse) + { + context |= HandshakeOptions.NodeReuse; + } + if (lowPriority) + { + context |= HandshakeOptions.LowPriority; + } + + return $"MSBuild.RAR.{userName}.{(int)context}"; + } } } From 58e07d7f34d74137271adefc882aa26073cbf738 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Wed, 5 Aug 2020 15:37:28 +0200 Subject: [PATCH 03/61] RAR controller and client --- Directory.Build.props | 2 +- eng/Packages.props | 3 +- src/Build/BackEnd/Node/RarNode.cs | 57 ++++++++ src/Build/Microsoft.Build.csproj | 3 +- src/Framework/IRarBuildEngine.cs | 28 ++++ src/MSBuild/Properties/launchSettings.json | 8 ++ src/MSBuild/XMake.cs | 9 ++ src/Shared/NamedPipeUtil.cs | 68 +++++++++ .../ResolveAssemblyReference.cs | 30 ++++ src/Tasks/Microsoft.Build.Tasks.csproj | 22 +++ .../Microsoft.Common.CurrentVersion.targets | 5 + .../Client/RarClient.cs | 67 +++++++++ .../IResolveAssemblyReferenceTaskHandler.cs | 11 ++ .../ResolveAssemblyReferences/RpcUtils.cs | 21 +++ .../Server/RarController.cs | 130 ++++++++++++++++++ .../Server/ServerMutex.cs | 38 +++++ .../Services/RarTaskHandler.cs | 25 ++++ 17 files changed, 524 insertions(+), 3 deletions(-) create mode 100644 src/Build/BackEnd/Node/RarNode.cs create mode 100644 src/Framework/IRarBuildEngine.cs create mode 100644 src/MSBuild/Properties/launchSettings.json create mode 100644 src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs create mode 100644 src/Tasks/ResolveAssemblyReferences/Contract/IResolveAssemblyReferenceTaskHandler.cs create mode 100644 src/Tasks/ResolveAssemblyReferences/RpcUtils.cs create mode 100644 src/Tasks/ResolveAssemblyReferences/Server/RarController.cs create mode 100644 src/Tasks/ResolveAssemblyReferences/Server/ServerMutex.cs create mode 100644 src/Tasks/ResolveAssemblyReferences/Services/RarTaskHandler.cs diff --git a/Directory.Build.props b/Directory.Build.props index 1683a4c99e3..06f7144e812 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -51,7 +51,7 @@ NU5125: Arcade uses licenseUrl when doing pack, which now causes NU5125 warning. This disables that warning until arcade can switch over. --> - $(NoWarn);NU1603;NU5105;NU5125;1701;1702 + $(NoWarn);NU1603;NU5105;NU5125;1701;1702;VSTHRD002;VSTHRD105;VSTHRD110;VSTHRD200 diff --git a/eng/Packages.props b/eng/Packages.props index 34ef37a4d0f..d98f92b56ff 100644 --- a/eng/Packages.props +++ b/eng/Packages.props @@ -16,7 +16,7 @@ - + @@ -48,6 +48,7 @@ + diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs new file mode 100644 index 00000000000..d8a1314dc65 --- /dev/null +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -0,0 +1,57 @@ +using Microsoft.Build.BackEnd; +using Microsoft.Build.Internal; +using Microsoft.Build.Tasks.ResolveAssemblyReferences.Server; +using Microsoft.VisualStudio.Threading; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Build.Execution +{ + public sealed class RarNode : INode + { + private readonly OutOfProcNode _msBuildNode; + + private Task _rarTask; + private int rarResult; + + private Task _msBuildTask; + private Exception shutdownException; + private NodeEngineShutdownReason shutdownReason; + + public RarNode() + { + _msBuildNode = new OutOfProcNode(); + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", + Justification = "We need to wait for completion of async method in synchronous method (required by interface)")] + public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Exception shutdownException) + { + var cancellationTokenSource = new CancellationTokenSource(); + + var pipeName = CommunicationsUtilities.GetRARPipeName(nodeReuse, lowPriority); + var controller = new RarController(pipeName); + + Console.CancelKeyPress += (e, sender) => cancellationTokenSource.Cancel(); + + _rarTask = Task.Run(async () => rarResult = await controller.StartAsync(cancellationTokenSource.Token)); + _msBuildTask = Task.Run(() => shutdownReason = _msBuildNode.Run(nodeReuse, lowPriority, out this.shutdownException)).WithCancellation(cancellationTokenSource.Token); + + Task.WaitAny(_msBuildTask, _rarTask); + cancellationTokenSource.Cancel(); + Console.ReadLine(); + shutdownException = this.shutdownException; + return shutdownReason; + } + + public NodeEngineShutdownReason Run(out Exception shutdownException) + { + return Run(false, false, out shutdownException); + } + } +} diff --git a/src/Build/Microsoft.Build.csproj b/src/Build/Microsoft.Build.csproj index fb4f5adce77..9d474f889cf 100644 --- a/src/Build/Microsoft.Build.csproj +++ b/src/Build/Microsoft.Build.csproj @@ -1,4 +1,4 @@ - + @@ -159,6 +159,7 @@ + diff --git a/src/Framework/IRarBuildEngine.cs b/src/Framework/IRarBuildEngine.cs new file mode 100644 index 00000000000..7eec5c61f7e --- /dev/null +++ b/src/Framework/IRarBuildEngine.cs @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.IO.Pipes; + +namespace Microsoft.Build.Framework +{ + /// + /// This interface provides necessary funcionality from to RAR as a service funcionality + /// + internal interface IRarBuildEngine + { + /// + /// Inialize new RAR node + /// + internal bool CreateRarNode(); + + /// + /// Provides RAR node name for current configuration + /// + internal string GetRarPipeName(); + + /// + /// Constructs + /// + internal NamedPipeClientStream GetRarClientStream(string pipeName, int timeout); + } +} diff --git a/src/MSBuild/Properties/launchSettings.json b/src/MSBuild/Properties/launchSettings.json new file mode 100644 index 00000000000..e9938be846a --- /dev/null +++ b/src/MSBuild/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "MSBuild": { + "commandName": "Project", + "commandLineArgs": "C:/dev/sample" + } + } +} \ No newline at end of file diff --git a/src/MSBuild/XMake.cs b/src/MSBuild/XMake.cs index 524d4dc1141..60dc2fd5fd6 100644 --- a/src/MSBuild/XMake.cs +++ b/src/MSBuild/XMake.cs @@ -2635,6 +2635,15 @@ private static void StartLocalNode(CommandLineSwitches commandLineSwitches) OutOfProcTaskHostNode node = new OutOfProcTaskHostNode(); shutdownReason = node.Run(out nodeException); } + else if (nodeModeNumber == 3) + { + var node = new RarNode(); + // If FEATURE_NODE_REUSE is OFF, just validates that the switch is OK, and always returns False + bool nodeReuse = ProcessNodeReuseSwitch(commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.NodeReuse]); + bool lowPriority = commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.LowPriority][0].Equals("true"); + + shutdownReason = node.Run(nodeReuse, lowPriority, out nodeException); + } else { CommandLineSwitchException.Throw("InvalidNodeNumberValue", input[0]); diff --git a/src/Shared/NamedPipeUtil.cs b/src/Shared/NamedPipeUtil.cs index a7f8913e7d7..ea0236b1579 100644 --- a/src/Shared/NamedPipeUtil.cs +++ b/src/Shared/NamedPipeUtil.cs @@ -3,6 +3,8 @@ using System; using System.IO; +using System.IO.Pipes; +using System.Security.Principal; namespace Microsoft.Build.Shared { @@ -25,5 +27,71 @@ internal static string GetPipeNameOrPath(string pipeName) return pipeName; } } + internal static NamedPipeClientStream GetClientStream(string pipeName, int timeout) + { + // Try and connect to the process. + var nodeStream = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.Asynchronous +#if FEATURE_PIPEOPTIONS_CURRENTUSERONLY + | PipeOptions.CurrentUserOnly +#endif + ); + try + { + nodeStream.Connect(timeout); + +#if !FEATURE_PIPEOPTIONS_CURRENTUSERONLY + if (NativeMethodsShared.IsWindows && !NativeMethodsShared.IsMono) + { + // Verify that the owner of the pipe is us. This prevents a security hole where a remote node has + // been faked up with ACLs that would let us attach to it. It could then issue fake build requests back to + // us, potentially causing us to execute builds that do harmful or unexpected things. The pipe owner can + // only be set to the user's own SID by a normal, unprivileged process. The conditions where a faked up + // remote node could set the owner to something else would also let it change owners on other objects, so + // this would be a security flaw upstream of us. + ValidateRemotePipeSecurityOnWindows(nodeStream); + + } + + return nodeStream; +#endif + } + catch (Exception e) when (!ExceptionHandling.IsCriticalException(e)) + { + // Can be: + // UnauthorizedAccessException -- Couldn't connect, might not be a node. + // IOException -- Couldn't connect, already in use. + // TimeoutException -- Couldn't connect, might not be a node. + // InvalidOperationException Couldnt connect, probably a different build + + // If we don't close any stream, we might hang up the child + if (nodeStream != null) + { + nodeStream.Dispose(); + } + } + + return null; + } + +#if !FEATURE_PIPEOPTIONS_CURRENTUSERONLY + // This code needs to be in a separate method so that we don't try (and fail) to load the Windows-only APIs when JIT-ing the code + // on non-Windows operating systems + private static void ValidateRemotePipeSecurityOnWindows(NamedPipeClientStream nodeStream) + { + SecurityIdentifier identifier = WindowsIdentity.GetCurrent().Owner; +#if FEATURE_PIPE_SECURITY + PipeSecurity remoteSecurity = nodeStream.GetAccessControl(); +#else + var remoteSecurity = new PipeSecurity(nodeStream.SafePipeHandle, System.Security.AccessControl.AccessControlSections.Access | + System.Security.AccessControl.AccessControlSections.Owner | System.Security.AccessControl.AccessControlSections.Group); +#endif + IdentityReference remoteOwner = remoteSecurity.GetOwner(typeof(SecurityIdentifier)); + if (remoteOwner != identifier) + { + //CommunicationsUtilities.Trace("The remote pipe owner {0} does not match {1}", remoteOwner.Value, identifier.Value); + throw new UnauthorizedAccessException(); + } + } +#endif } } diff --git a/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs b/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs index 61e2a6a93e5..0a6529ffcd6 100644 --- a/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs +++ b/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs @@ -15,6 +15,7 @@ using Microsoft.Build.Framework; using Microsoft.Build.Shared; using Microsoft.Build.Tasks.AssemblyDependency; +using Microsoft.Build.Tasks.ResolveAssemblyReferences.Client; using Microsoft.Build.Utilities; using FrameworkNameVersioning = System.Runtime.Versioning.FrameworkName; @@ -203,6 +204,11 @@ public bool IgnoreTargetFrameworkAttributeVersionMismatch } } + /// + /// Indicates if ResolveAssemblyReference task should be run in its own node or not. + /// + public bool UseResolveAssemblyReferenceService { get; set; } + /// /// Force dependencies to be walked even when a reference is marked with ExternallyResolved=true /// metadata. @@ -2960,6 +2966,30 @@ private string GetAssemblyPathInGac(AssemblyNameExtension assemblyName, SystemPr /// True if there was success. public override bool Execute() { + if(UseResolveAssemblyReferenceService && BuildEngine is IRarBuildEngine rarBuildEngine) + { + using var client = new RarClient(rarBuildEngine); + + var connected = client.Connect(); + if (!connected) + { + if(client.CreateNode()) + { + connected = client.Connect(); + } + } + + if(connected) + { + // Client is connected to the RAR node, we can execute RAR task remotely + // return client.Execute(); // TODO: Let it do something. + var number = client.GetNumber(42); + + Debug.Assert(number == 42); + } + + } + return Execute ( new FileExists(p => FileUtilities.FileExistsNoThrow(p)), diff --git a/src/Tasks/Microsoft.Build.Tasks.csproj b/src/Tasks/Microsoft.Build.Tasks.csproj index 6275d3bcd30..c6f3c52c7f8 100644 --- a/src/Tasks/Microsoft.Build.Tasks.csproj +++ b/src/Tasks/Microsoft.Build.Tasks.csproj @@ -339,6 +339,12 @@ true + + + + + + @@ -979,6 +985,7 @@ + @@ -999,6 +1006,7 @@ + @@ -1007,6 +1015,20 @@ + + + + + + + + + + + + + + diff --git a/src/Tasks/Microsoft.Common.CurrentVersion.targets b/src/Tasks/Microsoft.Common.CurrentVersion.targets index b6afab6807b..1ff70fb1770 100644 --- a/src/Tasks/Microsoft.Common.CurrentVersion.targets +++ b/src/Tasks/Microsoft.Common.CurrentVersion.targets @@ -2082,6 +2082,10 @@ Copyright (C) Microsoft Corporation. All rights reserved. true + + false + + diff --git a/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs b/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs new file mode 100644 index 00000000000..c6f652e790c --- /dev/null +++ b/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs @@ -0,0 +1,67 @@ +using Microsoft.Build.Framework; +using Microsoft.Build.Shared; +using Microsoft.Build.Tasks.ResolveAssemblyReferences.Contract; +using Microsoft.VisualStudio.Threading; +using StreamJsonRpc; +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Pipes; +using System.Linq; +using System.Security.Principal; +using System.Text; +using System.Threading.Tasks; + +namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Client +{ + internal sealed class RarClient : IDisposable + { + private const int ConnectionTimeout = 30; + private readonly IRarBuildEngine _rarBuildEngine; + private NamedPipeClientStream _clientStream; + + public RarClient(IRarBuildEngine rarBuildEngine) + { + _rarBuildEngine = rarBuildEngine; + } + + + internal bool Connect() + { + var pipeName = _rarBuildEngine.GetRarPipeName(); + var stream = _rarBuildEngine.GetRarClientStream(pipeName, ConnectionTimeout); + + if (stream == null) + return false; // We couldn't connect + + _clientStream = stream; + return true; + } + + internal bool CreateNode() + { + return _rarBuildEngine.CreateRarNode(); + } + + internal int GetNumber(int parameter) + { + using var client = GetRpcClient(); + // TODO: Find out if there is any possibility of awaiting it. + return client.GetNumber(parameter).GetAwaiter().GetResult(); + } + + private IResolveAssemblyReferenceTaskHandler GetRpcClient() + { + ErrorUtilities.VerifyThrowArgumentNull(_clientStream, nameof(_clientStream)); + + var handler = RpcUtils.GetRarMessageHandler(_clientStream); + return JsonRpc.Attach(handler); + } + + public void Dispose() + { + if (_clientStream != null) + ((IDisposable)_clientStream).Dispose(); + } + } +} diff --git a/src/Tasks/ResolveAssemblyReferences/Contract/IResolveAssemblyReferenceTaskHandler.cs b/src/Tasks/ResolveAssemblyReferences/Contract/IResolveAssemblyReferenceTaskHandler.cs new file mode 100644 index 00000000000..4aa64dc699e --- /dev/null +++ b/src/Tasks/ResolveAssemblyReferences/Contract/IResolveAssemblyReferenceTaskHandler.cs @@ -0,0 +1,11 @@ +using System; +using System.Runtime.InteropServices; +using System.Threading.Tasks; + +namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Contract +{ + public interface IResolveAssemblyReferenceTaskHandler : IDisposable + { + Task GetNumber(int parameter); + } +} diff --git a/src/Tasks/ResolveAssemblyReferences/RpcUtils.cs b/src/Tasks/ResolveAssemblyReferences/RpcUtils.cs new file mode 100644 index 00000000000..4235a0df1b8 --- /dev/null +++ b/src/Tasks/ResolveAssemblyReferences/RpcUtils.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Nerdbank.Streams; +using StreamJsonRpc; + +#nullable enable +namespace Microsoft.Build.Tasks.ResolveAssemblyReferences +{ + internal static class RpcUtils + { + internal static IJsonRpcMessageHandler GetRarMessageHandler(Stream stream) + { + var formatter = new MessagePackFormatter(); + return new LengthHeaderMessageHandler(stream.UsePipe(), formatter); + } + } +} diff --git a/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs b/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs new file mode 100644 index 00000000000..17615d565c7 --- /dev/null +++ b/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs @@ -0,0 +1,130 @@ +using Microsoft.Build.Internal; +using Microsoft.Build.Shared; +using System; +using System.IO; +using System.IO.Pipes; +using System.Security.AccessControl; +using System.Security.Principal; +using System.Threading; +using System.Threading.Tasks; + +using StreamJsonRpc; +using Microsoft.Build.Tasks.ResolveAssemblyReferences; +using System.Collections.Generic; +using Nerdbank.Streams; +using Microsoft.VisualStudio.Threading; +using System.Diagnostics; +using Microsoft.Build.Tasks.ResolveAssemblyReferences.Contract; +using Microsoft.Build.Tasks.ResolveAssemblyReferences.Services; + +#nullable enable +namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Server +{ + public sealed class RarController + { + private const int PipeBufferSize = 131072; + + private readonly string _pipeName; + + private readonly IResolveAssemblyReferenceTaskHandler _rarTaskHandler; + + private NamedPipeServerStream? _serverStream; + + + public RarController(string pipeName) + { + _pipeName = pipeName; + _rarTaskHandler = new RarTaskHandler(); + } + + public async Task StartAsync(CancellationToken cancellationToken = default) + { + + using var mutex = new ServerMutex(_pipeName, out var createdNew); + + if (!createdNew) + return 1; + + while (true) + { + if (cancellationToken.IsCancellationRequested) + break; + + _serverStream = GetStream(_pipeName); + await _serverStream.WaitForConnectionAsync(cancellationToken); + // TODO: This waits for completion of the connection, make to accept multiple connection + await HandelConnectionAsync(_serverStream, cancellationToken); + } + return 0; + } + + private async Task HandelConnectionAsync(Stream serverStream, CancellationToken cancellationToken = default) + { + var server = GetRpcServer(serverStream, _rarTaskHandler); + server.StartListening(); + + await server.Completion.WithCancellation(cancellationToken); + } + + private JsonRpc GetRpcServer(Stream stream, IResolveAssemblyReferenceTaskHandler handler) + { + var serverHandler = RpcUtils.GetRarMessageHandler(stream); + var rpc = new JsonRpc(serverHandler, handler); + return rpc; + } + + /// + /// Instantiates an endpoint to act as a client + /// + /// The name of the pipe to which we should connect. + private NamedPipeServerStream GetStream(string pipeName) + { + ErrorUtilities.VerifyThrowArgumentLength(pipeName, "pipeName"); + + //_sharedReadBuffer = InterningBinaryReader.CreateSharedBuffer(); + +#if FEATURE_PIPE_SECURITY && FEATURE_NAMED_PIPE_SECURITY_CONSTRUCTOR + if (!NativeMethodsShared.IsMono) + { + var identifier = WindowsIdentity.GetCurrent().Owner; + var security = new PipeSecurity(); + + // Restrict access to just this account. We set the owner specifically here, and on the + // pipe client side they will check the owner against this one - they must have identical + // SIDs or the client will reject this server. This is used to avoid attacks where a + // hacked server creates a less restricted pipe in an attempt to lure us into using it and + // then sending build requests to the real pipe client (which is the MSBuild Build Manager.) + var rule = new PipeAccessRule(identifier, PipeAccessRights.ReadWrite, AccessControlType.Allow); + security.AddAccessRule(rule); + security.SetOwner(identifier); + + return new NamedPipeServerStream + ( + pipeName, + PipeDirection.InOut, + 1, // Only allow one connection at a time. + PipeTransmissionMode.Byte, + PipeOptions.Asynchronous | PipeOptions.WriteThrough, + PipeBufferSize, // Default input buffer + PipeBufferSize, // Default output buffer + security, + HandleInheritability.None + ); + } + else +#endif + { + return new NamedPipeServerStream + ( + pipeName, + PipeDirection.InOut, + 1, // Only allow one connection at a time. + PipeTransmissionMode.Byte, + PipeOptions.Asynchronous | PipeOptions.WriteThrough, + PipeBufferSize, // Default input buffer + PipeBufferSize // Default output buffer + ); + } + } + } +} diff --git a/src/Tasks/ResolveAssemblyReferences/Server/ServerMutex.cs b/src/Tasks/ResolveAssemblyReferences/Server/ServerMutex.cs new file mode 100644 index 00000000000..4d152ce8e3b --- /dev/null +++ b/src/Tasks/ResolveAssemblyReferences/Server/ServerMutex.cs @@ -0,0 +1,38 @@ +using System; +using System.Threading; + +namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Server +{ + internal sealed class ServerMutex : IDisposable + { + private readonly Mutex _mutex; + public bool IsLocked { get; private set; } + public bool IsDisposed { get; private set; } + + public ServerMutex(string name, out bool createdNew) + { + _mutex = new Mutex(true, name, out createdNew); + if (createdNew) + IsLocked = true; + } + + public void Dispose() + { + + if (IsDisposed) + return; + IsDisposed = true; + + try + { + if (IsLocked) + _mutex.ReleaseMutex(); + } + finally + { + _mutex.Dispose(); + IsLocked = false; + } + } + } +} diff --git a/src/Tasks/ResolveAssemblyReferences/Services/RarTaskHandler.cs b/src/Tasks/ResolveAssemblyReferences/Services/RarTaskHandler.cs new file mode 100644 index 00000000000..0a73fe08159 --- /dev/null +++ b/src/Tasks/ResolveAssemblyReferences/Services/RarTaskHandler.cs @@ -0,0 +1,25 @@ +using Microsoft.Build.Tasks.ResolveAssemblyReferences.Contract; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Services +{ + internal class RarTaskHandler : IResolveAssemblyReferenceTaskHandler + { + + public Task GetNumber(int parameter) + { + Console.WriteLine(parameter); + Console.WriteLine(); + return Task.FromResult(parameter); + } + + public void Dispose() + { + // For RPC dispose + } + } +} From 5dc03677c90a1021fa6eecf1a5724db74c3b54af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Wed, 5 Aug 2020 15:42:49 +0200 Subject: [PATCH 04/61] References --- .../net/Microsoft.Build.Tasks.Core.cs | 16 ++++++++++++++++ .../netstandard/Microsoft.Build.Tasks.Core.cs | 16 ++++++++++++++++ ref/Microsoft.Build/net/Microsoft.Build.cs | 8 ++++++++ .../netstandard/Microsoft.Build.cs | 8 ++++++++ 4 files changed, 48 insertions(+) diff --git a/ref/Microsoft.Build.Tasks.Core/net/Microsoft.Build.Tasks.Core.cs b/ref/Microsoft.Build.Tasks.Core/net/Microsoft.Build.Tasks.Core.cs index 4edef43d503..e333c727d44 100644 --- a/ref/Microsoft.Build.Tasks.Core/net/Microsoft.Build.Tasks.Core.cs +++ b/ref/Microsoft.Build.Tasks.Core/net/Microsoft.Build.Tasks.Core.cs @@ -940,6 +940,7 @@ public ResolveAssemblyReference() { } public string TargetFrameworkVersion { get { throw null; } set { } } public string TargetProcessorArchitecture { get { throw null; } set { } } public bool UnresolveFrameworkAssembliesFromHigherFrameworks { get { throw null; } set { } } + public bool UseResolveAssemblyReferenceService { get { throw null; } set { } } public string WarnOrErrorOnTargetArchitectureMismatch { get { throw null; } set { } } public override bool Execute() { throw null; } } @@ -2543,6 +2544,21 @@ public partial interface IVbcHostObjectFreeThreaded bool Compile(); } } +namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Contract +{ + public partial interface IResolveAssemblyReferenceTaskHandler : System.IDisposable + { + System.Threading.Tasks.Task GetNumber(int parameter); + } +} +namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Server +{ + public sealed partial class RarController + { + public RarController(string pipeName) { } + public System.Threading.Tasks.Task StartAsync(System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken)) { throw null; } + } +} namespace Microsoft.Build.Tasks.Xaml { public partial class CommandLineArgumentRelation : Microsoft.Build.Tasks.Xaml.PropertyRelation diff --git a/ref/Microsoft.Build.Tasks.Core/netstandard/Microsoft.Build.Tasks.Core.cs b/ref/Microsoft.Build.Tasks.Core/netstandard/Microsoft.Build.Tasks.Core.cs index 410b0fc73a8..f1c0aa1c600 100644 --- a/ref/Microsoft.Build.Tasks.Core/netstandard/Microsoft.Build.Tasks.Core.cs +++ b/ref/Microsoft.Build.Tasks.Core/netstandard/Microsoft.Build.Tasks.Core.cs @@ -598,6 +598,7 @@ public ResolveAssemblyReference() { } public string TargetFrameworkVersion { get { throw null; } set { } } public string TargetProcessorArchitecture { get { throw null; } set { } } public bool UnresolveFrameworkAssembliesFromHigherFrameworks { get { throw null; } set { } } + public bool UseResolveAssemblyReferenceService { get { throw null; } set { } } public string WarnOrErrorOnTargetArchitectureMismatch { get { throw null; } set { } } public override bool Execute() { throw null; } } @@ -1045,3 +1046,18 @@ public partial interface IVbcHostObjectFreeThreaded bool Compile(); } } +namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Contract +{ + public partial interface IResolveAssemblyReferenceTaskHandler : System.IDisposable + { + System.Threading.Tasks.Task GetNumber(int parameter); + } +} +namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Server +{ + public sealed partial class RarController + { + public RarController(string pipeName) { } + public System.Threading.Tasks.Task StartAsync(System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken)) { throw null; } + } +} diff --git a/ref/Microsoft.Build/net/Microsoft.Build.cs b/ref/Microsoft.Build/net/Microsoft.Build.cs index 835cbaf394f..6a73e861935 100644 --- a/ref/Microsoft.Build/net/Microsoft.Build.cs +++ b/ref/Microsoft.Build/net/Microsoft.Build.cs @@ -1096,6 +1096,7 @@ public enum NodeAffinity Any = 2, InProc = 0, OutOfProc = 1, + RarNode = 3, } public enum NodeEngineShutdownReason { @@ -1107,6 +1108,7 @@ public enum NodeEngineShutdownReason public partial class OutOfProcNode { public OutOfProcNode() { } + public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool enableReuse, bool lowPriority, bool workerNode, out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool enableReuse, bool lowPriority, out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool enableReuse, out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } public Microsoft.Build.Execution.NodeEngineShutdownReason Run(out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } @@ -1382,6 +1384,12 @@ internal ProjectTaskOutputPropertyInstance() { } public string TaskParameter { get { throw null; } } public override Microsoft.Build.Construction.ElementLocation TaskParameterLocation { get { throw null; } } } + public sealed partial class RarNode + { + public RarNode() { } + public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } + public Microsoft.Build.Execution.NodeEngineShutdownReason Run(out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } + } public partial class RequestedProjectState { public RequestedProjectState() { } diff --git a/ref/Microsoft.Build/netstandard/Microsoft.Build.cs b/ref/Microsoft.Build/netstandard/Microsoft.Build.cs index f659dab2bac..44a5cf67099 100644 --- a/ref/Microsoft.Build/netstandard/Microsoft.Build.cs +++ b/ref/Microsoft.Build/netstandard/Microsoft.Build.cs @@ -1090,6 +1090,7 @@ public enum NodeAffinity Any = 2, InProc = 0, OutOfProc = 1, + RarNode = 3, } public enum NodeEngineShutdownReason { @@ -1101,6 +1102,7 @@ public enum NodeEngineShutdownReason public partial class OutOfProcNode { public OutOfProcNode() { } + public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool enableReuse, bool lowPriority, bool workerNode, out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool enableReuse, bool lowPriority, out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool enableReuse, out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } public Microsoft.Build.Execution.NodeEngineShutdownReason Run(out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } @@ -1376,6 +1378,12 @@ internal ProjectTaskOutputPropertyInstance() { } public string TaskParameter { get { throw null; } } public override Microsoft.Build.Construction.ElementLocation TaskParameterLocation { get { throw null; } } } + public sealed partial class RarNode + { + public RarNode() { } + public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } + public Microsoft.Build.Execution.NodeEngineShutdownReason Run(out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } + } public partial class RequestedProjectState { public RequestedProjectState() { } From 55268c1cb12c1c3c4e769f1c38ff5660378846a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Thu, 6 Aug 2020 12:24:21 +0200 Subject: [PATCH 05/61] Chganes based on comment in PR review --- .../Communications/NodeEndpointOutOfProc.cs | 7 +++- .../Components/Communications/NodeManager.cs | 16 +++----- .../NodeProviderOutOfProcBase.cs | 4 +- .../NodeProviderOutOfProcRar.cs | 19 ++++----- src/Build/BackEnd/Node/RarNode.cs | 21 +++++----- src/Tasks/Microsoft.Build.Tasks.csproj | 14 ------- .../Client/RarClient.cs | 21 +++++----- .../IResolveAssemblyReferenceTaskHandler.cs | 6 ++- .../ResolveAssemblyReferences/RpcUtils.cs | 9 ++--- .../Server/RarController.cs | 40 +++++++++---------- .../Server/ServerMutex.cs | 11 ++++- .../Services/RarTaskHandler.cs | 9 +++-- 12 files changed, 82 insertions(+), 95 deletions(-) diff --git a/src/Build/BackEnd/Components/Communications/NodeEndpointOutOfProc.cs b/src/Build/BackEnd/Components/Communications/NodeEndpointOutOfProc.cs index 654adbe383b..0c124e22c87 100644 --- a/src/Build/BackEnd/Components/Communications/NodeEndpointOutOfProc.cs +++ b/src/Build/BackEnd/Components/Communications/NodeEndpointOutOfProc.cs @@ -60,7 +60,12 @@ internal NodeEndpointOutOfProc( /// protected override Handshake GetHandshake() { - return new Handshake(CommunicationsUtilities.GetHandshakeOptions(taskHost: false, is64Bit: EnvironmentUtilities.Is64BitProcess, nodeReuse: _enableReuse, lowPriority: _lowPriority, _workerNode)); + return new Handshake(CommunicationsUtilities.GetHandshakeOptions( + taskHost: false, + is64Bit: EnvironmentUtilities.Is64BitProcess, + nodeReuse: _enableReuse, + lowPriority: _lowPriority, + _workerNode)); } #region Structs diff --git a/src/Build/BackEnd/Components/Communications/NodeManager.cs b/src/Build/BackEnd/Components/Communications/NodeManager.cs index 6b8e496b406..dc61bffae81 100644 --- a/src/Build/BackEnd/Components/Communications/NodeManager.cs +++ b/src/Build/BackEnd/Components/Communications/NodeManager.cs @@ -119,7 +119,7 @@ public NodeInfo CreateNode(NodeConfiguration configuration, NodeAffinity nodeAff nodeId = AttemptCreateNode(_outOfProcNodeProvider, configuration); } - if (nodeId == InvalidNodeId && (nodeAffinity == NodeAffinity.RarNode)) + if (nodeId == InvalidNodeId && nodeAffinity == NodeAffinity.RarNode) { nodeId = AttemptCreateNode(_outOfProcRarNodeProvider, configuration); } @@ -178,10 +178,7 @@ public void ShutdownConnectedNodes(bool enableReuse) _outOfProcNodeProvider.ShutdownConnectedNodes(enableReuse); } - if(null != _outOfProcRarNodeProvider) - { - _outOfProcRarNodeProvider.ShutdownConnectedNodes(enableReuse); - } + _outOfProcRarNodeProvider?.ShutdownConnectedNodes(enableReuse); } /// @@ -195,10 +192,7 @@ public void ShutdownAllNodes() _outOfProcNodeProvider.ShutdownAllNodes(); } - if (null != _outOfProcRarNodeProvider) - { - _outOfProcRarNodeProvider.ShutdownAllNodes(); - } + _outOfProcRarNodeProvider?.ShutdownAllNodes(); } #endregion @@ -239,9 +233,9 @@ public void ShutdownComponent() ((IDisposable)_outOfProcNodeProvider).Dispose(); } - if (_outOfProcRarNodeProvider != null && _outOfProcRarNodeProvider is IDisposable) + if (_outOfProcRarNodeProvider is IDisposable rarNodeProvider) { - ((IDisposable)_outOfProcRarNodeProvider).Dispose(); + rarNodeProvider.Dispose(); } _inProcNodeProvider = null; diff --git a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs index 59a8386e263..589559c74e8 100644 --- a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs +++ b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs @@ -133,14 +133,14 @@ protected void ShutdownAllNodes(bool nodeReuse, NodeContextTerminateDelegate ter nodeStream = TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, true, true)); } - if (null == nodeStream) + if (nodeStream == null) { // Attempt to connect to the non-worker process // Attempt to connect to the process with the handshake without low priority. nodeStream = TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, false, false)); - if (null == nodeStream) + if (nodeStream == null) { // If we couldn't connect attempt to connect to the process with the handshake including low priority. nodeStream = TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, true, false)); diff --git a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcRar.cs b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcRar.cs index bc9c0f0590f..0e912831c9b 100644 --- a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcRar.cs +++ b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcRar.cs @@ -5,7 +5,7 @@ namespace Microsoft.Build.BackEnd { - class NodeProviderOutOfProcRar : NodeProviderOutOfProcBase, INodeProvider + internal sealed class NodeProviderOutOfProcRar : NodeProviderOutOfProcBase, INodeProvider { private int? _rarNodeId = null; private NodeContext _rarNodeContext = null; @@ -17,15 +17,10 @@ class NodeProviderOutOfProcRar : NodeProviderOutOfProcBase, INodeProvider public bool CreateNode(int nodeId, INodePacketFactory factory, NodeConfiguration configuration) { ErrorUtilities.VerifyThrowArgumentNull(factory, "factory"); + ErrorUtilities.VerifyThrow(_rarNodeId.HasValue, "RAR node already created."); - if (_rarNodeId.HasValue) - { - ErrorUtilities.ThrowInternalError("RAR node already creared."); - return false; - } - - // Start the new process. We pass in a node mode with a node number of 1, to indicate that we - // want to start up just a standard MSBuild out-of-proc node. + // Start the new process. We pass in a node mode with a node number of 3, to indicate that we + // want to start up RAR out-of-proc node. // Note: We need to always pass /nodeReuse to ensure the value for /nodeReuse from msbuild.rsp // (next to msbuild.exe) is ignored. string commandLineArgs = $"/nologo /nodemode:3 /nodeReuse:{ComponentHost.BuildParameters.EnableNodeReuse.ToString().ToLower()} /low:{ComponentHost.BuildParameters.LowPriority.ToString().ToLower()}"; @@ -40,7 +35,7 @@ public bool CreateNode(int nodeId, INodePacketFactory factory, NodeConfiguration workerNode: false)); NodeContext context = GetNode(null, commandLineArgs, nodeId, factory, hostHandshake, NodeContextTerminated); - if (null != context) + if (context != null) { _rarNodeId = nodeId; _rarNodeContext = context; @@ -98,6 +93,8 @@ static internal IBuildComponent CreateComponent(BuildComponentType componentType public void SendData(int node, INodePacket packet) { + ErrorUtilities.VerifyThrowInternalNull(packet, "Packet is null"); + if (_rarNodeId == node) { _rarNodeContext.SendData(packet); @@ -127,7 +124,7 @@ public void ShutdownConnectedNodes(bool enableReuse) // RAR node is special if (_rarNodeId != null && !enableReuse) { - var contextList = new List() + List contextList = new List() { _rarNodeContext }; diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs index d8a1314dc65..7d4101d09ff 100644 --- a/src/Build/BackEnd/Node/RarNode.cs +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -1,15 +1,16 @@ -using Microsoft.Build.BackEnd; -using Microsoft.Build.Internal; -using Microsoft.Build.Tasks.ResolveAssemblyReferences.Server; -using Microsoft.VisualStudio.Threading; +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + using System; -using System.Collections.Generic; using System.Linq; -using System.Security.Cryptography.X509Certificates; -using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.Build.BackEnd; +using Microsoft.Build.Internal; +using Microsoft.Build.Tasks.ResolveAssemblyReferences.Server; +using Microsoft.VisualStudio.Threading; + namespace Microsoft.Build.Execution { public sealed class RarNode : INode @@ -17,7 +18,7 @@ public sealed class RarNode : INode private readonly OutOfProcNode _msBuildNode; private Task _rarTask; - private int rarResult; + private int _rarResult; private Task _msBuildTask; private Exception shutdownException; @@ -39,12 +40,12 @@ public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Except Console.CancelKeyPress += (e, sender) => cancellationTokenSource.Cancel(); - _rarTask = Task.Run(async () => rarResult = await controller.StartAsync(cancellationTokenSource.Token)); + _rarTask = Task.Run(async () => _rarResult = await controller.StartAsync(cancellationTokenSource.Token).ConfigureAwait(false)); _msBuildTask = Task.Run(() => shutdownReason = _msBuildNode.Run(nodeReuse, lowPriority, out this.shutdownException)).WithCancellation(cancellationTokenSource.Token); Task.WaitAny(_msBuildTask, _rarTask); cancellationTokenSource.Cancel(); - Console.ReadLine(); + shutdownException = this.shutdownException; return shutdownReason; } diff --git a/src/Tasks/Microsoft.Build.Tasks.csproj b/src/Tasks/Microsoft.Build.Tasks.csproj index c6f3c52c7f8..456953e71e4 100644 --- a/src/Tasks/Microsoft.Build.Tasks.csproj +++ b/src/Tasks/Microsoft.Build.Tasks.csproj @@ -1015,20 +1015,6 @@ - - - - - - - - - - - - - - diff --git a/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs b/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs index c6f652e790c..29965290b84 100644 --- a/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs +++ b/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs @@ -1,16 +1,14 @@ -using Microsoft.Build.Framework; +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.IO.Pipes; + +using Microsoft.Build.Framework; using Microsoft.Build.Shared; using Microsoft.Build.Tasks.ResolveAssemblyReferences.Contract; -using Microsoft.VisualStudio.Threading; using StreamJsonRpc; -using System; -using System.Collections.Generic; -using System.IO; -using System.IO.Pipes; -using System.Linq; -using System.Security.Principal; -using System.Text; -using System.Threading.Tasks; + namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Client { @@ -60,8 +58,7 @@ private IResolveAssemblyReferenceTaskHandler GetRpcClient() public void Dispose() { - if (_clientStream != null) - ((IDisposable)_clientStream).Dispose(); + _clientStream?.Dispose(); } } } diff --git a/src/Tasks/ResolveAssemblyReferences/Contract/IResolveAssemblyReferenceTaskHandler.cs b/src/Tasks/ResolveAssemblyReferences/Contract/IResolveAssemblyReferenceTaskHandler.cs index 4aa64dc699e..2a320469821 100644 --- a/src/Tasks/ResolveAssemblyReferences/Contract/IResolveAssemblyReferenceTaskHandler.cs +++ b/src/Tasks/ResolveAssemblyReferences/Contract/IResolveAssemblyReferenceTaskHandler.cs @@ -1,5 +1,7 @@ -using System; -using System.Runtime.InteropServices; +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; using System.Threading.Tasks; namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Contract diff --git a/src/Tasks/ResolveAssemblyReferences/RpcUtils.cs b/src/Tasks/ResolveAssemblyReferences/RpcUtils.cs index 4235a0df1b8..2d1d17d3af9 100644 --- a/src/Tasks/ResolveAssemblyReferences/RpcUtils.cs +++ b/src/Tasks/ResolveAssemblyReferences/RpcUtils.cs @@ -1,9 +1,8 @@ -using System; -using System.Collections.Generic; +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; + using Nerdbank.Streams; using StreamJsonRpc; diff --git a/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs b/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs index 17615d565c7..d05e57c83c7 100644 --- a/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs +++ b/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs @@ -1,6 +1,6 @@ -using Microsoft.Build.Internal; -using Microsoft.Build.Shared; -using System; +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + using System.IO; using System.IO.Pipes; using System.Security.AccessControl; @@ -8,14 +8,12 @@ using System.Threading; using System.Threading.Tasks; -using StreamJsonRpc; -using Microsoft.Build.Tasks.ResolveAssemblyReferences; -using System.Collections.Generic; -using Nerdbank.Streams; -using Microsoft.VisualStudio.Threading; -using System.Diagnostics; +using Microsoft.Build.Shared; using Microsoft.Build.Tasks.ResolveAssemblyReferences.Contract; using Microsoft.Build.Tasks.ResolveAssemblyReferences.Services; +using Microsoft.VisualStudio.Threading; + +using StreamJsonRpc; #nullable enable namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Server @@ -26,23 +24,26 @@ public sealed class RarController private readonly string _pipeName; - private readonly IResolveAssemblyReferenceTaskHandler _rarTaskHandler; + private readonly IResolveAssemblyReferenceTaskHandler _resolveAssemblyReferenceTaskHandler; private NamedPipeServerStream? _serverStream; + public RarController(string pipeName) : this(pipeName, new RarTaskHandler()) + { + } - public RarController(string pipeName) + internal RarController(string pipeName, IResolveAssemblyReferenceTaskHandler resolveAssemblyReferenceTaskHandler) { _pipeName = pipeName; - _rarTaskHandler = new RarTaskHandler(); + _resolveAssemblyReferenceTaskHandler = resolveAssemblyReferenceTaskHandler; } public async Task StartAsync(CancellationToken cancellationToken = default) { - using var mutex = new ServerMutex(_pipeName, out var createdNew); + using var mutex = new ServerMutex(_pipeName); - if (!createdNew) + if (mutex.CreatedNew) return 1; while (true) @@ -51,19 +52,19 @@ public async Task StartAsync(CancellationToken cancellationToken = default) break; _serverStream = GetStream(_pipeName); - await _serverStream.WaitForConnectionAsync(cancellationToken); + await _serverStream.WaitForConnectionAsync(cancellationToken).ConfigureAwait(false); // TODO: This waits for completion of the connection, make to accept multiple connection - await HandelConnectionAsync(_serverStream, cancellationToken); + await HandelConnectionAsync(_serverStream, cancellationToken).ConfigureAwait(false); } return 0; } private async Task HandelConnectionAsync(Stream serverStream, CancellationToken cancellationToken = default) { - var server = GetRpcServer(serverStream, _rarTaskHandler); + var server = GetRpcServer(serverStream, _resolveAssemblyReferenceTaskHandler); server.StartListening(); - await server.Completion.WithCancellation(cancellationToken); + await server.Completion.WithCancellation(cancellationToken).ConfigureAwait(false); } private JsonRpc GetRpcServer(Stream stream, IResolveAssemblyReferenceTaskHandler handler) @@ -80,9 +81,6 @@ private JsonRpc GetRpcServer(Stream stream, IResolveAssemblyReferenceTaskHandler private NamedPipeServerStream GetStream(string pipeName) { ErrorUtilities.VerifyThrowArgumentLength(pipeName, "pipeName"); - - //_sharedReadBuffer = InterningBinaryReader.CreateSharedBuffer(); - #if FEATURE_PIPE_SECURITY && FEATURE_NAMED_PIPE_SECURITY_CONSTRUCTOR if (!NativeMethodsShared.IsMono) { diff --git a/src/Tasks/ResolveAssemblyReferences/Server/ServerMutex.cs b/src/Tasks/ResolveAssemblyReferences/Server/ServerMutex.cs index 4d152ce8e3b..fe162b9514f 100644 --- a/src/Tasks/ResolveAssemblyReferences/Server/ServerMutex.cs +++ b/src/Tasks/ResolveAssemblyReferences/Server/ServerMutex.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; using System.Threading; namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Server @@ -8,12 +11,16 @@ internal sealed class ServerMutex : IDisposable private readonly Mutex _mutex; public bool IsLocked { get; private set; } public bool IsDisposed { get; private set; } + public bool CreatedNew { get; } - public ServerMutex(string name, out bool createdNew) + public ServerMutex(string name) { + bool createdNew; _mutex = new Mutex(true, name, out createdNew); if (createdNew) IsLocked = true; + + CreatedNew = createdNew; } public void Dispose() diff --git a/src/Tasks/ResolveAssemblyReferences/Services/RarTaskHandler.cs b/src/Tasks/ResolveAssemblyReferences/Services/RarTaskHandler.cs index 0a73fe08159..5e1854f9873 100644 --- a/src/Tasks/ResolveAssemblyReferences/Services/RarTaskHandler.cs +++ b/src/Tasks/ResolveAssemblyReferences/Services/RarTaskHandler.cs @@ -1,10 +1,11 @@ -using Microsoft.Build.Tasks.ResolveAssemblyReferences.Contract; +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading.Tasks; +using Microsoft.Build.Tasks.ResolveAssemblyReferences.Contract; + namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Services { internal class RarTaskHandler : IResolveAssemblyReferenceTaskHandler From 5ebe6f7985f0e2255f0a4ae9926565019eaec4e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Thu, 6 Aug 2020 12:55:44 +0200 Subject: [PATCH 06/61] PR comments --- .../NodeProviderOutOfProcBase.cs | 25 ++++++------------- .../Components/RequestBuilder/TaskHost.cs | 2 +- src/Build/BackEnd/Node/RarNode.cs | 2 +- src/MSBuild/Properties/launchSettings.json | 8 ------ src/Shared/CommunicationsUtilities.cs | 25 ++++++++++++++++--- src/Shared/NamedPipeUtil.cs | 8 ++++-- 6 files changed, 36 insertions(+), 34 deletions(-) delete mode 100644 src/MSBuild/Properties/launchSettings.json diff --git a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs index 589559c74e8..263bc3b1904 100644 --- a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs +++ b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs @@ -127,25 +127,14 @@ protected void ShutdownAllNodes(bool nodeReuse, NodeContextTerminateDelegate ter // Attempt to connect to the process with the handshake without low priority. Stream nodeStream = TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, false, true)); - if (null == nodeStream) - { - // If we couldn't connect attempt to connect to the process with the handshake including low priority. - nodeStream = TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, true, true)); - } - - if (nodeStream == null) - { - // Attempt to connect to the non-worker process - - // Attempt to connect to the process with the handshake without low priority. - nodeStream = TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, false, false)); + // If we couldn't connect attempt to connect to the process with the handshake including low priority. + nodeStream ??= TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, true, true)); - if (nodeStream == null) - { - // If we couldn't connect attempt to connect to the process with the handshake including low priority. - nodeStream = TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, true, false)); - } - } + // Attempt to connect to the non-worker process + // Attempt to connect to the process with the handshake without low priority. + nodeStream ??= TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, false, false)); + // If we couldn't connect attempt to connect to the process with the handshake including low priority. + nodeStream ??= TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, true, false)); if (null != nodeStream) { diff --git a/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs b/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs index aab52a01b24..b5bb2110a26 100644 --- a/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs +++ b/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs @@ -1021,7 +1021,7 @@ bool IRarBuildEngine.CreateRarNode() string IRarBuildEngine.GetRarPipeName() { var parameters = _host.BuildParameters; - return CommunicationsUtilities.GetRARPipeName(parameters.EnableNodeReuse, parameters.LowPriority); + return CommunicationsUtilities.GetRarPipeName(parameters.EnableNodeReuse, parameters.LowPriority); } /// diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs index 7d4101d09ff..39194357e04 100644 --- a/src/Build/BackEnd/Node/RarNode.cs +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -35,7 +35,7 @@ public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Except { var cancellationTokenSource = new CancellationTokenSource(); - var pipeName = CommunicationsUtilities.GetRARPipeName(nodeReuse, lowPriority); + var pipeName = CommunicationsUtilities.GetRarPipeName(nodeReuse, lowPriority); var controller = new RarController(pipeName); Console.CancelKeyPress += (e, sender) => cancellationTokenSource.Cancel(); diff --git a/src/MSBuild/Properties/launchSettings.json b/src/MSBuild/Properties/launchSettings.json deleted file mode 100644 index e9938be846a..00000000000 --- a/src/MSBuild/Properties/launchSettings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "profiles": { - "MSBuild": { - "commandName": "Project", - "commandLineArgs": "C:/dev/sample" - } - } -} \ No newline at end of file diff --git a/src/Shared/CommunicationsUtilities.cs b/src/Shared/CommunicationsUtilities.cs index 6b11537696b..134048e722f 100644 --- a/src/Shared/CommunicationsUtilities.cs +++ b/src/Shared/CommunicationsUtilities.cs @@ -7,12 +7,13 @@ using System.Globalization; using System.IO; using System.IO.Pipes; +using System.Reflection; using System.Runtime.InteropServices; using System.Security.Principal; using System.Threading; using Microsoft.Build.Shared; -using System.Reflection; +using Microsoft.Build.BackEnd.Logging; #if !FEATURE_APM using System.Threading.Tasks; @@ -154,6 +155,22 @@ static internal int NodeConnectionTimeout get { return GetIntegerVariableOrDefault("MSBUILDNODECONNECTIONTIMEOUT", DefaultNodeConnectionTimeout); } } + private static int? _clrVersion = null; + /// + /// Provides cahced value of current CLR version + /// + private static int ClrVersion + { + get + { + if (_clrVersion.HasValue) + return _clrVersion.Value; + + _clrVersion = typeof(bool).GetTypeInfo().Assembly.GetName().Version.Major; + return _clrVersion.Value; + } + } + /// /// Get environment block /// @@ -471,7 +488,7 @@ internal static HandshakeOptions GetHandshakeOptions(bool taskHost, bool is64Bit // Take the current TaskHost context if (taskHostParameters == null) { - clrVersion = typeof(bool).GetTypeInfo().Assembly.GetName().Version.Major; + clrVersion = ClrVersion; is64Bit = XMakeAttributes.GetCurrentMSBuildArchitecture().Equals(XMakeAttributes.MSBuildArchitectureValues.x64); } else @@ -629,11 +646,11 @@ internal static int AvoidEndOfHandshakeSignal(int x) return x == EndOfHandshakeSignal ? ~x : x; } - internal static string GetRARPipeName(bool nodeReuse, bool lowPriority) + internal static string GetRarPipeName(bool nodeReuse, bool lowPriority) { var context = HandshakeOptions.None; var userName = Environment.UserName; - var clrVersion = typeof(bool).GetTypeInfo().Assembly.GetName().Version.Major; + var clrVersion = ClrVersion; var is64Bit = XMakeAttributes.GetCurrentMSBuildArchitecture().Equals(XMakeAttributes.MSBuildArchitectureValues.x64); if (is64Bit) diff --git a/src/Shared/NamedPipeUtil.cs b/src/Shared/NamedPipeUtil.cs index ea0236b1579..89ecbd99c90 100644 --- a/src/Shared/NamedPipeUtil.cs +++ b/src/Shared/NamedPipeUtil.cs @@ -6,10 +6,14 @@ using System.IO.Pipes; using System.Security.Principal; +using Microsoft.Build.Internal; + namespace Microsoft.Build.Shared { internal static class NamedPipeUtil { + private static readonly Type SecurityIdentiferType = typeof(SecurityIdentifier); + internal static string GetPipeNameOrPath(string pipeName) { if (NativeMethodsShared.IsUnixLike) @@ -85,10 +89,10 @@ private static void ValidateRemotePipeSecurityOnWindows(NamedPipeClientStream no var remoteSecurity = new PipeSecurity(nodeStream.SafePipeHandle, System.Security.AccessControl.AccessControlSections.Access | System.Security.AccessControl.AccessControlSections.Owner | System.Security.AccessControl.AccessControlSections.Group); #endif - IdentityReference remoteOwner = remoteSecurity.GetOwner(typeof(SecurityIdentifier)); + IdentityReference remoteOwner = remoteSecurity.GetOwner(SecurityIdentiferType); if (remoteOwner != identifier) { - //CommunicationsUtilities.Trace("The remote pipe owner {0} does not match {1}", remoteOwner.Value, identifier.Value); + CommunicationsUtilities.Trace("The remote pipe owner {0} does not match {1}", remoteOwner.Value, identifier.Value); throw new UnauthorizedAccessException(); } } From de63fce8072cef45d3a39cb1c45e410449bca28d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Thu, 6 Aug 2020 16:09:34 +0200 Subject: [PATCH 07/61] Update src/Shared/CommunicationsUtilities.cs Co-authored-by: Ladi Prosek --- src/Shared/CommunicationsUtilities.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Shared/CommunicationsUtilities.cs b/src/Shared/CommunicationsUtilities.cs index 134048e722f..aa246a40c44 100644 --- a/src/Shared/CommunicationsUtilities.cs +++ b/src/Shared/CommunicationsUtilities.cs @@ -163,10 +163,10 @@ private static int ClrVersion { get { - if (_clrVersion.HasValue) - return _clrVersion.Value; - - _clrVersion = typeof(bool).GetTypeInfo().Assembly.GetName().Version.Major; + if (!_clrVersion.HasValue) + { + _clrVersion = typeof(bool).GetTypeInfo().Assembly.GetName().Version.Major; + } return _clrVersion.Value; } } From ba9af0a4b9567fc5ccd72a79f226dbbf745a89fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Thu, 6 Aug 2020 19:21:58 +0200 Subject: [PATCH 08/61] PR comments --- src/Framework/IRarBuildEngine.cs | 2 +- src/Shared/CommunicationsUtilities.cs | 4 ++-- src/Shared/NamedPipeUtil.cs | 4 +--- src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs | 8 +++----- src/Tasks/Microsoft.Common.CurrentVersion.targets | 4 ---- .../ResolveAssemblyReferences/Server/RarController.cs | 8 ++++---- .../ResolveAssemblyReferences/Server/ServerMutex.cs | 9 ++------- 7 files changed, 13 insertions(+), 26 deletions(-) diff --git a/src/Framework/IRarBuildEngine.cs b/src/Framework/IRarBuildEngine.cs index 7eec5c61f7e..003bfe3aee9 100644 --- a/src/Framework/IRarBuildEngine.cs +++ b/src/Framework/IRarBuildEngine.cs @@ -6,7 +6,7 @@ namespace Microsoft.Build.Framework { /// - /// This interface provides necessary funcionality from to RAR as a service funcionality + /// This interface provides necessary functionality from to RAR as a service funcionality /// internal interface IRarBuildEngine { diff --git a/src/Shared/CommunicationsUtilities.cs b/src/Shared/CommunicationsUtilities.cs index 134048e722f..d38de512082 100644 --- a/src/Shared/CommunicationsUtilities.cs +++ b/src/Shared/CommunicationsUtilities.cs @@ -157,7 +157,7 @@ static internal int NodeConnectionTimeout private static int? _clrVersion = null; /// - /// Provides cahced value of current CLR version + /// Provides cached value of current CLR version /// private static int ClrVersion { @@ -649,7 +649,7 @@ internal static int AvoidEndOfHandshakeSignal(int x) internal static string GetRarPipeName(bool nodeReuse, bool lowPriority) { var context = HandshakeOptions.None; - var userName = Environment.UserName; + var userName = $"{Environment.UserDomainName}.{Environment.UserName}"; var clrVersion = ClrVersion; var is64Bit = XMakeAttributes.GetCurrentMSBuildArchitecture().Equals(XMakeAttributes.MSBuildArchitectureValues.x64); diff --git a/src/Shared/NamedPipeUtil.cs b/src/Shared/NamedPipeUtil.cs index 89ecbd99c90..a34217b02ea 100644 --- a/src/Shared/NamedPipeUtil.cs +++ b/src/Shared/NamedPipeUtil.cs @@ -12,8 +12,6 @@ namespace Microsoft.Build.Shared { internal static class NamedPipeUtil { - private static readonly Type SecurityIdentiferType = typeof(SecurityIdentifier); - internal static string GetPipeNameOrPath(string pipeName) { if (NativeMethodsShared.IsUnixLike) @@ -89,7 +87,7 @@ private static void ValidateRemotePipeSecurityOnWindows(NamedPipeClientStream no var remoteSecurity = new PipeSecurity(nodeStream.SafePipeHandle, System.Security.AccessControl.AccessControlSections.Access | System.Security.AccessControl.AccessControlSections.Owner | System.Security.AccessControl.AccessControlSections.Group); #endif - IdentityReference remoteOwner = remoteSecurity.GetOwner(SecurityIdentiferType); + IdentityReference remoteOwner = remoteSecurity.GetOwner(typeof(SecurityIdentifier)); if (remoteOwner != identifier) { CommunicationsUtilities.Trace("The remote pipe owner {0} does not match {1}", remoteOwner.Value, identifier.Value); diff --git a/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs b/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs index 8c81f91638e..a1f0a6ceb75 100644 --- a/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs +++ b/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs @@ -2979,7 +2979,7 @@ private string GetAssemblyPathInGac(AssemblyNameExtension assemblyName, SystemPr /// True if there was success. public override bool Execute() { - if(UseResolveAssemblyReferenceService && BuildEngine is IRarBuildEngine rarBuildEngine) + if (UseResolveAssemblyReferenceService && BuildEngine is IRarBuildEngine rarBuildEngine) { using var client = new RarClient(rarBuildEngine); @@ -2992,13 +2992,11 @@ public override bool Execute() } } - if(connected) + if (connected) { // Client is connected to the RAR node, we can execute RAR task remotely // return client.Execute(); // TODO: Let it do something. - var number = client.GetNumber(42); - - Debug.Assert(number == 42); + //var number = client.GetNumber(42); } } diff --git a/src/Tasks/Microsoft.Common.CurrentVersion.targets b/src/Tasks/Microsoft.Common.CurrentVersion.targets index 1ff70fb1770..7aad0c816a4 100644 --- a/src/Tasks/Microsoft.Common.CurrentVersion.targets +++ b/src/Tasks/Microsoft.Common.CurrentVersion.targets @@ -2082,10 +2082,6 @@ Copyright (C) Microsoft Corporation. All rights reserved. true - - false - - StartAsync(CancellationToken cancellationToken = default) using var mutex = new ServerMutex(_pipeName); - if (mutex.CreatedNew) + if (mutex.IsLocked) return 1; while (true) @@ -54,12 +54,12 @@ public async Task StartAsync(CancellationToken cancellationToken = default) _serverStream = GetStream(_pipeName); await _serverStream.WaitForConnectionAsync(cancellationToken).ConfigureAwait(false); // TODO: This waits for completion of the connection, make to accept multiple connection - await HandelConnectionAsync(_serverStream, cancellationToken).ConfigureAwait(false); + await HandleConnectionAsync(_serverStream, cancellationToken).ConfigureAwait(false); } return 0; } - private async Task HandelConnectionAsync(Stream serverStream, CancellationToken cancellationToken = default) + private async Task HandleConnectionAsync(Stream serverStream, CancellationToken cancellationToken = default) { var server = GetRpcServer(serverStream, _resolveAssemblyReferenceTaskHandler); server.StartListening(); @@ -113,7 +113,7 @@ private NamedPipeServerStream GetStream(string pipeName) #endif { return new NamedPipeServerStream - ( + ( pipeName, PipeDirection.InOut, 1, // Only allow one connection at a time. diff --git a/src/Tasks/ResolveAssemblyReferences/Server/ServerMutex.cs b/src/Tasks/ResolveAssemblyReferences/Server/ServerMutex.cs index fe162b9514f..7d314d89e30 100644 --- a/src/Tasks/ResolveAssemblyReferences/Server/ServerMutex.cs +++ b/src/Tasks/ResolveAssemblyReferences/Server/ServerMutex.cs @@ -11,16 +11,11 @@ internal sealed class ServerMutex : IDisposable private readonly Mutex _mutex; public bool IsLocked { get; private set; } public bool IsDisposed { get; private set; } - public bool CreatedNew { get; } public ServerMutex(string name) { - bool createdNew; - _mutex = new Mutex(true, name, out createdNew); - if (createdNew) - IsLocked = true; - - CreatedNew = createdNew; + _mutex = new Mutex(true, name, out bool createdNew); + IsLocked = createdNew; } public void Dispose() From 268b4d743e22a6b84a8841a728a005f3dff63385 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Mon, 10 Aug 2020 13:05:07 +0200 Subject: [PATCH 09/61] PR comments --- ref/Microsoft.Build/net/Microsoft.Build.cs | 1 - .../netstandard/Microsoft.Build.cs | 1 - .../BackEnd/BuildManager/BuildManager.cs | 7 + .../BuildComponentFactoryCollection.cs | 1 - .../Communications/INodeProvider.cs | 7 +- .../Components/Communications/NodeManager.cs | 22 --- .../Communications/NodeProviderOutOfProc.cs | 42 ++++-- .../NodeProviderOutOfProcBase.cs | 107 +------------- .../NodeProviderOutOfProcRar.cs | 135 ------------------ .../BackEnd/Components/IBuildComponentHost.cs | 5 - .../Components/RequestBuilder/TaskHost.cs | 20 +-- src/Build/BackEnd/Node/NodeConfiguration.cs | 16 ++- src/Build/BackEnd/Node/RarNode.cs | 4 +- src/Build/Instance/HostServices.cs | 7 +- src/Build/Microsoft.Build.csproj | 1 - src/MSBuild/XMake.cs | 3 +- src/Shared/CommunicationsUtilities.cs | 33 ++--- src/Shared/NamedPipeUtil.cs | 96 +++++++++---- .../ResolveAssemblyReference.cs | 2 +- .../Client/RarClient.cs | 8 +- 20 files changed, 154 insertions(+), 364 deletions(-) delete mode 100644 src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcRar.cs diff --git a/ref/Microsoft.Build/net/Microsoft.Build.cs b/ref/Microsoft.Build/net/Microsoft.Build.cs index 6a73e861935..ef0efa9c422 100644 --- a/ref/Microsoft.Build/net/Microsoft.Build.cs +++ b/ref/Microsoft.Build/net/Microsoft.Build.cs @@ -1096,7 +1096,6 @@ public enum NodeAffinity Any = 2, InProc = 0, OutOfProc = 1, - RarNode = 3, } public enum NodeEngineShutdownReason { diff --git a/ref/Microsoft.Build/netstandard/Microsoft.Build.cs b/ref/Microsoft.Build/netstandard/Microsoft.Build.cs index 44a5cf67099..4240899acad 100644 --- a/ref/Microsoft.Build/netstandard/Microsoft.Build.cs +++ b/ref/Microsoft.Build/netstandard/Microsoft.Build.cs @@ -1090,7 +1090,6 @@ public enum NodeAffinity Any = 2, InProc = 0, OutOfProc = 1, - RarNode = 3, } public enum NodeEngineShutdownReason { diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index 7b0b1998900..eb9a12cdb3c 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -2021,6 +2021,13 @@ private void PerformSchedulingActions(IEnumerable responses) } } + internal NodeInfo CreateRarNode() + { + NodeConfiguration configuration = GetNodeConfiguration(); + configuration.RarNode = true; + return _nodeManager.CreateNode(configuration, NodeAffinity.OutOfProc); + } + /// /// Completes a submission using the specified overall results. /// diff --git a/src/Build/BackEnd/Components/BuildComponentFactoryCollection.cs b/src/Build/BackEnd/Components/BuildComponentFactoryCollection.cs index 702c0a0a87e..05ea23f5425 100644 --- a/src/Build/BackEnd/Components/BuildComponentFactoryCollection.cs +++ b/src/Build/BackEnd/Components/BuildComponentFactoryCollection.cs @@ -61,7 +61,6 @@ public void RegisterDefaultFactories() _componentEntriesByType[BuildComponentType.InProcNodeProvider] = new BuildComponentEntry(BuildComponentType.InProcNodeProvider, NodeProviderInProc.CreateComponent, CreationPattern.Singleton); _componentEntriesByType[BuildComponentType.OutOfProcNodeProvider] = new BuildComponentEntry(BuildComponentType.OutOfProcNodeProvider, NodeProviderOutOfProc.CreateComponent, CreationPattern.Singleton); - _componentEntriesByType[BuildComponentType.OutOfProcNodeRarProvider] = new BuildComponentEntry(BuildComponentType.OutOfProcNodeRarProvider, NodeProviderOutOfProcRar.CreateComponent, CreationPattern.Singleton); _componentEntriesByType[BuildComponentType.OutOfProcTaskHostNodeProvider] = new BuildComponentEntry(BuildComponentType.OutOfProcTaskHostNodeProvider, NodeProviderOutOfProcTaskHost.CreateComponent, CreationPattern.Singleton); // PropertyCache, diff --git a/src/Build/BackEnd/Components/Communications/INodeProvider.cs b/src/Build/BackEnd/Components/Communications/INodeProvider.cs index d6f8116f414..bd2cacc7266 100644 --- a/src/Build/BackEnd/Components/Communications/INodeProvider.cs +++ b/src/Build/BackEnd/Components/Communications/INodeProvider.cs @@ -24,12 +24,7 @@ internal enum NodeProviderType /// /// The provider provides remote nodes. /// - Remote, - - /// - /// The provider provides RAR nodes. - /// - ResolveAssemblyReference + Remote } /// diff --git a/src/Build/BackEnd/Components/Communications/NodeManager.cs b/src/Build/BackEnd/Components/Communications/NodeManager.cs index dc61bffae81..e0c45681ff0 100644 --- a/src/Build/BackEnd/Components/Communications/NodeManager.cs +++ b/src/Build/BackEnd/Components/Communications/NodeManager.cs @@ -35,12 +35,6 @@ internal class NodeManager : INodeManager /// private INodeProvider _outOfProcNodeProvider; - - /// - /// The node provider for out-of-proc RAR nodes. - /// - private INodeProvider _outOfProcRarNodeProvider; - /// /// The build component host. /// @@ -119,11 +113,6 @@ public NodeInfo CreateNode(NodeConfiguration configuration, NodeAffinity nodeAff nodeId = AttemptCreateNode(_outOfProcNodeProvider, configuration); } - if (nodeId == InvalidNodeId && nodeAffinity == NodeAffinity.RarNode) - { - nodeId = AttemptCreateNode(_outOfProcRarNodeProvider, configuration); - } - if (nodeId == InvalidNodeId) { return null; @@ -177,8 +166,6 @@ public void ShutdownConnectedNodes(bool enableReuse) { _outOfProcNodeProvider.ShutdownConnectedNodes(enableReuse); } - - _outOfProcRarNodeProvider?.ShutdownConnectedNodes(enableReuse); } /// @@ -191,8 +178,6 @@ public void ShutdownAllNodes() { _outOfProcNodeProvider.ShutdownAllNodes(); } - - _outOfProcRarNodeProvider?.ShutdownAllNodes(); } #endregion @@ -211,7 +196,6 @@ public void InitializeComponent(IBuildComponentHost host) _inProcNodeProvider = _componentHost.GetComponent(BuildComponentType.InProcNodeProvider) as INodeProvider; _outOfProcNodeProvider = _componentHost.GetComponent(BuildComponentType.OutOfProcNodeProvider) as INodeProvider; - _outOfProcRarNodeProvider = _componentHost.GetComponent(BuildComponentType.OutOfProcNodeRarProvider) as INodeProvider; _componentShutdown = false; @@ -233,14 +217,8 @@ public void ShutdownComponent() ((IDisposable)_outOfProcNodeProvider).Dispose(); } - if (_outOfProcRarNodeProvider is IDisposable rarNodeProvider) - { - rarNodeProvider.Dispose(); - } - _inProcNodeProvider = null; _outOfProcNodeProvider = null; - _outOfProcRarNodeProvider = null; _componentHost = null; _componentShutdown = true; diff --git a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProc.cs b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProc.cs index a4cdb9e0e31..e59e31d7613 100644 --- a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProc.cs +++ b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProc.cs @@ -18,10 +18,15 @@ namespace Microsoft.Build.BackEnd internal class NodeProviderOutOfProc : NodeProviderOutOfProcBase, INodeProvider { /// - /// A mapping of all the nodes managed by this provider. + /// A mapping of all normal nodes managed by this provider. /// private Dictionary _nodeContexts; + /// + /// A mapping of all RAR nodes managed by this provider. + /// + private Dictionary _rarNodeContexts; + /// /// Constructor. /// @@ -87,7 +92,7 @@ public bool CreateNode(int nodeId, INodePacketFactory factory, NodeConfiguration // want to start up just a standard MSBuild out-of-proc node. // Note: We need to always pass /nodeReuse to ensure the value for /nodeReuse from msbuild.rsp // (next to msbuild.exe) is ignored. - string commandLineArgs = $"/nologo /nodemode:1 /nodeReuse:{ComponentHost.BuildParameters.EnableNodeReuse.ToString().ToLower()} /low:{ComponentHost.BuildParameters.LowPriority.ToString().ToLower()}"; + string commandLineArgs = $"/nologo /nodemode:{(configuration.RarNode ? 3 : 1)} /nodeReuse:{ComponentHost.BuildParameters.EnableNodeReuse.ToString().ToLower()} /low:{ComponentHost.BuildParameters.LowPriority.ToString().ToLower()}"; // Make it here. CommunicationsUtilities.Trace("Starting to acquire a new or existing node to establish node ID {0}...", nodeId); @@ -97,7 +102,14 @@ public bool CreateNode(int nodeId, INodePacketFactory factory, NodeConfiguration if (null != context) { - _nodeContexts[nodeId] = context; + if (configuration.RarNode) + { + _rarNodeContexts[nodeId] = context; + } + else + { + _nodeContexts[nodeId] = context; + } // Start the asynchronous read. context.BeginAsyncPacketRead(); @@ -118,9 +130,18 @@ public bool CreateNode(int nodeId, INodePacketFactory factory, NodeConfiguration /// The packet to send. public void SendData(int nodeId, INodePacket packet) { - ErrorUtilities.VerifyThrow(_nodeContexts.ContainsKey(nodeId), "Invalid node id specified: {0}.", nodeId); - - SendData(_nodeContexts[nodeId], packet); + if (_nodeContexts.ContainsKey(nodeId)) + { + SendData(_nodeContexts[nodeId], packet); + } + else if (_rarNodeContexts.ContainsKey(nodeId)) + { + SendData(_rarNodeContexts[nodeId], packet); + } + else + { + ErrorUtilities.ThrowInternalError("Invalid node id specified: {0}.", nodeId); + } } /// @@ -135,8 +156,9 @@ public void ShutdownConnectedNodes(bool enableReuse) lock (_nodeContexts) { contextsToShutDown = new List(_nodeContexts.Values); + contextsToShutDown.AddRange(_rarNodeContexts.Values); } - + ShutdownConnectedNodes(contextsToShutDown, enableReuse); } @@ -170,6 +192,7 @@ public void InitializeComponent(IBuildComponentHost host) { this.ComponentHost = host; _nodeContexts = new Dictionary(); + _rarNodeContexts = new Dictionary(); } /// @@ -197,7 +220,10 @@ private void NodeContextTerminated(int nodeId) { lock (_nodeContexts) { - _nodeContexts.Remove(nodeId); + if (!_nodeContexts.Remove(nodeId)) + { + _rarNodeContexts.Remove(nodeId); + } } } } diff --git a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs index 263bc3b1904..a2089118206 100644 --- a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs +++ b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs @@ -125,18 +125,18 @@ protected void ShutdownAllNodes(bool nodeReuse, NodeContextTerminateDelegate ter int timeout = 30; // Attempt to connect to the process with the handshake without low priority. - Stream nodeStream = TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, false, true)); + Stream nodeStream = NamedPipeUtil.TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, false, true)); // If we couldn't connect attempt to connect to the process with the handshake including low priority. - nodeStream ??= TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, true, true)); + nodeStream ??= NamedPipeUtil.TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, true, true)); // Attempt to connect to the non-worker process // Attempt to connect to the process with the handshake without low priority. - nodeStream ??= TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, false, false)); + nodeStream ??= NamedPipeUtil.TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, false, false)); // If we couldn't connect attempt to connect to the process with the handshake including low priority. - nodeStream ??= TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, true, false)); + nodeStream ??= NamedPipeUtil.TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, true, false)); - if (null != nodeStream) + if (nodeStream != null) { // If we're able to connect to such a process, send a packet requesting its termination CommunicationsUtilities.Trace("Shutting down node with pid = {0}", nodeProcess.Id); @@ -201,7 +201,7 @@ protected NodeContext GetNode(string msbuildLocation, string commandLineArgs, in _processesToIgnore.Add(nodeLookupKey); // Attempt to connect to each process in turn. - Stream nodeStream = TryConnectToProcess(nodeProcess.Id, 0 /* poll, don't wait for connections */, hostHandshake); + Stream nodeStream = NamedPipeUtil.TryConnectToProcess(nodeProcess.Id, 0 /* poll, don't wait for connections */, hostHandshake); if (nodeStream != null) { // Connection successful, use this node. @@ -252,7 +252,7 @@ protected NodeContext GetNode(string msbuildLocation, string commandLineArgs, in // to the debugger process. Instead, use MSBUILDDEBUGONSTART=1 // Now try to connect to it. - Stream nodeStream = TryConnectToProcess(msbuildProcessId, TimeoutForNewNodeCreation, hostHandshake); + Stream nodeStream = NamedPipeUtil.TryConnectToProcess(msbuildProcessId, TimeoutForNewNodeCreation, hostHandshake); if (nodeStream != null) { // Connection successful, use this node. @@ -300,99 +300,6 @@ private string GetProcessesToIgnoreKey(Handshake hostHandshake, int nodeProcessI return hostHandshake.ToString() + "|" + nodeProcessId.ToString(CultureInfo.InvariantCulture); } -#if !FEATURE_PIPEOPTIONS_CURRENTUSERONLY - // This code needs to be in a separate method so that we don't try (and fail) to load the Windows-only APIs when JIT-ing the code - // on non-Windows operating systems - private void ValidateRemotePipeSecurityOnWindows(NamedPipeClientStream nodeStream) - { - SecurityIdentifier identifier = WindowsIdentity.GetCurrent().Owner; -#if FEATURE_PIPE_SECURITY - PipeSecurity remoteSecurity = nodeStream.GetAccessControl(); -#else - var remoteSecurity = new PipeSecurity(nodeStream.SafePipeHandle, System.Security.AccessControl.AccessControlSections.Access | - System.Security.AccessControl.AccessControlSections.Owner | System.Security.AccessControl.AccessControlSections.Group); -#endif - IdentityReference remoteOwner = remoteSecurity.GetOwner(typeof(SecurityIdentifier)); - if (remoteOwner != identifier) - { - CommunicationsUtilities.Trace("The remote pipe owner {0} does not match {1}", remoteOwner.Value, identifier.Value); - throw new UnauthorizedAccessException(); - } - } -#endif - - /// - /// Attempts to connect to the specified process. - /// - private Stream TryConnectToProcess(int nodeProcessId, int timeout, Handshake handshake) - { - // Try and connect to the process. - string pipeName = NamedPipeUtil.GetPipeNameOrPath("MSBuild" + nodeProcessId); - - NamedPipeClientStream nodeStream = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.Asynchronous -#if FEATURE_PIPEOPTIONS_CURRENTUSERONLY - | PipeOptions.CurrentUserOnly -#endif - ); - CommunicationsUtilities.Trace("Attempting connect to PID {0} with pipe {1} with timeout {2} ms", nodeProcessId, pipeName, timeout); - - try - { - nodeStream.Connect(timeout); - -#if !FEATURE_PIPEOPTIONS_CURRENTUSERONLY - if (NativeMethodsShared.IsWindows && !NativeMethodsShared.IsMono) - { - // Verify that the owner of the pipe is us. This prevents a security hole where a remote node has - // been faked up with ACLs that would let us attach to it. It could then issue fake build requests back to - // us, potentially causing us to execute builds that do harmful or unexpected things. The pipe owner can - // only be set to the user's own SID by a normal, unprivileged process. The conditions where a faked up - // remote node could set the owner to something else would also let it change owners on other objects, so - // this would be a security flaw upstream of us. - ValidateRemotePipeSecurityOnWindows(nodeStream); - } -#endif - - int[] handshakeComponents = handshake.RetrieveHandshakeComponents(); - for (int i = 0; i < handshakeComponents.Length; i++) - { - CommunicationsUtilities.Trace("Writing handshake part {0} to pipe {1}", i, pipeName); - nodeStream.WriteIntForHandshake(handshakeComponents[i]); - } - - // This indicates that we have finished all the parts of our handshake; hopefully the endpoint has as well. - nodeStream.WriteEndOfHandshakeSignal(); - - CommunicationsUtilities.Trace("Reading handshake from pipe {0}", pipeName); - -#if NETCOREAPP2_1 || MONO - nodeStream.ReadEndOfHandshakeSignal(true, timeout); -#else - nodeStream.ReadEndOfHandshakeSignal(true); -#endif - // We got a connection. - CommunicationsUtilities.Trace("Successfully connected to pipe {0}...!", pipeName); - return nodeStream; - } - catch (Exception e) when (!ExceptionHandling.IsCriticalException(e)) - { - // Can be: - // UnauthorizedAccessException -- Couldn't connect, might not be a node. - // IOException -- Couldn't connect, already in use. - // TimeoutException -- Couldn't connect, might not be a node. - // InvalidOperationException – Couldn’t connect, probably a different build - CommunicationsUtilities.Trace("Failed to connect to pipe {0}. {1}", pipeName, e.Message.TrimEnd()); - - // If we don't close any stream, we might hang up the child - if (nodeStream != null) - { - nodeStream.Dispose(); - } - } - - return null; - } - /// /// Creates a new MSBuild process /// diff --git a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcRar.cs b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcRar.cs deleted file mode 100644 index 0e912831c9b..00000000000 --- a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcRar.cs +++ /dev/null @@ -1,135 +0,0 @@ -using Microsoft.Build.Exceptions; -using Microsoft.Build.Internal; -using Microsoft.Build.Shared; -using System.Collections.Generic; - -namespace Microsoft.Build.BackEnd -{ - internal sealed class NodeProviderOutOfProcRar : NodeProviderOutOfProcBase, INodeProvider - { - private int? _rarNodeId = null; - private NodeContext _rarNodeContext = null; - - public NodeProviderType ProviderType => NodeProviderType.ResolveAssemblyReference; - - public int AvailableNodes => 1; - - public bool CreateNode(int nodeId, INodePacketFactory factory, NodeConfiguration configuration) - { - ErrorUtilities.VerifyThrowArgumentNull(factory, "factory"); - ErrorUtilities.VerifyThrow(_rarNodeId.HasValue, "RAR node already created."); - - // Start the new process. We pass in a node mode with a node number of 3, to indicate that we - // want to start up RAR out-of-proc node. - // Note: We need to always pass /nodeReuse to ensure the value for /nodeReuse from msbuild.rsp - // (next to msbuild.exe) is ignored. - string commandLineArgs = $"/nologo /nodemode:3 /nodeReuse:{ComponentHost.BuildParameters.EnableNodeReuse.ToString().ToLower()} /low:{ComponentHost.BuildParameters.LowPriority.ToString().ToLower()}"; - - // Make it here. - CommunicationsUtilities.Trace("Starting to acquire a new or existing node to establish node ID {0}...", nodeId); - - Handshake hostHandshake = new Handshake(CommunicationsUtilities.GetHandshakeOptions(taskHost: false, - nodeReuse: ComponentHost.BuildParameters.EnableNodeReuse, - lowPriority: ComponentHost.BuildParameters.LowPriority, - is64Bit: EnvironmentUtilities.Is64BitProcess, - workerNode: false)); - NodeContext context = GetNode(null, commandLineArgs, nodeId, factory, hostHandshake, NodeContextTerminated); - - if (context != null) - { - _rarNodeId = nodeId; - _rarNodeContext = context; - - // Is this necesarry? - // Start the asynchronous read. - context.BeginAsyncPacketRead(); - - // Configure the node. - context.SendData(configuration); - - return true; - } - - throw new BuildAbortedException(ResourceUtilities.FormatResourceStringStripCodeAndKeyword("CouldNotConnectToMSBuildExe", ComponentHost.BuildParameters.NodeExeLocation)); - } - - private void NodeContextTerminated(int nodeId) - { - if (_rarNodeId == nodeId) - { - _rarNodeId = null; - _rarNodeContext = null; - } - } - - #region IBuildComponent Members - - /// - /// Initializes the component. - /// - /// The component host. - public void InitializeComponent(IBuildComponentHost host) - { - this.ComponentHost = host; - } - - /// - /// Shuts down the component - /// - public void ShutdownComponent() - { - } - - #endregion - - /// - /// Static factory for component creation. - /// - static internal IBuildComponent CreateComponent(BuildComponentType componentType) - { - ErrorUtilities.VerifyThrow(componentType == BuildComponentType.OutOfProcNodeRarProvider, "Factory cannot create components of type {0}", componentType); - return new NodeProviderOutOfProcRar(); - } - - public void SendData(int node, INodePacket packet) - { - ErrorUtilities.VerifyThrowInternalNull(packet, "Packet is null"); - - if (_rarNodeId == node) - { - _rarNodeContext.SendData(packet); - } - } - - public void ShutdownAllNodes() - { - // If no BuildParameters were specified for this build, - // we must be trying to shut down idle nodes from some - // other, completed build. If they're still around, - // they must have been started with node reuse. - bool nodeReuse = ComponentHost.BuildParameters?.EnableNodeReuse ?? true; - - // To avoid issues with mismatched priorities not shutting - // down all the nodes on exit, we will attempt to shutdown - // all matching nodes with and without the priority bit set. - // This means we need both versions of the handshake. - - // RAR node is special... - if (!nodeReuse) - ShutdownAllNodes(nodeReuse, NodeContextTerminated); - } - - public void ShutdownConnectedNodes(bool enableReuse) - { - // RAR node is special - if (_rarNodeId != null && !enableReuse) - { - List contextList = new List() - { - _rarNodeContext - }; - ShutdownConnectedNodes(contextList, enableReuse); - } - } - } -} diff --git a/src/Build/BackEnd/Components/IBuildComponentHost.cs b/src/Build/BackEnd/Components/IBuildComponentHost.cs index 16b2276e4e5..4e57c5f2ae1 100644 --- a/src/Build/BackEnd/Components/IBuildComponentHost.cs +++ b/src/Build/BackEnd/Components/IBuildComponentHost.cs @@ -128,11 +128,6 @@ internal enum BuildComponentType /// The SDK resolution service. /// SdkResolverService, - - /// - /// The OutOfProc RAR node provider. - /// - OutOfProcNodeRarProvider, } /// diff --git a/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs b/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs index b5bb2110a26..8ada8167e06 100644 --- a/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs +++ b/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs @@ -997,21 +997,7 @@ private void VerifyActiveProxy() /// bool IRarBuildEngine.CreateRarNode() { - var nodeManager = _host.GetComponent(BuildComponentType.NodeManager) as INodeManager; - - var configuration = new NodeConfiguration - ( - -1, /* must be assigned by the NodeManager */ - _host.BuildParameters, - null - #if FEATURE_APPDOMAIN - , AppDomain.CurrentDomain.SetupInformation - #endif - , new LoggingNodeConfiguration(_host.LoggingService.IncludeEvaluationMetaprojects, _host.LoggingService.IncludeEvaluationProfile, _host.LoggingService.IncludeTaskInputs) - ); - - var nodeInfo = nodeManager.CreateNode(configuration, NodeAffinity.RarNode); - + NodeInfo nodeInfo = BuildManager.DefaultBuildManager.CreateRarNode(); return nodeInfo != null; } @@ -1020,7 +1006,7 @@ bool IRarBuildEngine.CreateRarNode() /// string IRarBuildEngine.GetRarPipeName() { - var parameters = _host.BuildParameters; + BuildParameters parameters = _host.BuildParameters; return CommunicationsUtilities.GetRarPipeName(parameters.EnableNodeReuse, parameters.LowPriority); } @@ -1029,7 +1015,7 @@ string IRarBuildEngine.GetRarPipeName() /// NamedPipeClientStream IRarBuildEngine.GetRarClientStream(string pipeName, int timeout) { - return NamedPipeUtil.GetClientStream(pipeName, timeout); + return NamedPipeUtil.TryConnectToProcess(pipeName, timeout, null); } } } diff --git a/src/Build/BackEnd/Node/NodeConfiguration.cs b/src/Build/BackEnd/Node/NodeConfiguration.cs index 3708b9be7f2..2246e19069f 100644 --- a/src/Build/BackEnd/Node/NodeConfiguration.cs +++ b/src/Build/BackEnd/Node/NodeConfiguration.cs @@ -39,6 +39,7 @@ internal class NodeConfiguration : INodePacket /// The logging configuration for the node. /// private LoggingNodeConfiguration _loggingNodeConfiguration; + private bool _rarNode; #if FEATURE_APPDOMAIN /// @@ -153,6 +154,11 @@ public LoggingNodeConfiguration LoggingNodeConfiguration { return _loggingNodeConfiguration; } } + /// + /// Indicates if the node is RAR node or not (executes only one task) + /// + public bool RarNode { get => _rarNode; set => _rarNode = value; } + #region INodePacket Members /// @@ -165,14 +171,9 @@ public NodePacketType Type { return NodePacketType.NodeConfiguration; } } - /// - /// Indicates if the node is RAR node or not (executes only one task) - /// - public bool RarNode { get; } - - #endregion +#endregion - #region INodePacketTranslatable Members +#region INodePacketTranslatable Members /// /// Translates the packet to/from binary form. @@ -187,6 +188,7 @@ public void Translate(ITranslator translator) translator.TranslateDotNet(ref _appDomainSetup); #endif translator.Translate(ref _loggingNodeConfiguration); + translator.Translate(ref _rarNode); } /// diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs index 39194357e04..d04cafff383 100644 --- a/src/Build/BackEnd/Node/RarNode.cs +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -35,8 +35,8 @@ public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Except { var cancellationTokenSource = new CancellationTokenSource(); - var pipeName = CommunicationsUtilities.GetRarPipeName(nodeReuse, lowPriority); - var controller = new RarController(pipeName); + string pipeName = CommunicationsUtilities.GetRarPipeName(nodeReuse, lowPriority); + RarController controller = new RarController(pipeName); Console.CancelKeyPress += (e, sender) => cancellationTokenSource.Cancel(); diff --git a/src/Build/Instance/HostServices.cs b/src/Build/Instance/HostServices.cs index 8a4e9eaa2f1..4035072f365 100644 --- a/src/Build/Instance/HostServices.cs +++ b/src/Build/Instance/HostServices.cs @@ -35,12 +35,7 @@ public enum NodeAffinity /// /// The project may be scheduled anywhere. /// - Any, - - /// - /// The node accepts only RAR tasks. - /// - RarNode + Any } /// diff --git a/src/Build/Microsoft.Build.csproj b/src/Build/Microsoft.Build.csproj index 9d474f889cf..966336543eb 100644 --- a/src/Build/Microsoft.Build.csproj +++ b/src/Build/Microsoft.Build.csproj @@ -157,7 +157,6 @@ - diff --git a/src/MSBuild/XMake.cs b/src/MSBuild/XMake.cs index a26d0b3359d..57c4bacd7c0 100644 --- a/src/MSBuild/XMake.cs +++ b/src/MSBuild/XMake.cs @@ -2651,7 +2651,8 @@ private static void StartLocalNode(CommandLineSwitches commandLineSwitches) var node = new RarNode(); // If FEATURE_NODE_REUSE is OFF, just validates that the switch is OK, and always returns False bool nodeReuse = ProcessNodeReuseSwitch(commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.NodeReuse]); - bool lowPriority = commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.LowPriority][0].Equals("true"); + string[] lowPriorityInput = commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.LowPriority]; + bool lowPriority = lowPriorityInput.Length > 0 ? lowPriorityInput[0].Equals("true") : false; shutdownReason = node.Run(nodeReuse, lowPriority, out nodeException); } diff --git a/src/Shared/CommunicationsUtilities.cs b/src/Shared/CommunicationsUtilities.cs index 32d6ca9b5a9..250e5a2efcf 100644 --- a/src/Shared/CommunicationsUtilities.cs +++ b/src/Shared/CommunicationsUtilities.cs @@ -57,7 +57,12 @@ internal enum HandshakeOptions /// /// Building with administrator privileges /// - Administrator = 32 + Administrator = 32, + + /// + /// Is worker node. Worker node can accept normal build requests. + /// + Worker = 64 } internal readonly struct Handshake @@ -527,6 +532,10 @@ internal static HandshakeOptions GetHandshakeOptions(bool taskHost, bool is64Bit context |= HandshakeOptions.Administrator; } #endif + if (workerNode) + { + context |= HandshakeOptions.Worker; + } return context; } @@ -648,28 +657,8 @@ internal static int AvoidEndOfHandshakeSignal(int x) internal static string GetRarPipeName(bool nodeReuse, bool lowPriority) { - var context = HandshakeOptions.None; + var context = GetHandshakeOptions(true); var userName = $"{Environment.UserDomainName}.{Environment.UserName}"; - var clrVersion = ClrVersion; - var is64Bit = XMakeAttributes.GetCurrentMSBuildArchitecture().Equals(XMakeAttributes.MSBuildArchitectureValues.x64); - - if (is64Bit) - { - context |= HandshakeOptions.X64; - } - if (clrVersion == 2) - { - context |= HandshakeOptions.CLR2; - } - if (nodeReuse) - { - context |= HandshakeOptions.NodeReuse; - } - if (lowPriority) - { - context |= HandshakeOptions.LowPriority; - } - return $"MSBuild.RAR.{userName}.{(int)context}"; } } diff --git a/src/Shared/NamedPipeUtil.cs b/src/Shared/NamedPipeUtil.cs index a34217b02ea..427e4eb7410 100644 --- a/src/Shared/NamedPipeUtil.cs +++ b/src/Shared/NamedPipeUtil.cs @@ -29,14 +29,61 @@ internal static string GetPipeNameOrPath(string pipeName) return pipeName; } } - internal static NamedPipeClientStream GetClientStream(string pipeName, int timeout) + +#if !FEATURE_PIPEOPTIONS_CURRENTUSERONLY + // This code needs to be in a separate method so that we don't try (and fail) to load the Windows-only APIs when JIT-ing the code + // on non-Windows operating systems + private static void ValidateRemotePipeSecurityOnWindows(NamedPipeClientStream nodeStream) + { + SecurityIdentifier identifier = WindowsIdentity.GetCurrent().Owner; +#if FEATURE_PIPE_SECURITY + PipeSecurity remoteSecurity = nodeStream.GetAccessControl(); +#else + var remoteSecurity = new PipeSecurity(nodeStream.SafePipeHandle, System.Security.AccessControl.AccessControlSections.Access | + System.Security.AccessControl.AccessControlSections.Owner | System.Security.AccessControl.AccessControlSections.Group); +#endif + IdentityReference remoteOwner = remoteSecurity.GetOwner(typeof(SecurityIdentifier)); + if (remoteOwner != identifier) + { + CommunicationsUtilities.Trace("The remote pipe owner {0} does not match {1}", remoteOwner.Value, identifier.Value); + throw new UnauthorizedAccessException(); + } + } +#endif + /// + /// Attempts to connect to the specified process. + /// + internal static NamedPipeClientStream TryConnectToProcess(int nodeProcessId, int timeout, Handshake? handshake) + { + string pipeName = GetPipeNameOrPath("MSBuild" + nodeProcessId); + return TryConnectToProcess(pipeName, timeout, timeout, handshake); + } + + /// + /// Attempts to connect to the specified process. + /// + internal static NamedPipeClientStream TryConnectToProcess(string pipeName, int timeout, Handshake? handshake) + { + return TryConnectToProcess(pipeName, null, timeout, handshake); + } + + private static NamedPipeClientStream TryConnectToProcess(string pipeName, int? nodeProcessId, int timeout, Handshake? handshake) { // Try and connect to the process. - var nodeStream = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.Asynchronous + NamedPipeClientStream nodeStream = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.Asynchronous #if FEATURE_PIPEOPTIONS_CURRENTUSERONLY | PipeOptions.CurrentUserOnly #endif ); + if (nodeProcessId.HasValue) + { + CommunicationsUtilities.Trace("Attempting connect to PID {0} with pipe {1} with timeout {2} ms", nodeProcessId.Value, pipeName, timeout); + } + else + { + CommunicationsUtilities.Trace("Attempting connect to process {0} with pipe {1} with timeout {2} ms", pipeName, pipeName, timeout); + } + try { nodeStream.Connect(timeout); @@ -51,11 +98,32 @@ internal static NamedPipeClientStream GetClientStream(string pipeName, int timeo // remote node could set the owner to something else would also let it change owners on other objects, so // this would be a security flaw upstream of us. ValidateRemotePipeSecurityOnWindows(nodeStream); + } +#endif + if (handshake.HasValue) + { + int[] handshakeComponents = handshake.Value.RetrieveHandshakeComponents(); + for (int i = 0; i < handshakeComponents.Length; i++) + { + CommunicationsUtilities.Trace("Writing handshake part {0} to pipe {1}", i, pipeName); + nodeStream.WriteIntForHandshake(handshakeComponents[i]); + } + + // This indicates that we have finished all the parts of our handshake; hopefully the endpoint has as well. + nodeStream.WriteEndOfHandshakeSignal(); + CommunicationsUtilities.Trace("Reading handshake from pipe {0}", pipeName); + +#if NETCOREAPP2_1 || MONO + nodeStream.ReadEndOfHandshakeSignal(true, timeout); +#else + nodeStream.ReadEndOfHandshakeSignal(true); +#endif } + // We got a connection. + CommunicationsUtilities.Trace("Successfully connected to pipe {0}...!", pipeName); return nodeStream; -#endif } catch (Exception e) when (!ExceptionHandling.IsCriticalException(e)) { @@ -64,6 +132,7 @@ internal static NamedPipeClientStream GetClientStream(string pipeName, int timeo // IOException -- Couldn't connect, already in use. // TimeoutException -- Couldn't connect, might not be a node. // InvalidOperationException Couldnt connect, probably a different build + CommunicationsUtilities.Trace("Failed to connect to pipe {0}. {1}", pipeName, e.Message.TrimEnd()); // If we don't close any stream, we might hang up the child if (nodeStream != null) @@ -74,26 +143,5 @@ internal static NamedPipeClientStream GetClientStream(string pipeName, int timeo return null; } - -#if !FEATURE_PIPEOPTIONS_CURRENTUSERONLY - // This code needs to be in a separate method so that we don't try (and fail) to load the Windows-only APIs when JIT-ing the code - // on non-Windows operating systems - private static void ValidateRemotePipeSecurityOnWindows(NamedPipeClientStream nodeStream) - { - SecurityIdentifier identifier = WindowsIdentity.GetCurrent().Owner; -#if FEATURE_PIPE_SECURITY - PipeSecurity remoteSecurity = nodeStream.GetAccessControl(); -#else - var remoteSecurity = new PipeSecurity(nodeStream.SafePipeHandle, System.Security.AccessControl.AccessControlSections.Access | - System.Security.AccessControl.AccessControlSections.Owner | System.Security.AccessControl.AccessControlSections.Group); -#endif - IdentityReference remoteOwner = remoteSecurity.GetOwner(typeof(SecurityIdentifier)); - if (remoteOwner != identifier) - { - CommunicationsUtilities.Trace("The remote pipe owner {0} does not match {1}", remoteOwner.Value, identifier.Value); - throw new UnauthorizedAccessException(); - } - } -#endif } } diff --git a/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs b/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs index a1f0a6ceb75..22e76612f40 100644 --- a/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs +++ b/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs @@ -2996,7 +2996,7 @@ public override bool Execute() { // Client is connected to the RAR node, we can execute RAR task remotely // return client.Execute(); // TODO: Let it do something. - //var number = client.GetNumber(42); + // var number = client.GetNumber(42); } } diff --git a/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs b/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs index 29965290b84..5c25cf823fd 100644 --- a/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs +++ b/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs @@ -26,8 +26,8 @@ public RarClient(IRarBuildEngine rarBuildEngine) internal bool Connect() { - var pipeName = _rarBuildEngine.GetRarPipeName(); - var stream = _rarBuildEngine.GetRarClientStream(pipeName, ConnectionTimeout); + string pipeName = _rarBuildEngine.GetRarPipeName(); + NamedPipeClientStream stream = _rarBuildEngine.GetRarClientStream(pipeName, ConnectionTimeout); if (stream == null) return false; // We couldn't connect @@ -43,7 +43,7 @@ internal bool CreateNode() internal int GetNumber(int parameter) { - using var client = GetRpcClient(); + using IResolveAssemblyReferenceTaskHandler client = GetRpcClient(); // TODO: Find out if there is any possibility of awaiting it. return client.GetNumber(parameter).GetAwaiter().GetResult(); } @@ -52,7 +52,7 @@ private IResolveAssemblyReferenceTaskHandler GetRpcClient() { ErrorUtilities.VerifyThrowArgumentNull(_clientStream, nameof(_clientStream)); - var handler = RpcUtils.GetRarMessageHandler(_clientStream); + IJsonRpcMessageHandler handler = RpcUtils.GetRarMessageHandler(_clientStream); return JsonRpc.Attach(handler); } From 332a5afddeb703d8ff9eacc001e58ce913762618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Wed, 12 Aug 2020 10:42:48 +0200 Subject: [PATCH 10/61] StremJsonRpc upgrade and json fix --- eng/Packages.props | 2 +- src/MSBuild/app.amd64.config | 4 ++++ src/MSBuild/app.config | 5 +++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/eng/Packages.props b/eng/Packages.props index d98f92b56ff..17a9f43be34 100644 --- a/eng/Packages.props +++ b/eng/Packages.props @@ -48,7 +48,7 @@ - + diff --git a/src/MSBuild/app.amd64.config b/src/MSBuild/app.amd64.config index 0d9ca6d8f34..c66af314664 100644 --- a/src/MSBuild/app.amd64.config +++ b/src/MSBuild/app.amd64.config @@ -61,6 +61,10 @@ + + + + diff --git a/src/MSBuild/app.config b/src/MSBuild/app.config index 07b6a964c1c..b109b8abef5 100644 --- a/src/MSBuild/app.config +++ b/src/MSBuild/app.config @@ -40,6 +40,11 @@ + + + + + From be02cdffab4d16878064402bc027021d5ec1a004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Wed, 12 Aug 2020 11:16:41 +0200 Subject: [PATCH 11/61] Worker to Special (rename) --- ref/Microsoft.Build/net/Microsoft.Build.cs | 2 +- ref/Microsoft.Build/netstandard/Microsoft.Build.cs | 2 +- .../Components/Communications/NodeEndpointOutOfProc.cs | 10 +++++----- .../Components/Communications/NodeProviderOutOfProc.cs | 6 +++--- .../Communications/NodeProviderOutOfProcBase.cs | 10 +++++----- src/Build/BackEnd/Node/NodeConfiguration.cs | 7 +++++-- src/Build/BackEnd/Node/OutOfProcNode.cs | 8 ++++---- src/Build/BackEnd/Node/RarNode.cs | 7 ++----- src/Shared/CommunicationsUtilities.cs | 10 +++++----- 9 files changed, 31 insertions(+), 31 deletions(-) diff --git a/ref/Microsoft.Build/net/Microsoft.Build.cs b/ref/Microsoft.Build/net/Microsoft.Build.cs index ef0efa9c422..0b47d428f89 100644 --- a/ref/Microsoft.Build/net/Microsoft.Build.cs +++ b/ref/Microsoft.Build/net/Microsoft.Build.cs @@ -1107,7 +1107,7 @@ public enum NodeEngineShutdownReason public partial class OutOfProcNode { public OutOfProcNode() { } - public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool enableReuse, bool lowPriority, bool workerNode, out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } + public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool enableReuse, bool lowPriority, bool specialNode, out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool enableReuse, bool lowPriority, out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool enableReuse, out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } public Microsoft.Build.Execution.NodeEngineShutdownReason Run(out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } diff --git a/ref/Microsoft.Build/netstandard/Microsoft.Build.cs b/ref/Microsoft.Build/netstandard/Microsoft.Build.cs index 4240899acad..436b0946a2f 100644 --- a/ref/Microsoft.Build/netstandard/Microsoft.Build.cs +++ b/ref/Microsoft.Build/netstandard/Microsoft.Build.cs @@ -1101,7 +1101,7 @@ public enum NodeEngineShutdownReason public partial class OutOfProcNode { public OutOfProcNode() { } - public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool enableReuse, bool lowPriority, bool workerNode, out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } + public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool enableReuse, bool lowPriority, bool specialNode, out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool enableReuse, bool lowPriority, out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool enableReuse, out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } public Microsoft.Build.Execution.NodeEngineShutdownReason Run(out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } diff --git a/src/Build/BackEnd/Components/Communications/NodeEndpointOutOfProc.cs b/src/Build/BackEnd/Components/Communications/NodeEndpointOutOfProc.cs index 0c124e22c87..9e36c945dc0 100644 --- a/src/Build/BackEnd/Components/Communications/NodeEndpointOutOfProc.cs +++ b/src/Build/BackEnd/Components/Communications/NodeEndpointOutOfProc.cs @@ -22,7 +22,7 @@ internal class NodeEndpointOutOfProc : NodeEndpointOutOfProcBase private readonly bool _lowPriority; - private readonly bool _workerNode; + private readonly bool _specialNode; #endregion @@ -35,19 +35,19 @@ internal class NodeEndpointOutOfProc : NodeEndpointOutOfProcBase /// The component host. /// Whether this node may be reused for a later build. /// Whether this node is low priority. - /// Indicates if node is worker node (can accept normal MSBuild work) + /// Indicates if node is special node (can not accept normal MSBuild work) internal NodeEndpointOutOfProc( string pipeName, IBuildComponentHost host, bool enableReuse, bool lowPriority, - bool workerNode) + bool specialNode) { ErrorUtilities.VerifyThrowArgumentNull(host, "host"); _componentHost = host; _enableReuse = enableReuse; _lowPriority = lowPriority; - _workerNode = workerNode; + _specialNode = specialNode; InternalConstruct(pipeName); @@ -65,7 +65,7 @@ protected override Handshake GetHandshake() is64Bit: EnvironmentUtilities.Is64BitProcess, nodeReuse: _enableReuse, lowPriority: _lowPriority, - _workerNode)); + _specialNode)); } #region Structs diff --git a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProc.cs b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProc.cs index e59e31d7613..1d031f47264 100644 --- a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProc.cs +++ b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProc.cs @@ -68,11 +68,11 @@ public int AvailableNodes /// /// Is reuse of build nodes allowed? /// Is the build running at low priority? - /// /Indicates if node can accept standard MSBuild work - internal static Handshake GetHandshake(bool enableNodeReuse, bool enableLowPriority, bool workerNode) + /// /Indicates if node can not accept standard MSBuild work + internal static Handshake GetHandshake(bool enableNodeReuse, bool enableLowPriority, bool specialNode) { CommunicationsUtilities.Trace("MSBUILDNODEHANDSHAKESALT=\"{0}\", msbuildDirectory=\"{1}\", enableNodeReuse={2}, enableLowPriority={3}", Traits.MSBuildNodeHandshakeSalt, BuildEnvironmentHelper.Instance.MSBuildToolsDirectory32, enableNodeReuse, enableLowPriority); - return new Handshake(CommunicationsUtilities.GetHandshakeOptions(taskHost: false, nodeReuse: enableNodeReuse, lowPriority: enableLowPriority, workerNode: workerNode, is64Bit: EnvironmentUtilities.Is64BitProcess)); + return new Handshake(CommunicationsUtilities.GetHandshakeOptions(taskHost: false, nodeReuse: enableNodeReuse, lowPriority: enableLowPriority, specialNode: specialNode, is64Bit: EnvironmentUtilities.Is64BitProcess)); } /// diff --git a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs index a2089118206..e686f4343b3 100644 --- a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs +++ b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs @@ -125,16 +125,16 @@ protected void ShutdownAllNodes(bool nodeReuse, NodeContextTerminateDelegate ter int timeout = 30; // Attempt to connect to the process with the handshake without low priority. - Stream nodeStream = NamedPipeUtil.TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, false, true)); + Stream nodeStream = NamedPipeUtil.TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, enableLowPriority: false, specialNode: false)); // If we couldn't connect attempt to connect to the process with the handshake including low priority. - nodeStream ??= NamedPipeUtil.TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, true, true)); + nodeStream ??= NamedPipeUtil.TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, enableLowPriority: true, specialNode: false)); // Attempt to connect to the non-worker process // Attempt to connect to the process with the handshake without low priority. - nodeStream ??= NamedPipeUtil.TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, false, false)); + nodeStream ??= NamedPipeUtil.TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, enableLowPriority: false, specialNode: true)); // If we couldn't connect attempt to connect to the process with the handshake including low priority. - nodeStream ??= NamedPipeUtil.TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, true, false)); + nodeStream ??= NamedPipeUtil.TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, enableLowPriority: true, specialNode: true)); if (nodeStream != null) { @@ -303,7 +303,7 @@ private string GetProcessesToIgnoreKey(Handshake hostHandshake, int nodeProcessI /// /// Creates a new MSBuild process /// - private int LaunchNode(string msbuildLocation, string commandLineArgs) + internal static int LaunchNode(string msbuildLocation, string commandLineArgs) { // Should always have been set already. ErrorUtilities.VerifyThrowInternalLength(msbuildLocation, "msbuildLocation"); diff --git a/src/Build/BackEnd/Node/NodeConfiguration.cs b/src/Build/BackEnd/Node/NodeConfiguration.cs index 2246e19069f..e4b3a7eaa81 100644 --- a/src/Build/BackEnd/Node/NodeConfiguration.cs +++ b/src/Build/BackEnd/Node/NodeConfiguration.cs @@ -76,18 +76,21 @@ public NodeConfiguration /// The build parameters /// The forwarding loggers. /// The logging configuration for the node. + /// Indicates if node works as RAR node. public NodeConfiguration ( int nodeId, BuildParameters buildParameters, LoggerDescription[] forwardingLoggers, - LoggingNodeConfiguration loggingNodeConfiguration + LoggingNodeConfiguration loggingNodeConfiguration, + bool rarNode = false ) { _nodeId = nodeId; _buildParameters = buildParameters; _forwardingLoggers = forwardingLoggers; _loggingNodeConfiguration = loggingNodeConfiguration; + RarNode = rarNode; } #endif @@ -211,7 +214,7 @@ internal NodeConfiguration Clone() #if FEATURE_APPDOMAIN , _appDomainSetup #endif - , _loggingNodeConfiguration + , _loggingNodeConfiguration, _rarNode ); } } diff --git a/src/Build/BackEnd/Node/OutOfProcNode.cs b/src/Build/BackEnd/Node/OutOfProcNode.cs index 81d79734bbe..132949d34bb 100644 --- a/src/Build/BackEnd/Node/OutOfProcNode.cs +++ b/src/Build/BackEnd/Node/OutOfProcNode.cs @@ -243,7 +243,7 @@ public NodeEngineShutdownReason Run(bool enableReuse, out Exception shutdownExce /// The reason for shutting down. public NodeEngineShutdownReason Run(bool enableReuse, bool lowPriority, out Exception shutdownException) { - return Run(enableReuse, lowPriority, true, out shutdownException); + return Run(enableReuse, lowPriority, specialNode: false, out shutdownException); } /// @@ -251,15 +251,15 @@ public NodeEngineShutdownReason Run(bool enableReuse, bool lowPriority, out Exce /// /// Whether this node is eligible for reuse later. /// Whether this node should be running with low priority. - /// Whether this node should act as worker node and accpet build requests. + /// Whether this node should act as special node and refuse build requests. /// The exception which caused shutdown, if any. /// The reason for shutting down. - public NodeEngineShutdownReason Run(bool enableReuse, bool lowPriority, bool workerNode, out Exception shutdownException) + public NodeEngineShutdownReason Run(bool enableReuse, bool lowPriority, bool specialNode, out Exception shutdownException) { // Console.WriteLine("Run called at {0}", DateTime.Now); string pipeName = NamedPipeUtil.GetPipeNameOrPath("MSBuild" + Process.GetCurrentProcess().Id); - _nodeEndpoint = new NodeEndpointOutOfProc(pipeName, this, enableReuse, lowPriority, workerNode); + _nodeEndpoint = new NodeEndpointOutOfProc(pipeName, this, enableReuse, lowPriority, specialNode); _nodeEndpoint.OnLinkStatusChanged += OnLinkStatusChanged; _nodeEndpoint.Listen(this); diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs index d04cafff383..684feac09c9 100644 --- a/src/Build/BackEnd/Node/RarNode.cs +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; @@ -38,10 +38,7 @@ public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Except string pipeName = CommunicationsUtilities.GetRarPipeName(nodeReuse, lowPriority); RarController controller = new RarController(pipeName); - Console.CancelKeyPress += (e, sender) => cancellationTokenSource.Cancel(); - - _rarTask = Task.Run(async () => _rarResult = await controller.StartAsync(cancellationTokenSource.Token).ConfigureAwait(false)); - _msBuildTask = Task.Run(() => shutdownReason = _msBuildNode.Run(nodeReuse, lowPriority, out this.shutdownException)).WithCancellation(cancellationTokenSource.Token); + _msBuildTask = Task.Run(() => shutdownReason = _msBuildNode.Run(nodeReuse, lowPriority, specialNode: true, out this.shutdownException), cts.Token); Task.WaitAny(_msBuildTask, _rarTask); cancellationTokenSource.Cancel(); diff --git a/src/Shared/CommunicationsUtilities.cs b/src/Shared/CommunicationsUtilities.cs index 250e5a2efcf..454b4ba3af6 100644 --- a/src/Shared/CommunicationsUtilities.cs +++ b/src/Shared/CommunicationsUtilities.cs @@ -60,9 +60,9 @@ internal enum HandshakeOptions Administrator = 32, /// - /// Is worker node. Worker node can accept normal build requests. + /// Is special node. Special node can not accept normal build requests. /// - Worker = 64 + Special = 64 } internal readonly struct Handshake @@ -481,7 +481,7 @@ internal static async Task ReadAsync(Stream stream, byte[] buffer, int byte /// /// Given the appropriate information, return the equivalent HandshakeOptions. /// - internal static HandshakeOptions GetHandshakeOptions(bool taskHost, bool is64Bit = false, bool nodeReuse = false, bool lowPriority = false, bool workerNode = true, IDictionary taskHostParameters = null) + internal static HandshakeOptions GetHandshakeOptions(bool taskHost, bool is64Bit = false, bool nodeReuse = false, bool lowPriority = false, bool specialNode = true, IDictionary taskHostParameters = null) { HandshakeOptions context = taskHost ? HandshakeOptions.TaskHost : HandshakeOptions.None; @@ -532,9 +532,9 @@ internal static HandshakeOptions GetHandshakeOptions(bool taskHost, bool is64Bit context |= HandshakeOptions.Administrator; } #endif - if (workerNode) + if (specialNode) { - context |= HandshakeOptions.Worker; + context |= HandshakeOptions.Special; } return context; } From 356a33a0f500fe6d632a88b056bdb1123f40f7c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Wed, 12 Aug 2020 11:49:43 +0200 Subject: [PATCH 12/61] Build fix --- src/Build/BackEnd/Node/RarNode.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs index 684feac09c9..87c10920110 100644 --- a/src/Build/BackEnd/Node/RarNode.cs +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; @@ -7,9 +7,9 @@ using System.Threading.Tasks; using Microsoft.Build.BackEnd; +using Microsoft.Build.Framework; using Microsoft.Build.Internal; using Microsoft.Build.Tasks.ResolveAssemblyReferences.Server; -using Microsoft.VisualStudio.Threading; namespace Microsoft.Build.Execution { @@ -18,7 +18,7 @@ public sealed class RarNode : INode private readonly OutOfProcNode _msBuildNode; private Task _rarTask; - private int _rarResult; + //private int _rarResult; private Task _msBuildTask; private Exception shutdownException; @@ -29,19 +29,19 @@ public RarNode() _msBuildNode = new OutOfProcNode(); } - [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits", - Justification = "We need to wait for completion of async method in synchronous method (required by interface)")] public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Exception shutdownException) { - var cancellationTokenSource = new CancellationTokenSource(); + using CancellationTokenSource cts = new CancellationTokenSource(); string pipeName = CommunicationsUtilities.GetRarPipeName(nodeReuse, lowPriority); RarController controller = new RarController(pipeName); + _rarTask = Task.Run(async () => /*_rarResult = */await controller.StartAsync(cts.Token).ConfigureAwait(false)); + // Exits in 15 mins (by default), if don't have any active connection _msBuildTask = Task.Run(() => shutdownReason = _msBuildNode.Run(nodeReuse, lowPriority, specialNode: true, out this.shutdownException), cts.Token); Task.WaitAny(_msBuildTask, _rarTask); - cancellationTokenSource.Cancel(); + cts.Cancel(); shutdownException = this.shutdownException; return shutdownReason; From f543437e688c954a8b1695a99ef5cff72b8814de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Wed, 12 Aug 2020 14:08:29 +0200 Subject: [PATCH 13/61] Handshake validation --- .../Communications/NodeEndpointOutOfProc.cs | 2 +- src/MSBuild/MSBuild.csproj | 1 + src/MSBuildTaskHost/MSBuildTaskHost.csproj | 1 + src/Shared/NamedPipeUtil.cs | 84 ++++++++++++++++++- src/Shared/NodeEndpointOutOfProcBase.cs | 78 +---------------- 5 files changed, 90 insertions(+), 76 deletions(-) diff --git a/src/Build/BackEnd/Components/Communications/NodeEndpointOutOfProc.cs b/src/Build/BackEnd/Components/Communications/NodeEndpointOutOfProc.cs index 4ad76f6a305..76a1fc36409 100644 --- a/src/Build/BackEnd/Components/Communications/NodeEndpointOutOfProc.cs +++ b/src/Build/BackEnd/Components/Communications/NodeEndpointOutOfProc.cs @@ -65,7 +65,7 @@ protected override Handshake GetHandshake() is64Bit: EnvironmentUtilities.Is64BitProcess, nodeReuse: _enableReuse, lowPriority: _lowPriority, - _specialNode)); + specialNode: _specialNode)); } #region Structs diff --git a/src/MSBuild/MSBuild.csproj b/src/MSBuild/MSBuild.csproj index 3bf42162617..74b1c3e0d35 100644 --- a/src/MSBuild/MSBuild.csproj +++ b/src/MSBuild/MSBuild.csproj @@ -141,6 +141,7 @@ + true diff --git a/src/MSBuildTaskHost/MSBuildTaskHost.csproj b/src/MSBuildTaskHost/MSBuildTaskHost.csproj index 7fa58465d0b..e1639a3ebe1 100644 --- a/src/MSBuildTaskHost/MSBuildTaskHost.csproj +++ b/src/MSBuildTaskHost/MSBuildTaskHost.csproj @@ -61,6 +61,7 @@ CopyOnWriteDictionary.cs + ErrorUtilities.cs diff --git a/src/Shared/NamedPipeUtil.cs b/src/Shared/NamedPipeUtil.cs index 82e45f069b8..8cf8843f42c 100644 --- a/src/Shared/NamedPipeUtil.cs +++ b/src/Shared/NamedPipeUtil.cs @@ -117,7 +117,7 @@ private static NamedPipeClientStream TryConnectToProcess(string pipeName, int? n #if NETCOREAPP2_1 || MONO nodeStream.ReadEndOfHandshakeSignal(true, timeout); #else - nodeStream.ReadEndOfHandshakeSignal(true); + nodeStream.ReadEndOfHandshakeSignal(true); #endif } @@ -140,5 +140,87 @@ private static NamedPipeClientStream TryConnectToProcess(string pipeName, int? n return null; } + + internal static bool ValidateHandshake(Handshake handshake, NamedPipeServerStream serverStream, int clientConnectTimeout) + { + // The handshake protocol is a series of int exchanges. The host sends us a each component, and we + // verify it. Afterwards, the host sends an "End of Handshake" signal, to which we respond in kind. + // Once the handshake is complete, both sides can be assured the other is ready to accept data. + + bool gotValidConnection = true; + try + { + int[] handshakeComponents = handshake.RetrieveHandshakeComponents(); + for (int i = 0; i < handshakeComponents.Length; i++) + { + int handshakePart = serverStream.ReadIntForHandshake(i == 0 ? (byte?)CommunicationsUtilities.handshakeVersion : null /* this will disconnect a < 16.8 host; it expects leading 00 or F5 or 06. 0x00 is a wildcard */ +#if NETCOREAPP2_1 || MONO + , clientConnectTimeout /* wait a long time for the handshake from this side */ +#endif + ); + + if (handshakePart != handshakeComponents[i]) + { + CommunicationsUtilities.Trace("Handshake failed. Received {0} from host not {1}. Probably the host is a different MSBuild build.", handshakePart, handshakeComponents[i]); + serverStream.WriteIntForHandshake(i + 1); + gotValidConnection = false; + break; + } + } + + if (gotValidConnection) + { + // To ensure that our handshake and theirs have the same number of bytes, receive and send a magic number indicating EOS. +#if NETCOREAPP2_1 || MONO + serverStream.ReadEndOfHandshakeSignal(false, clientConnectTimeout); /* wait a long time for the handshake from this side */ +#else + serverStream.ReadEndOfHandshakeSignal(false); +#endif + CommunicationsUtilities.Trace("Successfully connected to parent."); + serverStream.WriteEndOfHandshakeSignal(); + +#if FEATURE_SECURITY_PERMISSIONS + // We will only talk to a host that was started by the same user as us. Even though the pipe access is set to only allow this user, we want to ensure they + // haven't attempted to change those permissions out from under us. This ensures that the only way they can truly gain access is to be impersonating the + // user we were started by. + WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent(); + WindowsIdentity clientIdentity = null; + serverStream.RunAsClient(delegate () { clientIdentity = WindowsIdentity.GetCurrent(true); }); + + if (clientIdentity == null || !string.Equals(clientIdentity.Name, currentIdentity.Name, StringComparison.OrdinalIgnoreCase)) + { + CommunicationsUtilities.Trace("Handshake failed. Host user is {0} but we were created by {1}.", (clientIdentity == null) ? "" : clientIdentity.Name, currentIdentity.Name); + return false; + } +#endif + } + } + catch (IOException e) + { + // We will get here when: + // 1. The host (OOP main node) connects to us, it immediately checks for user privileges + // and if they don't match it disconnects immediately leaving us still trying to read the blank handshake + // 2. The host is too old sending us bits we automatically reject in the handshake + // 3. We expected to read the EndOfHandshake signal, but we received something else + CommunicationsUtilities.Trace("Client connection failed but we will wait for another connection. Exception: {0}", e.Message); + + gotValidConnection = false; + } + catch (InvalidOperationException) + { + gotValidConnection = false; + } + + if (!gotValidConnection) + { + if (serverStream.IsConnected) + { + serverStream.Disconnect(); + } + return false; + } + + return true; + } } } diff --git a/src/Shared/NodeEndpointOutOfProcBase.cs b/src/Shared/NodeEndpointOutOfProcBase.cs index 88b6cb2966b..40e45bbb222 100644 --- a/src/Shared/NodeEndpointOutOfProcBase.cs +++ b/src/Shared/NodeEndpointOutOfProcBase.cs @@ -32,12 +32,10 @@ internal abstract class NodeEndpointOutOfProcBase : INodeEndpoint { #region Private Data -#if NETCOREAPP2_1 || MONO /// /// The amount of time to wait for the client to connect to the host. /// private const int ClientConnectTimeout = 60000; -#endif // NETCOREAPP2_1 || MONO /// /// The size of the buffers to use for named pipes @@ -365,83 +363,15 @@ private void PacketPumpProc() localPipeServer.EndWaitForConnection(resultForConnection); #endif - // The handshake protocol is a series of int exchanges. The host sends us a each component, and we - // verify it. Afterwards, the host sends an "End of Handshake" signal, to which we respond in kind. - // Once the handshake is complete, both sides can be assured the other is ready to accept data. - Handshake handshake = GetHandshake(); - try - { - int[] handshakeComponents = handshake.RetrieveHandshakeComponents(); - for (int i = 0; i < handshakeComponents.Length; i++) - { - int handshakePart = _pipeServer.ReadIntForHandshake(i == 0 ? (byte?)CommunicationsUtilities.handshakeVersion : null /* this will disconnect a < 16.8 host; it expects leading 00 or F5 or 06. 0x00 is a wildcard */ -#if NETCOREAPP2_1 || MONO - , ClientConnectTimeout /* wait a long time for the handshake from this side */ -#endif - ); - - if (handshakePart != handshakeComponents[i]) - { - CommunicationsUtilities.Trace("Handshake failed. Received {0} from host not {1}. Probably the host is a different MSBuild build.", handshakePart, handshakeComponents[i]); - _pipeServer.WriteIntForHandshake(i + 1); - gotValidConnection = false; - break; - } - } - - if (gotValidConnection) - { - // To ensure that our handshake and theirs have the same number of bytes, receive and send a magic number indicating EOS. -#if NETCOREAPP2_1 || MONO - _pipeServer.ReadEndOfHandshakeSignal(false, ClientConnectTimeout); /* wait a long time for the handshake from this side */ -#else - _pipeServer.ReadEndOfHandshakeSignal(false); -#endif - CommunicationsUtilities.Trace("Successfully connected to parent."); - _pipeServer.WriteEndOfHandshakeSignal(); - -#if FEATURE_SECURITY_PERMISSIONS - // We will only talk to a host that was started by the same user as us. Even though the pipe access is set to only allow this user, we want to ensure they - // haven't attempted to change those permissions out from under us. This ensures that the only way they can truly gain access is to be impersonating the - // user we were started by. - WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent(); - WindowsIdentity clientIdentity = null; - localPipeServer.RunAsClient(delegate () { clientIdentity = WindowsIdentity.GetCurrent(true); }); - - if (clientIdentity == null || !String.Equals(clientIdentity.Name, currentIdentity.Name, StringComparison.OrdinalIgnoreCase)) - { - CommunicationsUtilities.Trace("Handshake failed. Host user is {0} but we were created by {1}.", (clientIdentity == null) ? "" : clientIdentity.Name, currentIdentity.Name); - gotValidConnection = false; - continue; - } -#endif - } - } - catch (IOException e) - { - // We will get here when: - // 1. The host (OOP main node) connects to us, it immediately checks for user privileges - // and if they don't match it disconnects immediately leaving us still trying to read the blank handshake - // 2. The host is too old sending us bits we automatically reject in the handshake - // 3. We expected to read the EndOfHandshake signal, but we received something else - CommunicationsUtilities.Trace("Client connection failed but we will wait for another connection. Exception: {0}", e.Message); - - gotValidConnection = false; - } - catch (InvalidOperationException) - { - gotValidConnection = false; - } + Handshake handshake = GetHandshake(); + gotValidConnection = NamedPipeUtil.ValidateHandshake(handshake, _pipeServer, ClientConnectTimeout); if (!gotValidConnection) { - if (localPipeServer.IsConnected) - { - localPipeServer.Disconnect(); - } - continue; + return; } + ChangeLinkStatus(LinkStatus.Active); } catch (Exception e) From bd0a66334dc8768ecc410931eece4daa2325a69d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Wed, 12 Aug 2020 19:44:42 +0200 Subject: [PATCH 14/61] RAR shutdown on its own --- ref/Microsoft.Build/net/Microsoft.Build.cs | 1 - .../netstandard/Microsoft.Build.cs | 1 - .../BackEnd/BuildManager/BuildManager.cs | 4 +- .../Communications/NodeEndpointOutOfProc.cs | 11 +-- .../Communications/NodeProviderOutOfProc.cs | 47 ++++------- .../NodeProviderOutOfProcBase.cs | 15 ++-- src/Build/BackEnd/Node/NodeConfiguration.cs | 19 +---- src/Build/BackEnd/Node/OutOfProcNode.cs | 15 +--- src/Build/BackEnd/Node/RarNode.cs | 78 ++++++++++++++----- src/Shared/NamedPipeUtil.cs | 55 ++++++++++++- src/Shared/NodeEndpointOutOfProcBase.cs | 74 ++++-------------- 11 files changed, 160 insertions(+), 160 deletions(-) diff --git a/ref/Microsoft.Build/net/Microsoft.Build.cs b/ref/Microsoft.Build/net/Microsoft.Build.cs index 0b47d428f89..ea72f3f30e4 100644 --- a/ref/Microsoft.Build/net/Microsoft.Build.cs +++ b/ref/Microsoft.Build/net/Microsoft.Build.cs @@ -1107,7 +1107,6 @@ public enum NodeEngineShutdownReason public partial class OutOfProcNode { public OutOfProcNode() { } - public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool enableReuse, bool lowPriority, bool specialNode, out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool enableReuse, bool lowPriority, out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool enableReuse, out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } public Microsoft.Build.Execution.NodeEngineShutdownReason Run(out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } diff --git a/ref/Microsoft.Build/netstandard/Microsoft.Build.cs b/ref/Microsoft.Build/netstandard/Microsoft.Build.cs index 436b0946a2f..f26460cd981 100644 --- a/ref/Microsoft.Build/netstandard/Microsoft.Build.cs +++ b/ref/Microsoft.Build/netstandard/Microsoft.Build.cs @@ -1101,7 +1101,6 @@ public enum NodeEngineShutdownReason public partial class OutOfProcNode { public OutOfProcNode() { } - public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool enableReuse, bool lowPriority, bool specialNode, out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool enableReuse, bool lowPriority, out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool enableReuse, out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } public Microsoft.Build.Execution.NodeEngineShutdownReason Run(out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index 1842743376b..d1284ce38a0 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -2020,9 +2020,7 @@ private void PerformSchedulingActions(IEnumerable responses) internal NodeInfo CreateRarNode() { - NodeConfiguration configuration = GetNodeConfiguration(); - configuration.RarNode = true; - return _nodeManager.CreateNode(configuration, NodeAffinity.OutOfProc); + return null; } /// diff --git a/src/Build/BackEnd/Components/Communications/NodeEndpointOutOfProc.cs b/src/Build/BackEnd/Components/Communications/NodeEndpointOutOfProc.cs index 76a1fc36409..221e575ac3d 100644 --- a/src/Build/BackEnd/Components/Communications/NodeEndpointOutOfProc.cs +++ b/src/Build/BackEnd/Components/Communications/NodeEndpointOutOfProc.cs @@ -22,8 +22,6 @@ internal class NodeEndpointOutOfProc : NodeEndpointOutOfProcBase private readonly bool _lowPriority; - private readonly bool _specialNode; - #endregion #region Constructors and Factories @@ -35,20 +33,16 @@ internal class NodeEndpointOutOfProc : NodeEndpointOutOfProcBase /// The component host. /// Whether this node may be reused for a later build. /// Whether this node is low priority. - /// Indicates if node is special node (can not accept normal MSBuild work) internal NodeEndpointOutOfProc( string pipeName, IBuildComponentHost host, bool enableReuse, - bool lowPriority, - bool specialNode) + bool lowPriority) { ErrorUtilities.VerifyThrowArgumentNull(host, nameof(host)); _componentHost = host; _enableReuse = enableReuse; _lowPriority = lowPriority; - _specialNode = specialNode; - InternalConstruct(pipeName); } @@ -64,8 +58,7 @@ protected override Handshake GetHandshake() taskHost: false, is64Bit: EnvironmentUtilities.Is64BitProcess, nodeReuse: _enableReuse, - lowPriority: _lowPriority, - specialNode: _specialNode)); + lowPriority: _lowPriority)); } #region Structs diff --git a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProc.cs b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProc.cs index 38096b353de..80bf29084f9 100644 --- a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProc.cs +++ b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProc.cs @@ -22,11 +22,6 @@ internal class NodeProviderOutOfProc : NodeProviderOutOfProcBase, INodeProvider /// private Dictionary _nodeContexts; - /// - /// A mapping of all RAR nodes managed by this provider. - /// - private Dictionary _rarNodeContexts; - /// /// Constructor. /// @@ -92,7 +87,7 @@ public bool CreateNode(int nodeId, INodePacketFactory factory, NodeConfiguration // want to start up just a standard MSBuild out-of-proc node. // Note: We need to always pass /nodeReuse to ensure the value for /nodeReuse from msbuild.rsp // (next to msbuild.exe) is ignored. - string commandLineArgs = $"/nologo /nodemode:{(configuration.RarNode ? 3 : 1)} /nodeReuse:{ComponentHost.BuildParameters.EnableNodeReuse.ToString().ToLower()} /low:{ComponentHost.BuildParameters.LowPriority.ToString().ToLower()}"; + string commandLineArgs = $"/nologo /nodemode:1 /nodeReuse:{ComponentHost.BuildParameters.EnableNodeReuse.ToString().ToLower()} /low:{ComponentHost.BuildParameters.LowPriority.ToString().ToLower()}"; // Make it here. CommunicationsUtilities.Trace("Starting to acquire a new or existing node to establish node ID {0}...", nodeId); @@ -102,14 +97,7 @@ public bool CreateNode(int nodeId, INodePacketFactory factory, NodeConfiguration if (null != context) { - if (configuration.RarNode) - { - _rarNodeContexts[nodeId] = context; - } - else - { - _nodeContexts[nodeId] = context; - } + _nodeContexts[nodeId] = context; // Start the asynchronous read. context.BeginAsyncPacketRead(); @@ -130,18 +118,9 @@ public bool CreateNode(int nodeId, INodePacketFactory factory, NodeConfiguration /// The packet to send. public void SendData(int nodeId, INodePacket packet) { - if (_nodeContexts.ContainsKey(nodeId)) - { - SendData(_nodeContexts[nodeId], packet); - } - else if (_rarNodeContexts.ContainsKey(nodeId)) - { - SendData(_rarNodeContexts[nodeId], packet); - } - else - { - ErrorUtilities.ThrowInternalError("Invalid node id specified: {0}.", nodeId); - } + ErrorUtilities.VerifyThrow(_nodeContexts.ContainsKey(nodeId), "Invalid node id specified: {0}.", nodeId); + + SendData(_nodeContexts[nodeId], packet); } /// @@ -156,10 +135,16 @@ public void ShutdownConnectedNodes(bool enableReuse) lock (_nodeContexts) { contextsToShutDown = new List(_nodeContexts.Values); - contextsToShutDown.AddRange(_rarNodeContexts.Values); } - + ShutdownConnectedNodes(contextsToShutDown, enableReuse); + + ShutdownAllNodes(enableReuse, ShutdownRarNode, onlySpecialNode: true); + } + + private void ShutdownRarNode(int nodeId) + { + // Do nothig } /// @@ -192,7 +177,6 @@ public void InitializeComponent(IBuildComponentHost host) { this.ComponentHost = host; _nodeContexts = new Dictionary(); - _rarNodeContexts = new Dictionary(); } /// @@ -220,10 +204,7 @@ private void NodeContextTerminated(int nodeId) { lock (_nodeContexts) { - if (!_nodeContexts.Remove(nodeId)) - { - _rarNodeContexts.Remove(nodeId); - } + _nodeContexts.Remove(nodeId); } } } diff --git a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs index 4efff7385f8..96edf09a701 100644 --- a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs +++ b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs @@ -102,7 +102,8 @@ protected void ShutdownConnectedNodes(List contextsToShutDown, bool /// /// Whether to reuse the node /// Delegate used to tell the node provider that a context has terminated - protected void ShutdownAllNodes(bool nodeReuse, NodeContextTerminateDelegate terminateNode) + /// Shutdown only special nodes (RAR node, ...) + protected void ShutdownAllNodes(bool nodeReuse, NodeContextTerminateDelegate terminateNode, bool onlySpecialNode = false) { // INodePacketFactory INodePacketFactory factory = new NodePacketFactory(); @@ -121,11 +122,15 @@ protected void ShutdownAllNodes(bool nodeReuse, NodeContextTerminateDelegate ter // A 2013 comment suggested some nodes take this long to respond, so a smaller timeout would miss nodes. int timeout = 30; - // Attempt to connect to the process with the handshake without low priority. - Stream nodeStream = NamedPipeUtil.TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, enableLowPriority: false, specialNode: false)); + Stream nodeStream = null; + if (!onlySpecialNode) + { + // Attempt to connect to the process with the handshake without low priority. + nodeStream = NamedPipeUtil.TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, enableLowPriority: false, specialNode: false)); - // If we couldn't connect attempt to connect to the process with the handshake including low priority. - nodeStream ??= NamedPipeUtil.TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, enableLowPriority: true, specialNode: false)); + // If we couldn't connect attempt to connect to the process with the handshake including low priority. + nodeStream ??= NamedPipeUtil.TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, enableLowPriority: true, specialNode: false)); + } // Attempt to connect to the non-worker process // Attempt to connect to the process with the handshake without low priority. diff --git a/src/Build/BackEnd/Node/NodeConfiguration.cs b/src/Build/BackEnd/Node/NodeConfiguration.cs index e4b3a7eaa81..5cb25db468c 100644 --- a/src/Build/BackEnd/Node/NodeConfiguration.cs +++ b/src/Build/BackEnd/Node/NodeConfiguration.cs @@ -39,7 +39,6 @@ internal class NodeConfiguration : INodePacket /// The logging configuration for the node. /// private LoggingNodeConfiguration _loggingNodeConfiguration; - private bool _rarNode; #if FEATURE_APPDOMAIN /// @@ -50,15 +49,13 @@ internal class NodeConfiguration : INodePacket /// The forwarding loggers. /// The AppDomain setup information. /// The logging configuration for the node. - /// Indicates if node works as RAR node. public NodeConfiguration ( int nodeId, BuildParameters buildParameters, LoggerDescription[] forwardingLoggers, AppDomainSetup appDomainSetup, - LoggingNodeConfiguration loggingNodeConfiguration, - bool rarNode = false + LoggingNodeConfiguration loggingNodeConfiguration ) { _nodeId = nodeId; @@ -66,7 +63,6 @@ public NodeConfiguration _forwardingLoggers = forwardingLoggers; _appDomainSetup = appDomainSetup; _loggingNodeConfiguration = loggingNodeConfiguration; - RarNode = rarNode; } #else /// @@ -76,21 +72,18 @@ public NodeConfiguration /// The build parameters /// The forwarding loggers. /// The logging configuration for the node. - /// Indicates if node works as RAR node. public NodeConfiguration ( int nodeId, BuildParameters buildParameters, LoggerDescription[] forwardingLoggers, - LoggingNodeConfiguration loggingNodeConfiguration, - bool rarNode = false + LoggingNodeConfiguration loggingNodeConfiguration ) { _nodeId = nodeId; _buildParameters = buildParameters; _forwardingLoggers = forwardingLoggers; _loggingNodeConfiguration = loggingNodeConfiguration; - RarNode = rarNode; } #endif @@ -157,11 +150,6 @@ public LoggingNodeConfiguration LoggingNodeConfiguration { return _loggingNodeConfiguration; } } - /// - /// Indicates if the node is RAR node or not (executes only one task) - /// - public bool RarNode { get => _rarNode; set => _rarNode = value; } - #region INodePacket Members /// @@ -191,7 +179,6 @@ public void Translate(ITranslator translator) translator.TranslateDotNet(ref _appDomainSetup); #endif translator.Translate(ref _loggingNodeConfiguration); - translator.Translate(ref _rarNode); } /// @@ -214,7 +201,7 @@ internal NodeConfiguration Clone() #if FEATURE_APPDOMAIN , _appDomainSetup #endif - , _loggingNodeConfiguration, _rarNode + , _loggingNodeConfiguration ); } } diff --git a/src/Build/BackEnd/Node/OutOfProcNode.cs b/src/Build/BackEnd/Node/OutOfProcNode.cs index 1e5b9748cec..4d170a3853c 100644 --- a/src/Build/BackEnd/Node/OutOfProcNode.cs +++ b/src/Build/BackEnd/Node/OutOfProcNode.cs @@ -242,24 +242,11 @@ public NodeEngineShutdownReason Run(bool enableReuse, out Exception shutdownExce /// The exception which caused shutdown, if any. /// The reason for shutting down. public NodeEngineShutdownReason Run(bool enableReuse, bool lowPriority, out Exception shutdownException) - { - return Run(enableReuse, lowPriority, specialNode: false, out shutdownException); - } - - /// - /// Starts up the node and processes messages until the node is requested to shut down. - /// - /// Whether this node is eligible for reuse later. - /// Whether this node should be running with low priority. - /// Whether this node should act as special node and refuse build requests. - /// The exception which caused shutdown, if any. - /// The reason for shutting down. - public NodeEngineShutdownReason Run(bool enableReuse, bool lowPriority, bool specialNode, out Exception shutdownException) { // Console.WriteLine("Run called at {0}", DateTime.Now); string pipeName = NamedPipeUtil.GetPipeNameOrPath("MSBuild" + Process.GetCurrentProcess().Id); - _nodeEndpoint = new NodeEndpointOutOfProc(pipeName, this, enableReuse, lowPriority, specialNode); + _nodeEndpoint = new NodeEndpointOutOfProc(pipeName, this, enableReuse, lowPriority); _nodeEndpoint.OnLinkStatusChanged += OnLinkStatusChanged; _nodeEndpoint.Listen(this); diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs index 87c10920110..33cf87d35be 100644 --- a/src/Build/BackEnd/Node/RarNode.cs +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -2,6 +2,8 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Diagnostics; +using System.IO.Pipes; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -9,47 +11,85 @@ using Microsoft.Build.BackEnd; using Microsoft.Build.Framework; using Microsoft.Build.Internal; +using Microsoft.Build.Shared; using Microsoft.Build.Tasks.ResolveAssemblyReferences.Server; namespace Microsoft.Build.Execution { public sealed class RarNode : INode { - private readonly OutOfProcNode _msBuildNode; + /// + /// The amount of time to wait for the client to connect to the host. + /// + private const int ClientConnectTimeout = 60000; - private Task _rarTask; - //private int _rarResult; - - private Task _msBuildTask; - private Exception shutdownException; - private NodeEngineShutdownReason shutdownReason; - - public RarNode() - { - _msBuildNode = new OutOfProcNode(); - } + private Task _rarTask; + private Task _msBuildShutdown; public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Exception shutdownException) { + shutdownException = null; using CancellationTokenSource cts = new CancellationTokenSource(); - string pipeName = CommunicationsUtilities.GetRarPipeName(nodeReuse, lowPriority); RarController controller = new RarController(pipeName); - _rarTask = Task.Run(async () => /*_rarResult = */await controller.StartAsync(cts.Token).ConfigureAwait(false)); - // Exits in 15 mins (by default), if don't have any active connection - _msBuildTask = Task.Run(() => shutdownReason = _msBuildNode.Run(nodeReuse, lowPriority, specialNode: true, out this.shutdownException), cts.Token); + _rarTask = controller.StartAsync(cts.Token); + + Handshake handshake = NodeProviderOutOfProc.GetHandshake(nodeReuse, enableLowPriority: lowPriority, specialNode: true); + _msBuildShutdown = RunShutdownCheckAsync(handshake, cts.Token); - Task.WaitAny(_msBuildTask, _rarTask); + int index = Task.WaitAny(_msBuildShutdown, _rarTask); cts.Cancel(); - shutdownException = this.shutdownException; - return shutdownReason; + if(index == 0) + { + // We know that this task is completed so we can accept + return _msBuildShutdown.Result; + } + else + { + // RAR task can only exit with error + return NodeEngineShutdownReason.Error; + } } public NodeEngineShutdownReason Run(out Exception shutdownException) { return Run(false, false, out shutdownException); } + + private async Task RunShutdownCheckAsync(Handshake handshake, CancellationToken cancellationToken = default) + { + string pipeName = NamedPipeUtil.GetPipeNameOrPath("MSBuild" + Process.GetCurrentProcess().Id); + using NamedPipeServerStream serverStream = NamedPipeUtil.CreateNamedPipeServer(pipeName, maxNumberOfServerInstances: NamedPipeServerStream.MaxAllowedServerInstances); + + while (true) + { + if (cancellationToken.IsCancellationRequested) + return NodeEngineShutdownReason.Error; + + await serverStream.WaitForConnectionAsync(cancellationToken); + bool conected = NamedPipeUtil.ValidateHandshake(handshake, serverStream, ClientConnectTimeout); + if (!conected) + continue; + + byte[] header = new byte[5]; + int bytesRead = await serverStream.ReadAsync(header, 0, header.Length); + if (bytesRead != header.Length) + { + continue; + } + + NodePacketType packetType = (NodePacketType)Enum.ToObject(typeof(NodePacketType), header[0]); + // Packet type sent by Shutdown + if (packetType == NodePacketType.NodeBuildComplete) + { + // Finish this task + break; + } + } + + return NodeEngineShutdownReason.BuildComplete; + } } } diff --git a/src/Shared/NamedPipeUtil.cs b/src/Shared/NamedPipeUtil.cs index 8cf8843f42c..4b6c39fc7d8 100644 --- a/src/Shared/NamedPipeUtil.cs +++ b/src/Shared/NamedPipeUtil.cs @@ -4,6 +4,7 @@ using System; using System.IO; using System.IO.Pipes; +using System.Security.AccessControl; using System.Security.Principal; using Microsoft.Build.Internal; @@ -12,6 +13,11 @@ namespace Microsoft.Build.Shared { internal static class NamedPipeUtil { + /// + /// The size of the buffers to use for named pipes + /// + private const int PipeBufferSize = 131072; + internal static string GetPipeNameOrPath(string pipeName) { if (NativeMethodsShared.IsUnixLike) @@ -56,7 +62,8 @@ private static void ValidateRemotePipeSecurityOnWindows(NamedPipeClientStream no internal static NamedPipeClientStream TryConnectToProcess(int nodeProcessId, int timeout, Handshake? handshake) { string pipeName = GetPipeNameOrPath("MSBuild" + nodeProcessId); - return TryConnectToProcess(pipeName, timeout, timeout, handshake); + Console.WriteLine(handshake); + return TryConnectToProcess(pipeName, nodeProcessId, timeout, handshake); } /// @@ -222,5 +229,51 @@ internal static bool ValidateHandshake(Handshake handshake, NamedPipeServerStrea return true; } + + internal static NamedPipeServerStream CreateNamedPipeServer(string pipeName, int? inputBufferSize = null, int? outputBufferSize = null, int maxNumberOfServerInstances = 1) + { + inputBufferSize ??= PipeBufferSize; + outputBufferSize ??= PipeBufferSize; + +#if FEATURE_PIPE_SECURITY && FEATURE_NAMED_PIPE_SECURITY_CONSTRUCTOR + if (!NativeMethodsShared.IsMono) + { + SecurityIdentifier identifier = WindowsIdentity.GetCurrent().Owner; + PipeSecurity security = new PipeSecurity(); + + // Restrict access to just this account. We set the owner specifically here, and on the + // pipe client side they will check the owner against this one - they must have identical + // SIDs or the client will reject this server. This is used to avoid attacks where a + // hacked server creates a less restricted pipe in an attempt to lure us into using it and + // then sending build requests to the real pipe client (which is the MSBuild Build Manager.) + PipeAccessRule rule = new PipeAccessRule(identifier, PipeAccessRights.ReadWrite, AccessControlType.Allow); + security.AddAccessRule(rule); + security.SetOwner(identifier); + + return new NamedPipeServerStream + ( + pipeName, + PipeDirection.InOut, + maxNumberOfServerInstances, // Only allow one connection at a time. + PipeTransmissionMode.Byte, + PipeOptions.Asynchronous | PipeOptions.WriteThrough, + inputBufferSize.Value, // Default input buffer + outputBufferSize.Value, // Default output buffer + security, + HandleInheritability.None + ); + } +#endif + return new NamedPipeServerStream + ( + pipeName, + PipeDirection.InOut, + maxNumberOfServerInstances, // Only allow one connection at a time. + PipeTransmissionMode.Byte, + PipeOptions.Asynchronous | PipeOptions.WriteThrough, + inputBufferSize.Value, // Default input buffer + outputBufferSize.Value // Default output buffer + ); + } } } diff --git a/src/Shared/NodeEndpointOutOfProcBase.cs b/src/Shared/NodeEndpointOutOfProcBase.cs index 40e45bbb222..00890c400aa 100644 --- a/src/Shared/NodeEndpointOutOfProcBase.cs +++ b/src/Shared/NodeEndpointOutOfProcBase.cs @@ -98,18 +98,18 @@ internal abstract class NodeEndpointOutOfProcBase : INodeEndpoint /// private SharedReadBuffer _sharedReadBuffer; -#endregion + #endregion -#region INodeEndpoint Events + #region INodeEndpoint Events /// /// Raised when the link status has changed. /// public event LinkStatusChangedDelegate OnLinkStatusChanged; -#endregion + #endregion -#region INodeEndpoint Properties + #region INodeEndpoint Properties /// /// Returns the link status of this node. @@ -119,13 +119,13 @@ public LinkStatus LinkStatus get { return _status; } } -#endregion + #endregion -#region Properties + #region Properties -#endregion + #endregion -#region INodeEndpoint Methods + #region INodeEndpoint Methods /// /// Causes this endpoint to wait for the remote endpoint to connect @@ -170,9 +170,9 @@ public void SendData(INodePacket packet) } } -#endregion + #endregion -#region Construction + #region Construction /// /// Instantiates an endpoint to act as a client @@ -187,52 +187,10 @@ internal void InternalConstruct(string pipeName) _status = LinkStatus.Inactive; _asyncDataMonitor = new object(); _sharedReadBuffer = InterningBinaryReader.CreateSharedBuffer(); - -#if FEATURE_PIPE_SECURITY && FEATURE_NAMED_PIPE_SECURITY_CONSTRUCTOR - if (!NativeMethodsShared.IsMono) - { - SecurityIdentifier identifier = WindowsIdentity.GetCurrent().Owner; - PipeSecurity security = new PipeSecurity(); - - // Restrict access to just this account. We set the owner specifically here, and on the - // pipe client side they will check the owner against this one - they must have identical - // SIDs or the client will reject this server. This is used to avoid attacks where a - // hacked server creates a less restricted pipe in an attempt to lure us into using it and - // then sending build requests to the real pipe client (which is the MSBuild Build Manager.) - PipeAccessRule rule = new PipeAccessRule(identifier, PipeAccessRights.ReadWrite, AccessControlType.Allow); - security.AddAccessRule(rule); - security.SetOwner(identifier); - - _pipeServer = new NamedPipeServerStream - ( - pipeName, - PipeDirection.InOut, - 1, // Only allow one connection at a time. - PipeTransmissionMode.Byte, - PipeOptions.Asynchronous | PipeOptions.WriteThrough, - PipeBufferSize, // Default input buffer - PipeBufferSize, // Default output buffer - security, - HandleInheritability.None - ); - } - else -#endif - { - _pipeServer = new NamedPipeServerStream - ( - pipeName, - PipeDirection.InOut, - 1, // Only allow one connection at a time. - PipeTransmissionMode.Byte, - PipeOptions.Asynchronous | PipeOptions.WriteThrough, - PipeBufferSize, // Default input buffer - PipeBufferSize // Default output buffer - ); - } + _pipeServer = NamedPipeUtil.CreateNamedPipeServer(pipeName, PipeBufferSize, PipeBufferSize); } -#endregion + #endregion /// /// Returns the host handshake for this node endpoint @@ -260,7 +218,7 @@ private void RaiseLinkStatusChanged(LinkStatus newStatus) OnLinkStatusChanged?.Invoke(this, newStatus); } -#region Private Methods + #region Private Methods /// /// This does the actual work of changing the status and shutting down any threads we may have for @@ -281,7 +239,7 @@ private void InternalDisconnect() ChangeLinkStatus(LinkStatus.Inactive); } -#region Asynchronous Mode Methods + #region Asynchronous Mode Methods /// /// Adds a packet to the packet queue when asynchronous mode is enabled. @@ -561,8 +519,8 @@ private void RunReadLoop(Stream localReadPipe, Stream localWritePipe, while (!exitLoop); } -#endregion + #endregion -#endregion + #endregion } } From d4a7d4f9939f7009395f4779d9f0287fc608a905 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Thu, 13 Aug 2020 19:46:48 +0200 Subject: [PATCH 15/61] Node startup reworked --- .../net/Microsoft.Build.Tasks.Core.cs | 2 +- .../netstandard/Microsoft.Build.Tasks.Core.cs | 2 +- .../BackEnd/BuildManager/BuildManager.cs | 29 ++++++- .../Communications/NodeProviderOutOfProc.cs | 9 +- .../NodeProviderOutOfProcBase.cs | 15 ++-- .../Components/RequestBuilder/TaskHost.cs | 4 +- src/Build/BackEnd/Node/OutOfProcNode.cs | 6 ++ src/Build/BackEnd/Node/RarNode.cs | 5 +- src/Shared/NamedPipeUtil.cs | 1 - src/Shared/NodeEndpointOutOfProcBase.cs | 31 ++++--- .../ResolveAssemblyReference.cs | 5 +- .../Client/RarClient.cs | 12 ++- .../Server/RarController.cs | 83 +++++++++++++------ .../Server/ServerMutex.cs | 6 ++ .../Services/RarTaskHandler.cs | 1 - 15 files changed, 136 insertions(+), 75 deletions(-) diff --git a/ref/Microsoft.Build.Tasks.Core/net/Microsoft.Build.Tasks.Core.cs b/ref/Microsoft.Build.Tasks.Core/net/Microsoft.Build.Tasks.Core.cs index e333c727d44..546dc9c5c27 100644 --- a/ref/Microsoft.Build.Tasks.Core/net/Microsoft.Build.Tasks.Core.cs +++ b/ref/Microsoft.Build.Tasks.Core/net/Microsoft.Build.Tasks.Core.cs @@ -2555,7 +2555,7 @@ namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Server { public sealed partial class RarController { - public RarController(string pipeName) { } + public RarController(string pipeName, System.Nullable timeout=default(System.Nullable)) { } public System.Threading.Tasks.Task StartAsync(System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken)) { throw null; } } } diff --git a/ref/Microsoft.Build.Tasks.Core/netstandard/Microsoft.Build.Tasks.Core.cs b/ref/Microsoft.Build.Tasks.Core/netstandard/Microsoft.Build.Tasks.Core.cs index 249c6d819b3..c1210720e23 100644 --- a/ref/Microsoft.Build.Tasks.Core/netstandard/Microsoft.Build.Tasks.Core.cs +++ b/ref/Microsoft.Build.Tasks.Core/netstandard/Microsoft.Build.Tasks.Core.cs @@ -2177,7 +2177,7 @@ namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Server { public sealed partial class RarController { - public RarController(string pipeName) { } + public RarController(string pipeName, System.Nullable timeout=default(System.Nullable)) { } public System.Threading.Tasks.Task StartAsync(System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken)) { throw null; } } } diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index d1284ce38a0..346810fe371 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -2018,9 +2018,34 @@ private void PerformSchedulingActions(IEnumerable responses) } } - internal NodeInfo CreateRarNode() + internal int CreateRarNode() { - return null; + string nodeLocation = _buildParameters?.NodeExeLocation; + nodeLocation ??= OutOfProcNode.MsBuildPath; + if (string.IsNullOrEmpty(nodeLocation)) + { + string msbuildExeName = Environment.GetEnvironmentVariable("MSBUILD_EXE_NAME"); + + if (!string.IsNullOrEmpty(msbuildExeName)) + { + // we assume that MSBUILD_EXE_NAME is, in fact, just the name. + nodeLocation = Path.Combine(msbuildExeName, ".exe"); + } + } + + bool nodeReuse = _buildParameters?.EnableNodeReuse ?? true; + bool lowPriority = _buildParameters?.LowPriority ?? false; + string commandLineArgs = $"/nologo /nodemode:3 /nodeReuse:{nodeReuse.ToString().ToLower()} /low:{lowPriority.ToString().ToLower()}"; + try + { + int nodeId = NodeProviderOutOfProcBase.LaunchNode(nodeLocation, commandLineArgs); + return nodeId; + } + catch (Exception) + { + // Fail silently + return -1; + } } /// diff --git a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProc.cs b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProc.cs index 80bf29084f9..44a070ac3db 100644 --- a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProc.cs +++ b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProc.cs @@ -18,7 +18,7 @@ namespace Microsoft.Build.BackEnd internal class NodeProviderOutOfProc : NodeProviderOutOfProcBase, INodeProvider { /// - /// A mapping of all normal nodes managed by this provider. + /// A mapping of all the nodes managed by this provider. /// private Dictionary _nodeContexts; @@ -138,13 +138,6 @@ public void ShutdownConnectedNodes(bool enableReuse) } ShutdownConnectedNodes(contextsToShutDown, enableReuse); - - ShutdownAllNodes(enableReuse, ShutdownRarNode, onlySpecialNode: true); - } - - private void ShutdownRarNode(int nodeId) - { - // Do nothig } /// diff --git a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs index 96edf09a701..4efff7385f8 100644 --- a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs +++ b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs @@ -102,8 +102,7 @@ protected void ShutdownConnectedNodes(List contextsToShutDown, bool /// /// Whether to reuse the node /// Delegate used to tell the node provider that a context has terminated - /// Shutdown only special nodes (RAR node, ...) - protected void ShutdownAllNodes(bool nodeReuse, NodeContextTerminateDelegate terminateNode, bool onlySpecialNode = false) + protected void ShutdownAllNodes(bool nodeReuse, NodeContextTerminateDelegate terminateNode) { // INodePacketFactory INodePacketFactory factory = new NodePacketFactory(); @@ -122,15 +121,11 @@ protected void ShutdownAllNodes(bool nodeReuse, NodeContextTerminateDelegate ter // A 2013 comment suggested some nodes take this long to respond, so a smaller timeout would miss nodes. int timeout = 30; - Stream nodeStream = null; - if (!onlySpecialNode) - { - // Attempt to connect to the process with the handshake without low priority. - nodeStream = NamedPipeUtil.TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, enableLowPriority: false, specialNode: false)); + // Attempt to connect to the process with the handshake without low priority. + Stream nodeStream = NamedPipeUtil.TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, enableLowPriority: false, specialNode: false)); - // If we couldn't connect attempt to connect to the process with the handshake including low priority. - nodeStream ??= NamedPipeUtil.TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, enableLowPriority: true, specialNode: false)); - } + // If we couldn't connect attempt to connect to the process with the handshake including low priority. + nodeStream ??= NamedPipeUtil.TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, enableLowPriority: true, specialNode: false)); // Attempt to connect to the non-worker process // Attempt to connect to the process with the handshake without low priority. diff --git a/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs b/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs index de1817ef241..bc54fc6227c 100644 --- a/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs +++ b/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs @@ -991,8 +991,8 @@ private void VerifyActiveProxy() /// bool IRarBuildEngine.CreateRarNode() { - NodeInfo nodeInfo = BuildManager.DefaultBuildManager.CreateRarNode(); - return nodeInfo != null; + int nodeId = BuildManager.DefaultBuildManager.CreateRarNode(); + return nodeId != -1; } /// diff --git a/src/Build/BackEnd/Node/OutOfProcNode.cs b/src/Build/BackEnd/Node/OutOfProcNode.cs index 4d170a3853c..28b6bbabc77 100644 --- a/src/Build/BackEnd/Node/OutOfProcNode.cs +++ b/src/Build/BackEnd/Node/OutOfProcNode.cs @@ -133,6 +133,11 @@ public class OutOfProcNode : INode, IBuildComponentHost, INodePacketFactory, INo /// private readonly ISdkResolverService _sdkResolverService; + /// + /// Path to the MSBuild executable or dll. + /// + internal static string MsBuildPath { get; private set; } + /// /// Constructor. /// @@ -643,6 +648,7 @@ private void HandleNodeConfiguration(NodeConfiguration configuration) { // Grab the system parameters. _buildParameters = configuration.BuildParameters; + MsBuildPath = _buildParameters.NodeExeLocation; _buildParameters.ProjectRootElementCache = s_projectRootElementCacheBase; diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs index 33cf87d35be..d0cf3578eb0 100644 --- a/src/Build/BackEnd/Node/RarNode.cs +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -48,8 +48,8 @@ public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Except } else { - // RAR task can only exit with error - return NodeEngineShutdownReason.Error; + // RAR task can only exit with connection error or timeout + return NodeEngineShutdownReason.ConnectionFailed; } } @@ -69,6 +69,7 @@ private async Task RunShutdownCheckAsync(Handshake han return NodeEngineShutdownReason.Error; await serverStream.WaitForConnectionAsync(cancellationToken); + bool conected = NamedPipeUtil.ValidateHandshake(handshake, serverStream, ClientConnectTimeout); if (!conected) continue; diff --git a/src/Shared/NamedPipeUtil.cs b/src/Shared/NamedPipeUtil.cs index 4b6c39fc7d8..970d84c0346 100644 --- a/src/Shared/NamedPipeUtil.cs +++ b/src/Shared/NamedPipeUtil.cs @@ -62,7 +62,6 @@ private static void ValidateRemotePipeSecurityOnWindows(NamedPipeClientStream no internal static NamedPipeClientStream TryConnectToProcess(int nodeProcessId, int timeout, Handshake? handshake) { string pipeName = GetPipeNameOrPath("MSBuild" + nodeProcessId); - Console.WriteLine(handshake); return TryConnectToProcess(pipeName, nodeProcessId, timeout, handshake); } diff --git a/src/Shared/NodeEndpointOutOfProcBase.cs b/src/Shared/NodeEndpointOutOfProcBase.cs index 00890c400aa..1e920fbbe74 100644 --- a/src/Shared/NodeEndpointOutOfProcBase.cs +++ b/src/Shared/NodeEndpointOutOfProcBase.cs @@ -31,7 +31,6 @@ namespace Microsoft.Build.BackEnd internal abstract class NodeEndpointOutOfProcBase : INodeEndpoint { #region Private Data - /// /// The amount of time to wait for the client to connect to the host. /// @@ -98,18 +97,18 @@ internal abstract class NodeEndpointOutOfProcBase : INodeEndpoint /// private SharedReadBuffer _sharedReadBuffer; - #endregion +#endregion - #region INodeEndpoint Events +#region INodeEndpoint Events /// /// Raised when the link status has changed. /// public event LinkStatusChangedDelegate OnLinkStatusChanged; - #endregion +#endregion - #region INodeEndpoint Properties +#region INodeEndpoint Properties /// /// Returns the link status of this node. @@ -119,13 +118,13 @@ public LinkStatus LinkStatus get { return _status; } } - #endregion +#endregion - #region Properties +#region Properties - #endregion +#endregion - #region INodeEndpoint Methods +#region INodeEndpoint Methods /// /// Causes this endpoint to wait for the remote endpoint to connect @@ -170,9 +169,9 @@ public void SendData(INodePacket packet) } } - #endregion +#endregion - #region Construction +#region Construction /// /// Instantiates an endpoint to act as a client @@ -190,7 +189,7 @@ internal void InternalConstruct(string pipeName) _pipeServer = NamedPipeUtil.CreateNamedPipeServer(pipeName, PipeBufferSize, PipeBufferSize); } - #endregion +#endregion /// /// Returns the host handshake for this node endpoint @@ -218,7 +217,7 @@ private void RaiseLinkStatusChanged(LinkStatus newStatus) OnLinkStatusChanged?.Invoke(this, newStatus); } - #region Private Methods +#region Private Methods /// /// This does the actual work of changing the status and shutting down any threads we may have for @@ -239,7 +238,7 @@ private void InternalDisconnect() ChangeLinkStatus(LinkStatus.Inactive); } - #region Asynchronous Mode Methods +#region Asynchronous Mode Methods /// /// Adds a packet to the packet queue when asynchronous mode is enabled. @@ -519,8 +518,8 @@ private void RunReadLoop(Stream localReadPipe, Stream localWritePipe, while (!exitLoop); } - #endregion +#endregion - #endregion +#endregion } } diff --git a/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs b/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs index 18bf8a6b2fe..24f6493fc31 100644 --- a/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs +++ b/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs @@ -2988,7 +2988,7 @@ public override bool Execute() { if(client.CreateNode()) { - connected = client.Connect(); + connected = client.Connect(5000); } } @@ -2996,9 +2996,8 @@ public override bool Execute() { // Client is connected to the RAR node, we can execute RAR task remotely // return client.Execute(); // TODO: Let it do something. - // var number = client.GetNumber(42); + var number = client.GetNumber(42); } - } return Execute diff --git a/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs b/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs index 5c25cf823fd..44a334a13e1 100644 --- a/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs +++ b/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs @@ -7,6 +7,7 @@ using Microsoft.Build.Framework; using Microsoft.Build.Shared; using Microsoft.Build.Tasks.ResolveAssemblyReferences.Contract; +using Microsoft.Build.Tasks.ResolveAssemblyReferences.Server; using StreamJsonRpc; @@ -14,7 +15,7 @@ namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Client { internal sealed class RarClient : IDisposable { - private const int ConnectionTimeout = 30; + private const int ConnectionTimeout = 300; private readonly IRarBuildEngine _rarBuildEngine; private NamedPipeClientStream _clientStream; @@ -23,11 +24,15 @@ public RarClient(IRarBuildEngine rarBuildEngine) _rarBuildEngine = rarBuildEngine; } + internal bool Connect() => Connect(ConnectionTimeout); - internal bool Connect() + internal bool Connect(int timeout) { + if (_clientStream != null) + return true; + string pipeName = _rarBuildEngine.GetRarPipeName(); - NamedPipeClientStream stream = _rarBuildEngine.GetRarClientStream(pipeName, ConnectionTimeout); + NamedPipeClientStream stream = _rarBuildEngine.GetRarClientStream(pipeName, timeout); if (stream == null) return false; // We couldn't connect @@ -44,6 +49,7 @@ internal bool CreateNode() internal int GetNumber(int parameter) { using IResolveAssemblyReferenceTaskHandler client = GetRpcClient(); + // TODO: Find out if there is any possibility of awaiting it. return client.GetNumber(parameter).GetAwaiter().GetResult(); } diff --git a/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs b/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs index b23250ffca6..2028f4d8394 100644 --- a/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs +++ b/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs @@ -1,13 +1,14 @@ // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; using System.IO; using System.IO.Pipes; using System.Security.AccessControl; using System.Security.Principal; using System.Threading; using System.Threading.Tasks; - +using Microsoft.Build.Framework; using Microsoft.Build.Shared; using Microsoft.Build.Tasks.ResolveAssemblyReferences.Contract; using Microsoft.Build.Tasks.ResolveAssemblyReferences.Services; @@ -21,56 +22,87 @@ namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Server public sealed class RarController { private const int PipeBufferSize = 131072; - + + /// + /// Name of + /// private readonly string _pipeName; + /// + /// Handler for all incoming tasks + /// private readonly IResolveAssemblyReferenceTaskHandler _resolveAssemblyReferenceTaskHandler; - private NamedPipeServerStream? _serverStream; + /// + /// Timeout for incoming connections + /// + private readonly TimeSpan Timeout = new TimeSpan(0, 15, 0); - public RarController(string pipeName) : this(pipeName, new RarTaskHandler()) + public RarController(string pipeName, TimeSpan? timeout = null) : this(pipeName, timeout: timeout, resolveAssemblyReferenceTaskHandler: new RarTaskHandler()) { } - internal RarController(string pipeName, IResolveAssemblyReferenceTaskHandler resolveAssemblyReferenceTaskHandler) + internal RarController(string pipeName, IResolveAssemblyReferenceTaskHandler resolveAssemblyReferenceTaskHandler, TimeSpan? timeout = null) { _pipeName = pipeName; _resolveAssemblyReferenceTaskHandler = resolveAssemblyReferenceTaskHandler; + + if (timeout.HasValue) + { + Timeout = timeout.Value; + } } public async Task StartAsync(CancellationToken cancellationToken = default) { + using ServerMutex mutex = new ServerMutex(_pipeName); - using var mutex = new ServerMutex(_pipeName); - - if (mutex.IsLocked) + if (!mutex.IsLocked) + { return 1; + } + + using CancellationTokenSource cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + CancellationToken token = cancellationTokenSource.Token; while (true) { - if (cancellationToken.IsCancellationRequested) + if (token.IsCancellationRequested) break; - _serverStream = GetStream(_pipeName); - await _serverStream.WaitForConnectionAsync(cancellationToken).ConfigureAwait(false); - // TODO: This waits for completion of the connection, make to accept multiple connection - await HandleConnectionAsync(_serverStream, cancellationToken).ConfigureAwait(false); + // server will dispose stream too. + NamedPipeServerStream serverStream = GetStream(_pipeName); + await serverStream.WaitForConnectionAsync(cancellationToken).ConfigureAwait(false); + + // Connected! Refresh timeout for incoming request + cancellationTokenSource.CancelAfter(Timeout); + + _ = HandleClientAsync(serverStream, token).ConfigureAwait(false); } + return 0; } - private async Task HandleConnectionAsync(Stream serverStream, CancellationToken cancellationToken = default) + private async Task HandleClientAsync(Stream serverStream, CancellationToken cancellationToken = default) { - var server = GetRpcServer(serverStream, _resolveAssemblyReferenceTaskHandler); + using JsonRpc server = GetRpcServer(serverStream, _resolveAssemblyReferenceTaskHandler); server.StartListening(); - await server.Completion.WithCancellation(cancellationToken).ConfigureAwait(false); + try + { + await server.Completion.WithCancellation(cancellationToken).ConfigureAwait(false); + } + catch (ConnectionLostException) + { + // Some problem with connection, let's ignore it. + // All other exceptions are issue though + } } private JsonRpc GetRpcServer(Stream stream, IResolveAssemblyReferenceTaskHandler handler) { - var serverHandler = RpcUtils.GetRarMessageHandler(stream); - var rpc = new JsonRpc(serverHandler, handler); + IJsonRpcMessageHandler serverHandler = RpcUtils.GetRarMessageHandler(stream); + JsonRpc rpc = new JsonRpc(serverHandler, handler); return rpc; } @@ -84,15 +116,16 @@ private NamedPipeServerStream GetStream(string pipeName) #if FEATURE_PIPE_SECURITY && FEATURE_NAMED_PIPE_SECURITY_CONSTRUCTOR if (!NativeMethodsShared.IsMono) { - var identifier = WindowsIdentity.GetCurrent().Owner; - var security = new PipeSecurity(); + SecurityIdentifier identifier = WindowsIdentity.GetCurrent().Owner; + PipeSecurity security = new PipeSecurity(); // Restrict access to just this account. We set the owner specifically here, and on the // pipe client side they will check the owner against this one - they must have identical // SIDs or the client will reject this server. This is used to avoid attacks where a // hacked server creates a less restricted pipe in an attempt to lure us into using it and // then sending build requests to the real pipe client (which is the MSBuild Build Manager.) - var rule = new PipeAccessRule(identifier, PipeAccessRights.ReadWrite, AccessControlType.Allow); + // NOTE: There has to be PipeAccessRights.CreateNewInstance, without it we can't create new pipes + PipeAccessRule rule = new PipeAccessRule(identifier, PipeAccessRights.ReadWrite | PipeAccessRights.CreateNewInstance, AccessControlType.Allow); security.AddAccessRule(rule); security.SetOwner(identifier); @@ -100,9 +133,9 @@ private NamedPipeServerStream GetStream(string pipeName) ( pipeName, PipeDirection.InOut, - 1, // Only allow one connection at a time. + NamedPipeServerStream.MaxAllowedServerInstances, // Only allow one connection at a time. PipeTransmissionMode.Byte, - PipeOptions.Asynchronous | PipeOptions.WriteThrough, + PipeOptions.Asynchronous, PipeBufferSize, // Default input buffer PipeBufferSize, // Default output buffer security, @@ -116,9 +149,9 @@ private NamedPipeServerStream GetStream(string pipeName) ( pipeName, PipeDirection.InOut, - 1, // Only allow one connection at a time. + NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Byte, - PipeOptions.Asynchronous | PipeOptions.WriteThrough, + PipeOptions.Asynchronous, PipeBufferSize, // Default input buffer PipeBufferSize // Default output buffer ); diff --git a/src/Tasks/ResolveAssemblyReferences/Server/ServerMutex.cs b/src/Tasks/ResolveAssemblyReferences/Server/ServerMutex.cs index 7d314d89e30..081904175c3 100644 --- a/src/Tasks/ResolveAssemblyReferences/Server/ServerMutex.cs +++ b/src/Tasks/ResolveAssemblyReferences/Server/ServerMutex.cs @@ -18,6 +18,12 @@ public ServerMutex(string name) IsLocked = createdNew; } + public bool Wait(int timeout) + { + return _mutex.WaitOne(timeout); + } + + public void Dispose() { diff --git a/src/Tasks/ResolveAssemblyReferences/Services/RarTaskHandler.cs b/src/Tasks/ResolveAssemblyReferences/Services/RarTaskHandler.cs index 5e1854f9873..9c7134a586a 100644 --- a/src/Tasks/ResolveAssemblyReferences/Services/RarTaskHandler.cs +++ b/src/Tasks/ResolveAssemblyReferences/Services/RarTaskHandler.cs @@ -14,7 +14,6 @@ internal class RarTaskHandler : IResolveAssemblyReferenceTaskHandler public Task GetNumber(int parameter) { Console.WriteLine(parameter); - Console.WriteLine(); return Task.FromResult(parameter); } From 80a9364f6e9c3688cedfcaa59fe7c00448e2c3e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Fri, 14 Aug 2020 00:27:04 +0200 Subject: [PATCH 16/61] Small fixes --- src/Build/BackEnd/Node/RarNode.cs | 6 +++--- .../ResolveAssemblyReferences/Server/RarController.cs | 7 ++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs index d0cf3578eb0..9a041cb3818 100644 --- a/src/Build/BackEnd/Node/RarNode.cs +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -43,7 +43,7 @@ public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Except if(index == 0) { - // We know that this task is completed so we can accept + // We know that this task is completed so we can get Result without worring about waiting for it return _msBuildShutdown.Result; } else @@ -68,14 +68,14 @@ private async Task RunShutdownCheckAsync(Handshake han if (cancellationToken.IsCancellationRequested) return NodeEngineShutdownReason.Error; - await serverStream.WaitForConnectionAsync(cancellationToken); + await serverStream.WaitForConnectionAsync(cancellationToken).ConfigureAwait(false); bool conected = NamedPipeUtil.ValidateHandshake(handshake, serverStream, ClientConnectTimeout); if (!conected) continue; byte[] header = new byte[5]; - int bytesRead = await serverStream.ReadAsync(header, 0, header.Length); + int bytesRead = await serverStream.ReadAsync(header, 0, header.Length).ConfigureAwait(false); if (bytesRead != header.Length) { continue; diff --git a/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs b/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs index 2028f4d8394..9f69607ee55 100644 --- a/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs +++ b/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs @@ -65,14 +65,11 @@ public async Task StartAsync(CancellationToken cancellationToken = default) using CancellationTokenSource cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); CancellationToken token = cancellationTokenSource.Token; - while (true) + while (!token.IsCancellationRequested) { - if (token.IsCancellationRequested) - break; - // server will dispose stream too. NamedPipeServerStream serverStream = GetStream(_pipeName); - await serverStream.WaitForConnectionAsync(cancellationToken).ConfigureAwait(false); + await serverStream.WaitForConnectionAsync(token).ConfigureAwait(false); // Connected! Refresh timeout for incoming request cancellationTokenSource.CancelAfter(Timeout); From 95bd354fad0a95725b9ce3885366bd48c25b4b71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Fri, 14 Aug 2020 14:29:54 +0200 Subject: [PATCH 17/61] PR comments --- .../net/Microsoft.Build.Tasks.Core.cs | 2 +- .../netstandard/Microsoft.Build.Tasks.Core.cs | 2 +- .../BackEnd/BuildManager/BuildManager.cs | 9 +-- src/Build/BackEnd/Node/RarNode.cs | 19 ++--- src/Framework/IRarBuildEngine.cs | 2 +- src/Shared/NamedPipeUtil.cs | 11 ++- src/Shared/NodeEndpointOutOfProcBase.cs | 1 - .../ResolveAssemblyReference.cs | 2 +- .../Client/RarClient.cs | 9 ++- .../Server/RarController.cs | 74 ++++++------------- 10 files changed, 52 insertions(+), 79 deletions(-) diff --git a/ref/Microsoft.Build.Tasks.Core/net/Microsoft.Build.Tasks.Core.cs b/ref/Microsoft.Build.Tasks.Core/net/Microsoft.Build.Tasks.Core.cs index 546dc9c5c27..039a999c61e 100644 --- a/ref/Microsoft.Build.Tasks.Core/net/Microsoft.Build.Tasks.Core.cs +++ b/ref/Microsoft.Build.Tasks.Core/net/Microsoft.Build.Tasks.Core.cs @@ -2555,7 +2555,7 @@ namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Server { public sealed partial class RarController { - public RarController(string pipeName, System.Nullable timeout=default(System.Nullable)) { } + public RarController(string pipeName, System.Func, System.Nullable, int, bool, System.IO.Pipes.NamedPipeServerStream> namedPipeServerFactory, System.Nullable timeout=default(System.Nullable)) { } public System.Threading.Tasks.Task StartAsync(System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken)) { throw null; } } } diff --git a/ref/Microsoft.Build.Tasks.Core/netstandard/Microsoft.Build.Tasks.Core.cs b/ref/Microsoft.Build.Tasks.Core/netstandard/Microsoft.Build.Tasks.Core.cs index c1210720e23..e01019c8412 100644 --- a/ref/Microsoft.Build.Tasks.Core/netstandard/Microsoft.Build.Tasks.Core.cs +++ b/ref/Microsoft.Build.Tasks.Core/netstandard/Microsoft.Build.Tasks.Core.cs @@ -2177,7 +2177,7 @@ namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Server { public sealed partial class RarController { - public RarController(string pipeName, System.Nullable timeout=default(System.Nullable)) { } + public RarController(string pipeName, System.Func, System.Nullable, int, bool, System.IO.Pipes.NamedPipeServerStream> namedPipeServerFactory, System.Nullable timeout=default(System.Nullable)) { } public System.Threading.Tasks.Task StartAsync(System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken)) { throw null; } } } diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index 346810fe371..9c86be13e10 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -2024,13 +2024,8 @@ internal int CreateRarNode() nodeLocation ??= OutOfProcNode.MsBuildPath; if (string.IsNullOrEmpty(nodeLocation)) { - string msbuildExeName = Environment.GetEnvironmentVariable("MSBUILD_EXE_NAME"); - - if (!string.IsNullOrEmpty(msbuildExeName)) - { - // we assume that MSBUILD_EXE_NAME is, in fact, just the name. - nodeLocation = Path.Combine(msbuildExeName, ".exe"); - } + // Couldn't find any path + return -1; } bool nodeReuse = _buildParameters?.EnableNodeReuse ?? true; diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs index 9a041cb3818..971319e4378 100644 --- a/src/Build/BackEnd/Node/RarNode.cs +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -23,28 +23,25 @@ public sealed class RarNode : INode /// private const int ClientConnectTimeout = 60000; - private Task _rarTask; - private Task _msBuildShutdown; - public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Exception shutdownException) { shutdownException = null; using CancellationTokenSource cts = new CancellationTokenSource(); string pipeName = CommunicationsUtilities.GetRarPipeName(nodeReuse, lowPriority); - RarController controller = new RarController(pipeName); + RarController controller = new RarController(pipeName, NamedPipeUtil.CreateNamedPipeServer); - _rarTask = controller.StartAsync(cts.Token); + Task rarTask = controller.StartAsync(cts.Token); Handshake handshake = NodeProviderOutOfProc.GetHandshake(nodeReuse, enableLowPriority: lowPriority, specialNode: true); - _msBuildShutdown = RunShutdownCheckAsync(handshake, cts.Token); + Task msBuildShutdown = RunShutdownCheckAsync(handshake, cts.Token); - int index = Task.WaitAny(_msBuildShutdown, _rarTask); + int index = Task.WaitAny(msBuildShutdown, rarTask); cts.Cancel(); - if(index == 0) + if (index == 0) { // We know that this task is completed so we can get Result without worring about waiting for it - return _msBuildShutdown.Result; + return msBuildShutdown.Result; } else { @@ -70,8 +67,8 @@ private async Task RunShutdownCheckAsync(Handshake han await serverStream.WaitForConnectionAsync(cancellationToken).ConfigureAwait(false); - bool conected = NamedPipeUtil.ValidateHandshake(handshake, serverStream, ClientConnectTimeout); - if (!conected) + bool connected = NamedPipeUtil.ValidateHandshake(handshake, serverStream, ClientConnectTimeout); + if (!connected) continue; byte[] header = new byte[5]; diff --git a/src/Framework/IRarBuildEngine.cs b/src/Framework/IRarBuildEngine.cs index 003bfe3aee9..7eec5c61f7e 100644 --- a/src/Framework/IRarBuildEngine.cs +++ b/src/Framework/IRarBuildEngine.cs @@ -6,7 +6,7 @@ namespace Microsoft.Build.Framework { /// - /// This interface provides necessary functionality from to RAR as a service funcionality + /// This interface provides necessary funcionality from to RAR as a service funcionality /// internal interface IRarBuildEngine { diff --git a/src/Shared/NamedPipeUtil.cs b/src/Shared/NamedPipeUtil.cs index 970d84c0346..7c34332d541 100644 --- a/src/Shared/NamedPipeUtil.cs +++ b/src/Shared/NamedPipeUtil.cs @@ -229,7 +229,7 @@ internal static bool ValidateHandshake(Handshake handshake, NamedPipeServerStrea return true; } - internal static NamedPipeServerStream CreateNamedPipeServer(string pipeName, int? inputBufferSize = null, int? outputBufferSize = null, int maxNumberOfServerInstances = 1) + internal static NamedPipeServerStream CreateNamedPipeServer(string pipeName, int? inputBufferSize = null, int? outputBufferSize = null, int maxNumberOfServerInstances = 1, bool allowNewInstances = false) { inputBufferSize ??= PipeBufferSize; outputBufferSize ??= PipeBufferSize; @@ -245,7 +245,14 @@ internal static NamedPipeServerStream CreateNamedPipeServer(string pipeName, int // SIDs or the client will reject this server. This is used to avoid attacks where a // hacked server creates a less restricted pipe in an attempt to lure us into using it and // then sending build requests to the real pipe client (which is the MSBuild Build Manager.) - PipeAccessRule rule = new PipeAccessRule(identifier, PipeAccessRights.ReadWrite, AccessControlType.Allow); + + PipeAccessRights rights = PipeAccessRights.ReadWrite; + if (allowNewInstances) + { + rights |= PipeAccessRights.CreateNewInstance; + } + + PipeAccessRule rule = new PipeAccessRule(identifier, rights, AccessControlType.Allow); security.AddAccessRule(rule); security.SetOwner(identifier); diff --git a/src/Shared/NodeEndpointOutOfProcBase.cs b/src/Shared/NodeEndpointOutOfProcBase.cs index 1e920fbbe74..0b2c088cf98 100644 --- a/src/Shared/NodeEndpointOutOfProcBase.cs +++ b/src/Shared/NodeEndpointOutOfProcBase.cs @@ -328,7 +328,6 @@ private void PacketPumpProc() return; } - ChangeLinkStatus(LinkStatus.Active); } catch (Exception e) diff --git a/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs b/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs index 24f6493fc31..0215969bbbf 100644 --- a/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs +++ b/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs @@ -2986,7 +2986,7 @@ public override bool Execute() var connected = client.Connect(); if (!connected) { - if(client.CreateNode()) + if (client.CreateNode()) { connected = client.Connect(5000); } diff --git a/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs b/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs index 44a334a13e1..8762f47f91e 100644 --- a/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs +++ b/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs @@ -15,7 +15,10 @@ namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Client { internal sealed class RarClient : IDisposable { - private const int ConnectionTimeout = 300; + /// + /// Default connection timeout for connection to the pipe. Timeout is in millisecond. + /// + private const int DefaultConnectionTimeout = 300; private readonly IRarBuildEngine _rarBuildEngine; private NamedPipeClientStream _clientStream; @@ -24,7 +27,7 @@ public RarClient(IRarBuildEngine rarBuildEngine) _rarBuildEngine = rarBuildEngine; } - internal bool Connect() => Connect(ConnectionTimeout); + internal bool Connect() => Connect(DefaultConnectionTimeout); internal bool Connect(int timeout) { @@ -56,7 +59,7 @@ internal int GetNumber(int parameter) private IResolveAssemblyReferenceTaskHandler GetRpcClient() { - ErrorUtilities.VerifyThrowArgumentNull(_clientStream, nameof(_clientStream)); + ErrorUtilities.VerifyThrowInvalidOperation(_clientStream != null, nameof(_clientStream)); IJsonRpcMessageHandler handler = RpcUtils.GetRarMessageHandler(_clientStream); return JsonRpc.Attach(handler); diff --git a/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs b/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs index 9f69607ee55..ca4193b1859 100644 --- a/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs +++ b/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs @@ -4,12 +4,8 @@ using System; using System.IO; using System.IO.Pipes; -using System.Security.AccessControl; -using System.Security.Principal; using System.Threading; using System.Threading.Tasks; -using Microsoft.Build.Framework; -using Microsoft.Build.Shared; using Microsoft.Build.Tasks.ResolveAssemblyReferences.Contract; using Microsoft.Build.Tasks.ResolveAssemblyReferences.Services; using Microsoft.VisualStudio.Threading; @@ -28,6 +24,16 @@ public sealed class RarController /// private readonly string _pipeName; + /// + /// Factory callback to NamedPipeUtils.CreateNamedPipeServer + /// 1. arg: pipe name + /// 2. arg: input buffer size + /// 3. arg: input buffer size + /// 4. arg. number of allow clients + /// 5. arg. add right to CreateNewInstance + /// + private readonly Func _namedPipeServerFactory; + /// /// Handler for all incoming tasks /// @@ -36,15 +42,20 @@ public sealed class RarController /// /// Timeout for incoming connections /// - private readonly TimeSpan Timeout = new TimeSpan(0, 15, 0); + private readonly TimeSpan Timeout = TimeSpan.FromMinutes(15); - public RarController(string pipeName, TimeSpan? timeout = null) : this(pipeName, timeout: timeout, resolveAssemblyReferenceTaskHandler: new RarTaskHandler()) + public RarController( + string pipeName, + Func namedPipeServerFactory, + TimeSpan? timeout = null) + : this(pipeName, namedPipeServerFactory, timeout: timeout, resolveAssemblyReferenceTaskHandler: new RarTaskHandler()) { } - internal RarController(string pipeName, IResolveAssemblyReferenceTaskHandler resolveAssemblyReferenceTaskHandler, TimeSpan? timeout = null) + internal RarController(string pipeName, Func namedPipeServerFactory, IResolveAssemblyReferenceTaskHandler resolveAssemblyReferenceTaskHandler, TimeSpan? timeout = null) { _pipeName = pipeName; + _namedPipeServerFactory = namedPipeServerFactory; _resolveAssemblyReferenceTaskHandler = resolveAssemblyReferenceTaskHandler; if (timeout.HasValue) @@ -109,50 +120,11 @@ private JsonRpc GetRpcServer(Stream stream, IResolveAssemblyReferenceTaskHandler /// The name of the pipe to which we should connect. private NamedPipeServerStream GetStream(string pipeName) { - ErrorUtilities.VerifyThrowArgumentLength(pipeName, "pipeName"); -#if FEATURE_PIPE_SECURITY && FEATURE_NAMED_PIPE_SECURITY_CONSTRUCTOR - if (!NativeMethodsShared.IsMono) - { - SecurityIdentifier identifier = WindowsIdentity.GetCurrent().Owner; - PipeSecurity security = new PipeSecurity(); - - // Restrict access to just this account. We set the owner specifically here, and on the - // pipe client side they will check the owner against this one - they must have identical - // SIDs or the client will reject this server. This is used to avoid attacks where a - // hacked server creates a less restricted pipe in an attempt to lure us into using it and - // then sending build requests to the real pipe client (which is the MSBuild Build Manager.) - // NOTE: There has to be PipeAccessRights.CreateNewInstance, without it we can't create new pipes - PipeAccessRule rule = new PipeAccessRule(identifier, PipeAccessRights.ReadWrite | PipeAccessRights.CreateNewInstance, AccessControlType.Allow); - security.AddAccessRule(rule); - security.SetOwner(identifier); - - return new NamedPipeServerStream - ( - pipeName, - PipeDirection.InOut, - NamedPipeServerStream.MaxAllowedServerInstances, // Only allow one connection at a time. - PipeTransmissionMode.Byte, - PipeOptions.Asynchronous, - PipeBufferSize, // Default input buffer - PipeBufferSize, // Default output buffer - security, - HandleInheritability.None - ); - } - else -#endif - { - return new NamedPipeServerStream - ( - pipeName, - PipeDirection.InOut, - NamedPipeServerStream.MaxAllowedServerInstances, - PipeTransmissionMode.Byte, - PipeOptions.Asynchronous, - PipeBufferSize, // Default input buffer - PipeBufferSize // Default output buffer - ); - } + return _namedPipeServerFactory(pipeName, + PipeBufferSize, + PipeBufferSize, + NamedPipeServerStream.MaxAllowedServerInstances, + true); } } } From ef6555ec97a51abda36ff5d47960c40676214d30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Fri, 14 Aug 2020 16:47:15 +0200 Subject: [PATCH 18/61] PR Comments --- src/Build/BackEnd/Node/RarNode.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs index 971319e4378..92e1272217c 100644 --- a/src/Build/BackEnd/Node/RarNode.cs +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -58,13 +58,13 @@ public NodeEngineShutdownReason Run(out Exception shutdownException) private async Task RunShutdownCheckAsync(Handshake handshake, CancellationToken cancellationToken = default) { string pipeName = NamedPipeUtil.GetPipeNameOrPath("MSBuild" + Process.GetCurrentProcess().Id); - using NamedPipeServerStream serverStream = NamedPipeUtil.CreateNamedPipeServer(pipeName, maxNumberOfServerInstances: NamedPipeServerStream.MaxAllowedServerInstances); while (true) { if (cancellationToken.IsCancellationRequested) return NodeEngineShutdownReason.Error; + using NamedPipeServerStream serverStream = NamedPipeUtil.CreateNamedPipeServer(pipeName, maxNumberOfServerInstances: NamedPipeServerStream.MaxAllowedServerInstances); await serverStream.WaitForConnectionAsync(cancellationToken).ConfigureAwait(false); bool connected = NamedPipeUtil.ValidateHandshake(handshake, serverStream, ClientConnectTimeout); From 42d330aaace2f5c598c10d8aad3098b0d1aba110 Mon Sep 17 00:00:00 2001 From: Nathan Mytelka Date: Fri, 14 Aug 2020 08:34:50 -0700 Subject: [PATCH 19/61] extra commit --- src/Tasks/StateFileBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tasks/StateFileBase.cs b/src/Tasks/StateFileBase.cs index 3d17a4967a4..2745c801dbc 100644 --- a/src/Tasks/StateFileBase.cs +++ b/src/Tasks/StateFileBase.cs @@ -47,7 +47,7 @@ internal virtual void SerializeCache(string stateFile, TaskLoggingHelper log) formatter.Serialize(s, this); } } - } + } catch (Exception e) { // If there was a problem writing the file (like it's read-only or locked on disk, for From 59a5df0846ad4f8a8a0cbab20c7d60840b7d118e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Fri, 14 Aug 2020 19:07:13 +0200 Subject: [PATCH 20/61] Typo --- src/Framework/IRarBuildEngine.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Framework/IRarBuildEngine.cs b/src/Framework/IRarBuildEngine.cs index 7eec5c61f7e..b5178887550 100644 --- a/src/Framework/IRarBuildEngine.cs +++ b/src/Framework/IRarBuildEngine.cs @@ -6,7 +6,7 @@ namespace Microsoft.Build.Framework { /// - /// This interface provides necessary funcionality from to RAR as a service funcionality + /// This interface provides necessary functionality from to RAR as a service functionality. /// internal interface IRarBuildEngine { From fd54e2ea6a942bae87cc1e20f51f1c44569ebb65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Fri, 14 Aug 2020 19:10:48 +0200 Subject: [PATCH 21/61] Remove dummy method --- src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs | 1 - src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs | 7 ++++--- .../Contract/IResolveAssemblyReferenceTaskHandler.cs | 1 - .../ResolveAssemblyReferences/Services/RarTaskHandler.cs | 7 ------- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs b/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs index 0215969bbbf..6262b8086fe 100644 --- a/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs +++ b/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs @@ -2996,7 +2996,6 @@ public override bool Execute() { // Client is connected to the RAR node, we can execute RAR task remotely // return client.Execute(); // TODO: Let it do something. - var number = client.GetNumber(42); } } diff --git a/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs b/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs index 8762f47f91e..737bcf50496 100644 --- a/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs +++ b/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs @@ -49,12 +49,13 @@ internal bool CreateNode() return _rarBuildEngine.CreateRarNode(); } - internal int GetNumber(int parameter) + internal object Execute() { - using IResolveAssemblyReferenceTaskHandler client = GetRpcClient(); + throw new NotImplementedException(); + //using IResolveAssemblyReferenceTaskHandler client = GetRpcClient(); // TODO: Find out if there is any possibility of awaiting it. - return client.GetNumber(parameter).GetAwaiter().GetResult(); + //return client.GetNumber(parameter).GetAwaiter().GetResult(); } private IResolveAssemblyReferenceTaskHandler GetRpcClient() diff --git a/src/Tasks/ResolveAssemblyReferences/Contract/IResolveAssemblyReferenceTaskHandler.cs b/src/Tasks/ResolveAssemblyReferences/Contract/IResolveAssemblyReferenceTaskHandler.cs index 2a320469821..c8a74410837 100644 --- a/src/Tasks/ResolveAssemblyReferences/Contract/IResolveAssemblyReferenceTaskHandler.cs +++ b/src/Tasks/ResolveAssemblyReferences/Contract/IResolveAssemblyReferenceTaskHandler.cs @@ -8,6 +8,5 @@ namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Contract { public interface IResolveAssemblyReferenceTaskHandler : IDisposable { - Task GetNumber(int parameter); } } diff --git a/src/Tasks/ResolveAssemblyReferences/Services/RarTaskHandler.cs b/src/Tasks/ResolveAssemblyReferences/Services/RarTaskHandler.cs index 9c7134a586a..90e9ca795de 100644 --- a/src/Tasks/ResolveAssemblyReferences/Services/RarTaskHandler.cs +++ b/src/Tasks/ResolveAssemblyReferences/Services/RarTaskHandler.cs @@ -10,13 +10,6 @@ namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Services { internal class RarTaskHandler : IResolveAssemblyReferenceTaskHandler { - - public Task GetNumber(int parameter) - { - Console.WriteLine(parameter); - return Task.FromResult(parameter); - } - public void Dispose() { // For RPC dispose From 6e16aef23a6a86a8e25ead7587d572700b289008 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Fri, 14 Aug 2020 20:00:24 +0200 Subject: [PATCH 22/61] ref --- ref/Microsoft.Build.Tasks.Core/net/Microsoft.Build.Tasks.Core.cs | 1 - .../netstandard/Microsoft.Build.Tasks.Core.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/ref/Microsoft.Build.Tasks.Core/net/Microsoft.Build.Tasks.Core.cs b/ref/Microsoft.Build.Tasks.Core/net/Microsoft.Build.Tasks.Core.cs index 039a999c61e..344e0b9ef0e 100644 --- a/ref/Microsoft.Build.Tasks.Core/net/Microsoft.Build.Tasks.Core.cs +++ b/ref/Microsoft.Build.Tasks.Core/net/Microsoft.Build.Tasks.Core.cs @@ -2548,7 +2548,6 @@ namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Contract { public partial interface IResolveAssemblyReferenceTaskHandler : System.IDisposable { - System.Threading.Tasks.Task GetNumber(int parameter); } } namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Server diff --git a/ref/Microsoft.Build.Tasks.Core/netstandard/Microsoft.Build.Tasks.Core.cs b/ref/Microsoft.Build.Tasks.Core/netstandard/Microsoft.Build.Tasks.Core.cs index e01019c8412..e56a2127dd3 100644 --- a/ref/Microsoft.Build.Tasks.Core/netstandard/Microsoft.Build.Tasks.Core.cs +++ b/ref/Microsoft.Build.Tasks.Core/netstandard/Microsoft.Build.Tasks.Core.cs @@ -2170,7 +2170,6 @@ namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Contract { public partial interface IResolveAssemblyReferenceTaskHandler : System.IDisposable { - System.Threading.Tasks.Task GetNumber(int parameter); } } namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Server From a64202af9e47cf9d68b2d0f0e1cd81a1452e0495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Sat, 15 Aug 2020 09:02:51 +0200 Subject: [PATCH 23/61] Apply suggestions from code review Co-authored-by: Forgind --- src/Build/BackEnd/BuildManager/BuildManager.cs | 3 +-- src/Shared/CommunicationsUtilities.cs | 2 +- src/Shared/NamedPipeUtil.cs | 9 +-------- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index 9c86be13e10..01b17504d69 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -2020,8 +2020,7 @@ private void PerformSchedulingActions(IEnumerable responses) internal int CreateRarNode() { - string nodeLocation = _buildParameters?.NodeExeLocation; - nodeLocation ??= OutOfProcNode.MsBuildPath; + string nodeLocation = _buildParameters?.NodeExeLocation ?? OutOfProcNode.MsBuildPath; if (string.IsNullOrEmpty(nodeLocation)) { // Couldn't find any path diff --git a/src/Shared/CommunicationsUtilities.cs b/src/Shared/CommunicationsUtilities.cs index 3c0fe8b2a44..26da01129da 100644 --- a/src/Shared/CommunicationsUtilities.cs +++ b/src/Shared/CommunicationsUtilities.cs @@ -60,7 +60,7 @@ internal enum HandshakeOptions Administrator = 32, /// - /// Is special node. Special node can not accept normal build requests. + /// Is a special node. Special nodes cannot accept normal build requests. /// Special = 64 } diff --git a/src/Shared/NamedPipeUtil.cs b/src/Shared/NamedPipeUtil.cs index 7c34332d541..63879466a2d 100644 --- a/src/Shared/NamedPipeUtil.cs +++ b/src/Shared/NamedPipeUtil.cs @@ -80,14 +80,7 @@ private static NamedPipeClientStream TryConnectToProcess(string pipeName, int? n | PipeOptions.CurrentUserOnly #endif ); - if (nodeProcessId.HasValue) - { - CommunicationsUtilities.Trace("Attempting connect to PID {0} with pipe {1} with timeout {2} ms", nodeProcessId.Value, pipeName, timeout); - } - else - { - CommunicationsUtilities.Trace("Attempting connect to process {0} with pipe {1} with timeout {2} ms", pipeName, pipeName, timeout); - } + CommunicationsUtilities.Trace("Attempting connect to PID {0} with pipe {1} with timeout {2} ms", nodeProcessId.HasValue ? nodeProcessId.Value : pipeName, pipeName, timeout); try { From 3b980239d04f697b4ecf1ec546745b9b4e6bce11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Sat, 15 Aug 2020 09:08:23 +0200 Subject: [PATCH 24/61] Update src/Tasks/ResolveAssemblyReferences/RpcUtils.cs Co-authored-by: Forgind --- src/Tasks/ResolveAssemblyReferences/RpcUtils.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Tasks/ResolveAssemblyReferences/RpcUtils.cs b/src/Tasks/ResolveAssemblyReferences/RpcUtils.cs index 2d1d17d3af9..e8d2d17e995 100644 --- a/src/Tasks/ResolveAssemblyReferences/RpcUtils.cs +++ b/src/Tasks/ResolveAssemblyReferences/RpcUtils.cs @@ -13,8 +13,7 @@ internal static class RpcUtils { internal static IJsonRpcMessageHandler GetRarMessageHandler(Stream stream) { - var formatter = new MessagePackFormatter(); - return new LengthHeaderMessageHandler(stream.UsePipe(), formatter); + return new LengthHeaderMessageHandler(stream.UsePipe(), new MessagePackFormatter()); } } } From bf7472289ed742bbeeeaa451ed8f593161de12d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Sat, 15 Aug 2020 09:30:48 +0200 Subject: [PATCH 25/61] PR Comments --- src/Build/BackEnd/BuildManager/BuildManager.cs | 2 +- src/Build/BackEnd/Node/RarNode.cs | 3 ++- src/Shared/NamedPipeUtil.cs | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index 01b17504d69..9223ab23002 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -2023,7 +2023,7 @@ internal int CreateRarNode() string nodeLocation = _buildParameters?.NodeExeLocation ?? OutOfProcNode.MsBuildPath; if (string.IsNullOrEmpty(nodeLocation)) { - // Couldn't find any path + // Couldn't find any path to MsBuild, not creating new node. return -1; } diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs index 92e1272217c..aacb2e432e3 100644 --- a/src/Build/BackEnd/Node/RarNode.cs +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -32,7 +32,8 @@ public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Except Task rarTask = controller.StartAsync(cts.Token); - Handshake handshake = NodeProviderOutOfProc.GetHandshake(nodeReuse, enableLowPriority: lowPriority, specialNode: true); + Handshake handshake = NodeProviderOutOfProc.GetHandshake(enableNodeReuse: nodeReuse, + enableLowPriority: lowPriority, specialNode: true); Task msBuildShutdown = RunShutdownCheckAsync(handshake, cts.Token); int index = Task.WaitAny(msBuildShutdown, rarTask); diff --git a/src/Shared/NamedPipeUtil.cs b/src/Shared/NamedPipeUtil.cs index 63879466a2d..c6765e5bd76 100644 --- a/src/Shared/NamedPipeUtil.cs +++ b/src/Shared/NamedPipeUtil.cs @@ -80,7 +80,7 @@ private static NamedPipeClientStream TryConnectToProcess(string pipeName, int? n | PipeOptions.CurrentUserOnly #endif ); - CommunicationsUtilities.Trace("Attempting connect to PID {0} with pipe {1} with timeout {2} ms", nodeProcessId.HasValue ? nodeProcessId.Value : pipeName, pipeName, timeout); + CommunicationsUtilities.Trace("Attempting connect to PID {0} with pipe {1} with timeout {2} ms", nodeProcessId.HasValue ? nodeProcessId.Value.ToString() : pipeName, pipeName, timeout); try { From dfdd2d35175d56a3a2cafb7dc3181d7fbf6e26b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Mon, 17 Aug 2020 09:56:16 +0200 Subject: [PATCH 26/61] PR Comments --- src/Build/BackEnd/Node/RarNode.cs | 13 +++++++++---- .../Server/RarController.cs | 6 ++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs index aacb2e432e3..236c19b0f87 100644 --- a/src/Build/BackEnd/Node/RarNode.cs +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -72,6 +72,9 @@ private async Task RunShutdownCheckAsync(Handshake han if (!connected) continue; + // Header consits of: + // 1 byte - Packet type + // 4 bytes - packet length byte[] header = new byte[5]; int bytesRead = await serverStream.ReadAsync(header, 0, header.Length).ConfigureAwait(false); if (bytesRead != header.Length) @@ -83,12 +86,14 @@ private async Task RunShutdownCheckAsync(Handshake han // Packet type sent by Shutdown if (packetType == NodePacketType.NodeBuildComplete) { - // Finish this task - break; + // Body of NodeBuildComplete contains only one boolean (= 1 byte) + byte[] packetBody = new byte[sizeof(bool)]; + await serverStream.ReadAsync(packetBody, 0, packetBody.Length, cancellationToken).ConfigureAwait(false); + bool nodeReuse = Convert.ToBoolean(packetBody[0]); + + return nodeReuse ? NodeEngineShutdownReason.BuildCompleteReuse : NodeEngineShutdownReason.BuildComplete; } } - - return NodeEngineShutdownReason.BuildComplete; } } } diff --git a/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs b/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs index ca4193b1859..0e0ee9081e1 100644 --- a/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs +++ b/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs @@ -17,8 +17,6 @@ namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Server { public sealed class RarController { - private const int PipeBufferSize = 131072; - /// /// Name of /// @@ -121,8 +119,8 @@ private JsonRpc GetRpcServer(Stream stream, IResolveAssemblyReferenceTaskHandler private NamedPipeServerStream GetStream(string pipeName) { return _namedPipeServerFactory(pipeName, - PipeBufferSize, - PipeBufferSize, + null, // Use default size + null, // Use default size NamedPipeServerStream.MaxAllowedServerInstances, true); } From 1836057f26ecdf10f27f551779cbda72310f5450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Tue, 18 Aug 2020 09:47:45 +0200 Subject: [PATCH 27/61] Version change --- eng/Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Packages.props b/eng/Packages.props index eb7aee9b051..4211da2cb73 100644 --- a/eng/Packages.props +++ b/eng/Packages.props @@ -52,7 +52,7 @@ - + From 55ad2b3108246d9e1181a6f8304efc61c2b1f664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Thu, 20 Aug 2020 10:29:50 +0200 Subject: [PATCH 28/61] Missing dlls fix --- .../MSBuild.Engine.Corext/MsBuild.Engine.Corext.nuspec | 8 ++++++++ src/Package/MSBuild.VSSetup/files.swr | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/src/Package/MSBuild.Engine.Corext/MsBuild.Engine.Corext.nuspec b/src/Package/MSBuild.Engine.Corext/MsBuild.Engine.Corext.nuspec index f2132af28e6..3539d5f540d 100644 --- a/src/Package/MSBuild.Engine.Corext/MsBuild.Engine.Corext.nuspec +++ b/src/Package/MSBuild.Engine.Corext/MsBuild.Engine.Corext.nuspec @@ -40,6 +40,10 @@ + + + + @@ -94,6 +98,10 @@ + + + + diff --git a/src/Package/MSBuild.VSSetup/files.swr b/src/Package/MSBuild.VSSetup/files.swr index 44277b783c7..74b440353ff 100644 --- a/src/Package/MSBuild.VSSetup/files.swr +++ b/src/Package/MSBuild.VSSetup/files.swr @@ -48,6 +48,10 @@ folder InstallDir:\MSBuild\Current\Bin file source=$(X86BinPath)System.Runtime.CompilerServices.Unsafe.dll vs.file.ngenArchitecture=all file source=$(X86BinPath)System.Threading.Tasks.Dataflow.dll vs.file.ngenArchitecture=all vs.file.ngenPriority=1 file source=$(X86BinPath)System.Collections.Immutable.dll vs.file.ngenArchitecture=all vs.file.ngenPriority=1 + file source=$(X86BinPath)StreamJsonRpc.dll vs.file.ngenArchitecture=all vs.file.ngenPriority=1 + file source=$(X86BinPath)Nerdbank.Streams.dll vs.file.ngenArchitecture=all + file source=$(X86BinPath)System.IO.Pipelines.dll vs.file.ngenArchitecture=all + file source=$(X86BinPath)Microsoft.VisualStudio.Threading.dll vs.file.ngenArchitecture=all file source=$(X86BinPath)Microsoft.Common.CurrentVersion.targets file source=$(X86BinPath)Microsoft.Common.CrossTargeting.targets file source=$(X86BinPath)Microsoft.Common.overridetasks @@ -197,6 +201,10 @@ folder InstallDir:\MSBuild\Current\Bin\amd64 file source=$(X86BinPath)System.Runtime.CompilerServices.Unsafe.dll vs.file.ngenArchitecture=all file source=$(X86BinPath)System.Threading.Tasks.Dataflow.dll vs.file.ngenArchitecture=all file source=$(X86BinPath)System.Collections.Immutable.dll vs.file.ngenArchitecture=all + file source=$(X86BinPath)StreamJsonRpc.dll vs.file.ngenArchitecture=all vs.file.ngenPriority=1 + file source=$(X86BinPath)Nerdbank.Streams.dll vs.file.ngenArchitecture=all + file source=$(X86BinPath)System.IO.Pipelines.dll vs.file.ngenArchitecture=all + file source=$(X86BinPath)Microsoft.VisualStudio.Threading.dll vs.file.ngenArchitecture=all file source=$(X86BinPath)Microsoft.Common.CurrentVersion.targets file source=$(X86BinPath)Microsoft.Common.CrossTargeting.targets file source=$(X86BinPath)Microsoft.Common.overridetasks From 8640658b20f8c988642777c07b7d884a157bc1c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Thu, 20 Aug 2020 11:00:50 +0200 Subject: [PATCH 29/61] FIX typo --- .../MSBuild.Engine.Corext/MsBuild.Engine.Corext.nuspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Package/MSBuild.Engine.Corext/MsBuild.Engine.Corext.nuspec b/src/Package/MSBuild.Engine.Corext/MsBuild.Engine.Corext.nuspec index 3539d5f540d..8eccc0b1a37 100644 --- a/src/Package/MSBuild.Engine.Corext/MsBuild.Engine.Corext.nuspec +++ b/src/Package/MSBuild.Engine.Corext/MsBuild.Engine.Corext.nuspec @@ -40,7 +40,7 @@ - + @@ -98,7 +98,7 @@ - + From d15f6bf1252fd1c04d472f73385e5761e28e2785 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Thu, 20 Aug 2020 11:27:42 +0200 Subject: [PATCH 30/61] Signing --- eng/Signing.props | 1 + 1 file changed, 1 insertion(+) diff --git a/eng/Signing.props b/eng/Signing.props index 83946d7c6e5..b0a307f5e5a 100644 --- a/eng/Signing.props +++ b/eng/Signing.props @@ -1,5 +1,6 @@ + \ No newline at end of file From 3dbeee1c428629b7d9d3f49836a032fa8d344d7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Thu, 20 Aug 2020 12:17:59 +0200 Subject: [PATCH 31/61] Triger commit From c325a1fe4fe076e70f49ab5d647fdf38b59c30a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Thu, 20 Aug 2020 12:31:28 +0200 Subject: [PATCH 32/61] extra commit --- eng/Signing.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Signing.props b/eng/Signing.props index b0a307f5e5a..0d653ff7b88 100644 --- a/eng/Signing.props +++ b/eng/Signing.props @@ -1,6 +1,6 @@ - + \ No newline at end of file From a0c2fc87248d736c21ea2bb2c25f06aac3a3cf56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Fri, 21 Aug 2020 12:42:13 +0200 Subject: [PATCH 33/61] GetRarPipeName fix --- src/Shared/CommunicationsUtilities.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Shared/CommunicationsUtilities.cs b/src/Shared/CommunicationsUtilities.cs index 26da01129da..a2a4dafbf2e 100644 --- a/src/Shared/CommunicationsUtilities.cs +++ b/src/Shared/CommunicationsUtilities.cs @@ -657,7 +657,7 @@ internal static int AvoidEndOfHandshakeSignal(int x) internal static string GetRarPipeName(bool nodeReuse, bool lowPriority) { - var context = GetHandshakeOptions(true); + var context = GetHandshakeOptions(taskHost: true, nodeReuse: nodeReuse, lowPriority: lowPriority, specialNode: true); var userName = $"{Environment.UserDomainName}.{Environment.UserName}"; return $"MSBuild.RAR.{userName}.{(int)context}"; } From 0abc9cc3881c67574212cff905b99ea7b6da8e0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Fri, 21 Aug 2020 13:33:51 +0200 Subject: [PATCH 34/61] Fixes from exp branch --- eng/Packages.props | 2 +- eng/Signing.props | 1 + .../MSBuild.Engine.Corext/MsBuild.Engine.Corext.nuspec | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/eng/Packages.props b/eng/Packages.props index eb7aee9b051..4211da2cb73 100644 --- a/eng/Packages.props +++ b/eng/Packages.props @@ -52,7 +52,7 @@ - + diff --git a/eng/Signing.props b/eng/Signing.props index 83946d7c6e5..0d653ff7b88 100644 --- a/eng/Signing.props +++ b/eng/Signing.props @@ -1,5 +1,6 @@ + \ No newline at end of file diff --git a/src/Package/MSBuild.Engine.Corext/MsBuild.Engine.Corext.nuspec b/src/Package/MSBuild.Engine.Corext/MsBuild.Engine.Corext.nuspec index 3539d5f540d..8eccc0b1a37 100644 --- a/src/Package/MSBuild.Engine.Corext/MsBuild.Engine.Corext.nuspec +++ b/src/Package/MSBuild.Engine.Corext/MsBuild.Engine.Corext.nuspec @@ -40,7 +40,7 @@ - + @@ -98,7 +98,7 @@ - + From 7c9379d21f11983248a83f0a66b76b04621ef31d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Fri, 21 Aug 2020 17:22:18 +0200 Subject: [PATCH 35/61] Missing files --- .../MSBuild.Engine.Corext/MsBuild.Engine.Corext.nuspec | 6 ++++++ src/Package/MSBuild.VSSetup/files.swr | 8 +++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Package/MSBuild.Engine.Corext/MsBuild.Engine.Corext.nuspec b/src/Package/MSBuild.Engine.Corext/MsBuild.Engine.Corext.nuspec index 8eccc0b1a37..6e3cd15181e 100644 --- a/src/Package/MSBuild.Engine.Corext/MsBuild.Engine.Corext.nuspec +++ b/src/Package/MSBuild.Engine.Corext/MsBuild.Engine.Corext.nuspec @@ -44,6 +44,9 @@ + + + @@ -102,6 +105,9 @@ + + + diff --git a/src/Package/MSBuild.VSSetup/files.swr b/src/Package/MSBuild.VSSetup/files.swr index 74b440353ff..87577196771 100644 --- a/src/Package/MSBuild.VSSetup/files.swr +++ b/src/Package/MSBuild.VSSetup/files.swr @@ -48,10 +48,13 @@ folder InstallDir:\MSBuild\Current\Bin file source=$(X86BinPath)System.Runtime.CompilerServices.Unsafe.dll vs.file.ngenArchitecture=all file source=$(X86BinPath)System.Threading.Tasks.Dataflow.dll vs.file.ngenArchitecture=all vs.file.ngenPriority=1 file source=$(X86BinPath)System.Collections.Immutable.dll vs.file.ngenArchitecture=all vs.file.ngenPriority=1 - file source=$(X86BinPath)StreamJsonRpc.dll vs.file.ngenArchitecture=all vs.file.ngenPriority=1 + file source=$(X86BinPath)StreamJsonRpc.dll vs.file.ngenArchitecture=all file source=$(X86BinPath)Nerdbank.Streams.dll vs.file.ngenArchitecture=all file source=$(X86BinPath)System.IO.Pipelines.dll vs.file.ngenArchitecture=all file source=$(X86BinPath)Microsoft.VisualStudio.Threading.dll vs.file.ngenArchitecture=all + file source=$(X86BinPath)Microsoft.VisualStudio.Validation.dll vs.file.ngenArchitecture=all + file source=$(X86BinPath)MessagePack.dll vs.file.ngenArchitecture=all + file source=$(X86BinPath)MessagePack.Annotations.dll vs.file.ngenArchitecture=all file source=$(X86BinPath)Microsoft.Common.CurrentVersion.targets file source=$(X86BinPath)Microsoft.Common.CrossTargeting.targets file source=$(X86BinPath)Microsoft.Common.overridetasks @@ -205,6 +208,9 @@ folder InstallDir:\MSBuild\Current\Bin\amd64 file source=$(X86BinPath)Nerdbank.Streams.dll vs.file.ngenArchitecture=all file source=$(X86BinPath)System.IO.Pipelines.dll vs.file.ngenArchitecture=all file source=$(X86BinPath)Microsoft.VisualStudio.Threading.dll vs.file.ngenArchitecture=all + file source=$(X86BinPath)Microsoft.VisualStudio.Validation.dll vs.file.ngenArchitecture=all + file source=$(X86BinPath)MessagePack.dll vs.file.ngenArchitecture=all + file source=$(X86BinPath)MessagePack.Annotations.dll vs.file.ngenArchitecture=all file source=$(X86BinPath)Microsoft.Common.CurrentVersion.targets file source=$(X86BinPath)Microsoft.Common.CrossTargeting.targets file source=$(X86BinPath)Microsoft.Common.overridetasks From d48a5a9e9796bf43d797d26bc77eebe573f13173 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Sat, 22 Aug 2020 11:30:42 +0200 Subject: [PATCH 36/61] MessagePack signing --- eng/Signing.props | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eng/Signing.props b/eng/Signing.props index 0d653ff7b88..13912cb79a5 100644 --- a/eng/Signing.props +++ b/eng/Signing.props @@ -1,6 +1,8 @@ + + \ No newline at end of file From bf9abf8fe8194e1e0b93e656536112ce26c1a891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Sat, 22 Aug 2020 16:32:59 +0200 Subject: [PATCH 37/61] Ngen priority --- src/Package/MSBuild.VSSetup/files.swr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Package/MSBuild.VSSetup/files.swr b/src/Package/MSBuild.VSSetup/files.swr index 87577196771..d813b8deb3d 100644 --- a/src/Package/MSBuild.VSSetup/files.swr +++ b/src/Package/MSBuild.VSSetup/files.swr @@ -204,7 +204,7 @@ folder InstallDir:\MSBuild\Current\Bin\amd64 file source=$(X86BinPath)System.Runtime.CompilerServices.Unsafe.dll vs.file.ngenArchitecture=all file source=$(X86BinPath)System.Threading.Tasks.Dataflow.dll vs.file.ngenArchitecture=all file source=$(X86BinPath)System.Collections.Immutable.dll vs.file.ngenArchitecture=all - file source=$(X86BinPath)StreamJsonRpc.dll vs.file.ngenArchitecture=all vs.file.ngenPriority=1 + file source=$(X86BinPath)StreamJsonRpc.dll vs.file.ngenArchitecture=all file source=$(X86BinPath)Nerdbank.Streams.dll vs.file.ngenArchitecture=all file source=$(X86BinPath)System.IO.Pipelines.dll vs.file.ngenArchitecture=all file source=$(X86BinPath)Microsoft.VisualStudio.Threading.dll vs.file.ngenArchitecture=all From 28228ccaba0ab2e295440defcb56af9f48ec7e9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Mon, 24 Aug 2020 15:25:12 +0200 Subject: [PATCH 38/61] Remove Newtonsoft.Json dll --- eng/Packages.props | 1 + src/Tasks/Microsoft.Build.Tasks.csproj | 1 + 2 files changed, 2 insertions(+) diff --git a/eng/Packages.props b/eng/Packages.props index 4211da2cb73..727964ed0b9 100644 --- a/eng/Packages.props +++ b/eng/Packages.props @@ -53,6 +53,7 @@ + diff --git a/src/Tasks/Microsoft.Build.Tasks.csproj b/src/Tasks/Microsoft.Build.Tasks.csproj index b0c0e8bfaed..9229fa0331c 100644 --- a/src/Tasks/Microsoft.Build.Tasks.csproj +++ b/src/Tasks/Microsoft.Build.Tasks.csproj @@ -989,6 +989,7 @@ + From af35387576674ad9ba2274257b7164436e9e9980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Mon, 24 Aug 2020 20:37:40 +0200 Subject: [PATCH 39/61] Remove binding redirect --- src/MSBuild/app.amd64.config | 6 +----- src/MSBuild/app.config | 5 ----- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/MSBuild/app.amd64.config b/src/MSBuild/app.amd64.config index c66af314664..0952c676d80 100644 --- a/src/MSBuild/app.amd64.config +++ b/src/MSBuild/app.amd64.config @@ -61,11 +61,7 @@ - - - - - + diff --git a/src/MSBuild/app.config b/src/MSBuild/app.config index b109b8abef5..07b6a964c1c 100644 --- a/src/MSBuild/app.config +++ b/src/MSBuild/app.config @@ -40,11 +40,6 @@ - - - - - From 192e0a2ad2f43189a8dfe2c9dffe87986d4d79ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Wed, 26 Aug 2020 19:02:45 +0200 Subject: [PATCH 40/61] Remove Tasks.Core dependency --- .../net/Microsoft.Build.Tasks.Core.cs | 14 ----------- .../netstandard/Microsoft.Build.Tasks.Core.cs | 14 ----------- .../NodeProviderOutOfProcBase.cs | 3 +-- .../MainNodeSdkResolverService.cs | 1 - src/Build/BackEnd/Node/RarNode.cs | 21 +++++++++++++--- .../TaskExecutionHost/TaskExecutionHost.cs | 2 +- src/Build/Microsoft.Build.csproj | 1 - src/Framework/IRarController.cs | 20 +++++++++++++++ .../IResolveAssemblyReferenceTaskHandler.cs | 2 +- .../Server/RarController.cs | 25 +++++++++++++------ 10 files changed, 58 insertions(+), 45 deletions(-) create mode 100644 src/Framework/IRarController.cs diff --git a/ref/Microsoft.Build.Tasks.Core/net/Microsoft.Build.Tasks.Core.cs b/ref/Microsoft.Build.Tasks.Core/net/Microsoft.Build.Tasks.Core.cs index 344e0b9ef0e..4acd75a5f5f 100644 --- a/ref/Microsoft.Build.Tasks.Core/net/Microsoft.Build.Tasks.Core.cs +++ b/ref/Microsoft.Build.Tasks.Core/net/Microsoft.Build.Tasks.Core.cs @@ -2544,20 +2544,6 @@ public partial interface IVbcHostObjectFreeThreaded bool Compile(); } } -namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Contract -{ - public partial interface IResolveAssemblyReferenceTaskHandler : System.IDisposable - { - } -} -namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Server -{ - public sealed partial class RarController - { - public RarController(string pipeName, System.Func, System.Nullable, int, bool, System.IO.Pipes.NamedPipeServerStream> namedPipeServerFactory, System.Nullable timeout=default(System.Nullable)) { } - public System.Threading.Tasks.Task StartAsync(System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken)) { throw null; } - } -} namespace Microsoft.Build.Tasks.Xaml { public partial class CommandLineArgumentRelation : Microsoft.Build.Tasks.Xaml.PropertyRelation diff --git a/ref/Microsoft.Build.Tasks.Core/netstandard/Microsoft.Build.Tasks.Core.cs b/ref/Microsoft.Build.Tasks.Core/netstandard/Microsoft.Build.Tasks.Core.cs index e56a2127dd3..af96c3bbc19 100644 --- a/ref/Microsoft.Build.Tasks.Core/netstandard/Microsoft.Build.Tasks.Core.cs +++ b/ref/Microsoft.Build.Tasks.Core/netstandard/Microsoft.Build.Tasks.Core.cs @@ -2166,20 +2166,6 @@ public partial interface IVbcHostObjectFreeThreaded bool Compile(); } } -namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Contract -{ - public partial interface IResolveAssemblyReferenceTaskHandler : System.IDisposable - { - } -} -namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Server -{ - public sealed partial class RarController - { - public RarController(string pipeName, System.Func, System.Nullable, int, bool, System.IO.Pipes.NamedPipeServerStream> namedPipeServerFactory, System.Nullable timeout=default(System.Nullable)) { } - public System.Threading.Tasks.Task StartAsync(System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken)) { throw null; } - } -} namespace System.Deployment.Internal.CodeSigning { public sealed partial class RSAPKCS1SHA256SignatureDescription : System.Security.Cryptography.SignatureDescription diff --git a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs index 4efff7385f8..8a681683154 100644 --- a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs +++ b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs @@ -11,7 +11,6 @@ using System.Threading.Tasks; using System.Runtime.InteropServices; using System.Security.Principal; -using Task = System.Threading.Tasks.Task; using Microsoft.Build.Eventing; using Microsoft.Build.Exceptions; @@ -225,7 +224,7 @@ protected NodeContext GetNode(string msbuildLocation, string commandLineArgs, in string taskHostNameForClr2TaskHost = Path.GetFileNameWithoutExtension(NodeProviderOutOfProcTaskHost.TaskHostNameForClr2TaskHost); if (Path.GetFileNameWithoutExtension(msbuildLocation).Equals(taskHostNameForClr2TaskHost, StringComparison.OrdinalIgnoreCase)) { - if (FrameworkLocationHelper.GetPathToDotNetFrameworkV35(Shared.DotNetFrameworkArchitecture.Current) == null) + if (FrameworkLocationHelper.GetPathToDotNetFrameworkV35(DotNetFrameworkArchitecture.Current) == null) { CommunicationsUtilities.Trace ( diff --git a/src/Build/BackEnd/Components/SdkResolution/MainNodeSdkResolverService.cs b/src/Build/BackEnd/Components/SdkResolution/MainNodeSdkResolverService.cs index 5310cfc916c..0c52dddff33 100644 --- a/src/Build/BackEnd/Components/SdkResolution/MainNodeSdkResolverService.cs +++ b/src/Build/BackEnd/Components/SdkResolution/MainNodeSdkResolverService.cs @@ -13,7 +13,6 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Task = System.Threading.Tasks.Task; namespace Microsoft.Build.BackEnd.SdkResolution { diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs index 236c19b0f87..a95ed365e66 100644 --- a/src/Build/BackEnd/Node/RarNode.cs +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -4,7 +4,7 @@ using System; using System.Diagnostics; using System.IO.Pipes; -using System.Linq; +using System.Reflection; using System.Threading; using System.Threading.Tasks; @@ -12,7 +12,6 @@ using Microsoft.Build.Framework; using Microsoft.Build.Internal; using Microsoft.Build.Shared; -using Microsoft.Build.Tasks.ResolveAssemblyReferences.Server; namespace Microsoft.Build.Execution { @@ -28,7 +27,7 @@ public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Except shutdownException = null; using CancellationTokenSource cts = new CancellationTokenSource(); string pipeName = CommunicationsUtilities.GetRarPipeName(nodeReuse, lowPriority); - RarController controller = new RarController(pipeName, NamedPipeUtil.CreateNamedPipeServer); + IRarController controller = GetController(pipeName); Task rarTask = controller.StartAsync(cts.Token); @@ -36,6 +35,9 @@ public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Except enableLowPriority: lowPriority, specialNode: true); Task msBuildShutdown = RunShutdownCheckAsync(handshake, cts.Token); + // Wait for any of these task to finish: + // - rarTask can timeout (default is 15 mins) + // - msBuildShutdown ends when it recieves command to shutdown int index = Task.WaitAny(msBuildShutdown, rarTask); cts.Cancel(); @@ -51,6 +53,19 @@ public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Except } } + private static IRarController GetController(string pipeName) + { + const string rarControllerName = "Microsoft.Build.Tasks.ResolveAssemblyReferences.Server.RarController, Microsoft.Build.Tasks.Core"; + Type rarControllerType = Type.GetType(rarControllerName); + + IRarController controller = (IRarController)Activator.CreateInstance(rarControllerType, pipeName); + ErrorUtilities.VerifyThrow(controller == null, "Couldn't create instace of IRarController for '{0}' type", rarControllerName); + + controller.SetStreamFactory(NamedPipeUtil.CreateNamedPipeServer); + return controller; + } + + public NodeEngineShutdownReason Run(out Exception shutdownException) { return Run(false, false, out shutdownException); diff --git a/src/Build/BackEnd/TaskExecutionHost/TaskExecutionHost.cs b/src/Build/BackEnd/TaskExecutionHost/TaskExecutionHost.cs index 26759da6f92..2a98b2fdf32 100644 --- a/src/Build/BackEnd/TaskExecutionHost/TaskExecutionHost.cs +++ b/src/Build/BackEnd/TaskExecutionHost/TaskExecutionHost.cs @@ -13,7 +13,6 @@ using System.Text; using System.Threading; using System.Threading.Tasks; -using Task = System.Threading.Tasks.Task; using Microsoft.Build.BackEnd.Logging; using Microsoft.Build.Construction; @@ -23,6 +22,7 @@ using Microsoft.Build.Framework; using Microsoft.Build.Shared; using Microsoft.Build.Utilities; + using TaskItem = Microsoft.Build.Execution.ProjectItemInstance.TaskItem; namespace Microsoft.Build.BackEnd diff --git a/src/Build/Microsoft.Build.csproj b/src/Build/Microsoft.Build.csproj index 966336543eb..126a75d9935 100644 --- a/src/Build/Microsoft.Build.csproj +++ b/src/Build/Microsoft.Build.csproj @@ -30,7 +30,6 @@ - diff --git a/src/Framework/IRarController.cs b/src/Framework/IRarController.cs new file mode 100644 index 00000000000..d494a856d21 --- /dev/null +++ b/src/Framework/IRarController.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.IO.Pipes; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Build.Framework +{ + /// + /// API for controller of ResolveAssemblyReference node + /// + internal interface IRarController + { + Task StartAsync(CancellationToken token); + + void SetStreamFactory(Func namedPipeServerFactory); + } +} diff --git a/src/Tasks/ResolveAssemblyReferences/Contract/IResolveAssemblyReferenceTaskHandler.cs b/src/Tasks/ResolveAssemblyReferences/Contract/IResolveAssemblyReferenceTaskHandler.cs index c8a74410837..0b6387394f1 100644 --- a/src/Tasks/ResolveAssemblyReferences/Contract/IResolveAssemblyReferenceTaskHandler.cs +++ b/src/Tasks/ResolveAssemblyReferences/Contract/IResolveAssemblyReferenceTaskHandler.cs @@ -6,7 +6,7 @@ namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Contract { - public interface IResolveAssemblyReferenceTaskHandler : IDisposable + internal interface IResolveAssemblyReferenceTaskHandler : IDisposable { } } diff --git a/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs b/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs index 0e0ee9081e1..fd2b568ce76 100644 --- a/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs +++ b/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs @@ -6,6 +6,9 @@ using System.IO.Pipes; using System.Threading; using System.Threading.Tasks; + +using Microsoft.Build.Framework; +using Microsoft.Build.Shared; using Microsoft.Build.Tasks.ResolveAssemblyReferences.Contract; using Microsoft.Build.Tasks.ResolveAssemblyReferences.Services; using Microsoft.VisualStudio.Threading; @@ -15,7 +18,7 @@ #nullable enable namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Server { - public sealed class RarController + internal sealed class RarController : IRarController { /// /// Name of @@ -30,7 +33,7 @@ public sealed class RarController /// 4. arg. number of allow clients /// 5. arg. add right to CreateNewInstance /// - private readonly Func _namedPipeServerFactory; + private Func? _namedPipeServerFactory; /// /// Handler for all incoming tasks @@ -44,16 +47,14 @@ public sealed class RarController public RarController( string pipeName, - Func namedPipeServerFactory, TimeSpan? timeout = null) - : this(pipeName, namedPipeServerFactory, timeout: timeout, resolveAssemblyReferenceTaskHandler: new RarTaskHandler()) + : this(pipeName, timeout: timeout, resolveAssemblyReferenceTaskHandler: new RarTaskHandler()) { } - internal RarController(string pipeName, Func namedPipeServerFactory, IResolveAssemblyReferenceTaskHandler resolveAssemblyReferenceTaskHandler, TimeSpan? timeout = null) + internal RarController(string pipeName, IResolveAssemblyReferenceTaskHandler resolveAssemblyReferenceTaskHandler, TimeSpan? timeout = null) { _pipeName = pipeName; - _namedPipeServerFactory = namedPipeServerFactory; _resolveAssemblyReferenceTaskHandler = resolveAssemblyReferenceTaskHandler; if (timeout.HasValue) @@ -64,8 +65,8 @@ internal RarController(string pipeName, Func StartAsync(CancellationToken cancellationToken = default) { - using ServerMutex mutex = new ServerMutex(_pipeName); + using ServerMutex mutex = new ServerMutex(_pipeName); if (!mutex.IsLocked) { return 1; @@ -118,11 +119,19 @@ private JsonRpc GetRpcServer(Stream stream, IResolveAssemblyReferenceTaskHandler /// The name of the pipe to which we should connect. private NamedPipeServerStream GetStream(string pipeName) { - return _namedPipeServerFactory(pipeName, + ErrorUtilities.VerifyThrow(_namedPipeServerFactory != null, "Stream factory is not set"); + + return _namedPipeServerFactory!(pipeName, null, // Use default size null, // Use default size NamedPipeServerStream.MaxAllowedServerInstances, true); } + + public void SetStreamFactory(Func namedPipeServerFactory) + { + ErrorUtilities.VerifyThrow(_namedPipeServerFactory == null, "Stream factory is already set"); + _namedPipeServerFactory = namedPipeServerFactory; + } } } From 93bfc4b68824be763552ac99edd97ab057e07300 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Wed, 26 Aug 2020 19:27:51 +0200 Subject: [PATCH 41/61] Fixed constructor --- src/Build/BackEnd/Node/RarNode.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs index a95ed365e66..6f50da17da0 100644 --- a/src/Build/BackEnd/Node/RarNode.cs +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -58,8 +58,8 @@ private static IRarController GetController(string pipeName) const string rarControllerName = "Microsoft.Build.Tasks.ResolveAssemblyReferences.Server.RarController, Microsoft.Build.Tasks.Core"; Type rarControllerType = Type.GetType(rarControllerName); - IRarController controller = (IRarController)Activator.CreateInstance(rarControllerType, pipeName); - ErrorUtilities.VerifyThrow(controller == null, "Couldn't create instace of IRarController for '{0}' type", rarControllerName); + IRarController controller = (IRarController)Activator.CreateInstance(rarControllerType, pipeName, null); + ErrorUtilities.VerifyThrow(controller != null, "Couldn't create instace of IRarController for '{0}' type", rarControllerName); controller.SetStreamFactory(NamedPipeUtil.CreateNamedPipeServer); return controller; From a305e82d3346c51bf0e853a81134f3ca917b2e00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Wed, 26 Aug 2020 20:32:26 +0200 Subject: [PATCH 42/61] Remove exe location from OutOfProcNode --- src/Build/BackEnd/BuildManager/BuildManager.cs | 2 +- src/Build/BackEnd/Node/OutOfProcNode.cs | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index df18a3eee4e..00d881ddf7b 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -2020,7 +2020,7 @@ private void PerformSchedulingActions(IEnumerable responses) internal int CreateRarNode() { - string nodeLocation = _buildParameters?.NodeExeLocation ?? OutOfProcNode.MsBuildPath; + string nodeLocation = _buildParameters?.NodeExeLocation ?? BuildEnvironmentHelper.Instance.CurrentMSBuildExePath; if (string.IsNullOrEmpty(nodeLocation)) { // Couldn't find any path to MsBuild, not creating new node. diff --git a/src/Build/BackEnd/Node/OutOfProcNode.cs b/src/Build/BackEnd/Node/OutOfProcNode.cs index a4451a7560d..0ae529953d0 100644 --- a/src/Build/BackEnd/Node/OutOfProcNode.cs +++ b/src/Build/BackEnd/Node/OutOfProcNode.cs @@ -133,11 +133,6 @@ public class OutOfProcNode : INode, IBuildComponentHost, INodePacketFactory, INo /// private readonly ISdkResolverService _sdkResolverService; - /// - /// Path to the MSBuild executable or dll. - /// - internal static string MsBuildPath { get; private set; } - /// /// Constructor. /// @@ -648,7 +643,6 @@ private void HandleNodeConfiguration(NodeConfiguration configuration) { // Grab the system parameters. _buildParameters = configuration.BuildParameters; - MsBuildPath = _buildParameters.NodeExeLocation; _buildParameters.ProjectRootElementCache = s_projectRootElementCacheBase; From 9a27bb75af85f3763ae1d9caa1d8c26c01d84534 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Wed, 26 Aug 2020 21:13:29 +0200 Subject: [PATCH 43/61] Logging --- src/Framework/MSBuildEventSource.cs | 12 ++++++++++++ .../AssemblyDependency/ResolveAssemblyReference.cs | 1 + .../ResolveAssemblyReferences/Client/RarClient.cs | 5 ++++- src/Tasks/StateFileBase.cs | 2 +- 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/Framework/MSBuildEventSource.cs b/src/Framework/MSBuildEventSource.cs index 5d73b6aa153..ae45efb429e 100644 --- a/src/Framework/MSBuildEventSource.cs +++ b/src/Framework/MSBuildEventSource.cs @@ -411,6 +411,18 @@ public void PacketReadSize(int size) { WriteEvent(55, size); } + + [Event(56)] + public void ResolveAssemblyReferenceNodeConnectStart() + { + WriteEvent(56); + } + + [Event(57)] + public void ResolveAssemblyReferenceNodeConnectStop() + { + WriteEvent(57); + } #endregion } } diff --git a/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs b/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs index 7e2094659c4..f1374324d0a 100644 --- a/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs +++ b/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs @@ -2986,6 +2986,7 @@ public override bool Execute() var connected = client.Connect(); if (!connected) { + Log.LogMessage(MessageImportance.Low, "Couldn't connect to RAR node, starting new one"); if (client.CreateNode()) { connected = client.Connect(5000); diff --git a/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs b/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs index 737bcf50496..92cc9bbfed8 100644 --- a/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs +++ b/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs @@ -3,7 +3,7 @@ using System; using System.IO.Pipes; - +using Microsoft.Build.Eventing; using Microsoft.Build.Framework; using Microsoft.Build.Shared; using Microsoft.Build.Tasks.ResolveAssemblyReferences.Contract; @@ -35,7 +35,10 @@ internal bool Connect(int timeout) return true; string pipeName = _rarBuildEngine.GetRarPipeName(); + + MSBuildEventSource.Log.ResolveAssemblyReferenceNodeConnectStart(); NamedPipeClientStream stream = _rarBuildEngine.GetRarClientStream(pipeName, timeout); + MSBuildEventSource.Log.ResolveAssemblyReferenceNodeConnectStop(); if (stream == null) return false; // We couldn't connect diff --git a/src/Tasks/StateFileBase.cs b/src/Tasks/StateFileBase.cs index 2745c801dbc..3d17a4967a4 100644 --- a/src/Tasks/StateFileBase.cs +++ b/src/Tasks/StateFileBase.cs @@ -47,7 +47,7 @@ internal virtual void SerializeCache(string stateFile, TaskLoggingHelper log) formatter.Serialize(s, this); } } - } + } catch (Exception e) { // If there was a problem writing the file (like it's read-only or locked on disk, for From 35e07f628c6c9e0cf33b78a132d869c925e2d606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Thu, 27 Aug 2020 11:48:11 +0200 Subject: [PATCH 44/61] Small improvements --- src/Build/BackEnd/Node/RarNode.cs | 9 +++++---- src/Framework/IRarController.cs | 2 -- .../Server/RarController.cs | 16 ++++++---------- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs index 6f50da17da0..b24493470fc 100644 --- a/src/Build/BackEnd/Node/RarNode.cs +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.CodeDom; using System.Diagnostics; using System.IO.Pipes; using System.Reflection; @@ -58,10 +59,10 @@ private static IRarController GetController(string pipeName) const string rarControllerName = "Microsoft.Build.Tasks.ResolveAssemblyReferences.Server.RarController, Microsoft.Build.Tasks.Core"; Type rarControllerType = Type.GetType(rarControllerName); - IRarController controller = (IRarController)Activator.CreateInstance(rarControllerType, pipeName, null); - ErrorUtilities.VerifyThrow(controller != null, "Couldn't create instace of IRarController for '{0}' type", rarControllerName); + Func streamFactory = NamedPipeUtil.CreateNamedPipeServer; + IRarController controller = (IRarController)Activator.CreateInstance(rarControllerType, pipeName, streamFactory, null); - controller.SetStreamFactory(NamedPipeUtil.CreateNamedPipeServer); + ErrorUtilities.VerifyThrow(controller != null, "Couldn't create instace of IRarController for '{0}' type", rarControllerName); return controller; } @@ -78,7 +79,7 @@ private async Task RunShutdownCheckAsync(Handshake han while (true) { if (cancellationToken.IsCancellationRequested) - return NodeEngineShutdownReason.Error; + return NodeEngineShutdownReason.BuildComplete; using NamedPipeServerStream serverStream = NamedPipeUtil.CreateNamedPipeServer(pipeName, maxNumberOfServerInstances: NamedPipeServerStream.MaxAllowedServerInstances); await serverStream.WaitForConnectionAsync(cancellationToken).ConfigureAwait(false); diff --git a/src/Framework/IRarController.cs b/src/Framework/IRarController.cs index d494a856d21..639daafb75a 100644 --- a/src/Framework/IRarController.cs +++ b/src/Framework/IRarController.cs @@ -14,7 +14,5 @@ namespace Microsoft.Build.Framework internal interface IRarController { Task StartAsync(CancellationToken token); - - void SetStreamFactory(Func namedPipeServerFactory); } } diff --git a/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs b/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs index fd2b568ce76..9697f47dcf8 100644 --- a/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs +++ b/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs @@ -33,7 +33,7 @@ internal sealed class RarController : IRarController /// 4. arg. number of allow clients /// 5. arg. add right to CreateNewInstance /// - private Func? _namedPipeServerFactory; + private readonly Func _namedPipeServerFactory; /// /// Handler for all incoming tasks @@ -46,15 +46,17 @@ internal sealed class RarController : IRarController private readonly TimeSpan Timeout = TimeSpan.FromMinutes(15); public RarController( - string pipeName, + string pipeName, Func namedPipeServerFactory, TimeSpan? timeout = null) - : this(pipeName, timeout: timeout, resolveAssemblyReferenceTaskHandler: new RarTaskHandler()) + : this(pipeName, namedPipeServerFactory, timeout: timeout, resolveAssemblyReferenceTaskHandler: new RarTaskHandler()) { } - internal RarController(string pipeName, IResolveAssemblyReferenceTaskHandler resolveAssemblyReferenceTaskHandler, TimeSpan? timeout = null) + internal RarController(string pipeName, Func namedPipeServerFactory, + IResolveAssemblyReferenceTaskHandler resolveAssemblyReferenceTaskHandler, TimeSpan? timeout = null) { _pipeName = pipeName; + _namedPipeServerFactory = namedPipeServerFactory; _resolveAssemblyReferenceTaskHandler = resolveAssemblyReferenceTaskHandler; if (timeout.HasValue) @@ -127,11 +129,5 @@ private NamedPipeServerStream GetStream(string pipeName) NamedPipeServerStream.MaxAllowedServerInstances, true); } - - public void SetStreamFactory(Func namedPipeServerFactory) - { - ErrorUtilities.VerifyThrow(_namedPipeServerFactory == null, "Stream factory is already set"); - _namedPipeServerFactory = namedPipeServerFactory; - } } } From 438af4e34ab154ffc7feb94894a003e5520d4f25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Thu, 27 Aug 2020 13:24:52 +0200 Subject: [PATCH 45/61] Whitespace fix --- src/MSBuild/app.amd64.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MSBuild/app.amd64.config b/src/MSBuild/app.amd64.config index 0952c676d80..0d9ca6d8f34 100644 --- a/src/MSBuild/app.amd64.config +++ b/src/MSBuild/app.amd64.config @@ -61,7 +61,7 @@ - + From 3880271c0eda1f216c843daa59f594ae009f2589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Sun, 30 Aug 2020 12:16:01 +0200 Subject: [PATCH 46/61] Apply suggestions from code review Co-authored-by: Forgind --- src/Build/BackEnd/BuildManager/BuildManager.cs | 2 +- src/Build/BackEnd/Node/RarNode.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index 00d881ddf7b..c198ef8e10c 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -2023,7 +2023,7 @@ internal int CreateRarNode() string nodeLocation = _buildParameters?.NodeExeLocation ?? BuildEnvironmentHelper.Instance.CurrentMSBuildExePath; if (string.IsNullOrEmpty(nodeLocation)) { - // Couldn't find any path to MsBuild, not creating new node. + // Couldn't find a path to MSBuild.exe; can't create a new node. return -1; } diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs index b24493470fc..6df66d04742 100644 --- a/src/Build/BackEnd/Node/RarNode.cs +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -44,7 +44,7 @@ public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Except if (index == 0) { - // We know that this task is completed so we can get Result without worring about waiting for it + // We know that the task completed, so we can get Result without waiting for it. return msBuildShutdown.Result; } else From 7d615b078378cbe7d20310a93f89481729fdf557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Sun, 30 Aug 2020 13:32:38 +0200 Subject: [PATCH 47/61] PR comments fix --- src/Build/BackEnd/BuildManager/BuildManager.cs | 2 +- src/MSBuild/XMake.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index c198ef8e10c..ad44bd2b5cc 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -2029,7 +2029,7 @@ internal int CreateRarNode() bool nodeReuse = _buildParameters?.EnableNodeReuse ?? true; bool lowPriority = _buildParameters?.LowPriority ?? false; - string commandLineArgs = $"/nologo /nodemode:3 /nodeReuse:{nodeReuse.ToString().ToLower()} /low:{lowPriority.ToString().ToLower()}"; + string commandLineArgs = $"/nologo /nodemode:3 /nodeReuse:{nodeReuse} /low:{lowPriority}"; try { int nodeId = NodeProviderOutOfProcBase.LaunchNode(nodeLocation, commandLineArgs); diff --git a/src/MSBuild/XMake.cs b/src/MSBuild/XMake.cs index adc40d51a95..de1957fbe8f 100644 --- a/src/MSBuild/XMake.cs +++ b/src/MSBuild/XMake.cs @@ -2648,7 +2648,7 @@ private static void StartLocalNode(CommandLineSwitches commandLineSwitches) // If FEATURE_NODE_REUSE is OFF, just validates that the switch is OK, and always returns False bool nodeReuse = ProcessNodeReuseSwitch(commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.NodeReuse]); string[] lowPriorityInput = commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.LowPriority]; - bool lowPriority = lowPriorityInput.Length > 0 ? lowPriorityInput[0].Equals("true") : false; + bool lowPriority = lowPriorityInput.Length > 0 ? string.Equals(lowPriorityInput[0], bool.TrueString, StringComparison.OrdinalIgnoreCase) : false; shutdownReason = node.Run(nodeReuse, lowPriority, out nodeException); } From eed1b1794032349dc58a8ce35957d8379adadd51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Sun, 30 Aug 2020 13:35:55 +0200 Subject: [PATCH 48/61] PR comments fix - method const to class constant --- src/Build/BackEnd/Node/RarNode.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs index 6df66d04742..32857c39882 100644 --- a/src/Build/BackEnd/Node/RarNode.cs +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -23,6 +23,11 @@ public sealed class RarNode : INode /// private const int ClientConnectTimeout = 60000; + /// + /// Fully qualified name of RarController, used for providing instance to + /// + const string RarControllerName = "Microsoft.Build.Tasks.ResolveAssemblyReferences.Server.RarController, Microsoft.Build.Tasks.Core"; + public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Exception shutdownException) { shutdownException = null; @@ -56,13 +61,12 @@ public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Except private static IRarController GetController(string pipeName) { - const string rarControllerName = "Microsoft.Build.Tasks.ResolveAssemblyReferences.Server.RarController, Microsoft.Build.Tasks.Core"; - Type rarControllerType = Type.GetType(rarControllerName); + Type rarControllerType = Type.GetType(RarControllerName); Func streamFactory = NamedPipeUtil.CreateNamedPipeServer; IRarController controller = (IRarController)Activator.CreateInstance(rarControllerType, pipeName, streamFactory, null); - ErrorUtilities.VerifyThrow(controller != null, "Couldn't create instace of IRarController for '{0}' type", rarControllerName); + ErrorUtilities.VerifyThrow(controller != null, "Couldn't create instace of IRarController for '{0}' type", RarControllerName); return controller; } From 0a83e1d2f7a6457f3ca90d0fa633a0242439c058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Sun, 30 Aug 2020 13:42:41 +0200 Subject: [PATCH 49/61] PR comments --- .../ResolveAssemblyReferences/Server/RarController.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs b/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs index 9697f47dcf8..18f4b9a3d43 100644 --- a/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs +++ b/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs @@ -46,14 +46,18 @@ internal sealed class RarController : IRarController private readonly TimeSpan Timeout = TimeSpan.FromMinutes(15); public RarController( - string pipeName, Func namedPipeServerFactory, + string pipeName, + Func namedPipeServerFactory, TimeSpan? timeout = null) : this(pipeName, namedPipeServerFactory, timeout: timeout, resolveAssemblyReferenceTaskHandler: new RarTaskHandler()) { } - internal RarController(string pipeName, Func namedPipeServerFactory, - IResolveAssemblyReferenceTaskHandler resolveAssemblyReferenceTaskHandler, TimeSpan? timeout = null) + internal RarController( + string pipeName, + Func namedPipeServerFactory, + IResolveAssemblyReferenceTaskHandler resolveAssemblyReferenceTaskHandler, + TimeSpan? timeout = null) { _pipeName = pipeName; _namedPipeServerFactory = namedPipeServerFactory; From 4500803e6bc3097c1be73edae80bdcca2e8162e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Sun, 30 Aug 2020 20:13:44 +0200 Subject: [PATCH 50/61] Moved string to resources --- src/Build/BackEnd/Node/RarNode.cs | 2 +- src/Build/Resources/Strings.resx | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs index 32857c39882..5139aac9487 100644 --- a/src/Build/BackEnd/Node/RarNode.cs +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -66,7 +66,7 @@ private static IRarController GetController(string pipeName) Func streamFactory = NamedPipeUtil.CreateNamedPipeServer; IRarController controller = (IRarController)Activator.CreateInstance(rarControllerType, pipeName, streamFactory, null); - ErrorUtilities.VerifyThrow(controller != null, "Couldn't create instace of IRarController for '{0}' type", RarControllerName); + ErrorUtilities.VerifyThrow(controller != null, ResourceUtilities.GetResourceString("RarControllerReflectionError"), RarControllerName); return controller; } diff --git a/src/Build/Resources/Strings.resx b/src/Build/Resources/Strings.resx index c2708c387c5..bd1d6707d36 100644 --- a/src/Build/Resources/Strings.resx +++ b/src/Build/Resources/Strings.resx @@ -1834,4 +1834,7 @@ Utilization: {0} Average Utilization: {1:###.0} "EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system." + + Couldn't create instace of IRarController for '{0}' type + From bb31424aa78aadd835ccb650351b67e44535114d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Mon, 31 Aug 2020 14:23:31 +0200 Subject: [PATCH 51/61] Apply suggestions from code review Co-authored-by: Ladi Prosek --- src/Build/BackEnd/Node/RarNode.cs | 2 +- src/MSBuild/XMake.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs index 5139aac9487..fb1319fa23d 100644 --- a/src/Build/BackEnd/Node/RarNode.cs +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -64,7 +64,7 @@ private static IRarController GetController(string pipeName) Type rarControllerType = Type.GetType(RarControllerName); Func streamFactory = NamedPipeUtil.CreateNamedPipeServer; - IRarController controller = (IRarController)Activator.CreateInstance(rarControllerType, pipeName, streamFactory, null); + IRarController controller = Activator.CreateInstance(rarControllerType, pipeName, streamFactory, null) as IRarController; ErrorUtilities.VerifyThrow(controller != null, ResourceUtilities.GetResourceString("RarControllerReflectionError"), RarControllerName); return controller; diff --git a/src/MSBuild/XMake.cs b/src/MSBuild/XMake.cs index de1957fbe8f..65d7bbc4030 100644 --- a/src/MSBuild/XMake.cs +++ b/src/MSBuild/XMake.cs @@ -2648,7 +2648,7 @@ private static void StartLocalNode(CommandLineSwitches commandLineSwitches) // If FEATURE_NODE_REUSE is OFF, just validates that the switch is OK, and always returns False bool nodeReuse = ProcessNodeReuseSwitch(commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.NodeReuse]); string[] lowPriorityInput = commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.LowPriority]; - bool lowPriority = lowPriorityInput.Length > 0 ? string.Equals(lowPriorityInput[0], bool.TrueString, StringComparison.OrdinalIgnoreCase) : false; + bool lowPriority = lowPriorityInput.Length > 0 && string.Equals(lowPriorityInput[0], bool.TrueString, StringComparison.OrdinalIgnoreCase); shutdownReason = node.Run(nodeReuse, lowPriority, out nodeException); } From 7fdac1b85c94ce5ee300a503631c90ef13178df1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Mon, 31 Aug 2020 14:29:18 +0200 Subject: [PATCH 52/61] Localization files --- src/Build/Resources/xlf/Strings.cs.xlf | 5 +++++ src/Build/Resources/xlf/Strings.de.xlf | 5 +++++ src/Build/Resources/xlf/Strings.en.xlf | 5 +++++ src/Build/Resources/xlf/Strings.es.xlf | 5 +++++ src/Build/Resources/xlf/Strings.fr.xlf | 5 +++++ src/Build/Resources/xlf/Strings.it.xlf | 5 +++++ src/Build/Resources/xlf/Strings.ja.xlf | 5 +++++ src/Build/Resources/xlf/Strings.ko.xlf | 5 +++++ src/Build/Resources/xlf/Strings.pl.xlf | 5 +++++ src/Build/Resources/xlf/Strings.pt-BR.xlf | 5 +++++ src/Build/Resources/xlf/Strings.ru.xlf | 5 +++++ src/Build/Resources/xlf/Strings.tr.xlf | 5 +++++ src/Build/Resources/xlf/Strings.zh-Hans.xlf | 5 +++++ src/Build/Resources/xlf/Strings.zh-Hant.xlf | 5 +++++ 14 files changed, 70 insertions(+) diff --git a/src/Build/Resources/xlf/Strings.cs.xlf b/src/Build/Resources/xlf/Strings.cs.xlf index ee4d13472fd..2585a639fb1 100644 --- a/src/Build/Resources/xlf/Strings.cs.xlf +++ b/src/Build/Resources/xlf/Strings.cs.xlf @@ -178,6 +178,11 @@ Počáteční hodnota vlastnosti: $({0})={1} Zdroj: {2} + + Couldn't create instace of IRarController for '{0}' type + Couldn't create instace of IRarController for '{0}' type + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: Projekt {0} přeskočil omezení izolace grafu v odkazovaném projektu {1}. diff --git a/src/Build/Resources/xlf/Strings.de.xlf b/src/Build/Resources/xlf/Strings.de.xlf index 44b17444d81..11109eb65d2 100644 --- a/src/Build/Resources/xlf/Strings.de.xlf +++ b/src/Build/Resources/xlf/Strings.de.xlf @@ -178,6 +178,11 @@ Anfangswert der Eigenschaft: $({0})="{1}", Quelle: {2} + + Couldn't create instace of IRarController for '{0}' type + Couldn't create instace of IRarController for '{0}' type + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: Das Projekt "{0}" hat Graphisolationseinschränkungen für das referenzierte Projekt "{1}" übersprungen. diff --git a/src/Build/Resources/xlf/Strings.en.xlf b/src/Build/Resources/xlf/Strings.en.xlf index 6f48da26a49..93c77d96ff8 100644 --- a/src/Build/Resources/xlf/Strings.en.xlf +++ b/src/Build/Resources/xlf/Strings.en.xlf @@ -178,6 +178,11 @@ Property initial value: $({0})="{1}" Source: {2} + + Couldn't create instace of IRarController for '{0}' type + Couldn't create instace of IRarController for '{0}' type + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" diff --git a/src/Build/Resources/xlf/Strings.es.xlf b/src/Build/Resources/xlf/Strings.es.xlf index ff6b7df796d..9b34d3f68e8 100644 --- a/src/Build/Resources/xlf/Strings.es.xlf +++ b/src/Build/Resources/xlf/Strings.es.xlf @@ -178,6 +178,11 @@ Valor inicial de la propiedad: $({0})="{1}" Origen: {2} + + Couldn't create instace of IRarController for '{0}' type + Couldn't create instace of IRarController for '{0}' type + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: El proyecto "{0}" ha omitido las restricciones de aislamiento de gráficos en el proyecto "{1}" al que se hace referencia. diff --git a/src/Build/Resources/xlf/Strings.fr.xlf b/src/Build/Resources/xlf/Strings.fr.xlf index 531f580e15a..68140ec5e3b 100644 --- a/src/Build/Resources/xlf/Strings.fr.xlf +++ b/src/Build/Resources/xlf/Strings.fr.xlf @@ -178,6 +178,11 @@ Valeur initiale de la propriété : $({0})="{1}" Source : {2} + + Couldn't create instace of IRarController for '{0}' type + Couldn't create instace of IRarController for '{0}' type + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: le projet "{0}" a ignoré les contraintes d'isolement de graphe dans le projet référencé "{1}" diff --git a/src/Build/Resources/xlf/Strings.it.xlf b/src/Build/Resources/xlf/Strings.it.xlf index 1a694c9d92c..296540e1833 100644 --- a/src/Build/Resources/xlf/Strings.it.xlf +++ b/src/Build/Resources/xlf/Strings.it.xlf @@ -178,6 +178,11 @@ Valore iniziale della proprietà: $({0})="{1}". Origine: {2} + + Couldn't create instace of IRarController for '{0}' type + Couldn't create instace of IRarController for '{0}' type + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: il progetto "{0}" ha ignorato i vincoli di isolamento del grafico nel progetto di riferimento "{1}" diff --git a/src/Build/Resources/xlf/Strings.ja.xlf b/src/Build/Resources/xlf/Strings.ja.xlf index 9ac0fcd13c4..32d9bddb44d 100644 --- a/src/Build/Resources/xlf/Strings.ja.xlf +++ b/src/Build/Resources/xlf/Strings.ja.xlf @@ -178,6 +178,11 @@ プロパティの初期値: $({0})="{1}" ソース: {2} + + Couldn't create instace of IRarController for '{0}' type + Couldn't create instace of IRarController for '{0}' type + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: プロジェクト "{0}" は、参照先のプロジェクト "{1}" で、グラフの分離制約をスキップしました diff --git a/src/Build/Resources/xlf/Strings.ko.xlf b/src/Build/Resources/xlf/Strings.ko.xlf index 6b4bb9305d7..1f97f11b778 100644 --- a/src/Build/Resources/xlf/Strings.ko.xlf +++ b/src/Build/Resources/xlf/Strings.ko.xlf @@ -178,6 +178,11 @@ 속성 초기 값: $({0})="{1}" 소스: {2} + + Couldn't create instace of IRarController for '{0}' type + Couldn't create instace of IRarController for '{0}' type + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: 프로젝트 "{0}"에서 참조된 프로젝트 "{1}"의 그래프 격리 제약 조건을 건너뛰었습니다. diff --git a/src/Build/Resources/xlf/Strings.pl.xlf b/src/Build/Resources/xlf/Strings.pl.xlf index afb3ebf2e36..006bdb4e1ef 100644 --- a/src/Build/Resources/xlf/Strings.pl.xlf +++ b/src/Build/Resources/xlf/Strings.pl.xlf @@ -178,6 +178,11 @@ Wartość początkowa właściwości: $({0})=„{1}” Źródło: {2} + + Couldn't create instace of IRarController for '{0}' type + Couldn't create instace of IRarController for '{0}' type + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: W przypadku projektu „{0}” pominięto ograniczenia izolacji grafu dla przywoływanego projektu „{1}” diff --git a/src/Build/Resources/xlf/Strings.pt-BR.xlf b/src/Build/Resources/xlf/Strings.pt-BR.xlf index 0af53bc16a2..be0a0b13c17 100644 --- a/src/Build/Resources/xlf/Strings.pt-BR.xlf +++ b/src/Build/Resources/xlf/Strings.pt-BR.xlf @@ -178,6 +178,11 @@ Valor inicial da propriedade: $({0})="{1}" Origem: {2} + + Couldn't create instace of IRarController for '{0}' type + Couldn't create instace of IRarController for '{0}' type + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: o projeto "{0}" ignorou as restrições de isolamento do gráfico no projeto referenciado "{1}" diff --git a/src/Build/Resources/xlf/Strings.ru.xlf b/src/Build/Resources/xlf/Strings.ru.xlf index 1fd04905eb0..18da3c449a1 100644 --- a/src/Build/Resources/xlf/Strings.ru.xlf +++ b/src/Build/Resources/xlf/Strings.ru.xlf @@ -178,6 +178,11 @@ Начальное значение свойства: $({0})="{1}" Источник: {2} + + Couldn't create instace of IRarController for '{0}' type + Couldn't create instace of IRarController for '{0}' type + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: проект "{0}" пропустил ограничения изоляции графа в проекте "{1}", на который указывает ссылка. diff --git a/src/Build/Resources/xlf/Strings.tr.xlf b/src/Build/Resources/xlf/Strings.tr.xlf index d65c72420e7..9354543c89d 100644 --- a/src/Build/Resources/xlf/Strings.tr.xlf +++ b/src/Build/Resources/xlf/Strings.tr.xlf @@ -178,6 +178,11 @@ Özellik başlangıç değeri: $({0})="{1}" Kaynak: {2} + + Couldn't create instace of IRarController for '{0}' type + Couldn't create instace of IRarController for '{0}' type + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: "{0}" projesi, başvurulan "{1}" projesindeki graf yalıtımı kısıtlamalarını atladı diff --git a/src/Build/Resources/xlf/Strings.zh-Hans.xlf b/src/Build/Resources/xlf/Strings.zh-Hans.xlf index be7e4e06f42..16f4ceb5ccb 100644 --- a/src/Build/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/Build/Resources/xlf/Strings.zh-Hans.xlf @@ -178,6 +178,11 @@ 属性初始值: $({0})=“{1}”,源: {2} + + Couldn't create instace of IRarController for '{0}' type + Couldn't create instace of IRarController for '{0}' type + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: 项目“{0}”已跳过所引用的项目“{1}”上的图形隔离约束 diff --git a/src/Build/Resources/xlf/Strings.zh-Hant.xlf b/src/Build/Resources/xlf/Strings.zh-Hant.xlf index eb53e039bba..cbec8983a50 100644 --- a/src/Build/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/Build/Resources/xlf/Strings.zh-Hant.xlf @@ -178,6 +178,11 @@ 屬性初始值: $({0})="{1}" 來源: {2} + + Couldn't create instace of IRarController for '{0}' type + Couldn't create instace of IRarController for '{0}' type + + MSB4260: Project "{0}" skipped graph isolation constraints on referenced project "{1}" MSB4260: 專案 "{0}" 已跳過參考專案 "{1}" 上的圖形隔離條件約束 From e08cbb82f30fd0460702660172fe030528458296 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Mon, 31 Aug 2020 17:15:03 +0200 Subject: [PATCH 53/61] Resources --- src/Build/Resources/Strings.resx | 2 +- src/Build/Resources/xlf/Strings.cs.xlf | 4 ++-- src/Build/Resources/xlf/Strings.de.xlf | 4 ++-- src/Build/Resources/xlf/Strings.en.xlf | 4 ++-- src/Build/Resources/xlf/Strings.es.xlf | 4 ++-- src/Build/Resources/xlf/Strings.fr.xlf | 4 ++-- src/Build/Resources/xlf/Strings.it.xlf | 4 ++-- src/Build/Resources/xlf/Strings.ja.xlf | 4 ++-- src/Build/Resources/xlf/Strings.ko.xlf | 4 ++-- src/Build/Resources/xlf/Strings.pl.xlf | 4 ++-- src/Build/Resources/xlf/Strings.pt-BR.xlf | 4 ++-- src/Build/Resources/xlf/Strings.ru.xlf | 4 ++-- src/Build/Resources/xlf/Strings.tr.xlf | 4 ++-- src/Build/Resources/xlf/Strings.zh-Hans.xlf | 4 ++-- src/Build/Resources/xlf/Strings.zh-Hant.xlf | 4 ++-- src/Tasks/Resources/Strings.resx | 3 +++ src/Tasks/Resources/xlf/Strings.cs.xlf | 5 +++++ src/Tasks/Resources/xlf/Strings.de.xlf | 5 +++++ src/Tasks/Resources/xlf/Strings.en.xlf | 5 +++++ src/Tasks/Resources/xlf/Strings.es.xlf | 5 +++++ src/Tasks/Resources/xlf/Strings.fr.xlf | 5 +++++ src/Tasks/Resources/xlf/Strings.it.xlf | 5 +++++ src/Tasks/Resources/xlf/Strings.ja.xlf | 5 +++++ src/Tasks/Resources/xlf/Strings.ko.xlf | 5 +++++ src/Tasks/Resources/xlf/Strings.pl.xlf | 5 +++++ src/Tasks/Resources/xlf/Strings.pt-BR.xlf | 5 +++++ src/Tasks/Resources/xlf/Strings.ru.xlf | 5 +++++ src/Tasks/Resources/xlf/Strings.tr.xlf | 5 +++++ src/Tasks/Resources/xlf/Strings.zh-Hans.xlf | 5 +++++ src/Tasks/Resources/xlf/Strings.zh-Hant.xlf | 5 +++++ 30 files changed, 102 insertions(+), 29 deletions(-) diff --git a/src/Build/Resources/Strings.resx b/src/Build/Resources/Strings.resx index bd1d6707d36..0196285954c 100644 --- a/src/Build/Resources/Strings.resx +++ b/src/Build/Resources/Strings.resx @@ -1835,6 +1835,6 @@ Utilization: {0} Average Utilization: {1:###.0} "EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system." - Couldn't create instace of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.cs.xlf b/src/Build/Resources/xlf/Strings.cs.xlf index 2585a639fb1..a48727fe3e6 100644 --- a/src/Build/Resources/xlf/Strings.cs.xlf +++ b/src/Build/Resources/xlf/Strings.cs.xlf @@ -179,8 +179,8 @@ - Couldn't create instace of IRarController for '{0}' type - Couldn't create instace of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.de.xlf b/src/Build/Resources/xlf/Strings.de.xlf index 11109eb65d2..3e4ceed782c 100644 --- a/src/Build/Resources/xlf/Strings.de.xlf +++ b/src/Build/Resources/xlf/Strings.de.xlf @@ -179,8 +179,8 @@ - Couldn't create instace of IRarController for '{0}' type - Couldn't create instace of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.en.xlf b/src/Build/Resources/xlf/Strings.en.xlf index 93c77d96ff8..607780a32e2 100644 --- a/src/Build/Resources/xlf/Strings.en.xlf +++ b/src/Build/Resources/xlf/Strings.en.xlf @@ -179,8 +179,8 @@ - Couldn't create instace of IRarController for '{0}' type - Couldn't create instace of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.es.xlf b/src/Build/Resources/xlf/Strings.es.xlf index 9b34d3f68e8..e129cd05c78 100644 --- a/src/Build/Resources/xlf/Strings.es.xlf +++ b/src/Build/Resources/xlf/Strings.es.xlf @@ -179,8 +179,8 @@ - Couldn't create instace of IRarController for '{0}' type - Couldn't create instace of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.fr.xlf b/src/Build/Resources/xlf/Strings.fr.xlf index 68140ec5e3b..c6266cce6f2 100644 --- a/src/Build/Resources/xlf/Strings.fr.xlf +++ b/src/Build/Resources/xlf/Strings.fr.xlf @@ -179,8 +179,8 @@ - Couldn't create instace of IRarController for '{0}' type - Couldn't create instace of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.it.xlf b/src/Build/Resources/xlf/Strings.it.xlf index 296540e1833..5f32313ebde 100644 --- a/src/Build/Resources/xlf/Strings.it.xlf +++ b/src/Build/Resources/xlf/Strings.it.xlf @@ -179,8 +179,8 @@ - Couldn't create instace of IRarController for '{0}' type - Couldn't create instace of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.ja.xlf b/src/Build/Resources/xlf/Strings.ja.xlf index 32d9bddb44d..411fe1abf5b 100644 --- a/src/Build/Resources/xlf/Strings.ja.xlf +++ b/src/Build/Resources/xlf/Strings.ja.xlf @@ -179,8 +179,8 @@ - Couldn't create instace of IRarController for '{0}' type - Couldn't create instace of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.ko.xlf b/src/Build/Resources/xlf/Strings.ko.xlf index 1f97f11b778..a44701756a5 100644 --- a/src/Build/Resources/xlf/Strings.ko.xlf +++ b/src/Build/Resources/xlf/Strings.ko.xlf @@ -179,8 +179,8 @@ - Couldn't create instace of IRarController for '{0}' type - Couldn't create instace of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.pl.xlf b/src/Build/Resources/xlf/Strings.pl.xlf index 006bdb4e1ef..0d82a057943 100644 --- a/src/Build/Resources/xlf/Strings.pl.xlf +++ b/src/Build/Resources/xlf/Strings.pl.xlf @@ -179,8 +179,8 @@ - Couldn't create instace of IRarController for '{0}' type - Couldn't create instace of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.pt-BR.xlf b/src/Build/Resources/xlf/Strings.pt-BR.xlf index be0a0b13c17..bbaf3825ed2 100644 --- a/src/Build/Resources/xlf/Strings.pt-BR.xlf +++ b/src/Build/Resources/xlf/Strings.pt-BR.xlf @@ -179,8 +179,8 @@ - Couldn't create instace of IRarController for '{0}' type - Couldn't create instace of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.ru.xlf b/src/Build/Resources/xlf/Strings.ru.xlf index 18da3c449a1..549997c9557 100644 --- a/src/Build/Resources/xlf/Strings.ru.xlf +++ b/src/Build/Resources/xlf/Strings.ru.xlf @@ -179,8 +179,8 @@ - Couldn't create instace of IRarController for '{0}' type - Couldn't create instace of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.tr.xlf b/src/Build/Resources/xlf/Strings.tr.xlf index 9354543c89d..c290c26e54b 100644 --- a/src/Build/Resources/xlf/Strings.tr.xlf +++ b/src/Build/Resources/xlf/Strings.tr.xlf @@ -179,8 +179,8 @@ - Couldn't create instace of IRarController for '{0}' type - Couldn't create instace of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.zh-Hans.xlf b/src/Build/Resources/xlf/Strings.zh-Hans.xlf index 16f4ceb5ccb..393fa931cb3 100644 --- a/src/Build/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/Build/Resources/xlf/Strings.zh-Hans.xlf @@ -179,8 +179,8 @@ - Couldn't create instace of IRarController for '{0}' type - Couldn't create instace of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.zh-Hant.xlf b/src/Build/Resources/xlf/Strings.zh-Hant.xlf index cbec8983a50..3f4d27b7007 100644 --- a/src/Build/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/Build/Resources/xlf/Strings.zh-Hant.xlf @@ -179,8 +179,8 @@ - Couldn't create instace of IRarController for '{0}' type - Couldn't create instace of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type + Couldn't create instance of IRarController for '{0}' type diff --git a/src/Tasks/Resources/Strings.resx b/src/Tasks/Resources/Strings.resx index cc1e2699443..1311fc552be 100644 --- a/src/Tasks/Resources/Strings.resx +++ b/src/Tasks/Resources/Strings.resx @@ -2931,4 +2931,7 @@ error codes, because those exceptions should ideally be caught at a higher scope and logged with a wrapper message that DOES have an error code. --> + + Couldn't connect to RAR node, starting new one. + diff --git a/src/Tasks/Resources/xlf/Strings.cs.xlf b/src/Tasks/Resources/xlf/Strings.cs.xlf index 9598c9d6157..a8c27562377 100644 --- a/src/Tasks/Resources/xlf/Strings.cs.xlf +++ b/src/Tasks/Resources/xlf/Strings.cs.xlf @@ -1412,6 +1412,11 @@ Vlastnost StopOnFirstFailure nebude mít žádný účinek, jsou-li splněny všechny následující podmínky: 1) systém pracuje v režimu více procesů, 2) vlastnost BuildInParallel má hodnotu True, 3) vlastnost RunEachTargetSeparately má hodnotu False. LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". + + Couldn't connect to RAR node, starting new one. + Couldn't connect to RAR node, starting new one. + + MSB3501: Could not read lines from file "{0}". {1} MSB3501: Nelze číst řádky ze souboru {0}. {1} diff --git a/src/Tasks/Resources/xlf/Strings.de.xlf b/src/Tasks/Resources/xlf/Strings.de.xlf index 44b9fbe1ba8..39dc594d128 100644 --- a/src/Tasks/Resources/xlf/Strings.de.xlf +++ b/src/Tasks/Resources/xlf/Strings.de.xlf @@ -1412,6 +1412,11 @@ StopOnFirstFailure hat keine Auswirkungen, wenn die folgenden Bedingungen alle gelten: 1) Das System wird im Mehrprozessmodus ausgeführt. 2) Die BuildInParallel-Eigenschaft ist TRUE. 3) Die RunEachTargetSeparately-Eigenschaft ist FALSE. LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". + + Couldn't connect to RAR node, starting new one. + Couldn't connect to RAR node, starting new one. + + MSB3501: Could not read lines from file "{0}". {1} MSB3501: Die Zeilen aus der Datei "{0}" konnten nicht gelesen werden. {1} diff --git a/src/Tasks/Resources/xlf/Strings.en.xlf b/src/Tasks/Resources/xlf/Strings.en.xlf index c9d6885f10c..58c6115a3e7 100644 --- a/src/Tasks/Resources/xlf/Strings.en.xlf +++ b/src/Tasks/Resources/xlf/Strings.en.xlf @@ -1457,6 +1457,11 @@ StopOnFirstFailure will have no effect when the following conditions are all present: 1) The system is running in multiple process mode 2) The BuildInParallel property is true. 3) The RunEachTargetSeparately property is false. LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". + + Couldn't connect to RAR node, starting new one. + Couldn't connect to RAR node, starting new one. + + MSB3501: Could not read lines from file "{0}". {1} MSB3501: Could not read lines from file "{0}". {1} diff --git a/src/Tasks/Resources/xlf/Strings.es.xlf b/src/Tasks/Resources/xlf/Strings.es.xlf index e34aa053c3e..c5694f5779b 100644 --- a/src/Tasks/Resources/xlf/Strings.es.xlf +++ b/src/Tasks/Resources/xlf/Strings.es.xlf @@ -1412,6 +1412,11 @@ StopOnFirstFailure no surtirá efecto si se dan todas las condiciones siguientes: 1) El sistema se ejecuta en modo de proceso múltiple. 2) La propiedad BuildInParallel es true. 3) La propiedad RunEachTargetSeparately es false. LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". + + Couldn't connect to RAR node, starting new one. + Couldn't connect to RAR node, starting new one. + + MSB3501: Could not read lines from file "{0}". {1} MSB3501: No se pudieron leer las líneas del archivo "{0}". {1} diff --git a/src/Tasks/Resources/xlf/Strings.fr.xlf b/src/Tasks/Resources/xlf/Strings.fr.xlf index 9720b69bf5f..625b19f49e4 100644 --- a/src/Tasks/Resources/xlf/Strings.fr.xlf +++ b/src/Tasks/Resources/xlf/Strings.fr.xlf @@ -1412,6 +1412,11 @@ StopOnFirstFailure reste sans effet dans les conditions suivantes : 1) Le système s'exécute en mode multiprocessus. 2) La propriété BuildInParallel a la valeur true. 3) La propriété RunEachTargetSeparately a la valeur false. LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". + + Couldn't connect to RAR node, starting new one. + Couldn't connect to RAR node, starting new one. + + MSB3501: Could not read lines from file "{0}". {1} MSB3501: Impossible de lire les lignes dans le fichier "{0}". {1} diff --git a/src/Tasks/Resources/xlf/Strings.it.xlf b/src/Tasks/Resources/xlf/Strings.it.xlf index 7ce334457fc..ac76beccc8e 100644 --- a/src/Tasks/Resources/xlf/Strings.it.xlf +++ b/src/Tasks/Resources/xlf/Strings.it.xlf @@ -1412,6 +1412,11 @@ StopOnFirstFailure non avrà alcun effetto in presenza di tutte le condizioni seguenti: 1) il sistema è in esecuzione in modalità a più processi 2) la proprietà BuildInParallel è true. 3) la proprietà RunEachTargetSeparately è false. LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". + + Couldn't connect to RAR node, starting new one. + Couldn't connect to RAR node, starting new one. + + MSB3501: Could not read lines from file "{0}". {1} MSB3501: non è stato possibile leggere le righe dal file "{0}". {1} diff --git a/src/Tasks/Resources/xlf/Strings.ja.xlf b/src/Tasks/Resources/xlf/Strings.ja.xlf index 52d2825682c..1d85ce7b6ea 100644 --- a/src/Tasks/Resources/xlf/Strings.ja.xlf +++ b/src/Tasks/Resources/xlf/Strings.ja.xlf @@ -1412,6 +1412,11 @@ StopOnFirstFailure は、次のすべての条件に該当する場合に無効となります。1) システムがマルチプロセッサ モードで実行されている。2) BuildInParallel プロパティが true に設定されている。3) RunEachTargetSeparately プロパティが false に設定されている。 LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". + + Couldn't connect to RAR node, starting new one. + Couldn't connect to RAR node, starting new one. + + MSB3501: Could not read lines from file "{0}". {1} MSB3501: ファイル "{0}" からの行を読み取れませんでした。{1} diff --git a/src/Tasks/Resources/xlf/Strings.ko.xlf b/src/Tasks/Resources/xlf/Strings.ko.xlf index 2e70e167585..7a637847c9a 100644 --- a/src/Tasks/Resources/xlf/Strings.ko.xlf +++ b/src/Tasks/Resources/xlf/Strings.ko.xlf @@ -1412,6 +1412,11 @@ 다음 조건이 모두 충족되면 StopOnFirstFailure가 효과가 없습니다. 1) 시스템이 다중 프로세스 모드에서 실행 중입니다. 2) BuildInParallel 속성이 true입니다. 3) RunEachTargetSeparately 속성이 false입니다. LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". + + Couldn't connect to RAR node, starting new one. + Couldn't connect to RAR node, starting new one. + + MSB3501: Could not read lines from file "{0}". {1} MSB3501: "{0}" 파일에서 줄을 읽을 수 없습니다. {1} diff --git a/src/Tasks/Resources/xlf/Strings.pl.xlf b/src/Tasks/Resources/xlf/Strings.pl.xlf index 6b53dc24fb7..96cc723b3f8 100644 --- a/src/Tasks/Resources/xlf/Strings.pl.xlf +++ b/src/Tasks/Resources/xlf/Strings.pl.xlf @@ -1412,6 +1412,11 @@ Działanie funkcji StopOnFirstFailure nie przyniesie efektu, jeśli będą spełnione wszystkie następujące warunki: 1) System działa w trybie wieloprocesowym. 2) Właściwość BuildInParallel ma wartość true. 3) Właściwość RunEachTargetSeparately ma wartość false. LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". + + Couldn't connect to RAR node, starting new one. + Couldn't connect to RAR node, starting new one. + + MSB3501: Could not read lines from file "{0}". {1} MSB3501: Nie można odczytać wierszy z pliku „{0}”. {1} diff --git a/src/Tasks/Resources/xlf/Strings.pt-BR.xlf b/src/Tasks/Resources/xlf/Strings.pt-BR.xlf index 0d31dafd981..1fb88f22573 100644 --- a/src/Tasks/Resources/xlf/Strings.pt-BR.xlf +++ b/src/Tasks/Resources/xlf/Strings.pt-BR.xlf @@ -1412,6 +1412,11 @@ StopOnFirstFailure não terá efeito quando estas condições existirem: 1) O sistema estiver sendo executado no modo de processamento múltiplo 2) A propriedade BuildInParallel for true. 3) A propriedade RunEachTargetSeparately for false. LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". + + Couldn't connect to RAR node, starting new one. + Couldn't connect to RAR node, starting new one. + + MSB3501: Could not read lines from file "{0}". {1} MSB3501: Não foi possível ler linhas do arquivo "{0}". {1} diff --git a/src/Tasks/Resources/xlf/Strings.ru.xlf b/src/Tasks/Resources/xlf/Strings.ru.xlf index 29fe42402d0..a2c59b35fdd 100644 --- a/src/Tasks/Resources/xlf/Strings.ru.xlf +++ b/src/Tasks/Resources/xlf/Strings.ru.xlf @@ -1412,6 +1412,11 @@ StopOnFirstFailure будет игнорироваться при одновременном соблюдении следующих условий: 1) система выполняется в режиме с несколькими процессами; 2) свойство BuildInParallel имеет значение true; 3) свойство RunEachTargetSeparately имеет значение false. LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". + + Couldn't connect to RAR node, starting new one. + Couldn't connect to RAR node, starting new one. + + MSB3501: Could not read lines from file "{0}". {1} MSB3501: Не удалось прочесть строки из файла "{0}". {1} diff --git a/src/Tasks/Resources/xlf/Strings.tr.xlf b/src/Tasks/Resources/xlf/Strings.tr.xlf index 5076d987e41..5180e0e5a07 100644 --- a/src/Tasks/Resources/xlf/Strings.tr.xlf +++ b/src/Tasks/Resources/xlf/Strings.tr.xlf @@ -1412,6 +1412,11 @@ Şu koşulların tümü doğru olduğunda StopOnFirstFailure etkisiz olur: 1) Sistem çoklu işlem modunda çalışıyorsa. 2) BuildInParallel özelliği true ise. 3) RunEachTargetSeparately özelliği false ise. LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". + + Couldn't connect to RAR node, starting new one. + Couldn't connect to RAR node, starting new one. + + MSB3501: Could not read lines from file "{0}". {1} MSB3501: "{0}" dosyasındaki satırlar okunamadı. {1} diff --git a/src/Tasks/Resources/xlf/Strings.zh-Hans.xlf b/src/Tasks/Resources/xlf/Strings.zh-Hans.xlf index 2797e21cd0b..936b248b2d8 100644 --- a/src/Tasks/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/Tasks/Resources/xlf/Strings.zh-Hans.xlf @@ -1412,6 +1412,11 @@ 如果满足以下所有条件,StopOnFirstFailure 将不起任何作用: 1) 系统在多进程模式下运行。2) BuildInParallel 属性为 true。3) RunEachTargetSeparately 属性为 false。 LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". + + Couldn't connect to RAR node, starting new one. + Couldn't connect to RAR node, starting new one. + + MSB3501: Could not read lines from file "{0}". {1} MSB3501: 未能从文件“{0}”读取命令行。{1} diff --git a/src/Tasks/Resources/xlf/Strings.zh-Hant.xlf b/src/Tasks/Resources/xlf/Strings.zh-Hant.xlf index 05c4f11672b..62425445b92 100644 --- a/src/Tasks/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/Tasks/Resources/xlf/Strings.zh-Hant.xlf @@ -1412,6 +1412,11 @@ 當下列條件全部成立時,StopOnFirstFailure 將沒有作用: 1) 系統正在多處理程序模式中執行 2) BuildInParallel 屬性為 true。3) RunEachTargetSeparately 屬性為 false。 LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". + + Couldn't connect to RAR node, starting new one. + Couldn't connect to RAR node, starting new one. + + MSB3501: Could not read lines from file "{0}". {1} MSB3501: 無法從檔案 "{0}" 讀取行。{1} From 5372f22396e73af3c1ad7aa997e19d6a4b597827 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Mon, 31 Aug 2020 17:17:20 +0200 Subject: [PATCH 54/61] PR comments --- .../BackEnd/BuildManager/BuildManager.cs | 23 ++++++++++--------- .../Components/RequestBuilder/TaskHost.cs | 2 +- src/Build/BackEnd/Node/RarNode.cs | 12 ++++++---- src/Shared/CommunicationsUtilities.cs | 6 +---- src/Shared/NamedPipeUtil.cs | 3 ++- .../ResolveAssemblyReference.cs | 14 +++++++++-- .../Client/RarClient.cs | 4 +--- 7 files changed, 37 insertions(+), 27 deletions(-) diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index ad44bd2b5cc..f9881722a7d 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -64,6 +64,11 @@ public class BuildManager : INodePacketHandler, IBuildComponentHost, IDisposable /// private static int s_nextBuildRequestConfigurationId; + /// + /// If this value is returened by then RAR node wasn't started + /// + internal const int RarNodeStartFailed = -1; + /// /// The cache for build request configurations. /// @@ -2020,26 +2025,22 @@ private void PerformSchedulingActions(IEnumerable responses) internal int CreateRarNode() { + // If the _buildParametrs is not set, we are in OutOfProc mode, so continue + // Else check if users specified that he want to use multiple nodes, if so use RARaaS + if (_buildParameters?.MaxNodeCount == 1) + return RarNodeStartFailed; + string nodeLocation = _buildParameters?.NodeExeLocation ?? BuildEnvironmentHelper.Instance.CurrentMSBuildExePath; if (string.IsNullOrEmpty(nodeLocation)) { // Couldn't find a path to MSBuild.exe; can't create a new node. - return -1; + return RarNodeStartFailed; } bool nodeReuse = _buildParameters?.EnableNodeReuse ?? true; bool lowPriority = _buildParameters?.LowPriority ?? false; string commandLineArgs = $"/nologo /nodemode:3 /nodeReuse:{nodeReuse} /low:{lowPriority}"; - try - { - int nodeId = NodeProviderOutOfProcBase.LaunchNode(nodeLocation, commandLineArgs); - return nodeId; - } - catch (Exception) - { - // Fail silently - return -1; - } + return NodeProviderOutOfProcBase.LaunchNode(nodeLocation, commandLineArgs); } /// diff --git a/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs b/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs index bc54fc6227c..5e9a750c1f3 100644 --- a/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs +++ b/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs @@ -992,7 +992,7 @@ private void VerifyActiveProxy() bool IRarBuildEngine.CreateRarNode() { int nodeId = BuildManager.DefaultBuildManager.CreateRarNode(); - return nodeId != -1; + return nodeId != BuildManager.RarNodeStartFailed; } /// diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs index fb1319fa23d..d55d362660c 100644 --- a/src/Build/BackEnd/Node/RarNode.cs +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -26,7 +26,7 @@ public sealed class RarNode : INode /// /// Fully qualified name of RarController, used for providing instance to /// - const string RarControllerName = "Microsoft.Build.Tasks.ResolveAssemblyReferences.Server.RarController, Microsoft.Build.Tasks.Core"; + private const string RarControllerName = "Microsoft.Build.Tasks.ResolveAssemblyReferences.Server.RarController, Microsoft.Build.Tasks.Core"; public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Exception shutdownException) { @@ -43,7 +43,7 @@ public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Except // Wait for any of these task to finish: // - rarTask can timeout (default is 15 mins) - // - msBuildShutdown ends when it recieves command to shutdown + // - msBuildShutdown ends when it receives command to shutdown int index = Task.WaitAny(msBuildShutdown, rarTask); cts.Cancel(); @@ -70,7 +70,6 @@ private static IRarController GetController(string pipeName) return controller; } - public NodeEngineShutdownReason Run(out Exception shutdownException) { return Run(false, false, out shutdownException); @@ -80,6 +79,11 @@ private async Task RunShutdownCheckAsync(Handshake han { string pipeName = NamedPipeUtil.GetPipeNameOrPath("MSBuild" + Process.GetCurrentProcess().Id); + // Most common path in this while loop in long run will be over the continue statement. + // This is happeing because the MSBuild when starting new nodes is trying in some cases to reuse nodes (see nodeReuse switch). + // It is done by listing the MSBuild processes and then connecting to them and validating the handshake. + // In most cases for this loop it will fail, which will lead to hitting the continue statement. + // If we get over that, the MSBuild should send NodeBuildComplete packet, which will indicate that the engine is requesting to shtudown this node. while (true) { if (cancellationToken.IsCancellationRequested) @@ -96,7 +100,7 @@ private async Task RunShutdownCheckAsync(Handshake han // 1 byte - Packet type // 4 bytes - packet length byte[] header = new byte[5]; - int bytesRead = await serverStream.ReadAsync(header, 0, header.Length).ConfigureAwait(false); + int bytesRead = await CommunicationsUtilities.ReadAsync(serverStream, header, header.Length).ConfigureAwait(false); if (bytesRead != header.Length) { continue; diff --git a/src/Shared/CommunicationsUtilities.cs b/src/Shared/CommunicationsUtilities.cs index a2a4dafbf2e..7b39a83c1b6 100644 --- a/src/Shared/CommunicationsUtilities.cs +++ b/src/Shared/CommunicationsUtilities.cs @@ -11,13 +11,11 @@ using System.Runtime.InteropServices; using System.Security.Principal; using System.Threading; +using System.Threading.Tasks; using Microsoft.Build.Shared; using Microsoft.Build.BackEnd.Logging; -#if !FEATURE_APM -using System.Threading.Tasks; -#endif namespace Microsoft.Build.Internal { @@ -461,7 +459,6 @@ internal static int ReadIntForHandshake(this PipeStream stream, byte? byteToAcce } #nullable disable -#if !FEATURE_APM internal static async Task ReadAsync(Stream stream, byte[] buffer, int bytesToRead) { int totalBytesRead = 0; @@ -476,7 +473,6 @@ internal static async Task ReadAsync(Stream stream, byte[] buffer, int byte } return totalBytesRead; } -#endif /// /// Given the appropriate information, return the equivalent HandshakeOptions. diff --git a/src/Shared/NamedPipeUtil.cs b/src/Shared/NamedPipeUtil.cs index c6765e5bd76..43c88d8b483 100644 --- a/src/Shared/NamedPipeUtil.cs +++ b/src/Shared/NamedPipeUtil.cs @@ -6,7 +6,8 @@ using System.IO.Pipes; using System.Security.AccessControl; using System.Security.Principal; - +using System.Threading; +using System.Threading.Tasks; using Microsoft.Build.Internal; namespace Microsoft.Build.Shared diff --git a/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs b/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs index f1374324d0a..0f88509dcc1 100644 --- a/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs +++ b/src/Tasks/AssemblyDependency/ResolveAssemblyReference.cs @@ -2986,8 +2986,18 @@ public override bool Execute() var connected = client.Connect(); if (!connected) { - Log.LogMessage(MessageImportance.Low, "Couldn't connect to RAR node, starting new one"); - if (client.CreateNode()) + Log.LogMessageFromResources(MessageImportance.Low, "RarCouldntConnect"); + bool nodeCreated = false; + try + { + nodeCreated = client.CreateNode(); + } + catch (Exception e) + { + Log.LogWarningFromException(e); + } + + if (nodeCreated) { connected = client.Connect(5000); } diff --git a/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs b/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs index 92cc9bbfed8..f35dc0f61b4 100644 --- a/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs +++ b/src/Tasks/ResolveAssemblyReferences/Client/RarClient.cs @@ -7,10 +7,8 @@ using Microsoft.Build.Framework; using Microsoft.Build.Shared; using Microsoft.Build.Tasks.ResolveAssemblyReferences.Contract; -using Microsoft.Build.Tasks.ResolveAssemblyReferences.Server; using StreamJsonRpc; - namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Client { internal sealed class RarClient : IDisposable @@ -63,7 +61,7 @@ internal object Execute() private IResolveAssemblyReferenceTaskHandler GetRpcClient() { - ErrorUtilities.VerifyThrowInvalidOperation(_clientStream != null, nameof(_clientStream)); + ErrorUtilities.VerifyThrowInternalErrorUnreachable(_clientStream != null); IJsonRpcMessageHandler handler = RpcUtils.GetRarMessageHandler(_clientStream); return JsonRpc.Attach(handler); From f789e025c8693854fdd915b344ebb792209821fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Mon, 31 Aug 2020 17:50:03 +0200 Subject: [PATCH 55/61] Build fix --- src/Build/BackEnd/Node/RarNode.cs | 18 +++++++++++++++++- src/Shared/CommunicationsUtilities.cs | 6 +++++- src/Shared/NamedPipeUtil.cs | 2 +- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs index d55d362660c..4913e2c7f66 100644 --- a/src/Build/BackEnd/Node/RarNode.cs +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -4,6 +4,7 @@ using System; using System.CodeDom; using System.Diagnostics; +using System.IO; using System.IO.Pipes; using System.Reflection; using System.Threading; @@ -79,6 +80,21 @@ private async Task RunShutdownCheckAsync(Handshake han { string pipeName = NamedPipeUtil.GetPipeNameOrPath("MSBuild" + Process.GetCurrentProcess().Id); + static async Task ReadAsync(Stream stream, byte[] buffer, int bytesToRead) + { + int totalBytesRead = 0; + while (totalBytesRead < bytesToRead) + { + int bytesRead = await stream.ReadAsync(buffer, totalBytesRead, bytesToRead - totalBytesRead); + if (bytesRead == 0) + { + return totalBytesRead; + } + totalBytesRead += bytesRead; + } + return totalBytesRead; + } + // Most common path in this while loop in long run will be over the continue statement. // This is happeing because the MSBuild when starting new nodes is trying in some cases to reuse nodes (see nodeReuse switch). // It is done by listing the MSBuild processes and then connecting to them and validating the handshake. @@ -100,7 +116,7 @@ private async Task RunShutdownCheckAsync(Handshake han // 1 byte - Packet type // 4 bytes - packet length byte[] header = new byte[5]; - int bytesRead = await CommunicationsUtilities.ReadAsync(serverStream, header, header.Length).ConfigureAwait(false); + int bytesRead = await ReadAsync(serverStream, header, header.Length).ConfigureAwait(false); if (bytesRead != header.Length) { continue; diff --git a/src/Shared/CommunicationsUtilities.cs b/src/Shared/CommunicationsUtilities.cs index 7b39a83c1b6..a2a4dafbf2e 100644 --- a/src/Shared/CommunicationsUtilities.cs +++ b/src/Shared/CommunicationsUtilities.cs @@ -11,11 +11,13 @@ using System.Runtime.InteropServices; using System.Security.Principal; using System.Threading; -using System.Threading.Tasks; using Microsoft.Build.Shared; using Microsoft.Build.BackEnd.Logging; +#if !FEATURE_APM +using System.Threading.Tasks; +#endif namespace Microsoft.Build.Internal { @@ -459,6 +461,7 @@ internal static int ReadIntForHandshake(this PipeStream stream, byte? byteToAcce } #nullable disable +#if !FEATURE_APM internal static async Task ReadAsync(Stream stream, byte[] buffer, int bytesToRead) { int totalBytesRead = 0; @@ -473,6 +476,7 @@ internal static async Task ReadAsync(Stream stream, byte[] buffer, int byte } return totalBytesRead; } +#endif /// /// Given the appropriate information, return the equivalent HandshakeOptions. diff --git a/src/Shared/NamedPipeUtil.cs b/src/Shared/NamedPipeUtil.cs index 43c88d8b483..2c2f5a1062b 100644 --- a/src/Shared/NamedPipeUtil.cs +++ b/src/Shared/NamedPipeUtil.cs @@ -7,7 +7,6 @@ using System.Security.AccessControl; using System.Security.Principal; using System.Threading; -using System.Threading.Tasks; using Microsoft.Build.Internal; namespace Microsoft.Build.Shared @@ -36,6 +35,7 @@ internal static string GetPipeNameOrPath(string pipeName) return pipeName; } } + #if !FEATURE_PIPEOPTIONS_CURRENTUSERONLY // This code needs to be in a separate method so that we don't try (and fail) to load the Windows-only APIs when JIT-ing the code // on non-Windows operating systems From 4957c458d04f0c61980848b5a2b549b231264bea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Mon, 31 Aug 2020 18:24:55 +0200 Subject: [PATCH 56/61] Add handshake validation to the RAR connection --- .../Components/RequestBuilder/TaskHost.cs | 6 +++- src/Build/BackEnd/Node/RarNode.cs | 12 ++++--- src/Shared/CommunicationsUtilities.cs | 1 - src/Shared/NamedPipeUtil.cs | 31 ++++++++-------- src/Tasks/Microsoft.Build.Tasks.csproj | 6 ++++ .../Server/RarController.cs | 36 ++++++++++++++++++- 6 files changed, 67 insertions(+), 25 deletions(-) diff --git a/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs b/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs index 5e9a750c1f3..79bdff63bc3 100644 --- a/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs +++ b/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs @@ -1009,7 +1009,11 @@ string IRarBuildEngine.GetRarPipeName() /// NamedPipeClientStream IRarBuildEngine.GetRarClientStream(string pipeName, int timeout) { - return NamedPipeUtil.TryConnectToProcess(pipeName, timeout, null); + BuildParameters parameters = _host.BuildParameters; + Handshake handshake = NodeProviderOutOfProc.GetHandshake(enableNodeReuse: parameters.EnableNodeReuse, + enableLowPriority: parameters.LowPriority, specialNode: true); + + return NamedPipeUtil.TryConnectToProcess(pipeName, timeout, handshake); } } } diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs index 4913e2c7f66..e17230fd817 100644 --- a/src/Build/BackEnd/Node/RarNode.cs +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -34,12 +34,13 @@ public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Except shutdownException = null; using CancellationTokenSource cts = new CancellationTokenSource(); string pipeName = CommunicationsUtilities.GetRarPipeName(nodeReuse, lowPriority); - IRarController controller = GetController(pipeName); + Handshake handshake = NodeProviderOutOfProc.GetHandshake(enableNodeReuse: nodeReuse, + enableLowPriority: lowPriority, specialNode: true); + + IRarController controller = GetController(pipeName, handshake); Task rarTask = controller.StartAsync(cts.Token); - Handshake handshake = NodeProviderOutOfProc.GetHandshake(enableNodeReuse: nodeReuse, - enableLowPriority: lowPriority, specialNode: true); Task msBuildShutdown = RunShutdownCheckAsync(handshake, cts.Token); // Wait for any of these task to finish: @@ -60,12 +61,13 @@ public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Except } } - private static IRarController GetController(string pipeName) + private static IRarController GetController(string pipeName, Handshake handshake) { Type rarControllerType = Type.GetType(RarControllerName); Func streamFactory = NamedPipeUtil.CreateNamedPipeServer; - IRarController controller = Activator.CreateInstance(rarControllerType, pipeName, streamFactory, null) as IRarController; + Func validateCallback = NamedPipeUtil.ValidateHandshake; + IRarController controller = Activator.CreateInstance(rarControllerType, pipeName, handshake, streamFactory, validateCallback, null) as IRarController; ErrorUtilities.VerifyThrow(controller != null, ResourceUtilities.GetResourceString("RarControllerReflectionError"), RarControllerName); return controller; diff --git a/src/Shared/CommunicationsUtilities.cs b/src/Shared/CommunicationsUtilities.cs index a2a4dafbf2e..6ef1da20e51 100644 --- a/src/Shared/CommunicationsUtilities.cs +++ b/src/Shared/CommunicationsUtilities.cs @@ -13,7 +13,6 @@ using System.Threading; using Microsoft.Build.Shared; -using Microsoft.Build.BackEnd.Logging; #if !FEATURE_APM using System.Threading.Tasks; diff --git a/src/Shared/NamedPipeUtil.cs b/src/Shared/NamedPipeUtil.cs index 2c2f5a1062b..6daf5d24058 100644 --- a/src/Shared/NamedPipeUtil.cs +++ b/src/Shared/NamedPipeUtil.cs @@ -60,7 +60,7 @@ private static void ValidateRemotePipeSecurityOnWindows(NamedPipeClientStream no /// /// Attempts to connect to the specified process. /// - internal static NamedPipeClientStream TryConnectToProcess(int nodeProcessId, int timeout, Handshake? handshake) + internal static NamedPipeClientStream TryConnectToProcess(int nodeProcessId, int timeout, Handshake handshake) { string pipeName = GetPipeNameOrPath("MSBuild" + nodeProcessId); return TryConnectToProcess(pipeName, nodeProcessId, timeout, handshake); @@ -69,19 +69,19 @@ internal static NamedPipeClientStream TryConnectToProcess(int nodeProcessId, int /// /// Attempts to connect to the specified process. /// - internal static NamedPipeClientStream TryConnectToProcess(string pipeName, int timeout, Handshake? handshake) + internal static NamedPipeClientStream TryConnectToProcess(string pipeName, int timeout, Handshake handshake) { return TryConnectToProcess(pipeName, null, timeout, handshake); } - private static NamedPipeClientStream TryConnectToProcess(string pipeName, int? nodeProcessId, int timeout, Handshake? handshake) + private static NamedPipeClientStream TryConnectToProcess(string pipeName, int? nodeProcessId, int timeout, Handshake handshake) { NamedPipeClientStream nodeStream = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.Asynchronous #if FEATURE_PIPEOPTIONS_CURRENTUSERONLY | PipeOptions.CurrentUserOnly #endif ); - CommunicationsUtilities.Trace("Attempting connect to PID {0} with pipe {1} with timeout {2} ms", nodeProcessId.HasValue ? nodeProcessId.Value.ToString() : pipeName, pipeName, timeout); + CommunicationsUtilities.Trace("Attempting connect to PID {0} with pipe {1} with timeout {2} ms", nodeProcessId.HasValue ? nodeProcessId.Value.ToString() : pipeName, pipeName, timeout); try { @@ -99,27 +99,24 @@ private static NamedPipeClientStream TryConnectToProcess(string pipeName, int? n ValidateRemotePipeSecurityOnWindows(nodeStream); } #endif - if (handshake.HasValue) - { - int[] handshakeComponents = handshake.Value.RetrieveHandshakeComponents(); - for (int i = 0; i < handshakeComponents.Length; i++) - { - CommunicationsUtilities.Trace("Writing handshake part {0} to pipe {1}", i, pipeName); - nodeStream.WriteIntForHandshake(handshakeComponents[i]); - } + int[] handshakeComponents = handshake.RetrieveHandshakeComponents(); + for (int i = 0; i < handshakeComponents.Length; i++) + { + CommunicationsUtilities.Trace("Writing handshake part {0} to pipe {1}", i, pipeName); + nodeStream.WriteIntForHandshake(handshakeComponents[i]); + } - // This indicates that we have finished all the parts of our handshake; hopefully the endpoint has as well. - nodeStream.WriteEndOfHandshakeSignal(); + // This indicates that we have finished all the parts of our handshake; hopefully the endpoint has as well. + nodeStream.WriteEndOfHandshakeSignal(); - CommunicationsUtilities.Trace("Reading handshake from pipe {0}", pipeName); + CommunicationsUtilities.Trace("Reading handshake from pipe {0}", pipeName); #if NETCOREAPP2_1 || MONO nodeStream.ReadEndOfHandshakeSignal(true, timeout); #else - nodeStream.ReadEndOfHandshakeSignal(true); + nodeStream.ReadEndOfHandshakeSignal(true); #endif - } // We got a connection. CommunicationsUtilities.Trace("Successfully connected to pipe {0}...!", pipeName); diff --git a/src/Tasks/Microsoft.Build.Tasks.csproj b/src/Tasks/Microsoft.Build.Tasks.csproj index 9229fa0331c..68ef82202f4 100644 --- a/src/Tasks/Microsoft.Build.Tasks.csproj +++ b/src/Tasks/Microsoft.Build.Tasks.csproj @@ -215,6 +215,12 @@ true + + true + + + true + true diff --git a/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs b/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs index 18f4b9a3d43..0a1bf42b5ca 100644 --- a/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs +++ b/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.Build.Framework; +using Microsoft.Build.Internal; using Microsoft.Build.Shared; using Microsoft.Build.Tasks.ResolveAssemblyReferences.Contract; using Microsoft.Build.Tasks.ResolveAssemblyReferences.Services; @@ -20,11 +21,22 @@ namespace Microsoft.Build.Tasks.ResolveAssemblyReferences.Server { internal sealed class RarController : IRarController { + /// + /// The amount of time to wait for the validation of connection. + /// + private const int ValidationTimeout = 60000; + /// /// Name of /// private readonly string _pipeName; + /// + /// Handshake used for validaion of incoming connections + /// + private readonly Handshake _handshake; + + /// /// Factory callback to NamedPipeUtils.CreateNamedPipeServer /// 1. arg: pipe name @@ -35,6 +47,14 @@ internal sealed class RarController : IRarController /// private readonly Func _namedPipeServerFactory; + /// + /// Callback to validate the handshake. + /// 1. arg: expected handshake + /// 2. arg: named pipe over which we should validate the handshake + /// 3. arg: timeout for validation + /// + private readonly Func _validateHandshakeCallback; + /// /// Handler for all incoming tasks /// @@ -47,20 +67,31 @@ internal sealed class RarController : IRarController public RarController( string pipeName, + Handshake handshake, Func namedPipeServerFactory, + Func validateHandshakeCallback, TimeSpan? timeout = null) - : this(pipeName, namedPipeServerFactory, timeout: timeout, resolveAssemblyReferenceTaskHandler: new RarTaskHandler()) + : this(pipeName, + handshake, + namedPipeServerFactory, + validateHandshakeCallback, + timeout: timeout, + resolveAssemblyReferenceTaskHandler: new RarTaskHandler()) { } internal RarController( string pipeName, + Handshake handshake, Func namedPipeServerFactory, + Func validateHandshakeCallback, IResolveAssemblyReferenceTaskHandler resolveAssemblyReferenceTaskHandler, TimeSpan? timeout = null) { _pipeName = pipeName; + _handshake = handshake; _namedPipeServerFactory = namedPipeServerFactory; + _validateHandshakeCallback = validateHandshakeCallback; _resolveAssemblyReferenceTaskHandler = resolveAssemblyReferenceTaskHandler; if (timeout.HasValue) @@ -87,6 +118,9 @@ public async Task StartAsync(CancellationToken cancellationToken = default) NamedPipeServerStream serverStream = GetStream(_pipeName); await serverStream.WaitForConnectionAsync(token).ConfigureAwait(false); + if (!_validateHandshakeCallback(_handshake, serverStream, ValidationTimeout)) + continue; + // Connected! Refresh timeout for incoming request cancellationTokenSource.CancelAfter(Timeout); From 0adb1cf9dacf7f9facc5746d1d8c22bafda1f745 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Mon, 31 Aug 2020 21:50:02 +0200 Subject: [PATCH 57/61] Add node expiration timeout --- src/Build/BackEnd/Node/RarNode.cs | 29 ++++++++++++++++++++++++----- src/MSBuild/XMake.cs | 2 +- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs index e17230fd817..66b713c83ed 100644 --- a/src/Build/BackEnd/Node/RarNode.cs +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -29,7 +29,13 @@ public sealed class RarNode : INode /// private const string RarControllerName = "Microsoft.Build.Tasks.ResolveAssemblyReferences.Server.RarController, Microsoft.Build.Tasks.Core"; - public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Exception shutdownException) + + /// + /// Timeout for node shutdwon + /// + private static readonly TimeSpan NodeShutdownTimeout = TimeSpan.FromHours(1); + + public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Exception shutdownException, CancellationToken cancellationToken = default) { shutdownException = null; using CancellationTokenSource cts = new CancellationTokenSource(); @@ -43,10 +49,23 @@ public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Except Task msBuildShutdown = RunShutdownCheckAsync(handshake, cts.Token); - // Wait for any of these task to finish: - // - rarTask can timeout (default is 15 mins) - // - msBuildShutdown ends when it receives command to shutdown - int index = Task.WaitAny(msBuildShutdown, rarTask); + // Timeout for node, limits lifetime of node to 1 hour + cts.CancelAfter(NodeShutdownTimeout); + int index; + try + { + // Wait for any of these task to finish: + // - rarTask can timeout (default is 15 mins) + // - msBuildShutdown ends when it recieves command to shutdown + // - node lifetime expires + index = Task.WaitAny(new Task[] { msBuildShutdown, rarTask }, cts.Token); + } + catch (OperationCanceledException e) + { + shutdownException = e; + return NodeEngineShutdownReason.Error; + } + cts.Cancel(); if (index == 0) diff --git a/src/MSBuild/XMake.cs b/src/MSBuild/XMake.cs index 65d7bbc4030..0640d2d95e2 100644 --- a/src/MSBuild/XMake.cs +++ b/src/MSBuild/XMake.cs @@ -2650,7 +2650,7 @@ private static void StartLocalNode(CommandLineSwitches commandLineSwitches) string[] lowPriorityInput = commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.LowPriority]; bool lowPriority = lowPriorityInput.Length > 0 && string.Equals(lowPriorityInput[0], bool.TrueString, StringComparison.OrdinalIgnoreCase); - shutdownReason = node.Run(nodeReuse, lowPriority, out nodeException); + shutdownReason = node.Run(nodeReuse, lowPriority, out nodeException, s_buildCancellationSource.Token); } else { From a5ac71778a3f4b825903b5e3f34c62d14b2a555b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Tue, 1 Sep 2020 09:41:41 +0200 Subject: [PATCH 58/61] Missing ref files --- ref/Microsoft.Build/net/Microsoft.Build.cs | 2 +- ref/Microsoft.Build/netstandard/Microsoft.Build.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ref/Microsoft.Build/net/Microsoft.Build.cs b/ref/Microsoft.Build/net/Microsoft.Build.cs index d5f566b2fe9..870bbe7458a 100644 --- a/ref/Microsoft.Build/net/Microsoft.Build.cs +++ b/ref/Microsoft.Build/net/Microsoft.Build.cs @@ -1386,7 +1386,7 @@ internal ProjectTaskOutputPropertyInstance() { } public sealed partial class RarNode { public RarNode() { } - public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } + public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out System.Exception shutdownException, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken)) { shutdownException = default(System.Exception); throw null; } public Microsoft.Build.Execution.NodeEngineShutdownReason Run(out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } } public partial class RequestedProjectState diff --git a/ref/Microsoft.Build/netstandard/Microsoft.Build.cs b/ref/Microsoft.Build/netstandard/Microsoft.Build.cs index f486e9e19ad..a47f5848144 100644 --- a/ref/Microsoft.Build/netstandard/Microsoft.Build.cs +++ b/ref/Microsoft.Build/netstandard/Microsoft.Build.cs @@ -1380,7 +1380,7 @@ internal ProjectTaskOutputPropertyInstance() { } public sealed partial class RarNode { public RarNode() { } - public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } + public Microsoft.Build.Execution.NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out System.Exception shutdownException, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken)) { shutdownException = default(System.Exception); throw null; } public Microsoft.Build.Execution.NodeEngineShutdownReason Run(out System.Exception shutdownException) { shutdownException = default(System.Exception); throw null; } } public partial class RequestedProjectState From 3bceb4dcc2b86e071a008086971c59e17dd87448 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Tue, 1 Sep 2020 11:29:54 +0200 Subject: [PATCH 59/61] Apply suggestions from code review Typos Co-authored-by: Ladi Prosek --- src/Build/BackEnd/Node/RarNode.cs | 2 +- src/Build/Resources/Strings.resx | 2 +- src/Tasks/Resources/Strings.resx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs index 66b713c83ed..1e936df6900 100644 --- a/src/Build/BackEnd/Node/RarNode.cs +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -54,7 +54,7 @@ public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Except int index; try { - // Wait for any of these task to finish: + // Wait for any of these tasks to finish: // - rarTask can timeout (default is 15 mins) // - msBuildShutdown ends when it recieves command to shutdown // - node lifetime expires diff --git a/src/Build/Resources/Strings.resx b/src/Build/Resources/Strings.resx index 0196285954c..55a89a1db36 100644 --- a/src/Build/Resources/Strings.resx +++ b/src/Build/Resources/Strings.resx @@ -1835,6 +1835,6 @@ Utilization: {0} Average Utilization: {1:###.0} "EvaluationContext objects created with SharingPolicy.Isolated do not support being passed an MSBuildFileSystemBase file system." - Couldn't create instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type diff --git a/src/Tasks/Resources/Strings.resx b/src/Tasks/Resources/Strings.resx index 1311fc552be..b4f042b78b1 100644 --- a/src/Tasks/Resources/Strings.resx +++ b/src/Tasks/Resources/Strings.resx @@ -2932,6 +2932,6 @@ DOES have an error code. --> - Couldn't connect to RAR node, starting new one. + Couldn't connect to the RAR node, starting a new one. From c4e41e9302a6b552f7f151510237a439a960e199 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Tue, 1 Sep 2020 11:51:09 +0200 Subject: [PATCH 60/61] xlf files --- src/Build/Resources/xlf/Strings.cs.xlf | 4 ++-- src/Build/Resources/xlf/Strings.de.xlf | 4 ++-- src/Build/Resources/xlf/Strings.en.xlf | 4 ++-- src/Build/Resources/xlf/Strings.es.xlf | 4 ++-- src/Build/Resources/xlf/Strings.fr.xlf | 4 ++-- src/Build/Resources/xlf/Strings.it.xlf | 4 ++-- src/Build/Resources/xlf/Strings.ja.xlf | 4 ++-- src/Build/Resources/xlf/Strings.ko.xlf | 4 ++-- src/Build/Resources/xlf/Strings.pl.xlf | 4 ++-- src/Build/Resources/xlf/Strings.pt-BR.xlf | 4 ++-- src/Build/Resources/xlf/Strings.ru.xlf | 4 ++-- src/Build/Resources/xlf/Strings.tr.xlf | 4 ++-- src/Build/Resources/xlf/Strings.zh-Hans.xlf | 4 ++-- src/Build/Resources/xlf/Strings.zh-Hant.xlf | 4 ++-- src/Tasks/Resources/xlf/Strings.cs.xlf | 4 ++-- src/Tasks/Resources/xlf/Strings.de.xlf | 4 ++-- src/Tasks/Resources/xlf/Strings.en.xlf | 4 ++-- src/Tasks/Resources/xlf/Strings.es.xlf | 4 ++-- src/Tasks/Resources/xlf/Strings.fr.xlf | 4 ++-- src/Tasks/Resources/xlf/Strings.it.xlf | 4 ++-- src/Tasks/Resources/xlf/Strings.ja.xlf | 4 ++-- src/Tasks/Resources/xlf/Strings.ko.xlf | 4 ++-- src/Tasks/Resources/xlf/Strings.pl.xlf | 4 ++-- src/Tasks/Resources/xlf/Strings.pt-BR.xlf | 4 ++-- src/Tasks/Resources/xlf/Strings.ru.xlf | 4 ++-- src/Tasks/Resources/xlf/Strings.tr.xlf | 4 ++-- src/Tasks/Resources/xlf/Strings.zh-Hans.xlf | 4 ++-- src/Tasks/Resources/xlf/Strings.zh-Hant.xlf | 4 ++-- 28 files changed, 56 insertions(+), 56 deletions(-) diff --git a/src/Build/Resources/xlf/Strings.cs.xlf b/src/Build/Resources/xlf/Strings.cs.xlf index a48727fe3e6..5991f465065 100644 --- a/src/Build/Resources/xlf/Strings.cs.xlf +++ b/src/Build/Resources/xlf/Strings.cs.xlf @@ -179,8 +179,8 @@ - Couldn't create instance of IRarController for '{0}' type - Couldn't create instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.de.xlf b/src/Build/Resources/xlf/Strings.de.xlf index 3e4ceed782c..662d0f59824 100644 --- a/src/Build/Resources/xlf/Strings.de.xlf +++ b/src/Build/Resources/xlf/Strings.de.xlf @@ -179,8 +179,8 @@ - Couldn't create instance of IRarController for '{0}' type - Couldn't create instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.en.xlf b/src/Build/Resources/xlf/Strings.en.xlf index 607780a32e2..9558c861f7b 100644 --- a/src/Build/Resources/xlf/Strings.en.xlf +++ b/src/Build/Resources/xlf/Strings.en.xlf @@ -179,8 +179,8 @@ - Couldn't create instance of IRarController for '{0}' type - Couldn't create instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.es.xlf b/src/Build/Resources/xlf/Strings.es.xlf index e129cd05c78..09e2180e0a3 100644 --- a/src/Build/Resources/xlf/Strings.es.xlf +++ b/src/Build/Resources/xlf/Strings.es.xlf @@ -179,8 +179,8 @@ - Couldn't create instance of IRarController for '{0}' type - Couldn't create instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.fr.xlf b/src/Build/Resources/xlf/Strings.fr.xlf index c6266cce6f2..f578b5ce53b 100644 --- a/src/Build/Resources/xlf/Strings.fr.xlf +++ b/src/Build/Resources/xlf/Strings.fr.xlf @@ -179,8 +179,8 @@ - Couldn't create instance of IRarController for '{0}' type - Couldn't create instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.it.xlf b/src/Build/Resources/xlf/Strings.it.xlf index 5f32313ebde..e583fca423e 100644 --- a/src/Build/Resources/xlf/Strings.it.xlf +++ b/src/Build/Resources/xlf/Strings.it.xlf @@ -179,8 +179,8 @@ - Couldn't create instance of IRarController for '{0}' type - Couldn't create instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.ja.xlf b/src/Build/Resources/xlf/Strings.ja.xlf index 411fe1abf5b..f25b31b5d56 100644 --- a/src/Build/Resources/xlf/Strings.ja.xlf +++ b/src/Build/Resources/xlf/Strings.ja.xlf @@ -179,8 +179,8 @@ - Couldn't create instance of IRarController for '{0}' type - Couldn't create instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.ko.xlf b/src/Build/Resources/xlf/Strings.ko.xlf index a44701756a5..79ffea47246 100644 --- a/src/Build/Resources/xlf/Strings.ko.xlf +++ b/src/Build/Resources/xlf/Strings.ko.xlf @@ -179,8 +179,8 @@ - Couldn't create instance of IRarController for '{0}' type - Couldn't create instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.pl.xlf b/src/Build/Resources/xlf/Strings.pl.xlf index 0d82a057943..107873c75b5 100644 --- a/src/Build/Resources/xlf/Strings.pl.xlf +++ b/src/Build/Resources/xlf/Strings.pl.xlf @@ -179,8 +179,8 @@ - Couldn't create instance of IRarController for '{0}' type - Couldn't create instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.pt-BR.xlf b/src/Build/Resources/xlf/Strings.pt-BR.xlf index bbaf3825ed2..dcd153df703 100644 --- a/src/Build/Resources/xlf/Strings.pt-BR.xlf +++ b/src/Build/Resources/xlf/Strings.pt-BR.xlf @@ -179,8 +179,8 @@ - Couldn't create instance of IRarController for '{0}' type - Couldn't create instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.ru.xlf b/src/Build/Resources/xlf/Strings.ru.xlf index 549997c9557..eeb54ff9174 100644 --- a/src/Build/Resources/xlf/Strings.ru.xlf +++ b/src/Build/Resources/xlf/Strings.ru.xlf @@ -179,8 +179,8 @@ - Couldn't create instance of IRarController for '{0}' type - Couldn't create instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.tr.xlf b/src/Build/Resources/xlf/Strings.tr.xlf index c290c26e54b..9854cc7ddfa 100644 --- a/src/Build/Resources/xlf/Strings.tr.xlf +++ b/src/Build/Resources/xlf/Strings.tr.xlf @@ -179,8 +179,8 @@ - Couldn't create instance of IRarController for '{0}' type - Couldn't create instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.zh-Hans.xlf b/src/Build/Resources/xlf/Strings.zh-Hans.xlf index 393fa931cb3..e2ca02b06c7 100644 --- a/src/Build/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/Build/Resources/xlf/Strings.zh-Hans.xlf @@ -179,8 +179,8 @@ - Couldn't create instance of IRarController for '{0}' type - Couldn't create instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type diff --git a/src/Build/Resources/xlf/Strings.zh-Hant.xlf b/src/Build/Resources/xlf/Strings.zh-Hant.xlf index 3f4d27b7007..15c7df1bd3c 100644 --- a/src/Build/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/Build/Resources/xlf/Strings.zh-Hant.xlf @@ -179,8 +179,8 @@ - Couldn't create instance of IRarController for '{0}' type - Couldn't create instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type + Couldn't create an instance of IRarController for '{0}' type diff --git a/src/Tasks/Resources/xlf/Strings.cs.xlf b/src/Tasks/Resources/xlf/Strings.cs.xlf index a8c27562377..07dc426327a 100644 --- a/src/Tasks/Resources/xlf/Strings.cs.xlf +++ b/src/Tasks/Resources/xlf/Strings.cs.xlf @@ -1413,8 +1413,8 @@ LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". - Couldn't connect to RAR node, starting new one. - Couldn't connect to RAR node, starting new one. + Couldn't connect to the RAR node, starting a new one. + Couldn't connect to the RAR node, starting a new one. diff --git a/src/Tasks/Resources/xlf/Strings.de.xlf b/src/Tasks/Resources/xlf/Strings.de.xlf index 39dc594d128..dbd4ddf4d4a 100644 --- a/src/Tasks/Resources/xlf/Strings.de.xlf +++ b/src/Tasks/Resources/xlf/Strings.de.xlf @@ -1413,8 +1413,8 @@ LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". - Couldn't connect to RAR node, starting new one. - Couldn't connect to RAR node, starting new one. + Couldn't connect to the RAR node, starting a new one. + Couldn't connect to the RAR node, starting a new one. diff --git a/src/Tasks/Resources/xlf/Strings.en.xlf b/src/Tasks/Resources/xlf/Strings.en.xlf index 58c6115a3e7..3d7361d1f1a 100644 --- a/src/Tasks/Resources/xlf/Strings.en.xlf +++ b/src/Tasks/Resources/xlf/Strings.en.xlf @@ -1458,8 +1458,8 @@ LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". - Couldn't connect to RAR node, starting new one. - Couldn't connect to RAR node, starting new one. + Couldn't connect to the RAR node, starting a new one. + Couldn't connect to the RAR node, starting a new one. diff --git a/src/Tasks/Resources/xlf/Strings.es.xlf b/src/Tasks/Resources/xlf/Strings.es.xlf index c5694f5779b..b60d06690f4 100644 --- a/src/Tasks/Resources/xlf/Strings.es.xlf +++ b/src/Tasks/Resources/xlf/Strings.es.xlf @@ -1413,8 +1413,8 @@ LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". - Couldn't connect to RAR node, starting new one. - Couldn't connect to RAR node, starting new one. + Couldn't connect to the RAR node, starting a new one. + Couldn't connect to the RAR node, starting a new one. diff --git a/src/Tasks/Resources/xlf/Strings.fr.xlf b/src/Tasks/Resources/xlf/Strings.fr.xlf index 625b19f49e4..75f298b0fc9 100644 --- a/src/Tasks/Resources/xlf/Strings.fr.xlf +++ b/src/Tasks/Resources/xlf/Strings.fr.xlf @@ -1413,8 +1413,8 @@ LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". - Couldn't connect to RAR node, starting new one. - Couldn't connect to RAR node, starting new one. + Couldn't connect to the RAR node, starting a new one. + Couldn't connect to the RAR node, starting a new one. diff --git a/src/Tasks/Resources/xlf/Strings.it.xlf b/src/Tasks/Resources/xlf/Strings.it.xlf index ac76beccc8e..3cb72b5dacf 100644 --- a/src/Tasks/Resources/xlf/Strings.it.xlf +++ b/src/Tasks/Resources/xlf/Strings.it.xlf @@ -1413,8 +1413,8 @@ LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". - Couldn't connect to RAR node, starting new one. - Couldn't connect to RAR node, starting new one. + Couldn't connect to the RAR node, starting a new one. + Couldn't connect to the RAR node, starting a new one. diff --git a/src/Tasks/Resources/xlf/Strings.ja.xlf b/src/Tasks/Resources/xlf/Strings.ja.xlf index 1d85ce7b6ea..e78fb6b8d75 100644 --- a/src/Tasks/Resources/xlf/Strings.ja.xlf +++ b/src/Tasks/Resources/xlf/Strings.ja.xlf @@ -1413,8 +1413,8 @@ LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". - Couldn't connect to RAR node, starting new one. - Couldn't connect to RAR node, starting new one. + Couldn't connect to the RAR node, starting a new one. + Couldn't connect to the RAR node, starting a new one. diff --git a/src/Tasks/Resources/xlf/Strings.ko.xlf b/src/Tasks/Resources/xlf/Strings.ko.xlf index 7a637847c9a..e3dfd3ff47c 100644 --- a/src/Tasks/Resources/xlf/Strings.ko.xlf +++ b/src/Tasks/Resources/xlf/Strings.ko.xlf @@ -1413,8 +1413,8 @@ LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". - Couldn't connect to RAR node, starting new one. - Couldn't connect to RAR node, starting new one. + Couldn't connect to the RAR node, starting a new one. + Couldn't connect to the RAR node, starting a new one. diff --git a/src/Tasks/Resources/xlf/Strings.pl.xlf b/src/Tasks/Resources/xlf/Strings.pl.xlf index 96cc723b3f8..deed816c0a7 100644 --- a/src/Tasks/Resources/xlf/Strings.pl.xlf +++ b/src/Tasks/Resources/xlf/Strings.pl.xlf @@ -1413,8 +1413,8 @@ LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". - Couldn't connect to RAR node, starting new one. - Couldn't connect to RAR node, starting new one. + Couldn't connect to the RAR node, starting a new one. + Couldn't connect to the RAR node, starting a new one. diff --git a/src/Tasks/Resources/xlf/Strings.pt-BR.xlf b/src/Tasks/Resources/xlf/Strings.pt-BR.xlf index 1fb88f22573..5a8373c8e40 100644 --- a/src/Tasks/Resources/xlf/Strings.pt-BR.xlf +++ b/src/Tasks/Resources/xlf/Strings.pt-BR.xlf @@ -1413,8 +1413,8 @@ LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". - Couldn't connect to RAR node, starting new one. - Couldn't connect to RAR node, starting new one. + Couldn't connect to the RAR node, starting a new one. + Couldn't connect to the RAR node, starting a new one. diff --git a/src/Tasks/Resources/xlf/Strings.ru.xlf b/src/Tasks/Resources/xlf/Strings.ru.xlf index a2c59b35fdd..8c9da6b1782 100644 --- a/src/Tasks/Resources/xlf/Strings.ru.xlf +++ b/src/Tasks/Resources/xlf/Strings.ru.xlf @@ -1413,8 +1413,8 @@ LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". - Couldn't connect to RAR node, starting new one. - Couldn't connect to RAR node, starting new one. + Couldn't connect to the RAR node, starting a new one. + Couldn't connect to the RAR node, starting a new one. diff --git a/src/Tasks/Resources/xlf/Strings.tr.xlf b/src/Tasks/Resources/xlf/Strings.tr.xlf index 5180e0e5a07..97e1112b975 100644 --- a/src/Tasks/Resources/xlf/Strings.tr.xlf +++ b/src/Tasks/Resources/xlf/Strings.tr.xlf @@ -1413,8 +1413,8 @@ LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". - Couldn't connect to RAR node, starting new one. - Couldn't connect to RAR node, starting new one. + Couldn't connect to the RAR node, starting a new one. + Couldn't connect to the RAR node, starting a new one. diff --git a/src/Tasks/Resources/xlf/Strings.zh-Hans.xlf b/src/Tasks/Resources/xlf/Strings.zh-Hans.xlf index 936b248b2d8..cbe8fdeb67a 100644 --- a/src/Tasks/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/Tasks/Resources/xlf/Strings.zh-Hans.xlf @@ -1413,8 +1413,8 @@ LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". - Couldn't connect to RAR node, starting new one. - Couldn't connect to RAR node, starting new one. + Couldn't connect to the RAR node, starting a new one. + Couldn't connect to the RAR node, starting a new one. diff --git a/src/Tasks/Resources/xlf/Strings.zh-Hant.xlf b/src/Tasks/Resources/xlf/Strings.zh-Hant.xlf index 62425445b92..42739e5841a 100644 --- a/src/Tasks/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/Tasks/Resources/xlf/Strings.zh-Hant.xlf @@ -1413,8 +1413,8 @@ LOCALIZATION: Do not localize the words "RunEachTargetSeparately", "BuildingInParallel", or "StopOnFirstFailure". - Couldn't connect to RAR node, starting new one. - Couldn't connect to RAR node, starting new one. + Couldn't connect to the RAR node, starting a new one. + Couldn't connect to the RAR node, starting a new one. From d82b3f30c57d24512857a751c83c5e5bf02a225b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0torc?= Date: Tue, 1 Sep 2020 12:59:43 +0200 Subject: [PATCH 61/61] Typos and small refactoring --- src/Build/BackEnd/BuildManager/BuildManager.cs | 13 ++++--------- .../BackEnd/Components/RequestBuilder/TaskHost.cs | 5 ++--- src/Build/BackEnd/Node/RarNode.cs | 12 ++++++------ .../Server/RarController.cs | 2 +- 4 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index f9881722a7d..a78e25f2103 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -64,11 +64,6 @@ public class BuildManager : INodePacketHandler, IBuildComponentHost, IDisposable /// private static int s_nextBuildRequestConfigurationId; - /// - /// If this value is returened by then RAR node wasn't started - /// - internal const int RarNodeStartFailed = -1; - /// /// The cache for build request configurations. /// @@ -2023,24 +2018,24 @@ private void PerformSchedulingActions(IEnumerable responses) } } - internal int CreateRarNode() + internal bool CreateRarNode() { // If the _buildParametrs is not set, we are in OutOfProc mode, so continue // Else check if users specified that he want to use multiple nodes, if so use RARaaS if (_buildParameters?.MaxNodeCount == 1) - return RarNodeStartFailed; + return false; string nodeLocation = _buildParameters?.NodeExeLocation ?? BuildEnvironmentHelper.Instance.CurrentMSBuildExePath; if (string.IsNullOrEmpty(nodeLocation)) { // Couldn't find a path to MSBuild.exe; can't create a new node. - return RarNodeStartFailed; + return false; } bool nodeReuse = _buildParameters?.EnableNodeReuse ?? true; bool lowPriority = _buildParameters?.LowPriority ?? false; string commandLineArgs = $"/nologo /nodemode:3 /nodeReuse:{nodeReuse} /low:{lowPriority}"; - return NodeProviderOutOfProcBase.LaunchNode(nodeLocation, commandLineArgs); + return NodeProviderOutOfProcBase.LaunchNode(nodeLocation, commandLineArgs) != -1; } /// diff --git a/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs b/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs index 79bdff63bc3..074df8881d9 100644 --- a/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs +++ b/src/Build/BackEnd/Components/RequestBuilder/TaskHost.cs @@ -987,12 +987,11 @@ private void VerifyActiveProxy() } /// - /// Inialize new RAR node + /// Initialize new RAR node /// bool IRarBuildEngine.CreateRarNode() { - int nodeId = BuildManager.DefaultBuildManager.CreateRarNode(); - return nodeId != BuildManager.RarNodeStartFailed; + return BuildManager.DefaultBuildManager.CreateRarNode(); } /// diff --git a/src/Build/BackEnd/Node/RarNode.cs b/src/Build/BackEnd/Node/RarNode.cs index 1e936df6900..888c24215d8 100644 --- a/src/Build/BackEnd/Node/RarNode.cs +++ b/src/Build/BackEnd/Node/RarNode.cs @@ -31,7 +31,7 @@ public sealed class RarNode : INode /// - /// Timeout for node shutdwon + /// Timeout for node shutdown /// private static readonly TimeSpan NodeShutdownTimeout = TimeSpan.FromHours(1); @@ -55,8 +55,8 @@ public NodeEngineShutdownReason Run(bool nodeReuse, bool lowPriority, out Except try { // Wait for any of these tasks to finish: - // - rarTask can timeout (default is 15 mins) - // - msBuildShutdown ends when it recieves command to shutdown + // - rarTask can timeout (default is 15 minutes) + // - msBuildShutdown ends when it receives command to shutdown // - node lifetime expires index = Task.WaitAny(new Task[] { msBuildShutdown, rarTask }, cts.Token); } @@ -117,10 +117,10 @@ static async Task ReadAsync(Stream stream, byte[] buffer, int bytesToRead) } // Most common path in this while loop in long run will be over the continue statement. - // This is happeing because the MSBuild when starting new nodes is trying in some cases to reuse nodes (see nodeReuse switch). + // This is happening because the MSBuild when starting new nodes is trying in some cases to reuse nodes (see nodeReuse switch). // It is done by listing the MSBuild processes and then connecting to them and validating the handshake. // In most cases for this loop it will fail, which will lead to hitting the continue statement. - // If we get over that, the MSBuild should send NodeBuildComplete packet, which will indicate that the engine is requesting to shtudown this node. + // If we get over that, the MSBuild should send NodeBuildComplete packet, which will indicate that the engine is requesting to shutdown this node. while (true) { if (cancellationToken.IsCancellationRequested) @@ -133,7 +133,7 @@ static async Task ReadAsync(Stream stream, byte[] buffer, int bytesToRead) if (!connected) continue; - // Header consits of: + // Header consists of: // 1 byte - Packet type // 4 bytes - packet length byte[] header = new byte[5]; diff --git a/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs b/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs index 0a1bf42b5ca..2852a7d620f 100644 --- a/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs +++ b/src/Tasks/ResolveAssemblyReferences/Server/RarController.cs @@ -32,7 +32,7 @@ internal sealed class RarController : IRarController private readonly string _pipeName; /// - /// Handshake used for validaion of incoming connections + /// Handshake used for validation of incoming connections /// private readonly Handshake _handshake;