/// <summary> /// Handles the NodeBuildComplete packet. /// </summary> private void HandleNodeBuildComplete(NodeBuildComplete buildComplete) { ErrorUtilities.VerifyThrow(!_isTaskExecuting, "We should never have a task in the process of executing when we receive NodeBuildComplete."); _shutdownReason = buildComplete.PrepareForReuse ? NodeEngineShutdownReason.BuildCompleteReuse : NodeEngineShutdownReason.BuildComplete; _shutdownEvent.Set(); }
/// <summary> /// The task has been completed /// </summary> private void CompleteTask() { ErrorUtilities.VerifyThrow(_isTaskExecuting == false, "The task should be done executing before CompleteTask."); if (_nodeEndpoint.LinkStatus == LinkStatus.Active) { TaskHostTaskComplete taskCompletePacketToSend; lock (_taskCompleteLock) { ErrorUtilities.VerifyThrowInternalNull(_taskCompletePacket, "taskCompletePacket"); taskCompletePacketToSend = _taskCompletePacket; _taskCompletePacket = null; } _nodeEndpoint.SendData(taskCompletePacketToSend); } _currentConfiguration = null; // If the task has been canceled, the event will still be set. // If so, now that we've completed the task, we want to shut down // this node -- with no reuse, since we don't know whether the // task we canceled left the node in a good state or not. if (_taskCancelledEvent.WaitOne(0, false)) { _shutdownReason = NodeEngineShutdownReason.BuildComplete; _shutdownEvent.Set(); } }
private void HandleNodeBuildComplete(NodeBuildComplete buildComplete) { _shutdownReason = buildComplete.PrepareForReuse ? NodeEngineShutdownReason.BuildCompleteReuse : NodeEngineShutdownReason.BuildComplete; if (_shutdownReason == NodeEngineShutdownReason.BuildCompleteReuse) { ProcessPriorityClass priorityClass = Process.GetCurrentProcess().PriorityClass; if (priorityClass != ProcessPriorityClass.Normal && priorityClass != ProcessPriorityClass.BelowNormal) { // This isn't a priority class known by MSBuild. We should avoid connecting to this node. _shutdownReason = NodeEngineShutdownReason.BuildComplete; } else { bool lowPriority = priorityClass == ProcessPriorityClass.BelowNormal; if (_nodeEndpoint.LowPriority != lowPriority) { if (!lowPriority || NativeMethodsShared.IsWindows) { Process.GetCurrentProcess().PriorityClass = lowPriority ? ProcessPriorityClass.Normal : ProcessPriorityClass.BelowNormal; } else { // On *nix, we can't adjust the priority up, so to avoid using this node at the wrong priority, we should not be reused. _shutdownReason = NodeEngineShutdownReason.BuildComplete; } } } } _shutdownEvent.Set(); }
/// <summary> /// Starts up the node and processes messages until the node is requested to shut down. /// </summary> /// <param name="enableReuse">Whether this node is eligible for reuse later.</param> /// <param name="shutdownException">The exception which caused shutdown, if any.</param> /// <returns>The reason for shutting down.</returns> public NodeEngineShutdownReason Run(bool enableReuse, out Exception shutdownException) { #if FEATURE_NAMED_PIPES_FULL_DUPLEX // Console.WriteLine("Run called at {0}", DateTime.Now); string pipeName = "MSBuild" + Process.GetCurrentProcess().Id; _nodeEndpoint = new NodeEndpointOutOfProc(pipeName, this, enableReuse); #else _nodeEndpoint = new NodeEndpointOutOfProc(_clientToServerPipeHandle, _serverToClientPipeHandle, this, enableReuse); #endif _nodeEndpoint.OnLinkStatusChanged += new LinkStatusChangedDelegate(OnLinkStatusChanged); _nodeEndpoint.Listen(this); WaitHandle[] waitHandles = new WaitHandle[] { _shutdownEvent, _packetReceivedEvent }; // Get the current directory before doing any work. We need this so we can restore the directory when the node shutsdown. while (true) { int index = WaitHandle.WaitAny(waitHandles); switch (index) { case 0: NodeEngineShutdownReason shutdownReason = HandleShutdown(out shutdownException); return(shutdownReason); case 1: INodePacket packet = null; int packetCount = _receivedPackets.Count; while (packetCount > 0) { lock (_receivedPackets) { if (_receivedPackets.Count > 0) { packet = _receivedPackets.Dequeue(); } else { break; } } if (packet != null) { HandlePacket(packet); } } break; } } // UNREACHABLE }
/// <summary> /// Event handler for the node endpoint's LinkStatusChanged event. /// </summary> private void OnLinkStatusChanged(INodeEndpoint endpoint, LinkStatus status) { switch (status) { case LinkStatus.ConnectionFailed: case LinkStatus.Failed: _shutdownReason = NodeEngineShutdownReason.ConnectionFailed; _shutdownEvent.Set(); break; case LinkStatus.Inactive: break; } }
/// <summary> /// Orchestrates the execution of the application. /// Also responsible for top-level error handling. /// </summary> /// <returns> /// A value of Success if the bootstrapping succeeds /// </returns> internal static ExitType Execute() { switch (Environment.GetEnvironmentVariable("MSBUILDDEBUGONSTART")) { #if FEATURE_DEBUG_LAUNCH case "1": Debugger.Launch(); break; #endif case "2": // Sometimes easier to attach rather than deal with JIT prompt Process currentProcess = Process.GetCurrentProcess(); Console.WriteLine($"Waiting for debugger to attach ({currentProcess.MainModule.FileName} PID {currentProcess.Id}). Press enter to continue..."); Console.ReadLine(); break; } bool restart = false; do { OutOfProcTaskHostNode oopTaskHostNode = new OutOfProcTaskHostNode(); Exception taskHostShutDownException = null; NodeEngineShutdownReason taskHostShutDownReason = oopTaskHostNode.Run(out taskHostShutDownException); if (taskHostShutDownException != null) { return(ExitType.TaskHostNodeFailed); } switch (taskHostShutDownReason) { case NodeEngineShutdownReason.BuildComplete: return(ExitType.Success); case NodeEngineShutdownReason.BuildCompleteReuse: restart = true; break; default: return(ExitType.TaskHostNodeFailed); } }while (restart); // Should not happen ErrorUtilities.ThrowInternalErrorUnreachable(); return(ExitType.Unexpected); }
/// <summary> /// Orchestrates the execution of the application. /// Also responsible for top-level error handling. /// </summary> /// <returns> /// A value of Success if the bootstrapping succeeds /// </returns> internal static ExitType Execute() { #if FEATURE_DEBUG_LAUNCH // Provide Hook for debugger if (Environment.GetEnvironmentVariable("MSBUILDDEBUGONSTART") == "1") { Debugger.Launch(); } #endif bool restart = false; do { OutOfProcTaskHostNode oopTaskHostNode = new OutOfProcTaskHostNode(); Exception taskHostShutDownException = null; NodeEngineShutdownReason taskHostShutDownReason = oopTaskHostNode.Run(out taskHostShutDownException); if (taskHostShutDownException != null) { return(ExitType.TaskHostNodeFailed); } switch (taskHostShutDownReason) { case NodeEngineShutdownReason.BuildComplete: return(ExitType.Success); case NodeEngineShutdownReason.BuildCompleteReuse: restart = true; break; default: return(ExitType.TaskHostNodeFailed); } }while (restart); // Should not happen ErrorUtilities.ThrowInternalErrorUnreachable(); return(ExitType.Unexpected); }
/// <summary> /// Starts up the node and processes messages until the node is requested to shut down. /// </summary> /// <param name="enableReuse">Whether this node is eligible for reuse later.</param> /// <param name="lowPriority">Whether this node should be running with low priority.</param> /// <param name="shutdownException">The exception which caused shutdown, if any.</param> /// <returns>The reason for shutting down.</returns> public NodeEngineShutdownReason Run(bool enableReuse, bool lowPriority, 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.OnLinkStatusChanged += OnLinkStatusChanged; _nodeEndpoint.Listen(this); var waitHandles = new WaitHandle[] { _shutdownEvent, _packetReceivedEvent }; // Get the current directory before doing any work. We need this so we can restore the directory when the node shutsdown. while (true) { int index = WaitHandle.WaitAny(waitHandles); switch (index) { case 0: NodeEngineShutdownReason shutdownReason = HandleShutdown(out shutdownException); return(shutdownReason); case 1: while (_receivedPackets.TryDequeue(out INodePacket packet)) { if (packet != null) { HandlePacket(packet); } } break; } } // UNREACHABLE }
private void HandleNodeBuildComplete(NodeBuildComplete buildComplete) { _shutdownReason = buildComplete.PrepareForReuse ? NodeEngineShutdownReason.BuildCompleteReuse : NodeEngineShutdownReason.BuildComplete; _shutdownEvent.Set(); }
private void OnEngineException(Exception e) { _shutdownException = e; _shutdownReason = NodeEngineShutdownReason.Error; _shutdownEvent.Set(); }
/// <summary> /// Event handler for the node endpoint's LinkStatusChanged event. /// </summary> private void OnLinkStatusChanged(INodeEndpoint endpoint, LinkStatus status) { switch (status) { case LinkStatus.ConnectionFailed: case LinkStatus.Failed: _shutdownReason = NodeEngineShutdownReason.ConnectionFailed; _shutdownEvent.Set(); break; case LinkStatus.Inactive: break; default: break; } }
/// <summary> /// Handles the NodeBuildComplete packet. /// </summary> private void HandleNodeBuildComplete(NodeBuildComplete buildComplete) { ErrorUtilities.VerifyThrow(!_isTaskExecuting, "We should never have a task in the process of executing when we receive NodeBuildComplete."); _shutdownReason = buildComplete.PrepareForReuse ? NodeEngineShutdownReason.BuildCompleteReuse : NodeEngineShutdownReason.BuildComplete; _shutdownEvent.Set(); }
/// <summary> /// The task has been completed /// </summary> private void CompleteTask() { ErrorUtilities.VerifyThrow(_isTaskExecuting == false, "The task should be done executing before CompleteTask."); if (_nodeEndpoint.LinkStatus == LinkStatus.Active) { TaskHostTaskComplete taskCompletePacketToSend; lock (_taskCompleteLock) { ErrorUtilities.VerifyThrowInternalNull(_taskCompletePacket, "taskCompletePacket"); taskCompletePacketToSend = _taskCompletePacket; _taskCompletePacket = null; } _nodeEndpoint.SendData(taskCompletePacketToSend); } _currentConfiguration = null; // If the task has been canceled, the event will still be set. // If so, now that we've completed the task, we want to shut down // this node -- with no reuse, since we don't know whether the // task we canceled left the node in a good state or not. if (_taskCancelledEvent.WaitOne(0, false)) { _shutdownReason = NodeEngineShutdownReason.BuildComplete; _shutdownEvent.Set(); } }
/// <summary> /// Perform necessary actions to shut down the node. /// </summary> private NodeEngineShutdownReason HandleShutdown(out Exception exception) { // Console.WriteLine("Node shutting down with reason {0} and exception: {1}", shutdownReason, shutdownException); try { // Clean up the engine if (_buildRequestEngine != null && _buildRequestEngine.Status != BuildRequestEngineStatus.Uninitialized) { _buildRequestEngine.CleanupForBuild(); } } catch (Exception ex) { if (ExceptionHandling.IsCriticalException(ex)) { throw; } // If we had some issue shutting down, don't reuse the node because we may be in some weird state. if (_shutdownReason == NodeEngineShutdownReason.BuildCompleteReuse) { _shutdownReason = NodeEngineShutdownReason.BuildComplete; } } // Dispose of any build registered objects IRegisteredTaskObjectCache objectCache = (IRegisteredTaskObjectCache)(_componentHost.GetComponent(BuildComponentType.RegisteredTaskObjectCache)); objectCache.DisposeCacheObjects(RegisteredTaskObjectLifetime.Build); if (_shutdownReason != NodeEngineShutdownReason.BuildCompleteReuse) { // Dispose of any node registered objects. ((IBuildComponent)objectCache).ShutdownComponent(); } if (_componentHost.BuildParameters.SaveOperatingEnvironment) { // Restore the original current directory. NativeMethodsShared.SetCurrentDirectory(_savedCurrentDirectory); // Restore the original environment. foreach (KeyValuePair <string, string> entry in CommunicationsUtilities.GetEnvironmentVariables()) { if (!_savedEnvironment.ContainsKey(entry.Key)) { Environment.SetEnvironmentVariable(entry.Key, null); } } foreach (KeyValuePair <string, string> entry in _savedEnvironment) { Environment.SetEnvironmentVariable(entry.Key, entry.Value); } } exception = _shutdownException; if (_loggingContext != null) { _loggingContext.LoggingService.OnLoggingThreadException -= OnLoggingThreadException; _loggingContext = null; } // Notify the BuildManager that we are done. if (_nodeEndpoint.LinkStatus == LinkStatus.Active) { _nodeEndpoint.SendData(new NodeShutdown(_shutdownReason == NodeEngineShutdownReason.Error ? NodeShutdownReason.Error : NodeShutdownReason.Requested, exception)); } _buildRequestEngine.OnEngineException -= _engineExceptionEventHandler; _buildRequestEngine.OnNewConfigurationRequest -= _newConfigurationRequestEventHandler; _buildRequestEngine.OnRequestBlocked -= _requestBlockedEventHandler; _buildRequestEngine.OnRequestComplete -= _requestCompleteEventHandler; _buildRequestEngine.OnResourceRequest -= _resourceRequestHandler; return(_shutdownReason); }
/// <summary> /// Starts up the node and processes messages until the node is requested to shut down. /// </summary> /// <param name="shutdownException">The exception which caused shutdown, if any.</param> /// <returns>The reason for shutting down.</returns> public NodeEngineShutdownReason Run(out Exception shutdownException) { try { _nodeEndpoint.OnLinkStatusChanged += OnLinkStatusChanged; _nodeEndpoint.Listen(this); var waitHandles = new WaitHandle[] { _shutdownEvent, _packetReceivedEvent }; // Get the current directory before doing work. We need this so we can restore the directory when the node shuts down. _savedCurrentDirectory = NativeMethodsShared.GetCurrentDirectory(); while (true) { int index = WaitHandle.WaitAny(waitHandles); switch (index) { case 0: { NodeEngineShutdownReason shutdownReason = HandleShutdown(out shutdownException); if (_componentHost.BuildParameters.ShutdownInProcNodeOnBuildFinish) { return(shutdownReason); } break; } case 1: while (_receivedPackets.TryDequeue(out INodePacket packet)) { if (packet != null) { HandlePacket(packet); } } break; } } } catch (ThreadAbortException) { // Do nothing. This will happen when the thread is forcibly terminated because we are shutting down, for example // when the unit test framework terminates. throw; } catch (Exception e) { // Dump all engine exceptions to a temp file // so that we have something to go on in the // event of a failure ExceptionHandling.DumpExceptionToFile(e); // This is fatal: process will terminate: make sure the // debugger launches ErrorUtilities.ThrowInternalError(e.Message, e); throw; } // UNREACHABLE }
/// <summary> /// Starts up the node and processes messages until the node is requested to shut down. /// </summary> /// <param name="shutdownException">The exception which caused shutdown, if any.</param> /// <returns>The reason for shutting down.</returns> public NodeEngineShutdownReason Run(out Exception shutdownException) { #if !CLR2COMPATIBILITY _registeredTaskObjectCache = new RegisteredTaskObjectCacheBase(); #endif shutdownException = null; // Snapshot the current environment _savedEnvironment = CommunicationsUtilities.GetEnvironmentVariables(); string pipeName = "MSBuild" + Process.GetCurrentProcess().Id; _nodeEndpoint = new NodeEndpointOutOfProcTaskHost(pipeName); _nodeEndpoint.OnLinkStatusChanged += new LinkStatusChangedDelegate(OnLinkStatusChanged); _nodeEndpoint.Listen(this); WaitHandle[] waitHandles = new WaitHandle[] { _shutdownEvent, _packetReceivedEvent, _taskCompleteEvent, _taskCancelledEvent }; while (true) { int index = WaitHandle.WaitAny(waitHandles); switch (index) { case 0: // shutdownEvent NodeEngineShutdownReason shutdownReason = HandleShutdown(); return(shutdownReason); case 1: // packetReceivedEvent INodePacket packet = null; int packetCount = _receivedPackets.Count; while (packetCount > 0) { lock (_receivedPackets) { if (_receivedPackets.Count > 0) { packet = _receivedPackets.Dequeue(); } else { break; } } if (packet != null) { HandlePacket(packet); } } break; case 2: // taskCompleteEvent CompleteTask(); break; case 3: // taskCancelledEvent CancelTask(); break; } } // UNREACHABLE }
/// <summary> /// Handles the NodeBuildComplete packet. /// </summary> private void HandleNodeBuildComplete(NodeBuildComplete buildComplete) { _shutdownReason = buildComplete.PrepareForReuse ? NodeEngineShutdownReason.BuildCompleteReuse : NodeEngineShutdownReason.BuildComplete; _shutdownEvent.Set(); }
/// <summary> /// Perform necessary actions to shut down the node. /// </summary> private NodeEngineShutdownReason HandleShutdown(out Exception exception) { // Console.WriteLine("Node shutting down with reason {0} and exception: {1}", shutdownReason, shutdownException); try { // Clean up the engine if (null != _buildRequestEngine && _buildRequestEngine.Status != BuildRequestEngineStatus.Uninitialized) { _buildRequestEngine.CleanupForBuild(); } } catch (Exception ex) { if (ExceptionHandling.IsCriticalException(ex)) { throw; } // If we had some issue shutting down, don't reuse the node because we may be in some weird state. if (_shutdownReason == NodeEngineShutdownReason.BuildCompleteReuse) { _shutdownReason = NodeEngineShutdownReason.BuildComplete; } } // Dispose of any build registered objects IRegisteredTaskObjectCache objectCache = (IRegisteredTaskObjectCache)(_componentHost.GetComponent(BuildComponentType.RegisteredTaskObjectCache)); objectCache.DisposeCacheObjects(RegisteredTaskObjectLifetime.Build); if (_shutdownReason != NodeEngineShutdownReason.BuildCompleteReuse) { // Dispose of any node registered objects. ((IBuildComponent)objectCache).ShutdownComponent(); } if (_componentHost.BuildParameters.SaveOperatingEnvironment) { // Restore the original current directory. NativeMethodsShared.SetCurrentDirectory(_savedCurrentDirectory); // Restore the original environment. foreach (KeyValuePair<string, string> entry in CommunicationsUtilities.GetEnvironmentVariables()) { if (!_savedEnvironment.ContainsKey(entry.Key)) { Environment.SetEnvironmentVariable(entry.Key, null); } } foreach (KeyValuePair<string, string> entry in _savedEnvironment) { Environment.SetEnvironmentVariable(entry.Key, entry.Value); } } exception = _shutdownException; if (null != _loggingContext) { _loggingContext.LoggingService.OnLoggingThreadException -= new LoggingExceptionDelegate(OnLoggingThreadException); _loggingContext = null; } // Notify the BuildManager that we are done. if (_nodeEndpoint.LinkStatus == LinkStatus.Active) { _nodeEndpoint.SendData(new NodeShutdown(_shutdownReason == NodeEngineShutdownReason.Error ? NodeShutdownReason.Error : NodeShutdownReason.Requested, exception)); } _buildRequestEngine.OnEngineException -= _engineExceptionEventHandler; _buildRequestEngine.OnNewConfigurationRequest -= _newConfigurationRequestEventHandler; _buildRequestEngine.OnRequestBlocked -= _requestBlockedEventHandler; _buildRequestEngine.OnRequestComplete -= _requestCompleteEventHandler; return _shutdownReason; }
/// <summary> /// Event handler for the BuildEngine's OnEngineException event. /// </summary> private void OnEngineException(Exception e) { _shutdownException = e; _shutdownReason = NodeEngineShutdownReason.Error; _shutdownEvent.Set(); }