<PackageReference Include="NUnit" Version="3.0.0-beta-3" />

EventPump

public class EventPump : IDisposable
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 Logger log = InternalTrace.GetLogger("EventPump"); private readonly AutoResetEvent synchronousEventSent = new AutoResetEvent(false); private ITestListener eventListener; private EventQueue events; private Thread pumpThread; private volatile EventPumpState pumpState; private string name; public EventPumpState PumpState { get { Thread.MemoryBarrier(); return pumpState; } set { pumpState = value; Thread.MemoryBarrier(); } } public string Name { get { return name; } set { name = value; } } public EventPump(ITestListener eventListener, EventQueue events) { this.eventListener = eventListener; this.events = events; this.events.SetWaitHandleForSynchronizedEvents(synchronousEventSent); } public void Dispose() { Stop(); ((IDisposable)synchronousEventSent).Dispose(); } public void Start() { if (PumpState == EventPumpState.Stopped) { pumpThread = new Thread(PumpThreadProc); pumpThread.Name = "EventPumpThread" + Name; pumpThread.Priority = ThreadPriority.Highest; pumpState = EventPumpState.Pumping; pumpThread.Start(); } } public void Stop() { if (pumpState == EventPumpState.Pumping) { PumpState = EventPumpState.Stopping; 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); } finally { if (event.IsSynchronous) synchronousEventSent.Set(); } } } catch (Exception ex2) { log.Error("Exception in pump thread", ex2); } finally { PumpState = EventPumpState.Stopped; if (events.Count > 0) log.Error("Event pump thread exiting with {0} events remaining"); } } } }