コード例 #1
0
            /// <summary>
            /// Constructor.
            /// </summary>
            public NodeContext(int nodeId, int processId,
#if FEATURE_NAMED_PIPES_FULL_DUPLEX
                               Stream nodePipe,
#else
                               AnonymousPipeServerStream clientToServerStream,
                               AnonymousPipeServerStream serverToClientStream,
#endif
                               INodePacketFactory factory, NodeContextTerminateDelegate terminateDelegate)
            {
                _nodeId    = nodeId;
                _processId = processId;
#if FEATURE_NAMED_PIPES_FULL_DUPLEX
                _clientToServerStream = nodePipe;
                _serverToClientStream = nodePipe;
#else
                _clientToServerStream = clientToServerStream;
                _serverToClientStream = serverToClientStream;
#endif
                _packetFactory     = factory;
                _headerByte        = new byte[5];    // 1 for the packet type, 4 for the body length
                _smallReadBuffer   = new byte[1000]; // 1000 was just an average seen on one profile run.
                _nodeTerminated    = new ManualResetEvent(false);
                _terminateDelegate = terminateDelegate;
                _sharedReadBuffer  = InterningBinaryReader.CreateSharedBuffer();
            }
コード例 #2
0
        /// <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
        }
コード例 #3
0
 /// <summary>
 /// Constructor.
 /// </summary>
 public NodeContext(int nodeId, int processId, NamedPipeClientStream nodePipe, INodePacketFactory factory, NodeContextTerminateDelegate terminateDelegate)
 {
     _nodeId            = nodeId;
     _processId         = processId;
     _nodePipe          = nodePipe;
     _packetFactory     = factory;
     _headerByte        = new byte[5];    // 1 for the packet type, 4 for the body length
     _smallReadBuffer   = new byte[1000]; // 1000 was just an average seen on one profile run.
     _nodeTerminated    = new ManualResetEvent(false);
     _terminateDelegate = terminateDelegate;
     _sharedReadBuffer  = InterningBinaryReader.CreateSharedBuffer();
 }
コード例 #4
0
 /// <summary>
 /// Constructor.
 /// </summary>
 public NodeContext(int nodeId, Process process,
                    Stream nodePipe,
                    INodePacketFactory factory, NodeContextTerminateDelegate terminateDelegate)
 {
     _nodeId  = nodeId;
     _process = process;
     _clientToServerStream    = nodePipe;
     _serverToClientStream    = nodePipe;
     _packetFactory           = factory;
     _headerByte              = new byte[5]; // 1 for the packet type, 4 for the body length
     _readBufferMemoryStream  = new MemoryStream();
     _writeBufferMemoryStream = new MemoryStream();
     _terminateDelegate       = terminateDelegate;
     _sharedReadBuffer        = InterningBinaryReader.CreateSharedBuffer();
 }
コード例 #5
0
        /// <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();
                }
            }
        }
コード例 #6
0
        /// <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();
                }
            }
        }
コード例 #7
0
        /// <summary>
        /// Finds or creates a child process which can act as a node.
        /// </summary>
        /// <returns>The pipe stream representing the node.</returns>
        protected NodeContext GetNode(string msbuildLocation, string commandLineArgs, int nodeId, INodePacketFactory factory, Handshake hostHandshake, NodeContextTerminateDelegate terminateNode)
        {
#if DEBUG
            if (Execution.BuildManager.WaitForDebugger)
            {
                commandLineArgs += " /wfd";
            }
#endif

            if (String.IsNullOrEmpty(msbuildLocation))
            {
                msbuildLocation = _componentHost.BuildParameters.NodeExeLocation;
            }

            if (String.IsNullOrEmpty(msbuildLocation))
            {
                string msbuildExeName = Environment.GetEnvironmentVariable("MSBUILD_EXE_NAME");

                if (!String.IsNullOrEmpty(msbuildExeName))
                {
                    // we assume that MSBUILD_EXE_NAME is, in fact, just the name.
                    msbuildLocation = Path.Combine(msbuildExeName, ".exe");
                }
            }

#if FEATURE_NODE_REUSE
            // Try to connect to idle nodes if node reuse is enabled.
            if (_componentHost.BuildParameters.EnableNodeReuse)
            {
                (string expectedProcessName, List <Process> processes)runningNodesTuple = GetPossibleRunningNodes(msbuildLocation);

                CommunicationsUtilities.Trace("Attempting to connect to each existing {1} process in turn to establish node {0}...", nodeId, runningNodesTuple.expectedProcessName);
                foreach (Process nodeProcess in runningNodesTuple.processes)
                {
                    if (nodeProcess.Id == Process.GetCurrentProcess().Id)
                    {
                        continue;
                    }

                    // Get the full context of this inspection so that we can always skip this process when we have the same taskhost context
                    string nodeLookupKey = GetProcessesToIgnoreKey(hostHandshake, nodeProcess.Id);
                    if (_processesToIgnore.Contains(nodeLookupKey))
                    {
                        continue;
                    }

                    // We don't need to check this again
                    _processesToIgnore.Add(nodeLookupKey);

                    // Attempt to connect to each process in turn.
                    Stream nodeStream = TryConnectToProcess(nodeProcess.Id, 0 /* poll, don't wait for connections */, hostHandshake);
                    if (nodeStream != null)
                    {
                        // Connection successful, use this node.
                        CommunicationsUtilities.Trace("Successfully connected to existed node {0} which is PID {1}", nodeId, nodeProcess.Id);
                        return(new NodeContext(nodeId, nodeProcess, nodeStream, factory, terminateNode));
                    }
                }
            }
#endif

            // None of the processes we tried to connect to allowed a connection, so create a new one.
            // We try this in a loop because it is possible that there is another MSBuild multiproc
            // host process running somewhere which is also trying to create nodes right now.  It might
            // find our newly created node and connect to it before we get a chance.
            CommunicationsUtilities.Trace("Could not connect to existing process, now creating a process...");
            int retries = NodeCreationRetries;
            while (retries-- > 0)
            {
#if FEATURE_NET35_TASKHOST
                // We will also check to see if .NET 3.5 is installed in the case where we need to launch a CLR2 OOP TaskHost.
                // Failure to detect this has been known to stall builds when Windows pops up a related dialog.
                // It's also a waste of time when we attempt several times to launch multiple MSBuildTaskHost.exe (CLR2 TaskHost)
                // nodes because we should never be able to connect in this case.
                string taskHostNameForClr2TaskHost = Path.GetFileNameWithoutExtension(NodeProviderOutOfProcTaskHost.TaskHostNameForClr2TaskHost);
                if (Path.GetFileNameWithoutExtension(msbuildLocation).Equals(taskHostNameForClr2TaskHost, StringComparison.OrdinalIgnoreCase))
                {
                    if (FrameworkLocationHelper.GetPathToDotNetFrameworkV35(DotNetFrameworkArchitecture.Current) == null)
                    {
                        CommunicationsUtilities.Trace
                        (
                            "Failed to launch node from {0}. The required .NET Framework v3.5 is not installed or enabled. CommandLine: {1}",
                            msbuildLocation,
                            commandLineArgs
                        );

                        string nodeFailedToLaunchError = ResourceUtilities.GetResourceString("TaskHostNodeFailedToLaunchErrorCodeNet35NotInstalled");
                        throw new NodeFailedToLaunchException(null, nodeFailedToLaunchError);
                    }
                }
#endif

                // Create the node process
                Process msbuildProcess = LaunchNode(msbuildLocation, commandLineArgs);
                _processesToIgnore.Add(GetProcessesToIgnoreKey(hostHandshake, msbuildProcess.Id));

                // Note, when running under IMAGEFILEEXECUTIONOPTIONS registry key to debug, the process ID
                // gotten back from CreateProcess is that of the debugger, which causes this to try to connect
                // to the debugger process. Instead, use MSBUILDDEBUGONSTART=1

                // Now try to connect to it.
                Stream nodeStream = TryConnectToProcess(msbuildProcess.Id, TimeoutForNewNodeCreation, hostHandshake);
                if (nodeStream != null)
                {
                    // Connection successful, use this node.
                    CommunicationsUtilities.Trace("Successfully connected to created node {0} which is PID {1}", nodeId, msbuildProcess.Id);
                    return(new NodeContext(nodeId, msbuildProcess, nodeStream, factory, terminateNode));
                }
            }

            // We were unable to launch a node.
            CommunicationsUtilities.Trace("FAILED TO CONNECT TO A CHILD NODE");
            return(null);
        }
コード例 #8
0
 /// <summary>
 /// Constructor.
 /// </summary>
 public NodeContext(int nodeId, int processId, NamedPipeClientStream nodePipe, INodePacketFactory factory, NodeContextTerminateDelegate terminateDelegate)
 {
     _nodeId = nodeId;
     _processId = processId;
     _nodePipe = nodePipe;
     _packetFactory = factory;
     _headerByte = new byte[5]; // 1 for the packet type, 4 for the body length
     _smallReadBuffer = new byte[1000]; // 1000 was just an average seen on one profile run.
     _nodeTerminated = new ManualResetEvent(false);
     _terminateDelegate = terminateDelegate;
     _sharedReadBuffer = InterningBinaryReader.CreateSharedBuffer();
 }
コード例 #9
0
        /// <summary>
        /// Finds or creates a child process which can act as a node.
        /// </summary>
        /// <returns>The pipe stream representing the node.</returns>
        protected NodeContext GetNode(string msbuildLocation, string commandLineArgs, int nodeId, INodePacketFactory factory, long hostHandshake, long clientHandshake, NodeContextTerminateDelegate terminateNode)
        {
            if (String.IsNullOrEmpty(msbuildLocation))
            {
                msbuildLocation = _componentHost.BuildParameters.NodeExeLocation;
            }

            if (String.IsNullOrEmpty(msbuildLocation))
            {
                string msbuildExeName = Environment.GetEnvironmentVariable("MSBUILD_EXE_NAME");

                if (!String.IsNullOrEmpty(msbuildExeName))
                {
                    // we assume that MSBUILD_EXE_NAME is, in fact, just the name.  
                    msbuildLocation = Path.Combine(msbuildExeName, ".exe");
                }
            }

            if (String.IsNullOrEmpty(msbuildLocation))
            {
                msbuildLocation = "MSBuild.exe";
            }

            string msbuildName = Path.GetFileNameWithoutExtension(msbuildLocation);

            List<Process> nodeProcesses = new List<Process>(Process.GetProcessesByName(msbuildName));

            // Trivial sort to try to prefer most recently used nodes
            nodeProcesses.Sort
                (
                delegate (Process left, Process right)
                {
                    return left.Id - right.Id;
                }

                );

            CommunicationsUtilities.Trace("Attempting to connect to each existing msbuild.exe process in turn to establish node {0}...", nodeId);
            foreach (Process nodeProcess in nodeProcesses)
            {
                if (nodeProcess.Id == Process.GetCurrentProcess().Id)
                {
                    continue;
                }

                // Get the full context of this inspection so that we can always skip this process when we have the same taskhost context
                string nodeLookupKey = GetProcessesToIgnoreKey(hostHandshake, clientHandshake, nodeProcess.Id);
                if (_processesToIgnore.Contains(nodeLookupKey))
                {
                    continue;
                }

                // We don't need to check this again
                _processesToIgnore.Add(nodeLookupKey);

                // Attempt to connect to each process in turn.
                NamedPipeClientStream nodeStream = TryConnectToProcess(nodeProcess.Id, 0 /* poll, don't wait for connections */, hostHandshake, clientHandshake);
                if (nodeStream != null)
                {
                    // Connection successful, use this node.   
                    CommunicationsUtilities.Trace("Successfully connected to existed node {0} which is PID {1}", nodeId, nodeProcess.Id);
                    return new NodeContext(nodeId, nodeProcess.Id, nodeStream, factory, terminateNode);
                }
            }

            // None of the processes we tried to connect to allowed a connection, so create a new one.
            // We try this in a loop because it is possible that there is another MSBuild multiproc
            // host process running somewhere which is also trying to create nodes right now.  It might
            // find our newly created node and connect to it before we get a chance.
            CommunicationsUtilities.Trace("Could not connect to existing process, now creating a process...");
            int retries = NodeCreationRetries;
            while (retries-- > 0)
            {
                // We will also check to see if .NET 3.5 is installed in the case where we need to launch a CLR2 OOP TaskHost.
                // Failure to detect this has been known to stall builds when Windows pops up a related dialog.
                // It's also a waste of time when we attempt several times to launch multiple MSBuildTaskHost.exe (CLR2 TaskHost)
                // nodes because we should never be able to connect in this case.
                string taskHostNameForClr2TaskHost = Path.GetFileNameWithoutExtension(NodeProviderOutOfProcTaskHost.TaskHostNameForClr2TaskHost);
                if (msbuildName.Equals(taskHostNameForClr2TaskHost, StringComparison.OrdinalIgnoreCase))
                {
                    if (FrameworkLocationHelper.GetPathToDotNetFrameworkV35(DotNetFrameworkArchitecture.Current) == null)
                    {
                        CommunicationsUtilities.Trace
                            (
                                "Failed to launch node from {0}. The required .NET Framework v3.5 is not installed or enabled. CommandLine: {1}",
                                msbuildLocation,
                                commandLineArgs
                            );

                        string nodeFailedToLaunchError = ResourceUtilities.FormatResourceString("TaskHostNodeFailedToLaunchErrorCodeNet35NotInstalled");
                        throw new NodeFailedToLaunchException(null, nodeFailedToLaunchError);
                    }
                }

                // Create the node process
                int msbuildProcessId = LaunchNode(msbuildLocation, commandLineArgs);
                _processesToIgnore.Add(GetProcessesToIgnoreKey(hostHandshake, clientHandshake, msbuildProcessId));

                // Note, when running under IMAGEFILEEXECUTIONOPTIONS registry key to debug, the process ID
                // gotten back from CreateProcess is that of the debugger, which causes this to try to connect
                // to the debugger process. Instead, use MSBUILDDEBUGONSTART=1

                // Now try to connect to it.
                NamedPipeClientStream nodeStream = TryConnectToProcess(msbuildProcessId, TimeoutForNewNodeCreation, hostHandshake, clientHandshake);
                if (nodeStream != null)
                {
                    // Connection successful, use this node.
                    CommunicationsUtilities.Trace("Successfully connected to created node {0} which is PID {1}", nodeId, msbuildProcessId);
                    return new NodeContext(nodeId, msbuildProcessId, nodeStream, factory, terminateNode);
                }
            }

            // We were unable to launch a node.
            CommunicationsUtilities.Trace("FAILED TO CONNECT TO A CHILD NODE");
            return null;
        }
コード例 #10
0
        /// <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();
                }
            }
        }