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.Threading;
namespace NUnit.Framework.Internal.Execution
{
public class EventPump : IDisposable
{
private static readonly Logger log = InternalTrace.GetLogger("EventPump");
private readonly ITestListener _eventListener;
private readonly EventQueue _events;
private Thread _pumpThread;
private int _pumpState;
public EventPumpState PumpState => (EventPumpState)_pumpState;
public string Name { get; set; }
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()
{
try {
while (true) {
Event event = _events.Dequeue(PumpState == EventPumpState.Pumping);
if (event == null)
break;
try {
event.Send(_eventListener);
} catch (Exception ex) {
log.Error("Exception in event handler\r\n {0}", ex);
}
}
} catch (Exception ex2) {
log.Error("Exception in pump thread", ex2);
} finally {
_pumpState = 0;
if (_events.Count > 0)
log.Error("Event pump thread exiting with {0} events remaining");
}
}
}
}