/// <summary> /// Make sure a node in the requested context exists. /// </summary> internal bool AcquireAndSetUpHost(TaskHostContext hostContext, INodePacketFactory factory, INodePacketHandler handler, TaskHostConfiguration configuration) { NodeContext context = null; bool nodeCreationSucceeded = false; if (!(_nodeContexts.TryGetValue(hostContext, out context))) { nodeCreationSucceeded = CreateNode(hostContext, factory, handler, configuration); } else { // node already exists, so "creation" automatically succeeded nodeCreationSucceeded = true; } if (nodeCreationSucceeded) { context = _nodeContexts[hostContext]; _nodeIdToPacketFactory[(int)hostContext] = factory; _nodeIdToPacketHandler[(int)hostContext] = handler; // Configure the node. context.SendData(configuration); return(true); } return(false); }
/// <summary> /// Shuts down all of the managed nodes permanently. /// </summary> /// <param name="hostHandshake">host handshake key</param> /// <param name="clientHandshake">client handshake key</param> /// <param name="terminateNode">Delegate used to tell the node provider that a context has terminated</param> protected void ShutdownAllNodes(long hostHandshake, long clientHandshake, NodeContextTerminateDelegate terminateNode) { #if FEATURE_NAMED_PIPES_FULL_DUPLEX // INodePacketFactory INodePacketFactory factory = new NodePacketFactory(); List <Process> nodeProcesses = GetPossibleRunningNodes(); // Find proper MSBuildTaskHost executable name string msbuildtaskhostExeName = NodeProviderOutOfProcTaskHost.TaskHostNameForClr2TaskHost; // Search for all instances of msbuildtaskhost process and add them to the process list nodeProcesses.AddRange(new List <Process>(Process.GetProcessesByName(Path.GetFileNameWithoutExtension(msbuildtaskhostExeName)))); // For all processes in the list, send signal to terminate if able to connect foreach (Process nodeProcess in nodeProcesses) { Stream nodeStream = TryConnectToProcess(nodeProcess.Id, 30 /*verified to miss nodes if smaller*/, hostHandshake, clientHandshake); if (null != nodeStream) { // 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); NodeContext nodeContext = new NodeContext(0, nodeProcess.Id, nodeStream, factory, terminateNode); nodeContext.SendData(new NodeBuildComplete(false /* no node reuse */)); nodeStream.Dispose(); } } #else throw new PlatformNotSupportedException("Shutting down nodes by enumerating processes and connecting to them is not supported when using anonymous pipes."); #endif }
/// <summary> /// Shuts down all of the managed nodes permanently. /// </summary> /// <param name="nodeReuse">Whether to reuse the node</param> /// <param name="terminateNode">Delegate used to tell the node provider that a context has terminated</param> protected void ShutdownAllNodes(bool nodeReuse, NodeContextTerminateDelegate terminateNode) { // INodePacketFactory INodePacketFactory factory = new NodePacketFactory(); List <Process> nodeProcesses = GetPossibleRunningNodes().nodeProcesses; // Find proper MSBuildTaskHost executable name string msbuildtaskhostExeName = NodeProviderOutOfProcTaskHost.TaskHostNameForClr2TaskHost; // Search for all instances of msbuildtaskhost process and add them to the process list nodeProcesses.AddRange(new List <Process>(Process.GetProcessesByName(Path.GetFileNameWithoutExtension(msbuildtaskhostExeName)))); // For all processes in the list, send signal to terminate if able to connect foreach (Process nodeProcess in nodeProcesses) { // 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)); // 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. 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, enableLowPriority: true, specialNode: true)); 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); NodeContext nodeContext = new NodeContext(0, nodeProcess.Id, nodeStream, factory, terminateNode); nodeContext.SendData(new NodeBuildComplete(false /* no node reuse */)); nodeStream.Dispose(); } } }
/// <summary> /// Instantiates a new MSBuild process acting as a child node. /// </summary> public bool CreateNode(int nodeId, INodePacketFactory factory, NodeConfiguration configuration) { ErrorUtilities.VerifyThrowArgumentNull(factory, "factory"); if (_nodeContexts.Count == ComponentHost.BuildParameters.MaxNodeCount) { ErrorUtilities.ThrowInternalError("All allowable nodes already created ({0}).", _nodeContexts.Count); 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. string commandLineArgs = " /nologo /nodemode:1 "; // Enable node re-use if it is set. if (ComponentHost.BuildParameters.EnableNodeReuse) { commandLineArgs += "/nr"; } // Make it here. CommunicationsUtilities.Trace("Starting to acquire a new or existing node to establish node ID {0}...", nodeId); NodeContext context = GetNode(null, commandLineArgs, nodeId, factory, NodeProviderOutOfProc.HostHandshake, NodeProviderOutOfProc.ClientHandshake, NodeContextTerminated); if (null != context) { _nodeContexts[nodeId] = context; // Start the asynchronous read. context.BeginAsyncPacketRead(); // Configure the node. context.SendData(configuration); return(true); } throw new BuildAbortedException(ResourceUtilities.FormatResourceString("CouldNotConnectToMSBuildExe", ComponentHost.BuildParameters.NodeExeLocation)); }
/// <summary> /// Instantiates a new MSBuild process acting as a child node. /// </summary> public bool CreateNode(int nodeId, INodePacketFactory factory, NodeConfiguration configuration) { ErrorUtilities.VerifyThrowArgumentNull(factory, "factory"); if (_nodeContexts.Count == ComponentHost.BuildParameters.MaxNodeCount) { ErrorUtilities.ThrowInternalError("All allowable nodes already created ({0}).", _nodeContexts.Count); 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: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); 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); if (null != context) { _nodeContexts[nodeId] = context; // Start the asynchronous read. context.BeginAsyncPacketRead(); // Configure the node. context.SendData(configuration); return(true); } throw new BuildAbortedException(ResourceUtilities.FormatResourceStringStripCodeAndKeyword("CouldNotConnectToMSBuildExe", ComponentHost.BuildParameters.NodeExeLocation)); }
/// <summary> /// Shuts down all of the managed nodes permanently. /// </summary> /// <param name="hostHandshake">host handshake key</param> /// <param name="clientHandshake">client handshake key</param> /// <param name="terminateNode">Delegate used to tell the node provider that a context has terminated</param> protected void ShutdownAllNodes(long hostHandshake, long clientHandshake, NodeContextTerminateDelegate terminateNode) { // INodePacketFactory INodePacketFactory factory = new NodePacketFactory(); // Find proper msbuild executable name string msbuildExeName = Environment.GetEnvironmentVariable("MSBUILD_EXE_NAME"); if (String.IsNullOrEmpty(msbuildExeName)) { msbuildExeName = "MSBuild.exe"; } // Search for all instances of the msbuild process and create a list of them List <Process> nodeProcesses = new List <Process>(Process.GetProcessesByName(Path.GetFileNameWithoutExtension(msbuildExeName))); // Find proper MSBuildTaskHost executable name string msbuildtaskhostExeName = NodeProviderOutOfProcTaskHost.TaskHostNameForClr2TaskHost; // Search for all instances of msbuildtaskhost process and add them to the process list nodeProcesses.AddRange(new List <Process>(Process.GetProcessesByName(Path.GetFileNameWithoutExtension(msbuildtaskhostExeName)))); // For all processes in the list, send signal to terminate if able to connect foreach (Process nodeProcess in nodeProcesses) { NamedPipeClientStream nodeStream = TryConnectToProcess(nodeProcess.Id, 30 /*verified to miss nodes if smaller*/, hostHandshake, clientHandshake); if (null != nodeStream) { // 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); NodeContext nodeContext = new NodeContext(0, nodeProcess.Id, nodeStream, factory, terminateNode); nodeContext.SendData(new NodeBuildComplete(false /* no node reuse */)); nodeStream.Close(); } } }
/// <summary> /// Sends data to the specified node. /// </summary> /// <param name="context">The node to which data shall be sent.</param> /// <param name="packet">The packet to send.</param> protected void SendData(NodeContext context, INodePacket packet) { ErrorUtilities.VerifyThrowArgumentNull(packet, nameof(packet)); context.SendData(packet); }
/// <summary> /// Sends data to the specified node. /// </summary> /// <param name="context">The node to which data shall be sent.</param> /// <param name="packet">The packet to send.</param> protected void SendData(NodeContext context, INodePacket packet) { ErrorUtilities.VerifyThrowArgumentNull(packet, "packet"); context.SendData(packet); }
/// <summary> /// Shuts down all of the managed nodes permanently. /// </summary> /// <param name="hostHandshake">host handshake key</param> /// <param name="clientHandshake">client handshake key</param> /// <param name="terminateNode">Delegate used to tell the node provider that a context has terminated</param> protected void ShutdownAllNodes(long hostHandshake, long clientHandshake, NodeContextTerminateDelegate terminateNode) { // INodePacketFactory INodePacketFactory factory = new NodePacketFactory(); // Find proper msbuild executable name string msbuildExeName = Environment.GetEnvironmentVariable("MSBUILD_EXE_NAME"); if (String.IsNullOrEmpty(msbuildExeName)) { msbuildExeName = "MSBuild.exe"; } // Search for all instances of the msbuild process and create a list of them List<Process> nodeProcesses = new List<Process>(Process.GetProcessesByName(Path.GetFileNameWithoutExtension(msbuildExeName))); // Find proper MSBuildTaskHost executable name string msbuildtaskhostExeName = NodeProviderOutOfProcTaskHost.TaskHostNameForClr2TaskHost; // Search for all instances of msbuildtaskhost process and add them to the process list nodeProcesses.AddRange(new List<Process>(Process.GetProcessesByName(Path.GetFileNameWithoutExtension(msbuildtaskhostExeName)))); // For all processes in the list, send signal to terminate if able to connect foreach (Process nodeProcess in nodeProcesses) { NamedPipeClientStream nodeStream = TryConnectToProcess(nodeProcess.Id, 30/*verified to miss nodes if smaller*/, hostHandshake, clientHandshake); if (null != nodeStream) { // 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); NodeContext nodeContext = new NodeContext(0, nodeProcess.Id, nodeStream, factory, terminateNode); nodeContext.SendData(new NodeBuildComplete(false /* no node reuse */)); nodeStream.Close(); } } }