using System;
using System.Threading;
namespace Renci.SshNet.Common
{
///
/// Light implementation of SemaphoreSlim.
///
public class SemaphoreLight
{
private readonly object _lock = new object();
private int _currentCount;
///
/// Initializes a new instance of the class, specifying
/// the initial number of requests that can be granted concurrently.
///
/// The initial number of requests for the semaphore that can be granted concurrently.
/// is a negative number.
public SemaphoreLight(int initialCount)
{
if (initialCount < 0 )
throw new ArgumentOutOfRangeException("initialCount", "The value cannot be negative.");
_currentCount = initialCount;
}
///
/// Gets the current count of the .
///
public int CurrentCount { get { return _currentCount; } }
///
/// Exits the once.
///
/// The previous count of the .
public int Release()
{
return Release(1);
}
///
/// Exits the a specified number of times.
///
/// The number of times to exit the semaphore.
/// The previous count of the .
public int Release(int releaseCount)
{
var oldCount = _currentCount;
lock (_lock)
{
_currentCount += releaseCount;
Monitor.Pulse(_lock);
}
return oldCount;
}
///
/// Blocks the current thread until it can enter the .
///
public void Wait()
{
lock (_lock)
{
while (_currentCount < 1)
{
Monitor.Wait(_lock);
}
_currentCount--;
Monitor.Pulse(_lock);
}
}
///
/// Blocks the current thread until it can either enter the ,
/// or until the specified timeout has expired.
///
///
///
public bool Wait(TimeSpan timeout)
{
var timeoutInMilliseconds = timeout.TotalMilliseconds;
if (timeoutInMilliseconds < -1d || timeoutInMilliseconds > int.MaxValue)
throw new ArgumentOutOfRangeException("timeout", "The timeout must represent a value between -1 and Int32.MaxValue, inclusive.");
lock (_lock)
{
if (timeoutInMilliseconds == -1)
{
while (_currentCount < 1)
Monitor.Wait(_lock);
}
else
{
if (_currentCount < 1)
{
var remainingTimeInMilliseconds = (int) 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--;
Monitor.Pulse(_lock);
return true;
}
}
}
}