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