/// <summary> /// Perform necessary actions to shut down the node. /// </summary> private NodeEngineShutdownReason HandleShutdown() { // Wait for the RunTask task runner thread before shutting down so that we can cleanly dispose all WaitHandles. if (_taskRunnerThread != null) { _taskRunnerThread.Join(); } if (_debugCommunications) { using (StreamWriter writer = File.CreateText(String.Format(CultureInfo.CurrentCulture, Path.Combine(Path.GetTempPath(), @"MSBuild_NodeShutdown_{0}.txt"), Process.GetCurrentProcess().Id))) { writer.WriteLine("Node shutting down with reason {0}.", _shutdownReason); } } #if !CLR2COMPATIBILITY _registeredTaskObjectCache.DisposeCacheObjects(RegisteredTaskObjectLifetime.Build); _registeredTaskObjectCache = null; #endif // On Windows, a process holds a handle to the current directory, // so reset it away from a user-requested folder that may get deleted. NativeMethodsShared.SetCurrentDirectory(BuildEnvironmentHelper.Instance.CurrentMSBuildToolsDirectory); // Restore the original environment. CommunicationsUtilities.SetEnvironment(_savedEnvironment); if (_nodeEndpoint.LinkStatus == LinkStatus.Active) { // Notify the BuildManager that we are done. _nodeEndpoint.SendData(new NodeShutdown(_shutdownReason == NodeEngineShutdownReason.Error ? NodeShutdownReason.Error : NodeShutdownReason.Requested)); // Flush all packets to the pipe and close it down. This blocks until the shutdown is complete. _nodeEndpoint.OnLinkStatusChanged -= new LinkStatusChangedDelegate(OnLinkStatusChanged); } _nodeEndpoint.Disconnect(); // Dispose these WaitHandles #if CLR2COMPATIBILITY _packetReceivedEvent.Close(); _shutdownEvent.Close(); _taskCompleteEvent.Close(); _taskCancelledEvent.Close(); #else _packetReceivedEvent.Dispose(); _shutdownEvent.Dispose(); _taskCompleteEvent.Dispose(); _taskCancelledEvent.Dispose(); #endif 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) { #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 }