Pārlūkot izejas kodu

Avoid race conditions when signaling events or setting waithandles. Remove empty lines.
Fixed event handler leak for Closed event on Channel.

Gert Driesen 11 gadi atpakaļ
vecāks
revīzija
07d575e78a
1 mainītis faili ar 28 papildinājumiem un 20 dzēšanām
  1. 28 20
      Renci.SshClient/Renci.SshNet/SubsystemSession.cs

+ 28 - 20
Renci.SshClient/Renci.SshNet/SubsystemSession.cs

@@ -1,9 +1,9 @@
 using System;
+using System.Globalization;
 using System.Text;
 using System.Threading;
 using Renci.SshNet.Channels;
 using Renci.SshNet.Common;
-using System.Globalization;
 
 namespace Renci.SshNet.Sftp
 {
@@ -13,15 +13,10 @@ namespace Renci.SshNet.Sftp
     public abstract class SubsystemSession : IDisposable
     {
         private readonly Session _session;
-
         private readonly string _subsystemName;
-
         private ChannelSession _channel;
-
         private Exception _exception;
-
         private EventWaitHandle _errorOccuredWaitHandle = new ManualResetEvent(false);
-
         private EventWaitHandle _channelClosedWaitHandle = new ManualResetEvent(false);
 
         /// <summary>
@@ -99,7 +94,6 @@ namespace Renci.SshNet.Sftp
         public void Disconnect()
         {
             this._channel.SendEof();
-
             this._channel.Close();
         }
 
@@ -132,12 +126,10 @@ namespace Renci.SshNet.Sftp
         {
             this._exception = error;
 
-            this._errorOccuredWaitHandle.Set();
-
-            if (this.ErrorOccurred != null)
-            {
-                this.ErrorOccurred(this, new ExceptionEventArgs(error));
-            }
+            var errorOccuredWaitHandle = _errorOccuredWaitHandle;
+            if (errorOccuredWaitHandle != null)
+                errorOccuredWaitHandle.Set();
+            SignalErrorOccurred(error);
         }
 
         private void Channel_DataReceived(object sender, ChannelDataEventArgs e)
@@ -147,7 +139,9 @@ namespace Renci.SshNet.Sftp
 
         private void Channel_Closed(object sender, ChannelEventArgs e)
         {
-            this._channelClosedWaitHandle.Set();
+            var channelClosedWaitHandle = _channelClosedWaitHandle;
+            if (channelClosedWaitHandle != null)
+                channelClosedWaitHandle.Set();
         }
 
         internal void WaitOnHandle(WaitHandle waitHandle, TimeSpan operationTimeout)
@@ -172,11 +166,7 @@ namespace Renci.SshNet.Sftp
 
         private void Session_Disconnected(object sender, EventArgs e)
         {
-            if (this.Disconnected != null)
-            {
-                this.Disconnected(this, new EventArgs());
-            }
-
+            SignalDisconnected();
             this.RaiseError(new SshException("Connection was lost"));
         }
 
@@ -185,6 +175,24 @@ namespace Renci.SshNet.Sftp
             this.RaiseError(e.Exception);
         }
 
+        private void SignalErrorOccurred(Exception error)
+        {
+            var errorOccurred = ErrorOccurred;
+            if (errorOccurred != null)
+            {
+                errorOccurred(this, new ExceptionEventArgs(error));
+            }
+        }
+
+        private void SignalDisconnected()
+        {
+            var disconnected = Disconnected;
+            if (disconnected != null)
+            {
+                disconnected(this, new EventArgs());
+            }
+        }
+
         #region IDisposable Members
 
         private bool _isDisposed;
@@ -195,7 +203,6 @@ namespace Renci.SshNet.Sftp
         public void Dispose()
         {
             Dispose(true);
-
             GC.SuppressFinalize(this);
         }
 
@@ -211,6 +218,7 @@ namespace Renci.SshNet.Sftp
                 if (this._channel != null)
                 {
                     this._channel.DataReceived -= Channel_DataReceived;
+                    this._channel.Closed -= Channel_Closed;
                     this._channel.Dispose();
                     this._channel = null;
                 }