/// <summary> /// Processes all requests that are currently in the queue. /// </summary> private void ProcessRequests() { // Store a list of threads which are resolving SDKs List <Task> tasks = new List <Task>(_requests.Count); SdkResolverRequest item; while (_requests.TryDequeue(out item)) { SdkResolverRequest request = item; // Start a thread to resolve an SDK and add it to the list of threads tasks.Add(Task.Run(() => { // Create an SdkReference from the request SdkReference sdkReference = new SdkReference(request.Name, request.Version, request.MinimumVersion); ILoggingService loggingService = Host.GetComponent(BuildComponentType.LoggingService) as ILoggingService; // This call is usually cached so is very fast but can take longer for a new SDK that is downloaded. Other queued threads for different SDKs will complete sooner and continue on which unblocks evaluations SdkResult result = GetSdkResultAndCache(request.SubmissionId, sdkReference, new EvaluationLoggingContext(loggingService, request.BuildEventContext, request.ProjectPath), request.ElementLocation, request.SolutionPath, request.ProjectPath); // Create a response SdkResolverResponse response = new SdkResolverResponse(result.Path, result.Version); // Get the node manager and send the response back to the node that requested the SDK INodeManager nodeManager = Host.GetComponent(BuildComponentType.NodeManager) as INodeManager; nodeManager.SendData(request.NodeId, response); })); } // Wait for all tasks to complete Task.WaitAll(tasks.ToArray()); }
/// <summary> /// Handles a response from the main node. /// </summary> /// <param name="response"></param> private void HandleResponse(SdkResolverResponse response) { // Store the last response so the awaiting thread can use it _lastResponse = response; // Signal that a response has been received _responseReceivedEvent.Set(); }
/// <inheritdoc cref="ISdkResolverService.ResolveSdk"/> public override string ResolveSdk(int submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, string solutionPath, string projectPath) { // Get a cached response if possible, otherwise send the request SdkResolverResponse response = _responseCache.GetOrAdd( sdk.Name, key => RequestSdkPathFromMainNode(submissionId, sdk, loggingContext, sdkReferenceLocation, solutionPath, projectPath)); if (response.Version != null && !SdkResolverService.IsReferenceSameVersion(sdk, response.Version)) { // MSB4240: Multiple versions of the same SDK "{0}" cannot be specified. The SDK version "{1}" already specified by "{2}" will be used and the version "{3}" will be ignored. loggingContext.LogWarning(null, new BuildEventFileInfo(sdkReferenceLocation), "ReferencingMultipleVersionsOfTheSameSdk", sdk.Name, response.Version, response.ElementLocation, sdk.Version); } return(response.FullPath); }
private SdkResolverResponse RequestSdkPathFromMainNode(int submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, string solutionPath, string projectPath) { // Clear out the last response for good measure _lastResponse = null; // Create the SdkResolverRequest packet to send INodePacket packet = SdkResolverRequest.Create(submissionId, sdk, loggingContext.BuildEventContext, sdkReferenceLocation, solutionPath, projectPath); SendPacket(packet); // Wait for either the response or a shutdown event. Either event means this thread should return WaitHandle.WaitAny(new WaitHandle[] { _responseReceivedEvent, ShutdownEvent }); // Keep track of the element location of the reference _lastResponse.ElementLocation = sdkReferenceLocation; // Return the response which was set by another thread. In the case of shutdown, it should be null. return(_lastResponse); }