/// <summary> /// This function checks if the given ProjectBuildState is caused by a given parent target (via /// a dependency, onerror or IBuildEngine relationship) /// </summary> internal bool CheckBuildContextForParentMatch ( EngineCallback engineCallback, TargetIdWrapper parentId, Target target, ProjectBuildState projectBuildState ) { BuildRequest parentRequest = null; TargetInProgessState.TargetIdWrapper parentName = FindParentTarget(engineCallback, projectBuildState, target, out parentRequest); if (parentName != null && parentName.Equals(parentId)) { return(true); } if (parentRequest != null) { for (int j = 0; j < parentBuildRequests.Count; j++) { if (parentRequest.HandleId == parentBuildRequests[j].HandleId && parentRequest.RequestId == parentBuildRequests[j].RequestId) { if (parentTargetsForBuildRequests[j].Equals(parentId)) { return(true); } else { return(false); } } } } return(false); }
/// <summary> /// For each target that has a cross node build request waiting for it to complete, iterate /// over the list of outstanding requests and find the matching out going request. Once /// the matching request is found - link the parent and child targets. /// </summary> private void LinkCrossNodeBuildRequests() { foreach (GraphNode node in dependencyGraph.Values) { TargetInProgessState.TargetIdWrapper[] parentsForBuildRequests = new TargetInProgessState.TargetIdWrapper[node.targetState.ParentBuildRequests.Count]; for (int j = 0; j < node.targetState.ParentBuildRequests.Count; j++) { BuildRequest buildRequest = node.targetState.ParentBuildRequests[j]; int nodeIndex = buildRequest.NodeIndex; int handleId = buildRequest.HandleId; int requestId = buildRequest.RequestId; bool foundParent = false; // Skip requests that originated from the host if (handleId == EngineCallback.invalidEngineHandle) { node.isRoot = true; continue; } // If the request being analyzed came from one of the child nodes, its incoming external request's // handleId will point at a routing context on the parent engine. If the outgoing request // orginated from another child the two requests (outgoing and incoming) point at different // routing contexts. In that case it is necessary to unwind the incoming request to the routing // context of the outgoing request. If outgoing request originated from the parent node - // there will be only one routing request. if (node.targetState.TargetId.nodeId != 0) { ExecutionContext executionContext = engineCallback.GetExecutionContextFromHandleId(buildRequest.HandleId); RequestRoutingContext routingContext = executionContext as RequestRoutingContext; if (routingContext != null && routingContext.ParentHandleId != EngineCallback.invalidEngineHandle) { ExecutionContext nextExecutionContext = engineCallback.GetExecutionContextFromHandleId(routingContext.ParentHandleId); if (nextExecutionContext is RequestRoutingContext) { nodeIndex = nextExecutionContext.NodeIndex; handleId = routingContext.ParentHandleId; requestId = routingContext.ParentRequestId; } } else { // Skip requests that originated from the host node.isRoot = true; continue; } } // Iterate over all outstanding requests until a match is found foreach (DictionaryEntry entry in outstandingExternalRequests) { BuildRequest[] externalRequests = (BuildRequest[])entry.Value; for (int i = 0; i < externalRequests.Length && !foundParent; i++) { if (handleId == externalRequests[i].HandleId && requestId == externalRequests[i].RequestId && nodeIndex == externalRequests[i].NodeIndex) { // Verify that the project name is the same ErrorUtilities.VerifyThrow( String.Compare(buildRequest.ProjectFileName, externalRequests[i].ProjectFileName, StringComparison.OrdinalIgnoreCase) == 0, "The two requests should have the same project name"); // Link the two graph nodes together GraphNode parentNode = (GraphNode)dependencyGraph[entry.Key]; parentNode.children.Add(node); parentsForBuildRequests[j] = parentNode.targetState.TargetId; foundParent = true; } } if (foundParent) { break; } } } node.targetState.ParentTargetsForBuildRequests = parentsForBuildRequests; } }