private bool InstantiateNode(INodePacketFactory factory) { ErrorUtilities.VerifyThrow(_inProcNode == null, "In Proc node already instantiated."); ErrorUtilities.VerifyThrow(_inProcNodeEndpoint == null, "In Proc node endpoint already instantiated."); NodeEndpointInProc.EndpointPair endpoints = NodeEndpointInProc.CreateInProcEndpoints(NodeEndpointInProc.EndpointMode.Synchronous, _componentHost); _inProcNodeEndpoint = endpoints.ManagerEndpoint; _inProcNodeEndpoint.OnLinkStatusChanged += new LinkStatusChangedDelegate(InProcNodeEndpoint_OnLinkStatusChanged); _packetFactory = factory; _inProcNode = new InProcNode(_componentHost, endpoints.NodeEndpoint); #if FEATURE_THREAD_CULTURE _inProcNodeThread = new Thread(InProcNodeThreadProc, BuildParameters.ThreadStackSize); #else CultureInfo culture = _componentHost.BuildParameters.Culture; CultureInfo uiCulture = _componentHost.BuildParameters.UICulture; _inProcNodeThread = new Thread(() => { CultureInfo.CurrentCulture = culture; CultureInfo.CurrentUICulture = uiCulture; InProcNodeThreadProc(); }); #endif _inProcNodeThread.Name = String.Format(CultureInfo.CurrentCulture, "In-proc Node ({0})", _componentHost.Name); _inProcNodeThread.IsBackground = true; #if FEATURE_THREAD_CULTURE _inProcNodeThread.CurrentCulture = _componentHost.BuildParameters.Culture; _inProcNodeThread.CurrentUICulture = _componentHost.BuildParameters.UICulture; #endif _inProcNodeThread.Start(); _inProcNodeEndpoint.Connect(this); int connectionTimeout = CommunicationsUtilities.NodeConnectionTimeout; bool connected = _endpointConnectedEvent.WaitOne(connectionTimeout); ErrorUtilities.VerifyThrow(connected, "In-proc node failed to start up within {0}ms", connectionTimeout); return(true); }
/// <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> /// Routes a packet. /// </summary> /// <param name="nodeId">The id of the node from which the packet is being routed.</param> /// <param name="packet">The packet to route.</param> public void RoutePacket(int nodeId, INodePacket packet) { INodePacketFactory factory = _packetFactory; if (_inProcNodeId != InvalidInProcNodeId) { // If this was a shutdown packet, we are done with the node. Release all context associated with it. Do this here, rather // than after we route the packet, because otherwise callbacks to the NodeManager to determine if we have available nodes // will report that the in-proc node is still in use when it has actually shut down. int savedInProcNodeId = _inProcNodeId; if (packet.Type == NodePacketType.NodeShutdown) { _inProcNodeId = InvalidInProcNodeId; // Release the operating environment semaphore if we were holding it. if ((_componentHost.BuildParameters.SaveOperatingEnvironment) && (_inProcNodeOwningOperatingEnvironment != null)) { _inProcNodeOwningOperatingEnvironment.Release(); _inProcNodeOwningOperatingEnvironment.Close(); _inProcNodeOwningOperatingEnvironment = null; } if (!_componentHost.BuildParameters.EnableNodeReuse) { _inProcNode = null; _inProcNodeEndpoint = null; _inProcNodeThread = null; _packetFactory = null; } } // Route the packet back to the NodeManager. factory.RoutePacket(savedInProcNodeId, packet); } }
/// <summary> /// Requests that a node be created on the specified machine. /// </summary> /// <param name="nodeId">The id of the node to create.</param> /// <param name="factory">The factory to use to create packets from this node.</param> /// <param name="configuration">The configuration for the node.</param> public bool CreateNode(int nodeId, INodePacketFactory factory, NodeConfiguration configuration) { ErrorUtilities.VerifyThrow(nodeId != InvalidInProcNodeId, "Cannot create in-proc node."); // Attempt to get the operating environment semaphore if requested. if (_componentHost.BuildParameters.SaveOperatingEnvironment) { // We can only create additional in-proc nodes if we have decided not to save the operating environment. This is the global // DTAR case in Visual Studio, but other clients might enable this as well under certain special circumstances. ErrorUtilities.VerifyThrow(_inProcNodeOwningOperatingEnvironment == null, "Unexpected non-null in-proc node semaphore."); // Blend.exe v4.x or earlier launches two nodes that co-own the same operating environment // and they will not patch this var p = Process.GetCurrentProcess(); { // This should be reasonably sufficient to assume MS Expression Blend 4 or earlier if ((FileUtilities.CurrentExecutableName.Equals("Blend", StringComparison.OrdinalIgnoreCase)) && (p.MainModule.FileVersionInfo.OriginalFilename.Equals("Blend.exe", StringComparison.OrdinalIgnoreCase)) && (p.MainModule.FileVersionInfo.ProductMajorPart < 5)) { _exclusiveOperatingEnvironment = false; } } if (Environment.GetEnvironmentVariable("MSBUILDINPROCENVCHECK") == "1") { _exclusiveOperatingEnvironment = true; } if (_exclusiveOperatingEnvironment) { _inProcNodeOwningOperatingEnvironment = new Semaphore(1, 1, "MSBuildIPN_" + Process.GetCurrentProcess().Id); if (!_inProcNodeOwningOperatingEnvironment.WaitOne(0)) { // Can't take the operating environment. return false; } } } // If it doesn't already exist, create it. if (_inProcNode == null) { if (!InstantiateNode(factory)) { return false; } } _inProcNodeEndpoint.SendData(configuration); _inProcNodeId = nodeId; return true; }
/// <summary> /// Instantiates a new MSBuild or MSBuildTaskHost process acting as a child node. /// </summary> internal bool CreateNode(TaskHostContext hostContext, INodePacketFactory factory, INodePacketHandler handler, TaskHostConfiguration configuration) { ErrorUtilities.VerifyThrowArgumentNull(factory, "factory"); ErrorUtilities.VerifyThrow(!_nodeIdToPacketFactory.ContainsKey((int)hostContext), "We should not already have a factory for this context! Did we forget to call DisconnectFromHost somewhere?"); if (AvailableNodes == 0) { 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 2, to indicate that we // want to start up an MSBuild task host node. string commandLineArgs = " /nologo /nodemode:2 "; string msbuildLocation = GetMSBuildLocationFromHostContext(hostContext); // we couldn't even figure out the location we're trying to launch ... just go ahead and fail. if (msbuildLocation == null) { return false; } CommunicationsUtilities.Trace("For a host context of {0}, spawning executable from {1}.", hostContext.ToString(), msbuildLocation ?? "MSBuild.exe"); // Make it here. NodeContext context = GetNode ( msbuildLocation, commandLineArgs, (int)hostContext, this, CommunicationsUtilities.GetTaskHostHostHandshake(hostContext), CommunicationsUtilities.GetTaskHostClientHandshake(hostContext), NodeContextTerminated ); if (null != context) { _nodeContexts[hostContext] = context; // Start the asynchronous read. context.BeginAsyncPacketRead(); _activeNodes.Add((int)hostContext); _noNodesActiveEvent.Reset(); return true; } return false; }
/// <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); }
/// <summary> /// Causes this node to connect to the matched endpoint. /// </summary> /// <param name="factory">The factory used to create packets.</param> public void Connect(INodePacketFactory factory) { ErrorUtilities.ThrowInternalError("Connect() not valid on the out of proc endpoint."); }
/// <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 = ComponentHost.BuildParameters.EnableNodeReuse ? "/nologo /nodemode:1 /nodeReuse:true" : "/nologo /nodemode:1 /nodeReuse:false"; // 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.GetHostHandshake(ComponentHost.BuildParameters.EnableNodeReuse), NodeProviderOutOfProc.GetClientHandshake(), 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> /// 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; }
/// <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(); }
/// <summary> /// Causes this endpoint to wait for the remote endpoint to connect /// </summary> /// <param name="factory">The factory used to create packets.</param> public void Listen(INodePacketFactory factory) { ErrorUtilities.VerifyThrow(_status == LinkStatus.Inactive, "Link not inactive. Status is {0}", _status); ErrorUtilities.VerifyThrowArgumentNull(factory, "factory"); _packetFactory = factory; InitializeAsyncPacketThread(); }
public IList <NodeInfo> CreateNodes(int nextNodeId, INodePacketFactory packetFactory, Func <NodeInfo, NodeConfiguration> configurationFactory, int numberOfNodesToCreate) { throw new NotImplementedException("Use the other overload of CreateNode instead"); }
/// <summary> /// Causes this node to connect to the matched endpoint. /// </summary> /// <param name="factory">Unused</param> public void Connect(INodePacketFactory factory) { ErrorUtilities.VerifyThrowInternalNull(factory, "factory"); _packetFactory = factory; // Set up asynchronous packet pump, if necessary. if (_mode == EndpointMode.Asynchronous) { InitializeAsyncPacketThread(); } // Notify the Build Manager-side endpoint that the connection is now active. _peerEndpoint.SetPeerNodeConnected(); }
/// <summary> /// Causes this endpoint to wait for the remote endpoint to connect /// </summary> /// <param name="factory">Unused</param> public void Listen(INodePacketFactory factory) { ErrorUtilities.VerifyThrowInternalNull(factory, "factory"); _packetFactory = factory; // Initialize our thread in async mode so we are ready when the Node-side endpoint "connects". if (_mode == EndpointMode.Asynchronous) { InitializeAsyncPacketThread(); } _peerEndpoint.SetPeerNodeConnected(); }
/// <summary> /// Creates a new in-proc node. /// </summary> private bool InstantiateNode(INodePacketFactory factory) { ErrorUtilities.VerifyThrow(null == _inProcNode, "In Proc node already instantiated."); ErrorUtilities.VerifyThrow(null == _inProcNodeEndpoint, "In Proc node endpoint already instantiated."); NodeEndpointInProc.EndpointPair endpoints = NodeEndpointInProc.CreateInProcEndpoints(NodeEndpointInProc.EndpointMode.Synchronous, _componentHost); _inProcNodeEndpoint = endpoints.ManagerEndpoint; _inProcNodeEndpoint.OnLinkStatusChanged += new LinkStatusChangedDelegate(InProcNodeEndpoint_OnLinkStatusChanged); _packetFactory = factory; _inProcNode = new InProcNode(_componentHost, endpoints.NodeEndpoint); _inProcNodeThread = new Thread(InProcNodeThreadProc, BuildParameters.ThreadStackSize); _inProcNodeThread.Name = String.Format(CultureInfo.CurrentCulture, "In-proc Node ({0})", _componentHost.Name); _inProcNodeThread.IsBackground = true; _inProcNodeThread.CurrentCulture = _componentHost.BuildParameters.Culture; _inProcNodeThread.CurrentUICulture = _componentHost.BuildParameters.UICulture; _inProcNodeThread.Start(); _inProcNodeEndpoint.Connect(this); int connectionTimeout = CommunicationsUtilities.NodeConnectionTimeout; bool connected = _endpointConnectedEvent.WaitOne(connectionTimeout, false); ErrorUtilities.VerifyThrow(connected, "In-proc node failed to start up within {0}ms", connectionTimeout); return true; }
/// <summary> /// Instantiates a new MSBuild process acting as a child node. /// </summary> public bool CreateNode(int nodeId, INodePacketFactory factory, NodeConfiguration configuration) { throw new NotImplementedException("Use the other overload of CreateNode instead"); }
/// <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> /// Requests that a node be created on the specified machine. /// </summary> /// <param name="nodeId">The id of the node to create.</param> /// <param name="factory">The factory to use to create packets from this node.</param> /// <param name="configuration">The configuration for the node.</param> public bool CreateNode(int nodeId, INodePacketFactory factory, NodeConfiguration configuration) { ErrorUtilities.VerifyThrow(nodeId != InvalidInProcNodeId, "Cannot create in-proc node."); // Attempt to get the operating environment semaphore if requested. if (_componentHost.BuildParameters.SaveOperatingEnvironment) { // We can only create additional in-proc nodes if we have decided not to save the operating environment. This is the global // DTAR case in Visual Studio, but other clients might enable this as well under certain special circumstances. ErrorUtilities.VerifyThrow(_inProcNodeOwningOperatingEnvironment == null, "Unexpected non-null in-proc node semaphore."); if (Environment.GetEnvironmentVariable("MSBUILDINPROCENVCHECK") == "1") { _exclusiveOperatingEnvironment = true; } if (_exclusiveOperatingEnvironment) { _inProcNodeOwningOperatingEnvironment = new Semaphore(1, 1, "MSBuildIPN_" + Process.GetCurrentProcess().Id); if (!_inProcNodeOwningOperatingEnvironment.WaitOne(0)) { // Can't take the operating environment. return false; } } } // If it doesn't already exist, create it. if (_inProcNode == null) { if (!InstantiateNode(factory)) { return false; } } _inProcNodeEndpoint.SendData(configuration); _inProcNodeId = nodeId; return true; }