<PackageReference Include="NUnit" Version="4.4.0" />

EventPump<TEvent, TListener>

public abstract class EventPump<TEvent, TListener> : IDisposable where TEvent : IEvent<TListener>
EventPump base class pulls events of any type out of an EventQueue and sends them to any listener. It is used to send events back to the client without using the CallContext of the test runner thread.
using System; using System.Runtime.CompilerServices; using System.Threading; namespace NUnit.Framework.Internal.Execution { [System.Runtime.CompilerServices.NullableContext(2)] [System.Runtime.CompilerServices.Nullable(0)] public abstract class EventPump<[System.Runtime.CompilerServices.Nullable(0)] TEvent, TListener> : IDisposable where TEvent : IEvent<TListener> { [System.Runtime.CompilerServices.Nullable(1)] private static readonly Logger Log = InternalTrace.GetLogger("EventPump"); [System.Runtime.CompilerServices.Nullable(1)] private readonly TListener _eventListener; [System.Runtime.CompilerServices.Nullable(1)] private readonly EventQueue<TEvent> _events; private Thread _pumpThread; private int _pumpState; public EventPumpState PumpState => (EventPumpState)_pumpState; public string Name { get; set; } [System.Runtime.CompilerServices.NullableContext(1)] protected EventPump(TListener eventListener, EventQueue<TEvent> events, string name = "Standard") { _eventListener = eventListener; _events = events; Name = name; } public void Dispose() { Stop(); } public void Start() { if (Interlocked.CompareExchange(ref _pumpState, 1, 0) == 0) { _pumpThread = new Thread(PumpThreadProc) { Name = "NUnit.Fw." + Name + "EventPumpThread", Priority = ThreadPriority.Highest }; _pumpThread.Start(); } } public void Stop() { if (Interlocked.CompareExchange(ref _pumpState, 2, 1) == 1) { _events.Stop(); _pumpThread?.Join(); } } private void PumpThreadProc() { Log.Debug("Starting " + Name); try { while (true) { TEvent val = _events.Dequeue(PumpState == EventPumpState.Pumping); if (val == null) break; try { val.Send(_eventListener); } catch (Exception exception) { Log.Error("Exception in event handler {0}", ExceptionHelper.BuildStackTrace(exception)); } } Log.Debug("EventPump Terminating"); } catch (Exception exception2) { Log.Error("Exception in pump thread {0}", ExceptionHelper.BuildStackTrace(exception2)); } finally { _pumpState = 0; if (_events.Count > 0) Log.Error("Event pump thread exiting with {0} events remaining"); } } } }