a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
170 lines
4.4 KiB
C#
170 lines
4.4 KiB
C#
// ****************************************************************
|
|
// This is free software licensed under the NUnit license. You
|
|
// may obtain a copy of the license as well as information regarding
|
|
// copyright ownership at http://nunit.org/?p=license&r=2.4.
|
|
// ****************************************************************
|
|
|
|
namespace NUnit.Core
|
|
{
|
|
using System;
|
|
using System.Threading;
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
public class EventPump : IDisposable
|
|
{
|
|
#region Instance Variables
|
|
/// <summary>
|
|
/// The downstream listener to which we send events
|
|
/// </summary>
|
|
EventListener eventListener;
|
|
|
|
/// <summary>
|
|
/// The queue that holds our events
|
|
/// </summary>
|
|
EventQueue events;
|
|
|
|
/// <summary>
|
|
/// Thread to do the pumping
|
|
/// </summary>
|
|
Thread pumpThread;
|
|
|
|
/// <summary>
|
|
/// Indicator that we are pumping events
|
|
/// </summary>
|
|
private bool pumping;
|
|
|
|
/// <summary>
|
|
/// Indicator that we are stopping
|
|
/// </summary>
|
|
private bool stopping;
|
|
|
|
/// <summary>
|
|
/// If true, stop after sending RunFinished
|
|
/// </summary>
|
|
private bool autostop;
|
|
#endregion
|
|
|
|
#region Constructor
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
/// <param name="eventListener">The EventListener to receive events</param>
|
|
/// <param name="events">The event queue to pull events from</param>
|
|
/// <param name="autostop">Set to true to stop pump after RunFinished</param>
|
|
public EventPump( EventListener eventListener, EventQueue events, bool autostop)
|
|
{
|
|
this.eventListener = eventListener;
|
|
this.events = events;
|
|
this.autostop = autostop;
|
|
}
|
|
#endregion
|
|
|
|
#region Properties
|
|
// TODO: Replace booleans with a state?
|
|
/// <summary>
|
|
/// Returns true if we are pumping events
|
|
/// </summary>
|
|
public bool Pumping
|
|
{
|
|
get { return pumping; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns true if a stop is in progress
|
|
/// </summary>
|
|
public bool Stopping
|
|
{
|
|
get { return stopping; }
|
|
}
|
|
#endregion
|
|
|
|
#region Public Methods
|
|
/// <summary>
|
|
/// Dispose stops the pump
|
|
/// </summary>
|
|
public void Dispose()
|
|
{
|
|
Stop();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Start the pump
|
|
/// </summary>
|
|
public void Start()
|
|
{
|
|
if ( !this.Pumping ) // Ignore if already started
|
|
{
|
|
this.pumpThread = new Thread( new ThreadStart( PumpThreadProc ) );
|
|
this.pumpThread.Name = "EventPumpThread";
|
|
pumping = true;
|
|
this.pumpThread.Start();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tell the pump to stop after emptying the queue.
|
|
/// </summary>
|
|
public void Stop()
|
|
{
|
|
if ( this.Pumping && !this.Stopping ) // Ignore extra calls
|
|
{
|
|
lock( events )
|
|
{
|
|
stopping = true;
|
|
Monitor.Pulse( events ); // In case thread is waiting
|
|
}
|
|
this.pumpThread.Join();
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region PumpThreadProc
|
|
/// <summary>
|
|
/// Our thread proc for removing items from the event
|
|
/// queue and sending them on. Note that this would
|
|
/// need to do more locking if any other thread were
|
|
/// removing events from the queue.
|
|
/// </summary>
|
|
private void PumpThreadProc()
|
|
{
|
|
EventListener hostListeners = CoreExtensions.Host.Listeners;
|
|
Monitor.Enter( events );
|
|
try
|
|
{
|
|
while (this.events.Count > 0 || !stopping)
|
|
{
|
|
while (this.events.Count > 0)
|
|
{
|
|
Event e = this.events.Dequeue();
|
|
e.Send(this.eventListener);
|
|
e.Send(hostListeners);
|
|
if (autostop && e is RunFinishedEvent)
|
|
stopping = true;
|
|
}
|
|
// Will be pulsed if there are any events added
|
|
// or if it's time to stop the pump.
|
|
if (!stopping)
|
|
Monitor.Wait(events);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new ApplicationException("Exception in pump thread", ex);
|
|
}
|
|
finally
|
|
{
|
|
Monitor.Exit( events );
|
|
pumping = false;
|
|
stopping = false;
|
|
//pumpThread = null;
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
}
|