Пример #1
0
        /// <summary>
        /// This is called back when this request needs to issue new requests and possible wait on them.  This method will
        /// block the builder's thread if any of the requests require us to wait for their results.
        /// </summary>
        /// <param name="requests">The list of build requests to be built.</param>
        /// <returns>The results, or null if the build should terminate.</returns>
        private async Task<BuildResult[]> StartNewBuildRequests(FullyQualifiedBuildRequest[] requests)
        {
            // Determine if we need to wait for results from any of these requests.
            // UNDONE: Currently we never set ResultsNeeded to anything but true.  The purpose of this flag would be
            // to issue another top-level build request which no other request depends on, but which must finish in order for
            // the build to be considered complete.  This would be brand new semantics.
            bool waitForResults = false;
            foreach (FullyQualifiedBuildRequest request in requests)
            {
                if (request.ResultsNeeded)
                {
                    waitForResults = true;
                    break;
                }
            }

            _blockType = BlockType.BlockedOnChildRequests;

            // Save the current operating environment, if necessary
            if (waitForResults)
            {
                SaveOperatingEnvironment();
            }

            // Issue the requests to the engine            
            RaiseOnNewBuildRequests(requests);

            // TODO: OPTIMIZATION: By returning null here, we commit to having to unwind the stack all the
            // way back to RequestThreadProc and then shutting down the thread before we can receive the
            // results and continue with them.  It is not always the case that this will be desirable, however,
            // particularly if the results we need are immediately available.  In those cases, it would be 
            // useful to wait here for a short period in case those results become available - one second
            // might be enough.  This means we may occasionally get more than one builder thread lying around
            // waiting for something to happen, but that would be short lived.  At the same time it would
            // allow these already-available results to be utilized immediately without the unwind
            // semantics.

            // Now wait for results if we are supposed to.
            BuildResult[] results;
            if (waitForResults)
            {
                WaitHandle[] handles = new WaitHandle[] { _terminateEvent, _continueEvent };

                int handle;
                if (IsBuilderUsingLegacyThreadingSemantics(_componentHost, _requestEntry))
                {
                    handle = RequestBuilder.WaitWithBuilderThreadStart(handles, true, _componentHost.LegacyThreadingData, _requestEntry.Request.SubmissionId);
                }
                else if (_inMSBuildCallback)
                {
                    CultureInfo savedCulture = CultureInfo.CurrentCulture;
                    CultureInfo savedUICulture = CultureInfo.CurrentUICulture;

                    handle = await handles.ToTask();

                    Thread.CurrentThread.CurrentCulture = savedCulture;
                    Thread.CurrentThread.CurrentUICulture = savedUICulture;
                }
                else
                {
                    handle = WaitHandle.WaitAny(handles);
                }

                // If this is not a shutdown case, then the entry should be in the active state.
                if (handle == 1)
                {
                    // Restore the operating environment.
                    RestoreOperatingEnvironment();
                    VerifyEntryInActiveState();
                }

                results = GetResultsForContinuation(requests, handle == 1);
            }
            else
            {
                results = new BuildResult[] { };
            }

            ErrorUtilities.VerifyThrow(requests.Length == results.Length, "# results != # requests");

            _blockType = BlockType.Unblocked;
            return results;
        }
Пример #2
0
        /// <summary>
        /// This method is called when the current request needs to build a target which is already in progress on this configuration, but which
        /// is being built by another request.
        /// </summary>
        /// <param name="blockingGlobalRequestId">The id of the request on which we are blocked.</param>
        public async Task BlockOnTargetInProgress(int blockingGlobalRequestId, string blockingTarget)
        {
            VerifyIsNotZombie();
            SaveOperatingEnvironment();

            _blockType = BlockType.BlockedOnTargetInProgress;

            RaiseOnBlockedRequest(blockingGlobalRequestId, blockingTarget);

            WaitHandle[] handles = new WaitHandle[] { _terminateEvent, _continueEvent };

            int handle;
            if (IsBuilderUsingLegacyThreadingSemantics(_componentHost, _requestEntry))
            {
                handle = WaitHandle.WaitAny(handles);
            }
            else
            {
                handle = await handles.ToTask();
            }

            RestoreOperatingEnvironment();

            if (handle == 0)
            {
                // We've been aborted
                throw new BuildAbortedException();
            }

            _blockType = BlockType.Unblocked;

            VerifyEntryInActiveState();
        }