/// <summary> /// This method is called by the node to post build /// requests into a queue in the parent engine /// </summary> public void PostBuildRequestsToHost(BuildRequest[] buildRequests) { LocalCallDescriptorForPostBuildRequests callDescriptor = new LocalCallDescriptorForPostBuildRequests(buildRequests); nodeCommandQueue.Enqueue(callDescriptor); }
public void PostBuildRequestToNode(int nodeIndex, BuildRequest buildRequest) { ErrorUtilities.VerifyThrow(nodeIndex < nodeData.Length && nodeIndex >= 0, "Node index must be within array boundaries"); if (nodeData[nodeIndex].NodeState != NodeState.Launched) { // Note that we have to check the node status again inside the mutex. This // ensures that that after flipping the status to launched inside the mutex // there will be no more writes to the queue of targets waiting to be sent lock (nodeStateLock) { // Check if we didn't initialize this node if (nodeData[nodeIndex].NodeState != NodeState.Launched && !shuttingDown) { // Check if launch is in progress if (nodeData[nodeIndex].NodeState == NodeState.NotLaunched) { nodeData[nodeIndex].NodeState = NodeState.LaunchInProgress; lock (nodesToLaunch) { nodesToLaunch.Enqueue(nodeIndex); } ThreadStart threadState = new ThreadStart(this.LaunchNodeAndPostBuildRequest); Thread taskThread = new Thread(threadState); taskThread.Name = "MSBuild Node Launcher"; taskThread.Start(); } nodeData[nodeIndex].TargetList.AddFirst(new LinkedListNode <BuildRequest>(buildRequest)); } else { LocalCallDescriptorForPostBuildRequests callDescriptor = new LocalCallDescriptorForPostBuildRequests(buildRequest); nodeData[nodeIndex].NodeCommandQueue.Enqueue(callDescriptor); } } } else { LocalCallDescriptorForPostBuildRequests callDescriptor = new LocalCallDescriptorForPostBuildRequests(buildRequest); nodeData[nodeIndex].NodeCommandQueue.Enqueue(callDescriptor); } }
/// <summary> /// This method first reads the objectId as an int from the stream, /// this int should be found in the "ObjectType" enumeration. This /// objectId informs the method what kind of object should be /// deserialized and returned from the method. The objectId is an /// output parameter. This parameter is also returned so it can be /// used in the read and write methods to determine if /// a frame or end marker was found. /// </summary> private object DeserializeFromStream(out int objectId) { object objectRead = null; objectId = readStream.ReadByte(); switch ((ObjectType)objectId) { case ObjectType.NetSerialization: objectRead = binaryFormatter.Deserialize(readStream); break; case ObjectType.FrameMarker: objectRead = binaryReader.ReadInt32(); break; case ObjectType.PostBuildResult: objectRead = new LocalCallDescriptorForPostBuildResult(); ((LocalCallDescriptorForPostBuildResult)objectRead).CreateFromStream(binaryReader); break; case ObjectType.PostBuildRequests: objectRead = new LocalCallDescriptorForPostBuildRequests(); ((LocalCallDescriptorForPostBuildRequests)objectRead).CreateFromStream(binaryReader); break; case ObjectType.PostLoggingMessagesToHost: objectRead = new LocalCallDescriptorForPostLoggingMessagesToHost(); ((LocalCallDescriptorForPostLoggingMessagesToHost)objectRead).CreateFromStream(binaryReader, loggingTypeCache); break; case ObjectType.InitializeNode: objectRead = new LocalCallDescriptorForInitializeNode(); ((LocalCallDescriptorForInitializeNode)objectRead).CreateFromStream(binaryReader); break; case ObjectType.InitializationComplete: objectRead = new LocalCallDescriptorForInitializationComplete(); ((LocalCallDescriptorForInitializationComplete)objectRead).CreateFromStream(binaryReader); break; case ObjectType.UpdateNodeSettings: objectRead = new LocalCallDescriptorForUpdateNodeSettings(); ((LocalCallDescriptorForUpdateNodeSettings)objectRead).CreateFromStream(binaryReader); break; case ObjectType.RequestStatus: objectRead = new LocalCallDescriptorForRequestStatus(); ((LocalCallDescriptorForRequestStatus)objectRead).CreateFromStream(binaryReader); break; case ObjectType.PostCacheEntriesToHost: objectRead = new LocalCallDescriptorForPostingCacheEntriesToHost(); ((LocalCallDescriptorForPostingCacheEntriesToHost)objectRead).CreateFromStream(binaryReader); break; case ObjectType.GetCacheEntriesFromHost: objectRead = new LocalCallDescriptorForGettingCacheEntriesFromHost(); ((LocalCallDescriptorForGettingCacheEntriesFromHost)objectRead).CreateFromStream(binaryReader); break; case ObjectType.ShutdownComplete: objectRead = new LocalCallDescriptorForShutdownComplete(); ((LocalCallDescriptorForShutdownComplete)objectRead).CreateFromStream(binaryReader); break; case ObjectType.ShutdownNode: objectRead = new LocalCallDescriptorForShutdownNode(); ((LocalCallDescriptorForShutdownNode)objectRead).CreateFromStream(binaryReader); break; case ObjectType.PostIntrospectorCommand: objectRead = new LocalCallDescriptorForPostIntrospectorCommand(null, null); ((LocalCallDescriptorForPostIntrospectorCommand)objectRead).CreateFromStream(binaryReader); break; case ObjectType.GenericSingleObjectReply: objectRead = new LocalReplyCallDescriptor(); ((LocalReplyCallDescriptor)objectRead).CreateFromStream(binaryReader); break; case ObjectType.PostStatus: objectRead = new LocalCallDescriptorForPostStatus(); ((LocalCallDescriptorForPostStatus)objectRead).CreateFromStream(binaryReader); break; case ObjectType.EndMarker: return(null); default: ErrorUtilities.VerifyThrow(false, "Should not be here, ObjectId:" + objectId + "Next:" + readStream.ReadByte()); break; } return(objectRead); }
/// <summary> /// This method first reads the objectId as an int from the stream, /// this int should be found in the "ObjectType" enumeration. This /// objectId informs the method what kind of object should be /// deserialized and returned from the method. The objectId is an /// output parameter. This parameter is also returned so it can be /// used in the read and write methods to determine if /// a frame or end marker was found. /// </summary> private object DeserializeFromStream(out int objectId) { object objectRead = null; objectId = readStream.ReadByte(); switch ((ObjectType)objectId) { case ObjectType.NetSerialization: objectRead = binaryFormatter.Deserialize(readStream); break; case ObjectType.FrameMarker: objectRead = binaryReader.ReadInt32(); break; case ObjectType.PostBuildResult: objectRead = new LocalCallDescriptorForPostBuildResult(); ((LocalCallDescriptorForPostBuildResult)objectRead).CreateFromStream(binaryReader); break; case ObjectType.PostBuildRequests: objectRead = new LocalCallDescriptorForPostBuildRequests(); ((LocalCallDescriptorForPostBuildRequests)objectRead).CreateFromStream(binaryReader); break; case ObjectType.PostLoggingMessagesToHost: objectRead = new LocalCallDescriptorForPostLoggingMessagesToHost(); ((LocalCallDescriptorForPostLoggingMessagesToHost)objectRead).CreateFromStream(binaryReader, loggingTypeCache); break; case ObjectType.InitializeNode: objectRead = new LocalCallDescriptorForInitializeNode(); ((LocalCallDescriptorForInitializeNode)objectRead).CreateFromStream(binaryReader); break; case ObjectType.InitializationComplete: objectRead = new LocalCallDescriptorForInitializationComplete(); ((LocalCallDescriptorForInitializationComplete)objectRead).CreateFromStream(binaryReader); break; case ObjectType.UpdateNodeSettings: objectRead = new LocalCallDescriptorForUpdateNodeSettings(); ((LocalCallDescriptorForUpdateNodeSettings)objectRead).CreateFromStream(binaryReader); break; case ObjectType.RequestStatus: objectRead = new LocalCallDescriptorForRequestStatus(); ((LocalCallDescriptorForRequestStatus)objectRead).CreateFromStream(binaryReader); break; case ObjectType.PostCacheEntriesToHost: objectRead = new LocalCallDescriptorForPostingCacheEntriesToHost(); ((LocalCallDescriptorForPostingCacheEntriesToHost)objectRead).CreateFromStream(binaryReader); break; case ObjectType.GetCacheEntriesFromHost: objectRead = new LocalCallDescriptorForGettingCacheEntriesFromHost(); ((LocalCallDescriptorForGettingCacheEntriesFromHost)objectRead).CreateFromStream(binaryReader); break; case ObjectType.ShutdownComplete: objectRead = new LocalCallDescriptorForShutdownComplete(); ((LocalCallDescriptorForShutdownComplete)objectRead).CreateFromStream(binaryReader); break; case ObjectType.ShutdownNode: objectRead = new LocalCallDescriptorForShutdownNode(); ((LocalCallDescriptorForShutdownNode)objectRead).CreateFromStream(binaryReader); break; case ObjectType.PostIntrospectorCommand: objectRead = new LocalCallDescriptorForPostIntrospectorCommand(null, null); ((LocalCallDescriptorForPostIntrospectorCommand)objectRead).CreateFromStream(binaryReader); break; case ObjectType.GenericSingleObjectReply: objectRead = new LocalReplyCallDescriptor(); ((LocalReplyCallDescriptor)objectRead).CreateFromStream(binaryReader); break; case ObjectType.PostStatus: objectRead = new LocalCallDescriptorForPostStatus(); ((LocalCallDescriptorForPostStatus)objectRead).CreateFromStream(binaryReader); break; case ObjectType.EndMarker: return null; default: ErrorUtilities.VerifyThrow(false, "Should not be here, ObjectId:" + objectId + "Next:" + readStream.ReadByte()); break; } return objectRead; }
/// <summary> /// This function will start a node and send requests to it /// </summary> private void LaunchNodeAndPostBuildRequest() { int nodeIndex = 0; // Find out what node to launch lock (nodesToLaunch) { nodeIndex = nodesToLaunch.Dequeue(); } // If the provider is shutting down - don't launch the node if (shuttingDown) { nodeData[nodeIndex].NodeState = NodeState.NotLaunched; return; } try { // Either launch node or connect to an already running node InitializeNode(nodeIndex); if (!nodeData[nodeIndex].CommunicationFailed) { // Change the state of the node to launched lock (nodeStateLock) { nodeData[nodeIndex].NodeState = NodeState.Launched; } // Send all the requests to the node. Note that the requests may end up in // mixed order with the request currently being posted. LinkedListNode <BuildRequest> current = nodeData[nodeIndex].TargetList.First; BuildRequest[] buildRequests = new BuildRequest[nodeData[nodeIndex].TargetList.Count]; int i = 0; while (current != null) { buildRequests[i] = current.Value; i++; current = current.Next; } LocalCallDescriptorForPostBuildRequests callDescriptor = new LocalCallDescriptorForPostBuildRequests(buildRequests); nodeData[nodeIndex].NodeCommandQueue.Enqueue(callDescriptor); nodeData[nodeIndex].TargetList = null; } else { // Allow the engine to decide how to proceed since the node failed to launch string message = ResourceUtilities.FormatResourceString("NodeProviderFailure"); ReportNodeCommunicationFailure(nodeIndex, new Exception(message), false); } } catch (Exception e) { // Allow the engine to deal with the exception ReportNodeCommunicationFailure(nodeIndex, e, false); } }
private static void ComparebuildRequests(LocalCallDescriptorForPostBuildRequests buildRequestsCallDescriptor) { BuildRequest[] requests = buildRequestsCallDescriptor.BuildRequests; Assert.IsTrue(requests.Length == 2); BuildEventContext testContext = new BuildEventContext(1, 2, 3, 4); ; foreach (BuildRequest request1 in requests) { Assert.IsTrue(request1.HandleId == 4, "Expected HandleId to Match"); Assert.IsTrue(request1.RequestId == 1, "Expected Request to Match"); Assert.IsTrue(string.Compare(request1.ProjectFileName, "ProjectFileName", StringComparison.OrdinalIgnoreCase) == 0, "Expected ProjectFileName to Match"); Assert.IsTrue(string.Compare(request1.TargetNames[0], "Build", StringComparison.OrdinalIgnoreCase) == 0, "Expected TargetNames to Match"); Assert.IsTrue(string.Compare(request1.ToolsetVersion, "Tool35", StringComparison.OrdinalIgnoreCase) == 0, "Expected ToolsetVersion to Match"); Assert.IsTrue(request1.TargetNames.Length == 1, "Expected there to be one TargetName"); Assert.IsTrue(request1.UnloadProjectsOnCompletion, "Expected UnloadProjectsOnCompletion to be true"); Assert.IsTrue(request1.UseResultsCache, "Expected UseResultsCache to be true"); Assert.IsTrue(string.Compare(request1.GlobalProperties["PropertyName"].Value, "Value", StringComparison.OrdinalIgnoreCase) == 0); Assert.AreEqual(request1.ParentBuildEventContext, testContext, "Expected BuildEventContext to Match"); } }
public void TestItemsInandOutOfSharedMemory() { string name = Guid.NewGuid().ToString(); // Create the shared memory buffer SharedMemory readSharedMemory = new SharedMemory ( name, SharedMemoryType.ReadOnly, true ); SharedMemory writeSharedMemory = new SharedMemory ( name, SharedMemoryType.WriteOnly, true ); DualQueue<LocalCallDescriptor> queue = new DualQueue<LocalCallDescriptor>(); DualQueue<LocalCallDescriptor> hiPriQueue = new DualQueue<LocalCallDescriptor>(); LocalCallDescriptorForPostLoggingMessagesToHost LargeLogEvent = CreatePostMessageCallDescriptor(1); LocalCallDescriptorForUpdateNodeSettings updateNodeSettings = new LocalCallDescriptorForUpdateNodeSettings(true, true, true); LocalCallDescriptorForPostBuildResult buildResult = new LocalCallDescriptorForPostBuildResult(CreateBuildResult()); LocalCallDescriptorForPostBuildRequests buildRequests = new LocalCallDescriptorForPostBuildRequests(CreateBuildRequest()); LocalCallDescriptorForRequestStatus requestStatus = new LocalCallDescriptorForRequestStatus(4); LocalCallDescriptorForPostStatus nodeStatusNoExcept = new LocalCallDescriptorForPostStatus(new NodeStatus(1, true, 2, 3, 4, true)); LocalCallDescriptorForPostStatus nodeStatusExcept = new LocalCallDescriptorForPostStatus(new NodeStatus(new Exception("I am bad"))); LocalCallDescriptorForShutdownNode shutdownNode = new LocalCallDescriptorForShutdownNode(Node.NodeShutdownLevel.BuildCompleteSuccess, true); LocalCallDescriptorForShutdownComplete shutdownComplete = new LocalCallDescriptorForShutdownComplete(Node.NodeShutdownLevel.BuildCompleteFailure, 0); LocalCallDescriptorForInitializationComplete initializeComplete = new LocalCallDescriptorForInitializationComplete(99); BuildPropertyGroup propertyGroup = new BuildPropertyGroup(); BuildProperty propertyToAdd = new BuildProperty("PropertyName", "Value"); propertyGroup.SetProperty(propertyToAdd); CacheEntry[] entries = CreateCacheEntries(); LocalCallDescriptorForGettingCacheEntriesFromHost getCacheEntries = new LocalCallDescriptorForGettingCacheEntriesFromHost(new string[] { "Hi", "Hello" }, "Name", propertyGroup, "3.5", CacheContentType.Properties); LocalCallDescriptorForPostingCacheEntriesToHost postCacheEntries = new LocalCallDescriptorForPostingCacheEntriesToHost(entries, "ScopeName", propertyGroup, "3.5", CacheContentType.BuildResults); LocalReplyCallDescriptor replyDescriptor1 = new LocalReplyCallDescriptor(1, entries); LocalReplyCallDescriptor replyDescriptor2 = new LocalReplyCallDescriptor(6, "Foo"); IDictionary environmentVariables = Environment.GetEnvironmentVariables(); Hashtable environmentVariablesHashtable = new Hashtable(environmentVariables); string className = "Class"; string loggerAssemblyName = "Class"; string loggerFileAssembly = null; string loggerSwitchParameters = "Class"; LoggerVerbosity verbosity = LoggerVerbosity.Detailed; LoggerDescription description = new LoggerDescription(className, loggerAssemblyName, loggerFileAssembly, loggerSwitchParameters, verbosity); LocalCallDescriptorForInitializeNode initializeNode = new LocalCallDescriptorForInitializeNode(environmentVariablesHashtable, new LoggerDescription[] { description }, 4, propertyGroup, ToolsetDefinitionLocations.ConfigurationFile, 5, String.Empty); queue.Enqueue(LargeLogEvent); queue.Enqueue(updateNodeSettings); queue.Enqueue(buildResult); queue.Enqueue(buildRequests); queue.Enqueue(requestStatus); queue.Enqueue(nodeStatusNoExcept); queue.Enqueue(nodeStatusExcept); queue.Enqueue(shutdownNode); queue.Enqueue(shutdownComplete); queue.Enqueue(initializeComplete); queue.Enqueue(getCacheEntries); queue.Enqueue(postCacheEntries); queue.Enqueue(replyDescriptor1); queue.Enqueue(replyDescriptor2); queue.Enqueue(initializeNode); writeSharedMemory.Write(queue, hiPriQueue, false); IList localCallDescriptorList = readSharedMemory.Read(); Assert.IsTrue(localCallDescriptorList.Count == 15); LocalCallDescriptorForPostLoggingMessagesToHost messageCallDescriptor = localCallDescriptorList[0] as LocalCallDescriptorForPostLoggingMessagesToHost; VerifyPostMessagesToHost(messageCallDescriptor, 1); LocalCallDescriptorForUpdateNodeSettings updateSettingsCallDescriptor = localCallDescriptorList[1] as LocalCallDescriptorForUpdateNodeSettings; VerifyUpdateSettings(updateSettingsCallDescriptor); LocalCallDescriptorForPostBuildResult buildResultCallDescriptor = localCallDescriptorList[2] as LocalCallDescriptorForPostBuildResult; CompareBuildResult(buildResultCallDescriptor); LocalCallDescriptorForPostBuildRequests buildRequestsCallDescriptor = localCallDescriptorList[3] as LocalCallDescriptorForPostBuildRequests; ComparebuildRequests(buildRequestsCallDescriptor); LocalCallDescriptorForRequestStatus requestStatusCallDescriptor = localCallDescriptorList[4] as LocalCallDescriptorForRequestStatus; Assert.IsTrue(requestStatusCallDescriptor.RequestId == 4); LocalCallDescriptorForPostStatus nodeStatus1CallDescriptor = localCallDescriptorList[5] as LocalCallDescriptorForPostStatus; VerifyNodeStatus1(nodeStatus1CallDescriptor); LocalCallDescriptorForPostStatus nodeStatus2CallDescriptor = localCallDescriptorList[6] as LocalCallDescriptorForPostStatus; VerifyNodeStatus2(nodeStatus2CallDescriptor); LocalCallDescriptorForShutdownNode shutdownNodeCallDescriptor = localCallDescriptorList[7] as LocalCallDescriptorForShutdownNode; Assert.IsTrue(shutdownNodeCallDescriptor.ShutdownLevel == Node.NodeShutdownLevel.BuildCompleteSuccess); Assert.IsTrue(shutdownNodeCallDescriptor.ExitProcess); LocalCallDescriptorForShutdownComplete shutdownNodeCompleteCallDescriptor = localCallDescriptorList[8] as LocalCallDescriptorForShutdownComplete; Assert.IsTrue(shutdownNodeCompleteCallDescriptor.ShutdownLevel == Node.NodeShutdownLevel.BuildCompleteFailure); LocalCallDescriptorForInitializationComplete initializeCompleteCallDescriptor = localCallDescriptorList[9] as LocalCallDescriptorForInitializationComplete; Assert.IsTrue(initializeCompleteCallDescriptor.ProcessId == 99); LocalCallDescriptorForGettingCacheEntriesFromHost getCacheEntriesCallDescriptor = localCallDescriptorList[10] as LocalCallDescriptorForGettingCacheEntriesFromHost; VerifyGetCacheEntryFromHost(getCacheEntriesCallDescriptor); LocalCallDescriptorForPostingCacheEntriesToHost postCacheEntriesCallDescriptor = localCallDescriptorList[11] as LocalCallDescriptorForPostingCacheEntriesToHost; Assert.IsTrue(string.Compare(postCacheEntriesCallDescriptor.ScopeName, "ScopeName", StringComparison.OrdinalIgnoreCase) == 0); Assert.IsTrue(string.Compare(postCacheEntriesCallDescriptor.ScopeProperties["PropertyName"].Value, "Value", StringComparison.OrdinalIgnoreCase) == 0); Assert.IsTrue(string.Compare(postCacheEntriesCallDescriptor.ScopeToolsVersion, "3.5", StringComparison.OrdinalIgnoreCase) == 0); Assert.IsTrue(postCacheEntriesCallDescriptor.ContentType == CacheContentType.BuildResults); VerifyGetCacheEntries(postCacheEntriesCallDescriptor.Entries); LocalReplyCallDescriptor reply1CallDescriptor = localCallDescriptorList[12] as LocalReplyCallDescriptor; Assert.IsTrue(reply1CallDescriptor.RequestingCallNumber == 1); VerifyGetCacheEntries((CacheEntry[])reply1CallDescriptor.ReplyData); LocalReplyCallDescriptor reply2CallDescriptor = localCallDescriptorList[13] as LocalReplyCallDescriptor; Assert.IsTrue(reply2CallDescriptor.RequestingCallNumber == 6); Assert.IsTrue(string.Compare("Foo", (string)reply2CallDescriptor.ReplyData, StringComparison.OrdinalIgnoreCase) == 0); LocalCallDescriptorForInitializeNode initializeCallDescriptor = localCallDescriptorList[14] as LocalCallDescriptorForInitializeNode; Assert.IsTrue(initializeCallDescriptor.ParentProcessId == 5); Assert.IsTrue(initializeCallDescriptor.NodeId == 4); Assert.IsTrue(initializeCallDescriptor.ToolsetSearchLocations == ToolsetDefinitionLocations.ConfigurationFile); Assert.IsTrue(string.Compare(initializeCallDescriptor.ParentGlobalProperties["PropertyName"].Value, "Value", StringComparison.OrdinalIgnoreCase) == 0); Assert.IsTrue(string.Compare(initializeCallDescriptor.NodeLoggers[0].Name, "Class", StringComparison.OrdinalIgnoreCase) == 0); IDictionary variables = Environment.GetEnvironmentVariables(); Assert.IsTrue(variables.Count == initializeCallDescriptor.EnvironmentVariables.Count); foreach (string key in variables.Keys) { Assert.IsTrue(string.Compare((string)initializeCallDescriptor.EnvironmentVariables[key], (string)variables[key], StringComparison.OrdinalIgnoreCase) == 0); } writeSharedMemory.Reset(); readSharedMemory.Reset(); readSharedMemory = null; writeSharedMemory = null; }
/// <summary> /// This function will start a node and send requests to it /// </summary> private void LaunchNodeAndPostBuildRequest() { int nodeIndex = 0; // Find out what node to launch lock (nodesToLaunch) { nodeIndex = nodesToLaunch.Dequeue(); } // If the provider is shutting down - don't launch the node if (shuttingDown) { nodeData[nodeIndex].NodeState = NodeState.NotLaunched; return; } try { // Either launch node or connect to an already running node InitializeNode(nodeIndex); if (!nodeData[nodeIndex].CommunicationFailed) { // Change the state of the node to launched lock (nodeStateLock) { nodeData[nodeIndex].NodeState = NodeState.Launched; } // Send all the requests to the node. Note that the requests may end up in // mixed order with the request currently being posted. LinkedListNode<BuildRequest> current = nodeData[nodeIndex].TargetList.First; BuildRequest[] buildRequests = new BuildRequest[nodeData[nodeIndex].TargetList.Count]; int i = 0; while (current != null) { buildRequests[i] = current.Value; i++; current = current.Next; } LocalCallDescriptorForPostBuildRequests callDescriptor = new LocalCallDescriptorForPostBuildRequests(buildRequests); nodeData[nodeIndex].NodeCommandQueue.Enqueue(callDescriptor); nodeData[nodeIndex].TargetList = null; } else { // Allow the engine to decide how to proceed since the node failed to launch string message = ResourceUtilities.FormatResourceString("NodeProviderFailure"); ReportNodeCommunicationFailure(nodeIndex, new Exception(message), false); } } catch (Exception e) { // Allow the engine to deal with the exception ReportNodeCommunicationFailure(nodeIndex, e, false); } }
public void PostBuildRequestToNode(int nodeIndex, BuildRequest buildRequest) { ErrorUtilities.VerifyThrow(nodeIndex < nodeData.Length && nodeIndex >= 0, "Node index must be within array boundaries"); if (nodeData[nodeIndex].NodeState != NodeState.Launched) { // Note that we have to check the node status again inside the mutex. This // ensures that that after flipping the status to launched inside the mutex // there will be no more writes to the queue of targets waiting to be sent lock (nodeStateLock) { // Check if we didn't initialize this node if (nodeData[nodeIndex].NodeState != NodeState.Launched && !shuttingDown) { // Check if launch is in progress if (nodeData[nodeIndex].NodeState == NodeState.NotLaunched) { nodeData[nodeIndex].NodeState = NodeState.LaunchInProgress; lock (nodesToLaunch) { nodesToLaunch.Enqueue(nodeIndex); } ThreadStart threadState = new ThreadStart(this.LaunchNodeAndPostBuildRequest); Thread taskThread = new Thread(threadState); taskThread.Name = "MSBuild Node Launcher"; taskThread.Start(); } nodeData[nodeIndex].TargetList.AddFirst(new LinkedListNode<BuildRequest>(buildRequest)); } else { LocalCallDescriptorForPostBuildRequests callDescriptor = new LocalCallDescriptorForPostBuildRequests(buildRequest); nodeData[nodeIndex].NodeCommandQueue.Enqueue(callDescriptor); } } } else { LocalCallDescriptorForPostBuildRequests callDescriptor = new LocalCallDescriptorForPostBuildRequests(buildRequest); nodeData[nodeIndex].NodeCommandQueue.Enqueue(callDescriptor); } }