EventPump
EventPump pulls events out of an EventQueue and sends
them to a listener. It is used to send events back to
the client without using the CallContext of the test
runner thread.
using NUnit.Framework.Interfaces;
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 class EventPump : IDisposable
{
[System.Runtime.CompilerServices.Nullable(1)]
private static readonly Logger Log = InternalTrace.GetLogger("EventPump");
[System.Runtime.CompilerServices.Nullable(1)]
private readonly ITestListener _eventListener;
[System.Runtime.CompilerServices.Nullable(1)]
private readonly EventQueue _events;
private Thread _pumpThread;
private int _pumpState;
public EventPumpState PumpState => (EventPumpState)_pumpState;
public string Name { get; set; }
[System.Runtime.CompilerServices.NullableContext(1)]
public EventPump(ITestListener eventListener, EventQueue events)
{
_eventListener = eventListener;
_events = events;
}
public void Dispose()
{
Stop();
}
public void Start()
{
if (Interlocked.CompareExchange(ref _pumpState, 1, 0) == 0) {
_pumpThread = new Thread(PumpThreadProc) {
Name = "EventPumpThread" + Name,
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 EventPump");
try {
while (true) {
Event event = _events.Dequeue(PumpState == EventPumpState.Pumping);
if (event == null)
break;
try {
event.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");
}
}
}
}