Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix deadlock in BuildManager vs LoggingService #6837

Merged
merged 5 commits into from
Sep 15, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 58 additions & 14 deletions src/Build/BackEnd/BuildManager/BuildManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ public BuildManager(string hostName)

_projectStartedEventHandler = OnProjectStarted;
_projectFinishedEventHandler = OnProjectFinished;
_loggingThreadExceptionEventHandler = OnThreadException;
_loggingThreadExceptionEventHandler = OnLoggingThreadException;
_legacyThreadingData = new LegacyThreadingData();
_instantiationTimeUtc = DateTime.UtcNow;
}
Expand Down Expand Up @@ -832,10 +832,15 @@ public void EndBuild()
ShutdownConnectedNodes(false /* normal termination */);
_noNodesActiveEvent.WaitOne();

// Wait for all of the actions in the work queue to drain. Wait() could throw here if there was an unhandled exception
// in the work queue, but the top level exception handler there should catch everything and have forwarded it to the
// Wait for all of the actions in the work queue to drain.
// _workQueue.Completion.Wait() could throw here if there was an unhandled exception in the work queue,
// but the top level exception handler there should catch everything and have forwarded it to the
// OnThreadException method in this class already.
_workQueue.Complete();
if (ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_0))
{
_workQueue.Completion.Wait();
}

// Stop the graph scheduling thread(s)
_graphSchedulingCancellationSource?.Cancel();
Expand Down Expand Up @@ -2798,7 +2803,7 @@ private NodeConfiguration GetNodeConfiguration()
}

/// <summary>
/// Handler for thread exceptions (logging thread, communications thread). This handler will only get called if the exception did not previously
/// Handler for thread exceptions. This handler will only get called if the exception did not previously
/// get handled by a node exception handlers (for instance because the build is complete for the node.) In this case we
/// get the exception and will put it into the OverallBuildResult so that the host can see what happened.
/// </summary>
Expand Down Expand Up @@ -2855,22 +2860,49 @@ private void OnThreadException(Exception e)
}
}

/// <summary>
/// Handler for LoggingService thread exceptions.
/// </summary>
private void OnLoggingThreadException(Exception e)
{
if (ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_0))
{
_workQueue.Post(() => OnThreadException(e));
}
else
{
OnThreadException(e);
}
}

/// <summary>
/// Raised when a project finished logging message has been processed.
/// </summary>
private void OnProjectFinished(object sender, ProjectFinishedEventArgs e)
{
lock (_syncLock)
if (ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_0))
{
if (_projectStartedEvents.TryGetValue(e.BuildEventContext.SubmissionId, out var originalArgs))
_workQueue.Post(() => OnProjectFinishedBody(e));
}
else
{
OnProjectFinishedBody(e);
}

void OnProjectFinishedBody(ProjectFinishedEventArgs e)
{
lock (_syncLock)
{
if (originalArgs.BuildEventContext.Equals(e.BuildEventContext))
if (_projectStartedEvents.TryGetValue(e.BuildEventContext.SubmissionId, out var originalArgs))
{
_projectStartedEvents.Remove(e.BuildEventContext.SubmissionId);
if (_buildSubmissions.TryGetValue(e.BuildEventContext.SubmissionId, out var submission))
if (originalArgs.BuildEventContext.Equals(e.BuildEventContext))
{
submission.CompleteLogging();
CheckSubmissionCompletenessAndRemove(submission);
_projectStartedEvents.Remove(e.BuildEventContext.SubmissionId);
if (_buildSubmissions.TryGetValue(e.BuildEventContext.SubmissionId, out var submission))
{
submission.CompleteLogging();
CheckSubmissionCompletenessAndRemove(submission);
}
}
}
}
Expand All @@ -2882,11 +2914,23 @@ private void OnProjectFinished(object sender, ProjectFinishedEventArgs e)
/// </summary>
private void OnProjectStarted(object sender, ProjectStartedEventArgs e)
{
lock (_syncLock)
if (ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_0))
{
_workQueue.Post(() => OnProjectStartedBody(e));
}
else
{
OnProjectStartedBody(e);
}

void OnProjectStartedBody(ProjectStartedEventArgs e)
{
if (!_projectStartedEvents.ContainsKey(e.BuildEventContext.SubmissionId))
lock (_syncLock)
{
_projectStartedEvents[e.BuildEventContext.SubmissionId] = e;
if (!_projectStartedEvents.ContainsKey(e.BuildEventContext.SubmissionId))
{
_projectStartedEvents[e.BuildEventContext.SubmissionId] = e;
}
}
}
}
Expand Down