private bool RunCore() { m_completedNodeCount = 0; m_pendingNodeCount = 0; bool completionSuccess = true; if (m_runList.Count == 0) { // nothing to build Trace.TraceInformation("nothing to build."); return true; } while (m_completedNodeCount < m_requiredNodes.Count) { // while (thingsToIssue AND allowedToLaunch) while ((m_runList.Count > 0) && (m_pendingNodeCount < m_buildOptions.MaxConcurrency)) { // launch one thing BuildNode buildNode = m_runList.Dequeue(); m_runSet.Remove(buildNode); BuildWorkItem workItem = new BuildWorkItem(buildNode); ThreadPool.QueueUserWorkItem(unused => DoAction(workItem)); m_pendingNodeCount += 1; } completionSuccess &= WaitForOneOrMorePendingNodes(); if (!completionSuccess && !m_buildOptions.ContinueOnError) { // Break out of the dispatch loop. break; } } // We have no more BuildNodes left to issue. // Wait for remaining pending nodes to complete. We do this even on failure, // so that we guarantee all work is drained prior to returning. while (m_pendingNodeCount > 0) { completionSuccess &= WaitForOneOrMorePendingNodes(); } return completionSuccess; }
private void DoAction(BuildWorkItem workItem) { BuildNode buildNode = workItem.BuildNode; if (m_buildAction == BuildAction.Build) { workItem.ReturnedStatus = ExecuteOneBuildNode(buildNode); } else if (m_buildAction == BuildAction.Clean) { foreach (var output in buildNode.Translation.ExplicitOutputs) { RemoveFile(output); } HashSet<string> intermediateBuildFiles = buildNode.Translation.GetIntermediateBuildFiles(); foreach (var output in intermediateBuildFiles) { RemoveFile(output); } RemoveFile(buildNode.Translation.DepsCacheFilePath); workItem.ReturnedStatus = BuildStatus.ExecuteSucceeded; } else { // Unhandled action. workItem.ReturnedStatus = BuildStatus.FailureUnknown; } lock (m_returnListMutex) { m_returnList.Enqueue(workItem); Monitor.Pulse(m_returnListMutex); } }