diff --git a/src/Build/BackEnd/Components/Logging/LoggingService.cs b/src/Build/BackEnd/Components/Logging/LoggingService.cs
index cfc289ad30e..8721af66c6b 100644
--- a/src/Build/BackEnd/Components/Logging/LoggingService.cs
+++ b/src/Build/BackEnd/Components/Logging/LoggingService.cs
@@ -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;
@@ -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
@@ -62,7 +62,7 @@ internal enum LoggingServiceState
ShuttingDown,
///
- /// The logging service completly shutdown
+ /// The logging service completely shutdown.
///
Shutdown
}
@@ -248,12 +248,14 @@ internal partial class LoggingService : ILoggingService, INodePacketHandler
/// Event set when message is consumed from queue.
///
private AutoResetEvent _dequeueEvent;
+
///
- /// Event set when queue become empty.
+ /// Event set when queue become empty.
///
private ManualResetEvent _emptyQueueEvent;
+
///
- /// Even set when message is added into queue.
+ /// Event set when message is added into queue.
///
private AutoResetEvent _enqueueEvent;
@@ -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;
+ }
}
}
-
///
/// Clean resources used for logging event processing queue.
///
@@ -1438,9 +1453,11 @@ private void CleanLoggingEventProcessing()
_loggingEventProcessingCancellation?.Dispose();
_eventQueue = null;
+
_dequeueEvent = null;
_enqueueEvent = null;
_emptyQueueEvent = null;
+
_loggingEventProcessingCancellation = null;
_loggingEventProcessingThread = null;
}