Skip to content
63 changes: 40 additions & 23 deletions src/Build/BackEnd/Components/Logging/LoggingService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
Expand All @@ -10,12 +10,12 @@
using System.Threading;
using Microsoft.Build.BackEnd.Components.RequestBuilder;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Experimental.BuildCheck;
using Microsoft.Build.Experimental.BuildCheck.Infrastructure;
using Microsoft.Build.Framework;
using Microsoft.Build.Shared;
using InternalLoggerException = Microsoft.Build.Exceptions.InternalLoggerException;
using LoggerDescription = Microsoft.Build.Logging.LoggerDescription;
using Microsoft.Build.Experimental.BuildCheck;

#nullable disable

Expand Down Expand Up @@ -62,7 +62,7 @@ internal enum LoggingServiceState
ShuttingDown,

/// <summary>
/// The logging service completly shutdown
/// The logging service completely shutdown.
/// </summary>
Shutdown
}
Expand Down Expand Up @@ -248,12 +248,14 @@ internal partial class LoggingService : ILoggingService, INodePacketHandler
/// Event set when message is consumed from queue.
/// </summary>
private AutoResetEvent _dequeueEvent;

/// <summary>
/// Event set when queue become empty.
/// Event set when queue become empty.
/// </summary>
private ManualResetEvent _emptyQueueEvent;

/// <summary>
/// Even set when message is added into queue.
/// Event set when message is added into queue.
/// </summary>
private AutoResetEvent _enqueueEvent;

Expand Down Expand Up @@ -1398,34 +1400,47 @@ private void StartLoggingEventProcessing()
void LoggingEventProc()
{
var completeAdding = _loggingEventProcessingCancellation.Token;
WaitHandle[] waitHandlesForNextEvent = { completeAdding.WaitHandle, _enqueueEvent };
WaitHandle[] waitHandlesForNextEvent = [completeAdding.WaitHandle, _enqueueEvent];

do
try
{
if (_eventQueue.TryDequeue(out object ev))
{
LoggingEventProcessor(ev);
_dequeueEvent.Set();
}
else
{
_emptyQueueEvent.Set();
// Store field references locally to prevent race with cleanup
var eventQueue = _eventQueue;
var dequeueEvent = _dequeueEvent;
var emptyQueueEvent = _emptyQueueEvent;
var enqueueEvent = _enqueueEvent;

// Wait for next event, or finish.
if (!completeAdding.IsCancellationRequested && _eventQueue.IsEmpty)
do
{
if (eventQueue.TryDequeue(out object ev))
{
WaitHandle.WaitAny(waitHandlesForNextEvent);
LoggingEventProcessor(ev);
dequeueEvent?.Set();
}
else
{
emptyQueueEvent?.Set();

_emptyQueueEvent.Reset();
}
} while (!_eventQueue.IsEmpty || !completeAdding.IsCancellationRequested);
// Wait for next event, or finish.
if (!completeAdding.IsCancellationRequested && eventQueue.IsEmpty)
{
WaitHandle.WaitAny(waitHandlesForNextEvent);
}

_emptyQueueEvent.Set();
emptyQueueEvent.Reset();
}
} while (!eventQueue.IsEmpty || !completeAdding.IsCancellationRequested);

emptyQueueEvent.Set();
}
catch (ObjectDisposedException)
{
// Events/queue were disposed during shutdown, exit processing
return;
}
}
}


/// <summary>
/// Clean resources used for logging event processing queue.
/// </summary>
Expand All @@ -1438,9 +1453,11 @@ private void CleanLoggingEventProcessing()
_loggingEventProcessingCancellation?.Dispose();

_eventQueue = null;

_dequeueEvent = null;
_enqueueEvent = null;
_emptyQueueEvent = null;

_loggingEventProcessingCancellation = null;
_loggingEventProcessingThread = null;
}
Expand Down