예제 #1
0
        /// <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();
        }
예제 #2
0
        /// <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();
            }
        }
예제 #3
0
        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();
        }
예제 #4
0
        /// <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
        }
예제 #5
0
        /// <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;
            }
        }
예제 #6
0
        /// <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);
        }
예제 #7
0
        /// <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);
        }
예제 #8
0
        /// <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
        }
예제 #9
0
 private void HandleNodeBuildComplete(NodeBuildComplete buildComplete)
 {
     _shutdownReason = buildComplete.PrepareForReuse ? NodeEngineShutdownReason.BuildCompleteReuse : NodeEngineShutdownReason.BuildComplete;
     _shutdownEvent.Set();
 }
예제 #10
0
 private void OnEngineException(Exception e)
 {
     _shutdownException = e;
     _shutdownReason    = NodeEngineShutdownReason.Error;
     _shutdownEvent.Set();
 }
예제 #11
0
        /// <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;
            }
        }
예제 #12
0
        /// <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();
        }
예제 #13
0
        /// <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();
            }
        }
예제 #14
0
        /// <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);
        }
예제 #15
0
        /// <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
        }
예제 #16
0
        /// <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
        }
예제 #17
0
 /// <summary>
 /// Handles the NodeBuildComplete packet.
 /// </summary>
 private void HandleNodeBuildComplete(NodeBuildComplete buildComplete)
 {
     _shutdownReason = buildComplete.PrepareForReuse ? NodeEngineShutdownReason.BuildCompleteReuse : NodeEngineShutdownReason.BuildComplete;
     _shutdownEvent.Set();
 }
예제 #18
0
        /// <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;
        }
예제 #19
0
 /// <summary>
 /// Event handler for the BuildEngine's OnEngineException event.
 /// </summary>
 private void OnEngineException(Exception e)
 {
     _shutdownException = e;
     _shutdownReason = NodeEngineShutdownReason.Error;
     _shutdownEvent.Set();
 }