Replace SemaphoreLight with SemaphoreSlim (#1265)

This paves the way for asynchronous synchronisation via WaitAsync
(and eliminates a timing test which sometimes fails in CI)

Co-authored-by: Wojciech Nagórski <wojtpl2@gmail.com>
This commit is contained in:
Rob Hague
2023-12-09 08:52:31 +01:00
committed by GitHub
parent 4c4883eed0
commit f45af38628
23 changed files with 46 additions and 384 deletions
+1 -1
View File
@@ -285,7 +285,7 @@ namespace Renci.SshNet.Channels
/// Gets the session semaphore to control number of session channels.
/// </summary>
/// <value>The session semaphore.</value>
protected SemaphoreLight SessionSemaphore
protected SemaphoreSlim SessionSemaphore
{
get { return _session.SessionSemaphore; }
}
-244
View File
@@ -1,244 +0,0 @@
using System;
using System.Threading;
namespace Renci.SshNet.Common
{
/// <summary>
/// Light implementation of SemaphoreSlim.
/// </summary>
public sealed class SemaphoreLight : IDisposable
{
private readonly object _lock = new object();
private ManualResetEvent _waitHandle;
private int _currentCount;
/// <summary>
/// Initializes a new instance of the <see cref="SemaphoreLight"/> class, specifying the initial number of requests that can
/// be granted concurrently.
/// </summary>
/// <param name="initialCount">The initial number of requests for the semaphore that can be granted concurrently.</param>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="initialCount"/> is a negative number.</exception>
public SemaphoreLight(int initialCount)
{
if (initialCount < 0)
{
throw new ArgumentOutOfRangeException(nameof(initialCount), "The value cannot be negative.");
}
_currentCount = initialCount;
}
/// <summary>
/// Gets the current count of the <see cref="SemaphoreLight"/>.
/// </summary>
public int CurrentCount
{
get { return _currentCount; }
}
/// <summary>
/// Gets a <see cref="WaitHandle"/> that can be used to wait on the semaphore.
/// </summary>
/// <value>
/// A <see cref="WaitHandle"/> that can be used to wait on the semaphore.
/// </value>
/// <remarks>
/// A successful wait on the <see cref="AvailableWaitHandle"/> does not imply a successful
/// wait on the <see cref="SemaphoreLight"/> itself. It should be followed by a true wait
/// on the semaphore.
/// </remarks>
public WaitHandle AvailableWaitHandle
{
get
{
if (_waitHandle is null)
{
lock (_lock)
{
_waitHandle ??= new ManualResetEvent(_currentCount > 0);
}
}
return _waitHandle;
}
}
/// <summary>
/// Exits the <see cref="SemaphoreLight"/> once.
/// </summary>
/// <returns>The previous count of the <see cref="SemaphoreLight"/>.</returns>
public int Release()
{
return Release(1);
}
/// <summary>
/// Exits the <see cref="SemaphoreLight"/> a specified number of times.
/// </summary>
/// <param name="releaseCount">The number of times to exit the semaphore.</param>
/// <returns>
/// The previous count of the <see cref="SemaphoreLight"/>.
/// </returns>
public int Release(int releaseCount)
{
lock (_lock)
{
var oldCount = _currentCount;
_currentCount += releaseCount;
// signal waithandle when the original semaphore count was zero
if (_waitHandle != null && oldCount == 0)
{
_ = _waitHandle.Set();
}
Monitor.PulseAll(_lock);
return oldCount;
}
}
/// <summary>
/// Blocks the current thread until it can enter the <see cref="SemaphoreLight"/>.
/// </summary>
public void Wait()
{
lock (_lock)
{
while (_currentCount < 1)
{
_ = Monitor.Wait(_lock);
}
_currentCount--;
// unsignal waithandle when the semaphore count reaches zero
if (_waitHandle != null && _currentCount == 0)
{
_ = _waitHandle.Reset();
}
Monitor.PulseAll(_lock);
}
}
/// <summary>
/// Blocks the current thread until it can enter the <see cref="SemaphoreLight"/>, using a 32-bit signed
/// integer that specifies the timeout.
/// </summary>
/// <param name="millisecondsTimeout">The number of milliseconds to wait, or Infinite(-1) to wait indefinitely.</param>
/// <returns>
/// <see langword="true"/> if the current thread successfully entered the <see cref="SemaphoreLight"/>; otherwise, <see langword="false"/>.
/// </returns>
public bool Wait(int millisecondsTimeout)
{
if (millisecondsTimeout < -1)
{
throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), "The timeout must represent a value between -1 and Int32.MaxValue, inclusive.");
}
return WaitWithTimeout(millisecondsTimeout);
}
/// <summary>
/// Blocks the current thread until it can enter the <see cref="SemaphoreLight"/>, using a <see cref="TimeSpan"/>
/// to specify the timeout.
/// </summary>
/// <param name="timeout">A <see cref="TimeSpan"/> that represents the number of milliseconds to wait, or a <see cref="TimeSpan"/> that represents -1 milliseconds to wait indefinitely.</param>
/// <returns>
/// <see langword="true"/> if the current thread successfully entered the <see cref="SemaphoreLight"/>; otherwise, <see langword="false"/>.
/// </returns>
public bool Wait(TimeSpan timeout)
{
var timeoutInMilliseconds = timeout.TotalMilliseconds;
if (timeoutInMilliseconds is < -1d or > int.MaxValue)
{
throw new ArgumentOutOfRangeException(nameof(timeout), "The timeout must represent a value between -1 and Int32.MaxValue, inclusive.");
}
return WaitWithTimeout((int) timeoutInMilliseconds);
}
private bool WaitWithTimeout(int timeoutInMilliseconds)
{
lock (_lock)
{
if (timeoutInMilliseconds == Session.Infinite)
{
while (_currentCount < 1)
{
_ = Monitor.Wait(_lock);
}
}
else
{
if (_currentCount < 1)
{
if (timeoutInMilliseconds > 0)
{
return false;
}
var remainingTimeInMilliseconds = timeoutInMilliseconds;
var startTicks = Environment.TickCount;
while (_currentCount < 1)
{
if (!Monitor.Wait(_lock, remainingTimeInMilliseconds))
{
return false;
}
var elapsed = Environment.TickCount - startTicks;
remainingTimeInMilliseconds -= elapsed;
if (remainingTimeInMilliseconds < 0)
{
return false;
}
}
}
}
_currentCount--;
// unsignal waithandle when the semaphore count is zero
if (_waitHandle != null && _currentCount == 0)
{
_ = _waitHandle.Reset();
}
Monitor.PulseAll(_lock);
return true;
}
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
/// <param name="disposing"><see langword="true"/> to release both managed and unmanaged resources; <see langword="false"/> to release only unmanaged resources.</param>
private void Dispose(bool disposing)
{
if (disposing)
{
var waitHandle = _waitHandle;
if (waitHandle is not null)
{
waitHandle.Dispose();
_waitHandle = null;
}
}
}
}
}
+1 -1
View File
@@ -36,7 +36,7 @@ namespace Renci.SshNet
/// <value>
/// The session semaphore.
/// </value>
SemaphoreLight SessionSemaphore { get; }
SemaphoreSlim SessionSemaphore { get; }
/// <summary>
/// Gets a <see cref="WaitHandle"/> that can be used to wait for the message listener loop to complete.
+4 -4
View File
@@ -87,7 +87,7 @@ namespace Renci.SshNet
/// <remarks>
/// Some server may restrict number to prevent authentication attacks.
/// </remarks>
private static readonly SemaphoreLight AuthenticationConnection = new SemaphoreLight(3);
private static readonly SemaphoreSlim AuthenticationConnection = new SemaphoreSlim(3);
/// <summary>
/// Holds the factory to use for creating new services.
@@ -196,7 +196,7 @@ namespace Renci.SshNet
private Compressor _clientCompression;
private SemaphoreLight _sessionSemaphore;
private SemaphoreSlim _sessionSemaphore;
private bool _isDisconnectMessageSent;
@@ -213,7 +213,7 @@ namespace Renci.SshNet
/// <value>
/// The session semaphore.
/// </value>
public SemaphoreLight SessionSemaphore
public SemaphoreSlim SessionSemaphore
{
get
{
@@ -221,7 +221,7 @@ namespace Renci.SshNet
{
lock (_connectAndLazySemaphoreInitLock)
{
_sessionSemaphore ??= new SemaphoreLight(ConnectionInfo.MaxSessions);
_sessionSemaphore ??= new SemaphoreSlim(ConnectionInfo.MaxSessions);
}
}
+2 -2
View File
@@ -16,7 +16,7 @@ namespace Renci.SshNet.Sftp
private readonly byte[] _handle;
private readonly ISftpSession _sftpSession;
private readonly uint _chunkSize;
private readonly SemaphoreLight _semaphore;
private readonly SemaphoreSlim _semaphore;
private readonly object _readLock;
private readonly ManualResetEvent _disposingWaitHandle;
private readonly ManualResetEvent _readAheadCompleted;
@@ -62,7 +62,7 @@ namespace Renci.SshNet.Sftp
_sftpSession = sftpSession;
_chunkSize = chunkSize;
_fileSize = fileSize;
_semaphore = new SemaphoreLight(maxPendingReads);
_semaphore = new SemaphoreSlim(maxPendingReads);
_queue = new Dictionary<int, BufferedRead>(maxPendingReads);
_readLock = new object();
_readAheadCompleted = new ManualResetEvent(initialState: false);
@@ -23,7 +23,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
private uint _remotePacketSize;
private uint _remoteChannelNumber;
private TimeSpan _channelCloseTimeout;
private SemaphoreLight _sessionSemaphore;
private SemaphoreSlim _sessionSemaphore;
private IList<ChannelEventArgs> _channelClosedRegister;
private List<ExceptionEventArgs> _channelExceptionRegister;
@@ -38,7 +38,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
_remoteWindowSize = (uint)random.Next(0, int.MaxValue);
_remotePacketSize = (uint)random.Next(100, 200);
_channelCloseTimeout = TimeSpan.FromSeconds(random.Next(10, 20));
_sessionSemaphore = new SemaphoreLight(1);
_sessionSemaphore = new SemaphoreSlim(1);
_channelClosedRegister = new List<ChannelEventArgs>();
_channelExceptionRegister = new List<ExceptionEventArgs>();
}
@@ -24,7 +24,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
private List<ExceptionEventArgs> _channelExceptionRegister;
private ChannelSession _channel;
private MockSequence _sequence;
private SemaphoreLight _sessionSemaphore;
private SemaphoreSlim _sessionSemaphore;
private int _initialSessionSemaphoreCount;
protected override void SetupData()
@@ -41,7 +41,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
_channelClosedRegister = new List<ChannelEventArgs>();
_channelExceptionRegister = new List<ExceptionEventArgs>();
_initialSessionSemaphoreCount = random.Next(10, 20);
_sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount);
_sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount);
}
protected override void SetupMocks()
@@ -22,7 +22,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
private List<ExceptionEventArgs> _channelExceptionRegister;
private ChannelSession _channel;
private MockSequence _sequence;
private SemaphoreLight _sessionSemaphore;
private SemaphoreSlim _sessionSemaphore;
private int _initialSessionSemaphoreCount;
protected override void SetupData()
@@ -38,7 +38,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
_channelClosedRegister = new List<ChannelEventArgs>();
_channelExceptionRegister = new List<ExceptionEventArgs>();
_initialSessionSemaphoreCount = random.Next(10, 20);
_sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount);
_sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount);
}
protected override void SetupMocks()
@@ -126,4 +126,4 @@ namespace Renci.SshNet.Tests.Classes.Channels
Assert.IsFalse(_channel.IsOpen);
}
}
}
}
@@ -23,7 +23,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
private IList<ChannelEventArgs> _channelClosedRegister;
private List<ExceptionEventArgs> _channelExceptionRegister;
private ChannelSession _channel;
private SemaphoreLight _sessionSemaphore;
private SemaphoreSlim _sessionSemaphore;
private int _initialSessionSemaphoreCount;
protected override void SetupData()
@@ -40,7 +40,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
_channelClosedRegister = new List<ChannelEventArgs>();
_channelExceptionRegister = new List<ExceptionEventArgs>();
_initialSessionSemaphoreCount = random.Next(10, 20);
_sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount);
_sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount);
}
protected override void SetupMocks()
@@ -134,4 +134,4 @@ namespace Renci.SshNet.Tests.Classes.Channels
Assert.IsFalse(_channel.IsOpen);
}
}
}
}
@@ -22,7 +22,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
private List<ExceptionEventArgs> _channelExceptionRegister;
private ChannelSession _channel;
private MockSequence _sequence;
private SemaphoreLight _sessionSemaphore;
private SemaphoreSlim _sessionSemaphore;
private int _initialSessionSemaphoreCount;
protected override void SetupData()
@@ -38,7 +38,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
_channelClosedRegister = new List<ChannelEventArgs>();
_channelExceptionRegister = new List<ExceptionEventArgs>();
_initialSessionSemaphoreCount = random.Next(10, 20);
_sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount);
_sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount);
}
protected override void SetupMocks()
@@ -23,7 +23,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
private IList<ChannelEventArgs> _channelClosedRegister;
private List<ExceptionEventArgs> _channelExceptionRegister;
private ChannelSession _channel;
private SemaphoreLight _sessionSemaphore;
private SemaphoreSlim _sessionSemaphore;
private int _initialSessionSemaphoreCount;
protected override void SetupData()
@@ -40,7 +40,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
_channelClosedRegister = new List<ChannelEventArgs>();
_channelExceptionRegister = new List<ExceptionEventArgs>();
_initialSessionSemaphoreCount = random.Next(10, 20);
_sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount);
_sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount);
}
protected override void SetupMocks()
@@ -22,7 +22,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
private List<ExceptionEventArgs> _channelExceptionRegister;
private ChannelSession _channel;
private MockSequence _sequence;
private SemaphoreLight _sessionSemaphore;
private SemaphoreSlim _sessionSemaphore;
private int _initialSessionSemaphoreCount;
protected override void SetupData()
@@ -38,7 +38,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
_channelClosedRegister = new List<ChannelEventArgs>();
_channelExceptionRegister = new List<ExceptionEventArgs>();
_initialSessionSemaphoreCount = random.Next(10, 20);
_sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount);
_sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount);
}
protected override void SetupMocks()
@@ -22,7 +22,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
private IList<ChannelEventArgs> _channelClosedRegister;
private List<ExceptionEventArgs> _channelExceptionRegister;
private ChannelSession _channel;
private SemaphoreLight _sessionSemaphore;
private SemaphoreSlim _sessionSemaphore;
private int _initialSessionSemaphoreCount;
protected override void SetupData()
@@ -39,7 +39,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
_channelClosedRegister = new List<ChannelEventArgs>();
_channelExceptionRegister = new List<ExceptionEventArgs>();
_initialSessionSemaphoreCount = random.Next(10, 20);
_sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount);
_sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount);
}
protected override void SetupMocks()
@@ -20,7 +20,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
private uint _remotePacketSize;
private uint _remoteChannelNumber;
private TimeSpan _channelCloseTimeout;
private SemaphoreLight _sessionSemaphore;
private SemaphoreSlim _sessionSemaphore;
private IList<ChannelEventArgs> _channelClosedRegister;
private List<ExceptionEventArgs> _channelExceptionRegister;
@@ -35,7 +35,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
_remoteWindowSize = (uint) random.Next(0, int.MaxValue);
_remotePacketSize = (uint) random.Next(100, 200);
_channelCloseTimeout = TimeSpan.FromSeconds(random.Next(10, 20));
_sessionSemaphore = new SemaphoreLight(1);
_sessionSemaphore = new SemaphoreSlim(1);
_channelClosedRegister = new List<ChannelEventArgs>();
_channelExceptionRegister = new List<ExceptionEventArgs>();
}
@@ -142,4 +142,4 @@ namespace Renci.SshNet.Tests.Classes.Channels
Assert.IsFalse(_channel.IsOpen);
}
}
}
}
@@ -20,7 +20,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
private uint _remotePacketSize;
private uint _remoteChannelNumber;
private TimeSpan _channelCloseTimeout;
private SemaphoreLight _sessionSemaphore;
private SemaphoreSlim _sessionSemaphore;
private IList<ChannelEventArgs> _channelClosedRegister;
private List<ExceptionEventArgs> _channelExceptionRegister;
@@ -35,7 +35,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
_remoteWindowSize = (uint) random.Next(0, int.MaxValue);
_remotePacketSize = (uint) random.Next(100, 200);
_channelCloseTimeout = TimeSpan.FromSeconds(random.Next(10, 20));
_sessionSemaphore = new SemaphoreLight(1);
_sessionSemaphore = new SemaphoreSlim(1);
_channelClosedRegister = new List<ChannelEventArgs>();
_channelExceptionRegister = new List<ExceptionEventArgs>();
}
@@ -22,7 +22,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
private List<ExceptionEventArgs> _channelExceptionRegister;
private ChannelSession _channel;
private MockSequence _sequence;
private SemaphoreLight _sessionSemaphore;
private SemaphoreSlim _sessionSemaphore;
private int _initialSessionSemaphoreCount;
protected override void SetupData()
@@ -38,7 +38,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
_channelClosedRegister = new List<ChannelEventArgs>();
_channelExceptionRegister = new List<ExceptionEventArgs>();
_initialSessionSemaphoreCount = random.Next(10, 20);
_sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount);
_sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount);
}
protected override void SetupMocks()
@@ -22,7 +22,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
private List<ExceptionEventArgs> _channelExceptionRegister;
private ChannelSession _channel;
private MockSequence _sequence;
private SemaphoreLight _sessionSemaphore;
private SemaphoreSlim _sessionSemaphore;
private int _initialSessionSemaphoreCount;
protected override void SetupData()
@@ -38,7 +38,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
_channelClosedRegister = new List<ChannelEventArgs>();
_channelExceptionRegister = new List<ExceptionEventArgs>();
_initialSessionSemaphoreCount = random.Next(10, 20);
_sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount);
_sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount);
}
protected override void SetupMocks()
@@ -22,7 +22,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
private List<ExceptionEventArgs> _channelExceptionRegister;
private ChannelSession _channel;
private MockSequence _sequence;
private SemaphoreLight _sessionSemaphore;
private SemaphoreSlim _sessionSemaphore;
private int _initialSessionSemaphoreCount;
protected override void SetupData()
@@ -38,7 +38,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
_channelClosedRegister = new List<ChannelEventArgs>();
_channelExceptionRegister = new List<ExceptionEventArgs>();
_initialSessionSemaphoreCount = random.Next(10, 20);
_sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount);
_sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount);
}
protected override void SetupMocks()
@@ -24,7 +24,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
private List<ExceptionEventArgs> _channelExceptionRegister;
private ChannelSession _channel;
private MockSequence _sequence;
private SemaphoreLight _sessionSemaphore;
private SemaphoreSlim _sessionSemaphore;
private int _initialSessionSemaphoreCount;
protected override void SetupData()
@@ -41,7 +41,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
_channelClosedRegister = new List<ChannelEventArgs>();
_channelExceptionRegister = new List<ExceptionEventArgs>();
_initialSessionSemaphoreCount = random.Next(10, 20);
_sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount);
_sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount);
}
protected override void SetupMocks()
@@ -18,7 +18,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
private uint _localPacketSize;
private IList<ChannelEventArgs> _channelClosedRegister;
private List<ExceptionEventArgs> _channelExceptionRegister;
private SemaphoreLight _sessionSemaphore;
private SemaphoreSlim _sessionSemaphore;
private int _initialSessionSemaphoreCount;
private Exception _waitOnConfirmationException;
private SystemException _actualException;
@@ -31,7 +31,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
_localWindowSize = (uint) random.Next(2000, 3000);
_localPacketSize = (uint) random.Next(1000, 2000);
_initialSessionSemaphoreCount = random.Next(10, 20);
_sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount);
_sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount);
_channelClosedRegister = new List<ChannelEventArgs>();
_channelExceptionRegister = new List<ExceptionEventArgs>();
_waitOnConfirmationException = new SystemException();
@@ -19,7 +19,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
private uint _localPacketSize;
private IList<ChannelEventArgs> _channelClosedRegister;
private List<ExceptionEventArgs> _channelExceptionRegister;
private SemaphoreLight _sessionSemaphore;
private SemaphoreSlim _sessionSemaphore;
private int _initialSessionSemaphoreCount;
private uint _failureReasonCode;
private string _failureDescription;
@@ -34,7 +34,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
_localWindowSize = (uint) random.Next(2000, 3000);
_localPacketSize = (uint) random.Next(1000, 2000);
_initialSessionSemaphoreCount = random.Next(10, 20);
_sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount);
_sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount);
_channelClosedRegister = new List<ChannelEventArgs>();
_channelExceptionRegister = new List<ExceptionEventArgs>();
_actualException = null;
@@ -22,7 +22,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
private uint _remotePacketSize;
private IList<ChannelEventArgs> _channelClosedRegister;
private List<ExceptionEventArgs> _channelExceptionRegister;
private SemaphoreLight _sessionSemaphore;
private SemaphoreSlim _sessionSemaphore;
private int _initialSessionSemaphoreCount;
private uint _failureReasonCode;
private string _failureDescription;
@@ -39,7 +39,7 @@ namespace Renci.SshNet.Tests.Classes.Channels
_remoteWindowSize = (uint) random.Next(0, int.MaxValue);
_remotePacketSize = (uint) random.Next(0, int.MaxValue);
_initialSessionSemaphoreCount = random.Next(10, 20);
_sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount);
_sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount);
_channelClosedRegister = new List<ChannelEventArgs>();
_channelExceptionRegister = new List<ExceptionEventArgs>();
@@ -147,4 +147,4 @@ namespace Renci.SshNet.Tests.Classes.Channels
Assert.IsTrue(_channel.IsOpen);
}
}
}
}
@@ -1,94 +0,0 @@
using System;
using System.Diagnostics;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Renci.SshNet.Common;
using Renci.SshNet.Tests.Common;
namespace Renci.SshNet.Tests.Classes.Common
{
[TestClass]
public class SemaphoreLightTest : TestBase
{
[TestMethod]
public void SemaphoreLightConstructorTest()
{
var initialCount = new Random().Next(1, 10);
var target = new SemaphoreLight(initialCount);
Assert.AreEqual(initialCount, target.CurrentCount);
}
[TestMethod]
public void Release()
{
var initialCount = new Random().Next(1, 10);
var target = new SemaphoreLight(initialCount);
Assert.AreEqual(initialCount, target.Release());
Assert.AreEqual(initialCount + 1, target.CurrentCount);
Assert.AreEqual(initialCount + 1, target.Release());
Assert.AreEqual(initialCount + 2, target.CurrentCount);
}
/// <summary>
///A test for Release
///</summary>
[TestMethod]
public void Release_ReleaseCount()
{
var initialCount = new Random().Next(1, 10);
var target = new SemaphoreLight(initialCount);
var releaseCount1 = new Random().Next(1, 10);
Assert.AreEqual(initialCount, target.Release(releaseCount1));
Assert.AreEqual(initialCount + releaseCount1, target.CurrentCount);
var releaseCount2 = new Random().Next(1, 10);
Assert.AreEqual(initialCount + releaseCount1, target.Release(releaseCount2));
Assert.AreEqual(initialCount + releaseCount1 + releaseCount2, target.CurrentCount);
}
/// <summary>
///A test for Wait
///</summary>
[TestMethod]
public void WaitTest()
{
const int sleepTime = 200;
const int initialCount = 2;
var target = new SemaphoreLight(initialCount);
var watch = new Stopwatch();
watch.Start();
target.Wait();
target.Wait();
Assert.IsTrue(watch.ElapsedMilliseconds < 50);
var releaseThread = new Thread(() =>
{
Thread.Sleep(sleepTime);
_ = target.Release();
});
releaseThread.Start();
target.Wait();
watch.Stop();
Assert.IsTrue(watch.ElapsedMilliseconds >= 200);
Assert.IsTrue(watch.ElapsedMilliseconds < 250);
}
[TestMethod]
public void CurrentCountTest()
{
var initialCount = new Random().Next(1, 20);
var target = new SemaphoreLight(initialCount);
Assert.AreEqual(initialCount, target.CurrentCount);
}
}
}