Skip to content

Commit

Permalink
fixed thread aborting
Browse files Browse the repository at this point in the history
  • Loading branch information
Zwirbelbart committed May 1, 2015
1 parent ebf0360 commit b69a423
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 128 deletions.
6 changes: 3 additions & 3 deletions src/IrcClient/Channel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ public class Channel
{
private string _Name;
private string _Key = String.Empty;
private Hashtable _Users = Hashtable.Synchronized(new Hashtable(new CaseInsensitiveHashCodeProvider(), new CaseInsensitiveComparer()));
private Hashtable _Ops = Hashtable.Synchronized(new Hashtable(new CaseInsensitiveHashCodeProvider(), new CaseInsensitiveComparer()));
private Hashtable _Voices = Hashtable.Synchronized(new Hashtable(new CaseInsensitiveHashCodeProvider(), new CaseInsensitiveComparer()));
private Hashtable _Users = Hashtable.Synchronized(new Hashtable(StringComparer.OrdinalIgnoreCase));
private Hashtable _Ops = Hashtable.Synchronized(new Hashtable(StringComparer.OrdinalIgnoreCase));
private Hashtable _Voices = Hashtable.Synchronized(new Hashtable(StringComparer.OrdinalIgnoreCase));
private StringCollection _Bans = new StringCollection();
private List<string> _BanExcepts = new List<string>();
private List<string> _InviteExcepts = new List<string>();
Expand Down
4 changes: 2 additions & 2 deletions src/IrcClient/IrcClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ public class IrcClient : IrcCommands
private bool _MotdReceived;
private Array _ReplyCodes = Enum.GetValues(typeof(ReplyCode));
private StringCollection _JoinedChannels = new StringCollection();
private Hashtable _Channels = Hashtable.Synchronized(new Hashtable(new CaseInsensitiveHashCodeProvider(), new CaseInsensitiveComparer()));
private Hashtable _IrcUsers = Hashtable.Synchronized(new Hashtable(new CaseInsensitiveHashCodeProvider(), new CaseInsensitiveComparer()));
private Hashtable _Channels = Hashtable.Synchronized(new Hashtable(StringComparer.OrdinalIgnoreCase));
private Hashtable _IrcUsers = Hashtable.Synchronized(new Hashtable(StringComparer.OrdinalIgnoreCase));
private List<ChannelInfo> _ChannelList;
private Object _ChannelListSyncRoot = new Object();
private AutoResetEvent _ChannelListReceivedEvent;
Expand Down
7 changes: 4 additions & 3 deletions src/IrcClient/NonRfcChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

using System;
using System.Collections;
using System.Collections.Specialized;

Expand All @@ -37,9 +38,9 @@ namespace Meebey.SmartIrc4net
/// <threadsafety static="true" instance="true" />
public class NonRfcChannel : Channel
{
private Hashtable _Owners = Hashtable.Synchronized(new Hashtable(new CaseInsensitiveHashCodeProvider(), new CaseInsensitiveComparer()));
private Hashtable _ChannelAdmins = Hashtable.Synchronized(new Hashtable(new CaseInsensitiveHashCodeProvider(), new CaseInsensitiveComparer()));
private Hashtable _Halfops = Hashtable.Synchronized(new Hashtable(new CaseInsensitiveHashCodeProvider(), new CaseInsensitiveComparer()));
private Hashtable _Owners = Hashtable.Synchronized(new Hashtable(StringComparer.OrdinalIgnoreCase));
private Hashtable _ChannelAdmins = Hashtable.Synchronized(new Hashtable(StringComparer.OrdinalIgnoreCase));
private Hashtable _Halfops = Hashtable.Synchronized(new Hashtable(StringComparer.OrdinalIgnoreCase));

/// <summary>
///
Expand Down
206 changes: 86 additions & 120 deletions src/IrcConnection/IrcConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -812,9 +812,9 @@ public void Disconnect()

IsDisconnecting = true;

_IdleWorkerThread.Stop();
_ReadThread.Stop();
_WriteThread.Stop();
_IdleWorkerThread.RequestStop();
_ReadThread.RequestStop();
_WriteThread.RequestStop();
_TcpClient.Close();
_IsConnected = false;
_IsRegistered = false;
Expand Down Expand Up @@ -1050,17 +1050,65 @@ private void _OnConnectionError(object sender, EventArgs e)
} catch (ConnectionException) {
}
}


/// <summary>
///
/// </summary>
private abstract class FiniteThread
{
/// <summary>
///
/// </summary>
public Thread Thread { get; internal set; }

/// <summary>
///
/// </summary>
public bool IsStopRequested { get; internal set; }

/// <summary>
///
/// </summary>
public string ThreadName { get; internal set; }

/// <summary>
///
/// </summary>
public void RequestStop()
{
IsStopRequested = true;
}

protected FiniteThread()
{
IsStopRequested = false;
ThreadName = "(unnamed thread)";
}

protected abstract void PrepareStart();

protected abstract void Worker();

/// <summary>
///
/// </summary>
public void Start() {
PrepareStart();

Thread = new Thread(Worker) { IsBackground = true, Name = ThreadName};
Thread.Start();
}
}

/// <summary>
///
/// </summary>
private class ReadThread
private class ReadThread : FiniteThread
{
#if LOG4NET
private static readonly log4net.ILog _Logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
#endif
private IrcConnection _Connection;
private Thread _Thread;
private Queue _Queue = Queue.Synchronized(new Queue());

public AutoResetEvent QueuedEvent;
Expand All @@ -1079,68 +1127,36 @@ public ReadThread(IrcConnection connection)
{
_Connection = connection;
QueuedEvent = new AutoResetEvent(false);
ThreadName = "ReadThread ("+_Connection.Address+":"+_Connection.Port+")";
}

/// <summary>
///
/// </summary>
public void Start()
{
_Thread = new Thread(new ThreadStart(_Worker));
_Thread.Name = "ReadThread ("+_Connection.Address+":"+_Connection.Port+")";
_Thread.IsBackground = true;
_Thread.Start();
}
protected override void PrepareStart() { }

/// <summary>
///
/// </summary>
public void Stop()
protected override void Worker()
{
#if LOG4NET
_Logger.Debug("Stop()");
#endif

#if LOG4NET
_Logger.Debug("Stop(): aborting thread...");
#endif
_Thread.Abort();
// make sure we close the stream after the thread is gone, else
// the thread will think the connection is broken!
#if LOG4NET
_Logger.Debug("Stop(): joining thread...");
#endif
_Thread.Join();

#if LOG4NET
_Logger.Debug("Stop(): closing reader...");
#endif
try {
_Connection._Reader.Close();
} catch (ObjectDisposedException) {
}

// clean up our receive queue else we continue processing old
// messages when the read thread is restarted!
_Queue.Clear();
}

private void _Worker()
{
#if LOG4NET
Logger.Socket.Debug("ReadThread started");
Logger.Socket.Debug("ReadThread Worker(): starting");
#endif
try {
string data = "";
try {
while (_Connection.IsConnected &&
while (!IsStopRequested && _Connection.IsConnected &&
((data = _Connection._Reader.ReadLine()) != null)) {
_Queue.Enqueue(data);
QueuedEvent.Set();
#if LOG4NET
Logger.Socket.Debug("received: \""+data+"\"");
#endif
}
#if LOG4NET
Logger.Socket.Debug("ReadThread Worker(): loop ended");
Logger.Socket.Debug("ReadThread Worker(): closing reader");
#endif
_Connection._Reader.Close();

// clean up our receive queue else we continue processing old
// messages when the read thread is restarted!
_Queue.Clear();
} catch (IOException e) {
#if LOG4NET
Logger.Socket.Warn("IOException: "+e.Message);
Expand All @@ -1155,11 +1171,6 @@ private void _Worker()
_Connection.IsConnectionError = true;
}
}
} catch (ThreadAbortException) {
Thread.ResetAbort();
#if LOG4NET
Logger.Socket.Debug("ReadThread aborted");
#endif
} catch (Exception ex) {
#if LOG4NET
Logger.Socket.Error(ex);
Expand All @@ -1171,10 +1182,9 @@ private void _Worker()
/// <summary>
///
/// </summary>
private class WriteThread
private class WriteThread : FiniteThread
{
private IrcConnection _Connection;
private Thread _Thread;
private int _HighCount;
private int _AboveMediumCount;
private int _MediumCount;
Expand All @@ -1198,54 +1208,31 @@ public WriteThread(IrcConnection connection)
{
_Connection = connection;
QueuedEvent = new AutoResetEvent(false);
ThreadName = "WriteThread (" + _Connection.Address + ":" + _Connection.Port + ")";
}

/// <summary>
///
/// </summary>
public void Start()
{
_Thread = new Thread(new ThreadStart(_Worker));
_Thread.Name = "WriteThread ("+_Connection.Address+":"+_Connection.Port+")";
_Thread.IsBackground = true;
_Thread.Start();
}
protected override void PrepareStart() { }

/// <summary>
///
/// </summary>
public void Stop()
{
#if LOG4NET
Logger.Connection.Debug("Stopping WriteThread...");
#endif

_Thread.Abort();
// make sure we close the stream after the thread is gone, else
// the thread will think the connection is broken!
_Thread.Join();

try {
_Connection._Writer.Close();
} catch (ObjectDisposedException) {
}
}

private void _Worker()
protected override void Worker()
{
#if LOG4NET
Logger.Socket.Debug("WriteThread started");
Logger.Socket.Debug("WriteThread Worker(): starting");
#endif
try {
try {
while (_Connection.IsConnected) {
while (!IsStopRequested && _Connection.IsConnected) {
QueuedEvent.WaitOne();
var isBufferEmpty = false;
do {
isBufferEmpty = _CheckBuffer() == 0;
Thread.Sleep(_Connection._SendDelay);
} while (!isBufferEmpty);
}
#if LOG4NET
Logger.Socket.Debug("WriteThread Worker(): loop ended");
Logger.Socket.Debug("WriteThread Worker(): closing writer");
#endif
_Connection._Writer.Close();
} catch (IOException e) {
#if LOG4NET
Logger.Socket.Warn("IOException: " + e.Message);
Expand All @@ -1260,11 +1247,6 @@ private void _Worker()
_Connection.IsConnectionError = true;
}
}
} catch (ThreadAbortException) {
Thread.ResetAbort();
#if LOG4NET
Logger.Socket.Debug("WriteThread aborted");
#endif
} catch (Exception ex) {
#if LOG4NET
Logger.Socket.Error(ex);
Expand Down Expand Up @@ -1433,10 +1415,9 @@ private bool _CheckLowBuffer()
/// <summary>
///
/// </summary>
private class IdleWorkerThread
private class IdleWorkerThread : FiniteThread
{
private IrcConnection _Connection;
private Thread _Thread;

/// <summary>
///
Expand All @@ -1445,39 +1426,26 @@ private class IdleWorkerThread
public IdleWorkerThread(IrcConnection connection)
{
_Connection = connection;
ThreadName = "IdleWorkerThread ("+_Connection.Address+":"+_Connection.Port+")";
}

/// <summary>
///
/// </summary>
public void Start()
protected override void PrepareStart()
{
DateTime now = DateTime.Now;
_Connection._LastPingSent = now;
_Connection._LastPongReceived = now;

_Thread = new Thread(new ThreadStart(_Worker));
_Thread.Name = "IdleWorkerThread ("+_Connection.Address+":"+_Connection.Port+")";
_Thread.IsBackground = true;
_Thread.Start();
}

/// <summary>
///
/// </summary>
public void Stop()
{
_Thread.Abort();
_Thread.Join();
}

private void _Worker()
protected override void Worker()
{
#if LOG4NET
Logger.Socket.Debug("IdleWorkerThread started");
Logger.Socket.Debug("IdleWorkerThread Worker(): starting");
#endif
try {
while (_Connection.IsConnected ) {
while (!IsStopRequested && _Connection.IsConnected ) {
Thread.Sleep(_Connection._IdleWorkerInterval * 1000);

// only send active pings if we are registered
Expand Down Expand Up @@ -1514,10 +1482,8 @@ private void _Worker()
break;
}
}
} catch (ThreadAbortException) {
Thread.ResetAbort();
#if LOG4NET
Logger.Socket.Debug("IdleWorkerThread aborted");
Logger.Socket.Debug("IdleWorkerThread Worker(): loop ended");
#endif
} catch (Exception ex) {
#if LOG4NET
Expand Down

0 comments on commit b69a423

Please sign in to comment.