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; }